From 9f40befc229da12294019d182e8e54fddcbf9395 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 30 Mar 2023 12:37:22 -0400 Subject: [PATCH 01/58] Fix ASKEM integration workflow --- .github/workflows/integration-issues.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/integration-issues.yml b/.github/workflows/integration-issues.yml index 31afbf47..2c2db6c2 100644 --- a/.github/workflows/integration-issues.yml +++ b/.github/workflows/integration-issues.yml @@ -5,6 +5,7 @@ on: types: - reopened - opened + - labeled jobs: add-to-project: From e855ae5483567e0e23724a3c5eacdb3045a7d601 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 29 Mar 2023 14:09:16 -0400 Subject: [PATCH 02/58] initial work on petri nets with metadata --- src/AlgebraicPetri.jl | 200 +++++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 82 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index d716ace8..3405a7bc 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -12,7 +12,8 @@ export SchPetriNet, PetriNet, OpenPetriNetOb, AbstractPetriNet, ns, nt, ni, no, SchLabelledReactionNet, LabelledReactionNet, AbstractLabelledReactionNet, Open, OpenPetriNet, OpenLabelledPetriNet, OpenReactionNet, OpenLabelledReactionNet, OpenPetriNetOb, OpenLabelledPetriNetOb, OpenReactionNetOb, OpenLabelledReactionNetOb, - mca, flatten_labels + mca, flatten_labels, + SchPropertyPetriNet, AbstractPropertyPetriNet, PropertyPetriNet, sprop, tprop, sprops, tprops using Catlab using Catlab.CategoricalAlgebra @@ -29,6 +30,14 @@ vectorify(n) = [n] state_dict(n) = Dict(s => i for (i, s) in enumerate(n)) +""" Abstract type for C-sets that contain a petri net. + +This type encompasses C-sets where the schema for graphs is a subcategory of C. +This includes, for example, graphs, symmetric graphs, and reflexive graphs, but +not half-edge graphs. +""" +@abstract_acset_type HasPetriNet + # Petri Nets ############ @@ -48,7 +57,7 @@ See Catlab.jl documentation for description of the @present syntax. os::Hom(O, S) end -@abstract_acset_type AbstractPetriNet +@abstract_acset_type AbstractPetriNet <: HasPetriNet @acset_type PetriNet(SchPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet const OpenPetriNetOb, OpenPetriNet = OpenCSetTypes(PetriNet, :S) @@ -60,19 +69,19 @@ the cospan. The OpenPetriNet can be composed over an undirected wiring diagram [blog post](https://www.algebraicjulia.org/blog/post/2020/11/structured-cospans-2/) for a description of this compositional tooling) """ -Open(p::AbstractPetriNet) = OpenPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) +Open(p::HasPetriNet) = OpenPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) """ Open(p::AbstractPetriNet, legs...) Generates on OpenPetriNet with legs bundled as described by `legs` """ -Open(p::AbstractPetriNet, legs...) = OpenPetriNet(p, map(l -> FinFunction(l, ns(p)), legs)...) +Open(p::HasPetriNet, legs...) = OpenPetriNet(p, map(l -> FinFunction(l, ns(p)), legs)...) """ Open(n, p::AbstractPetriNet, m) Generates on OpenPetriNet with two legs, `n` and `m` """ -Open(n, p::AbstractPetriNet, m) = Open(p, n, m) +Open(n, p::HasPetriNet, m) = Open(p, n, m) """ PetriNet(n::Int, ts::Vararg{Union{Pair,Tuple}}) @@ -98,54 +107,60 @@ PetriNet(n::Int, ts::Vararg{Union{Pair,Tuple}}) = begin p end +function (::Type{T})(pn::HasPetriNet) where T <: HasPetriNet + pn′ = T() + copy_parts!(pn′, pn) + pn′ +end + """ Number of states in a Petri net """ -ns(p::AbstractPetriNet) = nparts(p, :S) +ns(p::HasPetriNet) = nparts(p, :S) """ Number of transitions in a Petri net """ -nt(p::AbstractPetriNet) = nparts(p, :T) +nt(p::HasPetriNet) = nparts(p, :T) """ Number of input relationships in a Petri net """ -ni(p::AbstractPetriNet) = nparts(p, :I) +ni(p::HasPetriNet) = nparts(p, :I) """ Number of output relationships in a Petri net """ -no(p::AbstractPetriNet) = nparts(p, :O) +no(p::HasPetriNet) = nparts(p, :O) -is(p::AbstractPetriNet, args...) = subpart(p, args..., :is) -os(p::AbstractPetriNet, args...) = subpart(p, args..., :os) -it(p::AbstractPetriNet, args...) = subpart(p, args..., :it) -ot(p::AbstractPetriNet, args...) = subpart(p, args..., :ot) +is(p::HasPetriNet, args...) = subpart(p, args..., :is) +os(p::HasPetriNet, args...) = subpart(p, args..., :os) +it(p::HasPetriNet, args...) = subpart(p, args..., :it) +ot(p::HasPetriNet, args...) = subpart(p, args..., :ot) """ Add a species to the Petri net. Label and concentration can be provided depending on the kind of Petri net. Returns the ID of the species """ -add_species!(p::AbstractPetriNet; kw...) = add_part!(p, :S; kw...) +add_species!(p::HasPetriNet; kw...) = add_part!(p, :S; kw...) """ Add `n` species to the Petri net. Label and concentration can be provided depending on the kind of Petri net. Returns the ID of the species """ -add_species!(p::AbstractPetriNet, n; kw...) = add_parts!(p, :S, n; kw...) +add_species!(p::HasPetriNet, n; kw...) = add_parts!(p, :S, n; kw...) """ Add a transition to the Petri net. Label and rate can be provided depending on the kind of Petri net. Returns the ID of the transition """ -add_transition!(p::AbstractPetriNet; kw...) = add_part!(p, :T; kw...) +add_transition!(p::HasPetriNet; kw...) = add_part!(p, :T; kw...) """ Add `n` transitions to the Petri net. Label and rate can be provided depending on the kind of Petri net. Returns the ID of the transition """ -add_transitions!(p::AbstractPetriNet, n; kw...) = add_parts!(p, :T, n; kw...) +add_transitions!(p::HasPetriNet, n; kw...) = add_parts!(p, :T, n; kw...) """ add_input!(p::AbstractPetriNet,t,s;kw...) @@ -153,7 +168,7 @@ Add an input relationship to the Petri net between the transition `t` and specie Returns the ID of the input relationship """ -add_input!(p::AbstractPetriNet, t, s; kw...) = add_part!(p, :I; it=t, is=s, kw...) +add_input!(p::HasPetriNet, t, s; kw...) = add_part!(p, :I; it=t, is=s, kw...) """ add_inputs!(p::AbstractPetriNet,n,t,s;kw...) @@ -161,7 +176,7 @@ Add input relationships to the Petri net between the transitions `t` and species Returns the ID of the input relationship """ -add_inputs!(p::AbstractPetriNet, n, t, s; kw...) = add_parts!(p, :I, n; it=t, is=s, kw...) +add_inputs!(p::HasPetriNet, n, t, s; kw...) = add_parts!(p, :I, n; it=t, is=s, kw...) """ add_output!(p::AbstractPetriNet,t,s;kw...) @@ -169,7 +184,7 @@ Add an output relationship to the Petri net between the transition `t` and speci Returns the ID of the input relationship """ -add_output!(p::AbstractPetriNet, t, s; kw...) = add_part!(p, :O; ot=t, os=s, kw...) +add_output!(p::HasPetriNet, t, s; kw...) = add_part!(p, :O; ot=t, os=s, kw...) """ add_outputs!(p::AbstractPetriNet,n,t,s;kw...) @@ -177,41 +192,41 @@ Add output relationships to the Petri net between the transitions `t` and specie Returns the ID of the input relationship """ -add_outputs!(p::AbstractPetriNet, n, t, s; kw...) = add_parts!(p, :O, n; ot=t, os=s, kw...) +add_outputs!(p::HasPetriNet, n, t, s; kw...) = add_parts!(p, :O, n; ot=t, os=s, kw...) """ Name of species Note that this returns an index if labels are not present in the PetriNet """ -sname(p::AbstractPetriNet, s) = (1:ns(p))[s] +sname(p::HasPetriNet, s) = (1:ns(p))[s] """ Name of transition Note that this returns an index if labels are not present in the PetriNet """ -tname(p::AbstractPetriNet, t) = (1:nt(p))[t] +tname(p::HasPetriNet, t) = (1:nt(p))[t] """ Names of species in a Petri net Note that this returns indices if labels are not present in the PetriNet """ -snames(p::AbstractPetriNet) = map(s -> sname(p, s), 1:ns(p)) +snames(p::HasPetriNet) = map(s -> sname(p, s), 1:ns(p)) """ Names of transitions in a Petri net Note that this returns indices if labels are not present in the PetriNet """ -tnames(p::AbstractPetriNet) = map(t -> tname(p, t), 1:nt(p)) +tnames(p::HasPetriNet) = map(t -> tname(p, t), 1:nt(p)) # Note: although indexing makes this pretty fast, it is often faster to bulk-convert # the PetriNet net into a transition matrix, if you are working with all of the transitions """ Input relationships for a transition """ -inputs(p::AbstractPetriNet, t) = subpart(p, incident(p, t, :it), :is) +inputs(p::HasPetriNet, t) = subpart(p, incident(p, t, :it), :is) """ Output relationships for a transition """ -outputs(p::AbstractPetriNet, t) = subpart(p, incident(p, t, :ot), :os) +outputs(p::HasPetriNet, t) = subpart(p, incident(p, t, :ot), :os) """ TransitionMatrices @@ -222,7 +237,7 @@ Petri net. struct TransitionMatrices input::Matrix{Int} output::Matrix{Int} - TransitionMatrices(p::AbstractPetriNet) = begin + TransitionMatrices(p::HasPetriNet) = begin input, output = zeros(Int, (nt(p), ns(p))), zeros(Int, (nt(p), ns(p))) for i in 1:ni(p) input[subpart(p, i, :it), subpart(p, i, :is)] += 1 @@ -268,7 +283,7 @@ being simulated under the law of mass action. The resulting function has a signature of the form `f!(du, u, p, t)` and can be passed to the DifferentialEquations.jl solver package. """ -vectorfield(pn::AbstractPetriNet) = begin +vectorfield(pn::HasPetriNet) = begin tm = TransitionMatrices(pn) dt = tm.output - tm.input f(du, u, p, t) = begin @@ -294,7 +309,7 @@ vectorfield of the Petri net being simulated under the law of mass action. The resulting function has a signature of the form `f!(du, u, p, t)` and can be passed to the DifferentialEquations.jl solver package. """ -vectorfield_expr(pn::AbstractPetriNet) = begin +vectorfield_expr(pn::HasPetriNet) = begin fquote = Expr(:function, Expr(:tuple, :du, :u, :p, :t)) fcode = Expr[] p_ix = [tname(pn, i) for i in 1:nt(pn)] @@ -359,13 +374,12 @@ const LabelledPetriNet = LabelledPetriNetUntyped{Symbol} const OpenLabelledPetriNetObUntyped, OpenLabelledPetriNetUntyped = OpenACSetTypes(LabelledPetriNetUntyped, :S) const OpenLabelledPetriNetOb, OpenLabelledPetriNet = OpenLabelledPetriNetObUntyped{Symbol}, OpenLabelledPetriNetUntyped{Symbol} - Open(p::AbstractLabelledPetriNet) = OpenLabelledPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) Open(p::AbstractLabelledPetriNet, legs...) = begin s_idx = Dict(sname(p, s) => s for s in 1:ns(p)) OpenLabelledPetriNet(p, map(l -> FinFunction(map(i -> s_idx[i], l), ns(p)), legs)...) end -Open(n, p::AbstractLabelledPetriNet, m) = Open(p, n, m) + """ LabelledPetriNet(n, ts::Vararg{Union{Pair,Tuple}}) @@ -414,9 +428,8 @@ end @acset_type ReactionNet(SchReactionNet, index=[:it, :is, :ot, :os]) <: AbstractReactionNet const OpenReactionNetOb, OpenReactionNet = OpenACSetTypes(ReactionNet, :S) -Open(p::ReactionNet{R,C}) where {R,C} = OpenReactionNet{R,C}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) Open(p::ReactionNet{R,C}, legs...) where {R,C} = OpenReactionNet{R,C}(p, map(l -> FinFunction(l, ns(p)), legs)...) -Open(n, p::AbstractReactionNet, m) = Open(p, n, m) +Open(p::ReactionNet{R,C}) where {R,C} = OpenReactionNet{R,C}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) """ ReactionNet{R,C}(n, ts::Vararg{Union{Pair,Tuple}}) where {R,C} @@ -447,12 +460,6 @@ ReactionNet{R,C}(n::Union{AbstractVector,Tuple}, ts::Vararg{Union{Pair,Tuple}}) p end -concentration(p::AbstractReactionNet, s) = subpart(p, s, :concentration) -rate(p::AbstractReactionNet, t) = subpart(p, t, :rate) - -concentrations(p::AbstractReactionNet) = map(s -> concentration(p, s), 1:ns(p)) -rates(p::AbstractReactionNet) = map(t -> rate(p, t), 1:nt(p)) - """ ACSet definition for a ReactionNet with labels on transitions and states. See Catlab.jl documentation for description of the @present syntax. @@ -471,12 +478,11 @@ const OpenLabelledReactionNetObUntyped, OpenLabelledReactionNetUntyped = OpenACS const OpenLabelledReactionNetOb{R,C} = OpenLabelledReactionNetObUntyped{R,C,Symbol} const OpenLabelledReactionNet{R,C} = OpenLabelledReactionNetUntyped{R,C,Symbol} -Open(p::LabelledReactionNet{R,C}) where {R,C} = OpenLabelledReactionNet{R,C}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) Open(p::LabelledReactionNet{R,C}, legs...) where {R,C} = begin s_idx = Dict(sname(p, s) => s for s in 1:ns(p)) OpenLabelledReactionNet{R,C}(p, map(l -> FinFunction(map(i -> s_idx[i], l), ns(p)), legs)...) end -Open(n, p::AbstractLabelledReactionNet, m) = Open(p, n, m) +Open(p::LabelledReactionNet{R,C}) where {R,C} = OpenLabelledReactionNet{R,C}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) # Ex. LabelledReactionNet{Number, Int}((:S=>990, :I=>10, :R=>0), (:inf, .3/1000)=>((:S, :I)=>(:I,:I)), (:rec, .2)=>(:I=>:R)) """ LabelledReactionNet{R,C}(n, ts::Vararg{Union{Pair,Tuple}}) where {R,C} @@ -529,49 +535,22 @@ flatten_labels(pn::Union{AbstractLabelledPetriNet,AbstractLabelledReactionNet}) # Interoperability between different types -PetriNet(pn::AbstractPetriNet) = begin - pn′ = PetriNet() - copy_parts!(pn′, pn) - pn′ -end - -LabelledPetriNet(pn::Union{AbstractLabelledPetriNet,AbstractLabelledReactionNet}) = begin - pn′ = LabelledPetriNet() - copy_parts!(pn′, pn) - pn′ -end - -LabelledPetriNet(pn::AbstractPetriNet, snames, tnames) = begin - pn′ = LabelledPetriNet() - copy_parts!(pn′, pn) +LabelledPetriNet(pn::HasPetriNet, snames, tnames) = begin + pn′ = LabelledPetriNet(pn) map(k -> set_subpart!(pn′, k, :sname, snames[k]), keys(snames)) map(k -> set_subpart!(pn′, k, :tname, tnames[k]), keys(tnames)) pn′ end -ReactionNet{R,C}(pn::Union{AbstractReactionNet,AbstractLabelledReactionNet}) where {R,C} = begin - pn′ = ReactionNet{R,C}() - copy_parts!(pn′, pn) - pn′ -end - -ReactionNet{R,C}(pn::AbstractPetriNet, concentrations, rates) where {R,C} = begin - pn′ = ReactionNet{R,C}() - copy_parts!(pn′, pn) +ReactionNet{R,C}(pn::HasPetriNet, concentrations, rates) where {R,C} = begin + pn′ = ReactionNet{R,C}(pn) map(k -> set_subpart!(pn′, k, :concentration, concentrations[k]), keys(concentrations)) map(k -> set_subpart!(pn′, k, :rate, rates[k]), keys(rates)) pn′ end -LabelledReactionNet{R,C}(pn::AbstractLabelledReactionNet) where {R,C} = begin - pn′ = LabelledReactionNet{R,C}() - copy_parts!(pn′, pn) - pn′ -end - -LabelledReactionNet{R,C}(pn::AbstractPetriNet, s_labels, t_labels, concentrations, rates) where {R,C} = begin - pn′ = LabelledReactionNet{R,C}() - copy_parts!(pn′, pn) +LabelledReactionNet{R,C}(pn::HasPetriNet, s_labels, t_labels, concentrations, rates) where {R,C} = begin + pn′ = LabelledReactionNet{R,C}(pn) map(k -> set_subpart!(pn′, k, :sname, s_labels[k]), keys(s_labels)) map(k -> set_subpart!(pn′, k, :tname, t_labels[k]), keys(t_labels)) map(k -> set_subpart!(pn′, k, :concentration, concentrations[k]), keys(concentrations)) @@ -579,9 +558,8 @@ LabelledReactionNet{R,C}(pn::AbstractPetriNet, s_labels, t_labels, concentration pn′ end -LabelledReactionNet{R,C}(pn::Union{AbstractPetriNet}, states, transitions) where {R,C} = begin - pn′ = LabelledReactionNet{R,C}() - copy_parts!(pn′, pn) +LabelledReactionNet{R,C}(pn::HasPetriNet, states, transitions) where {R,C} = begin + pn′ = LabelledReactionNet{R,C}(pn) for (i, (k, v)) in enumerate(states) set_subpart!(pn′, i, :sname, k) set_subpart!(pn′, i, :concentration, v) @@ -593,28 +571,86 @@ LabelledReactionNet{R,C}(pn::Union{AbstractPetriNet}, states, transitions) where pn′ end + """ Concentration of a ReactionNet """ -concentration(p::AbstractLabelledReactionNet, s) = subpart(p, s, :concentration) +concentration(p::HasPetriNet, s) = subpart(p, s, :concentration) """ Rate of a RectionNet """ -rate(p::AbstractLabelledReactionNet, t) = subpart(p, t, :rate) +rate(p::HasPetriNet, t) = subpart(p, t, :rate) + +concentrations(p::HasPetriNet) = map(s -> concentration(p, s), 1:ns(p)) +rates(p::HasPetriNet) = map(t -> rate(p, t), 1:nt(p)) """ All concentrations of a ReactionNet """ -concentrations(p::AbstractLabelledReactionNet) = begin +concentrations(p::LabelledReactionNet) = begin snames = [sname(p, s) for s in 1:ns(p)] LVector(; [(snames[s] => concentration(p, s)) for s in 1:ns(p)]...) end """ All rates of a ReactionNet """ -rates(p::AbstractLabelledReactionNet) = begin +rates(p::LabelledReactionNet) = begin tnames = [tname(p, s) for s in 1:nt(p)] LVector(; [(tnames[t] => rate(p, t)) for t in 1:nt(p)]...) end + + +# PROPERTY PETRI NETS + + +@abstract_acset_type AbstractPropertyPetriNet <: HasPetriNet + +@present SchPropertyPetriNet <: SchPetriNet begin + Prop::AttrType + + sprop::Attr(S, Prop) + tprop::Attr(T, Prop) +end +@acset_type PropertyPetriNet(SchPropertyPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet +# const OpenPropertyPetriNetOb, OpenPropertyPetriNet = OpenCSetTypes(PropertyPetriNet, :S) + +sprop(g::AbstractPropertyPetriNet, s) = subpart(g, s, :sprop) +tprop(g::AbstractPropertyPetriNet, t) = subpart(g, t, :tprop) +sprops(p::AbstractPropertyPetriNet) = map(s -> sprop(p, s), 1:ns(p)) +tprops(p::AbstractPropertyPetriNet) = map(t -> tprop(p, t), 1:nt(p)) + +function (::Type{T})(pn::HasPetriNet, sprops, tprops) where T <: AbstractPropertyPetriNet + pn′ = T(pn) + map(k -> set_subpart!(pn′, k, :sprop, sprops[k]), keys(sprops)) + map(k -> set_subpart!(pn′, k, :tprop, tprops[k]), keys(tprops)) + pn′ +end + +@present SchPropertyLabelledPetriNet <: SchLabelledPetriNet begin + Prop::AttrType + + sprop::Attr(S, Prop) + tprop::Attr(T, Prop) +end +@acset_type PropertyLabelledPetriNetUntyped(SchPropertyLabelledPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet +const PropertyLabelledPetriNet{T} = PropertyLabelledPetriNetUntyped{Symbol,T} + +@present SchPropertyReactionNet <: SchReactionNet begin + Prop::AttrType + + sprop::Attr(S, Prop) + tprop::Attr(T, Prop) +end +@acset_type PropertyReactionNet(SchPropertyReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet + +@present SchPropertyLabelledReactionNet <: SchLabelledReactionNet begin + Prop::AttrType + + sprop::Attr(S, Prop) + tprop::Attr(T, Prop) +end +@acset_type PropertyLabelledReactionNetUntyped(SchPropertyLabelledReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet +const PropertyLabelledReactionNet{R,C,T} = PropertyLabelledReactionNetUntyped{R,C,Symbol,T} + include("interoperability.jl") include("visualization.jl") include("Epidemiology.jl") From e7907a9a27302273c36f8a5e8ae99b1a5f31743c Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 29 Mar 2023 15:59:56 -0400 Subject: [PATCH 03/58] continued work on property petri nets --- src/AlgebraicPetri.jl | 207 +++++++++++++++++++++++------------------- 1 file changed, 116 insertions(+), 91 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 3405a7bc..292f46c7 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -13,7 +13,11 @@ export SchPetriNet, PetriNet, OpenPetriNetOb, AbstractPetriNet, ns, nt, ni, no, Open, OpenPetriNet, OpenLabelledPetriNet, OpenReactionNet, OpenLabelledReactionNet, OpenPetriNetOb, OpenLabelledPetriNetOb, OpenReactionNetOb, OpenLabelledReactionNetOb, mca, flatten_labels, - SchPropertyPetriNet, AbstractPropertyPetriNet, PropertyPetriNet, sprop, tprop, sprops, tprops + AbstractPropertyPetriNet, sprop, tprop, sprops, tprops, + SchPropertyPetriNet, SchPropertyLabelledPetriNet, SchPropertyReactionNet, SchPropertyLabelledReactionNet, + PropertyPetriNet, PropertyLabelledPetriNet, PropertyReactionNet, PropertyLabelledReactionNet, + OpenPropertyPetriNet, OpenPropertyLabelledPetriNet, OpenPropertyReactionNet, OpenPropertyLabelledReactionNet, + OpenPropertyPetriNetOb, OpenPropertyLabelledPetriNetOb, OpenPropertyReactionNetOb, OpenPropertyLabelledReactionNetOb using Catlab using Catlab.CategoricalAlgebra @@ -36,7 +40,7 @@ This type encompasses C-sets where the schema for graphs is a subcategory of C. This includes, for example, graphs, symmetric graphs, and reflexive graphs, but not half-edge graphs. """ -@abstract_acset_type HasPetriNet +@abstract_acset_type AbstractPetriNet # Petri Nets ############ @@ -57,7 +61,6 @@ See Catlab.jl documentation for description of the @present syntax. os::Hom(O, S) end -@abstract_acset_type AbstractPetriNet <: HasPetriNet @acset_type PetriNet(SchPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet const OpenPetriNetOb, OpenPetriNet = OpenCSetTypes(PetriNet, :S) @@ -69,19 +72,19 @@ the cospan. The OpenPetriNet can be composed over an undirected wiring diagram [blog post](https://www.algebraicjulia.org/blog/post/2020/11/structured-cospans-2/) for a description of this compositional tooling) """ -Open(p::HasPetriNet) = OpenPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) +Open(p::AbstractPetriNet) = OpenPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) """ Open(p::AbstractPetriNet, legs...) Generates on OpenPetriNet with legs bundled as described by `legs` """ -Open(p::HasPetriNet, legs...) = OpenPetriNet(p, map(l -> FinFunction(l, ns(p)), legs)...) +Open(p::AbstractPetriNet, legs...) = OpenPetriNet(p, map(l -> FinFunction(l, ns(p)), legs)...) """ Open(n, p::AbstractPetriNet, m) Generates on OpenPetriNet with two legs, `n` and `m` """ -Open(n, p::HasPetriNet, m) = Open(p, n, m) +Open(n, p::AbstractPetriNet, m) = Open(p, n, m) """ PetriNet(n::Int, ts::Vararg{Union{Pair,Tuple}}) @@ -107,7 +110,7 @@ PetriNet(n::Int, ts::Vararg{Union{Pair,Tuple}}) = begin p end -function (::Type{T})(pn::HasPetriNet) where T <: HasPetriNet +function (::Type{T})(pn::AbstractPetriNet) where T <: AbstractPetriNet pn′ = T() copy_parts!(pn′, pn) pn′ @@ -115,52 +118,52 @@ end """ Number of states in a Petri net """ -ns(p::HasPetriNet) = nparts(p, :S) +ns(p::AbstractPetriNet) = nparts(p, :S) """ Number of transitions in a Petri net """ -nt(p::HasPetriNet) = nparts(p, :T) +nt(p::AbstractPetriNet) = nparts(p, :T) """ Number of input relationships in a Petri net """ -ni(p::HasPetriNet) = nparts(p, :I) +ni(p::AbstractPetriNet) = nparts(p, :I) """ Number of output relationships in a Petri net """ -no(p::HasPetriNet) = nparts(p, :O) +no(p::AbstractPetriNet) = nparts(p, :O) -is(p::HasPetriNet, args...) = subpart(p, args..., :is) -os(p::HasPetriNet, args...) = subpart(p, args..., :os) -it(p::HasPetriNet, args...) = subpart(p, args..., :it) -ot(p::HasPetriNet, args...) = subpart(p, args..., :ot) +is(p::AbstractPetriNet, args...) = subpart(p, args..., :is) +os(p::AbstractPetriNet, args...) = subpart(p, args..., :os) +it(p::AbstractPetriNet, args...) = subpart(p, args..., :it) +ot(p::AbstractPetriNet, args...) = subpart(p, args..., :ot) """ Add a species to the Petri net. Label and concentration can be provided depending on the kind of Petri net. Returns the ID of the species """ -add_species!(p::HasPetriNet; kw...) = add_part!(p, :S; kw...) +add_species!(p::AbstractPetriNet; kw...) = add_part!(p, :S; kw...) """ Add `n` species to the Petri net. Label and concentration can be provided depending on the kind of Petri net. Returns the ID of the species """ -add_species!(p::HasPetriNet, n; kw...) = add_parts!(p, :S, n; kw...) +add_species!(p::AbstractPetriNet, n; kw...) = add_parts!(p, :S, n; kw...) """ Add a transition to the Petri net. Label and rate can be provided depending on the kind of Petri net. Returns the ID of the transition """ -add_transition!(p::HasPetriNet; kw...) = add_part!(p, :T; kw...) +add_transition!(p::AbstractPetriNet; kw...) = add_part!(p, :T; kw...) """ Add `n` transitions to the Petri net. Label and rate can be provided depending on the kind of Petri net. Returns the ID of the transition """ -add_transitions!(p::HasPetriNet, n; kw...) = add_parts!(p, :T, n; kw...) +add_transitions!(p::AbstractPetriNet, n; kw...) = add_parts!(p, :T, n; kw...) """ add_input!(p::AbstractPetriNet,t,s;kw...) @@ -168,7 +171,7 @@ Add an input relationship to the Petri net between the transition `t` and specie Returns the ID of the input relationship """ -add_input!(p::HasPetriNet, t, s; kw...) = add_part!(p, :I; it=t, is=s, kw...) +add_input!(p::AbstractPetriNet, t, s; kw...) = add_part!(p, :I; it=t, is=s, kw...) """ add_inputs!(p::AbstractPetriNet,n,t,s;kw...) @@ -176,7 +179,7 @@ Add input relationships to the Petri net between the transitions `t` and species Returns the ID of the input relationship """ -add_inputs!(p::HasPetriNet, n, t, s; kw...) = add_parts!(p, :I, n; it=t, is=s, kw...) +add_inputs!(p::AbstractPetriNet, n, t, s; kw...) = add_parts!(p, :I, n; it=t, is=s, kw...) """ add_output!(p::AbstractPetriNet,t,s;kw...) @@ -184,7 +187,7 @@ Add an output relationship to the Petri net between the transition `t` and speci Returns the ID of the input relationship """ -add_output!(p::HasPetriNet, t, s; kw...) = add_part!(p, :O; ot=t, os=s, kw...) +add_output!(p::AbstractPetriNet, t, s; kw...) = add_part!(p, :O; ot=t, os=s, kw...) """ add_outputs!(p::AbstractPetriNet,n,t,s;kw...) @@ -192,41 +195,41 @@ Add output relationships to the Petri net between the transitions `t` and specie Returns the ID of the input relationship """ -add_outputs!(p::HasPetriNet, n, t, s; kw...) = add_parts!(p, :O, n; ot=t, os=s, kw...) +add_outputs!(p::AbstractPetriNet, n, t, s; kw...) = add_parts!(p, :O, n; ot=t, os=s, kw...) """ Name of species Note that this returns an index if labels are not present in the PetriNet """ -sname(p::HasPetriNet, s) = (1:ns(p))[s] +sname(p::AbstractPetriNet, s) = (1:ns(p))[s] """ Name of transition Note that this returns an index if labels are not present in the PetriNet """ -tname(p::HasPetriNet, t) = (1:nt(p))[t] +tname(p::AbstractPetriNet, t) = (1:nt(p))[t] """ Names of species in a Petri net Note that this returns indices if labels are not present in the PetriNet """ -snames(p::HasPetriNet) = map(s -> sname(p, s), 1:ns(p)) +snames(p::AbstractPetriNet) = map(s -> sname(p, s), 1:ns(p)) """ Names of transitions in a Petri net Note that this returns indices if labels are not present in the PetriNet """ -tnames(p::HasPetriNet) = map(t -> tname(p, t), 1:nt(p)) +tnames(p::AbstractPetriNet) = map(t -> tname(p, t), 1:nt(p)) # Note: although indexing makes this pretty fast, it is often faster to bulk-convert # the PetriNet net into a transition matrix, if you are working with all of the transitions """ Input relationships for a transition """ -inputs(p::HasPetriNet, t) = subpart(p, incident(p, t, :it), :is) +inputs(p::AbstractPetriNet, t) = subpart(p, incident(p, t, :it), :is) """ Output relationships for a transition """ -outputs(p::HasPetriNet, t) = subpart(p, incident(p, t, :ot), :os) +outputs(p::AbstractPetriNet, t) = subpart(p, incident(p, t, :ot), :os) """ TransitionMatrices @@ -237,7 +240,7 @@ Petri net. struct TransitionMatrices input::Matrix{Int} output::Matrix{Int} - TransitionMatrices(p::HasPetriNet) = begin + TransitionMatrices(p::AbstractPetriNet) = begin input, output = zeros(Int, (nt(p), ns(p))), zeros(Int, (nt(p), ns(p))) for i in 1:ni(p) input[subpart(p, i, :it), subpart(p, i, :is)] += 1 @@ -283,7 +286,7 @@ being simulated under the law of mass action. The resulting function has a signature of the form `f!(du, u, p, t)` and can be passed to the DifferentialEquations.jl solver package. """ -vectorfield(pn::HasPetriNet) = begin +vectorfield(pn::AbstractPetriNet) = begin tm = TransitionMatrices(pn) dt = tm.output - tm.input f(du, u, p, t) = begin @@ -309,7 +312,7 @@ vectorfield of the Petri net being simulated under the law of mass action. The resulting function has a signature of the form `f!(du, u, p, t)` and can be passed to the DifferentialEquations.jl solver package. """ -vectorfield_expr(pn::HasPetriNet) = begin +vectorfield_expr(pn::AbstractPetriNet) = begin fquote = Expr(:function, Expr(:tuple, :du, :u, :p, :t)) fcode = Expr[] p_ix = [tname(pn, i) for i in 1:nt(pn)] @@ -368,14 +371,13 @@ See Catlab.jl documentation for description of the @present syntax. sname::Attr(S, Name) end -@abstract_acset_type AbstractLabelledPetriNet <: AbstractPetriNet -@acset_type LabelledPetriNetUntyped(SchLabelledPetriNet, index=[:it, :is, :ot, :os]) <: AbstractLabelledPetriNet +@acset_type LabelledPetriNetUntyped(SchLabelledPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet const LabelledPetriNet = LabelledPetriNetUntyped{Symbol} const OpenLabelledPetriNetObUntyped, OpenLabelledPetriNetUntyped = OpenACSetTypes(LabelledPetriNetUntyped, :S) const OpenLabelledPetriNetOb, OpenLabelledPetriNet = OpenLabelledPetriNetObUntyped{Symbol}, OpenLabelledPetriNetUntyped{Symbol} -Open(p::AbstractLabelledPetriNet) = OpenLabelledPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) -Open(p::AbstractLabelledPetriNet, legs...) = begin +Open(p::LabelledPetriNet) = OpenLabelledPetriNet(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) +Open(p::LabelledPetriNet, legs...) = begin s_idx = Dict(sname(p, s) => s for s in 1:ns(p)) OpenLabelledPetriNet(p, map(l -> FinFunction(map(i -> s_idx[i], l), ns(p)), legs)...) end @@ -424,8 +426,7 @@ See Catlab.jl documentation for description of the @present syntax. concentration::Attr(S, Concentration) end -@abstract_acset_type AbstractReactionNet <: AbstractPetriNet -@acset_type ReactionNet(SchReactionNet, index=[:it, :is, :ot, :os]) <: AbstractReactionNet +@acset_type ReactionNet(SchReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet const OpenReactionNetOb, OpenReactionNet = OpenACSetTypes(ReactionNet, :S) Open(p::ReactionNet{R,C}, legs...) where {R,C} = OpenReactionNet{R,C}(p, map(l -> FinFunction(l, ns(p)), legs)...) @@ -471,8 +472,7 @@ See Catlab.jl documentation for description of the @present syntax. sname::Attr(S, Name) end -@abstract_acset_type AbstractLabelledReactionNet <: AbstractPetriNet -@acset_type LabelledReactionNetUntyped(SchLabelledReactionNet, index=[:it, :is, :ot, :os]) <: AbstractLabelledReactionNet +@acset_type LabelledReactionNetUntyped(SchLabelledReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet const LabelledReactionNet{R,C} = LabelledReactionNetUntyped{R,C,Symbol} const OpenLabelledReactionNetObUntyped, OpenLabelledReactionNetUntyped = OpenACSetTypes(LabelledReactionNetUntyped, :S) const OpenLabelledReactionNetOb{R,C} = OpenLabelledReactionNetObUntyped{R,C,Symbol} @@ -518,38 +518,23 @@ LabelledReactionNet{R,C}(n::Union{AbstractVector,Tuple}, ts::Vararg{Union{Pair,T p end -sname(p::Union{AbstractLabelledPetriNet,AbstractLabelledReactionNet}, s) = subpart(p, s, :sname) -tname(p::Union{AbstractLabelledPetriNet,AbstractLabelledReactionNet}, t) = subpart(p, t, :tname) - -flat_symbol(sym::Symbol)::Symbol = sym -flat_symbol(sym::Tuple)::Symbol = mapreduce(x -> isa(x, Tuple) ? flat_symbol(x) : x, (x, y) -> Symbol(x, "_", y), sym) - -""" flatten_labels(pn::AbstractLabelledPetriNet) - -Takes a labeled Petri net or reaction net and flattens arbitrarily nested labels -on the species and the transitions to a single symbol who's previously nested -parts are separated by `_`. -""" -flatten_labels(pn::Union{AbstractLabelledPetriNet,AbstractLabelledReactionNet}) = - map(pn, Name=flat_symbol) - # Interoperability between different types -LabelledPetriNet(pn::HasPetriNet, snames, tnames) = begin +LabelledPetriNet(pn::AbstractPetriNet, snames, tnames) = begin pn′ = LabelledPetriNet(pn) map(k -> set_subpart!(pn′, k, :sname, snames[k]), keys(snames)) map(k -> set_subpart!(pn′, k, :tname, tnames[k]), keys(tnames)) pn′ end -ReactionNet{R,C}(pn::HasPetriNet, concentrations, rates) where {R,C} = begin +ReactionNet{R,C}(pn::AbstractPetriNet, concentrations, rates) where {R,C} = begin pn′ = ReactionNet{R,C}(pn) map(k -> set_subpart!(pn′, k, :concentration, concentrations[k]), keys(concentrations)) map(k -> set_subpart!(pn′, k, :rate, rates[k]), keys(rates)) pn′ end -LabelledReactionNet{R,C}(pn::HasPetriNet, s_labels, t_labels, concentrations, rates) where {R,C} = begin +LabelledReactionNet{R,C}(pn::AbstractPetriNet, s_labels, t_labels, concentrations, rates) where {R,C} = begin pn′ = LabelledReactionNet{R,C}(pn) map(k -> set_subpart!(pn′, k, :sname, s_labels[k]), keys(s_labels)) map(k -> set_subpart!(pn′, k, :tname, t_labels[k]), keys(t_labels)) @@ -558,7 +543,7 @@ LabelledReactionNet{R,C}(pn::HasPetriNet, s_labels, t_labels, concentrations, ra pn′ end -LabelledReactionNet{R,C}(pn::HasPetriNet, states, transitions) where {R,C} = begin +LabelledReactionNet{R,C}(pn::AbstractPetriNet, states, transitions) where {R,C} = begin pn′ = LabelledReactionNet{R,C}(pn) for (i, (k, v)) in enumerate(states) set_subpart!(pn′, i, :sname, k) @@ -571,38 +556,9 @@ LabelledReactionNet{R,C}(pn::HasPetriNet, states, transitions) where {R,C} = beg pn′ end - -""" Concentration of a ReactionNet -""" -concentration(p::HasPetriNet, s) = subpart(p, s, :concentration) - -""" Rate of a RectionNet -""" -rate(p::HasPetriNet, t) = subpart(p, t, :rate) - -concentrations(p::HasPetriNet) = map(s -> concentration(p, s), 1:ns(p)) -rates(p::HasPetriNet) = map(t -> rate(p, t), 1:nt(p)) - -""" All concentrations of a ReactionNet -""" -concentrations(p::LabelledReactionNet) = begin - snames = [sname(p, s) for s in 1:ns(p)] - LVector(; [(snames[s] => concentration(p, s)) for s in 1:ns(p)]...) -end - -""" All rates of a ReactionNet -""" -rates(p::LabelledReactionNet) = begin - tnames = [tname(p, s) for s in 1:nt(p)] - LVector(; [(tnames[t] => rate(p, t)) for t in 1:nt(p)]...) -end - - - # PROPERTY PETRI NETS - -@abstract_acset_type AbstractPropertyPetriNet <: HasPetriNet +@abstract_acset_type AbstractPropertyPetriNet <: AbstractPetriNet @present SchPropertyPetriNet <: SchPetriNet begin Prop::AttrType @@ -611,14 +567,16 @@ end tprop::Attr(T, Prop) end @acset_type PropertyPetriNet(SchPropertyPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet -# const OpenPropertyPetriNetOb, OpenPropertyPetriNet = OpenCSetTypes(PropertyPetriNet, :S) +const OpenPropertyPetriNetOb, OpenPropertyPetriNet = OpenACSetTypes(PropertyPetriNet, :S) +Open(p::PropertyPetriNet{T}) where T = OpenPropertyPetriNet{T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) +Open(p::PropertyPetriNet{T}, legs...) where T = OpenPropertyPetriNet{T}(p, map(l -> FinFunction(l, ns(p)), legs)...) sprop(g::AbstractPropertyPetriNet, s) = subpart(g, s, :sprop) tprop(g::AbstractPropertyPetriNet, t) = subpart(g, t, :tprop) sprops(p::AbstractPropertyPetriNet) = map(s -> sprop(p, s), 1:ns(p)) tprops(p::AbstractPropertyPetriNet) = map(t -> tprop(p, t), 1:nt(p)) -function (::Type{T})(pn::HasPetriNet, sprops, tprops) where T <: AbstractPropertyPetriNet +function (::Type{T})(pn::AbstractPetriNet, sprops, tprops) where T <: AbstractPropertyPetriNet pn′ = T(pn) map(k -> set_subpart!(pn′, k, :sprop, sprops[k]), keys(sprops)) map(k -> set_subpart!(pn′, k, :tprop, tprops[k]), keys(tprops)) @@ -634,6 +592,15 @@ end @acset_type PropertyLabelledPetriNetUntyped(SchPropertyLabelledPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet const PropertyLabelledPetriNet{T} = PropertyLabelledPetriNetUntyped{Symbol,T} +const OpenPropertyLabelledPetriNetObUntyped, OpenPropertyLabelledPetriNetUntyped = OpenACSetTypes(PropertyLabelledPetriNetUntyped, :S) +const OpenPropertyLabelledPetriNetOb{T} = OpenPropertyLabelledPetriNetObUntyped{Symbol,T} +const OpenPropertyLabelledPetriNet{T} = OpenPropertyLabelledPetriNetUntyped{Symbol,T} +Open(p::PropertyLabelledPetriNet{T}) where T = OpenPropertyLabelledPetriNet{T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) +Open(p::PropertyLabelledPetriNet{T}, legs...) where T = begin + s_idx = Dict(sname(p, s) => s for s in 1:ns(p)) + OpenPropertyLabelledPetriNet{T}(p, map(l -> FinFunction(map(i -> s_idx[i], l), ns(p)), legs)...) +end + @present SchPropertyReactionNet <: SchReactionNet begin Prop::AttrType @@ -642,6 +609,10 @@ const PropertyLabelledPetriNet{T} = PropertyLabelledPetriNetUntyped{Symbol,T} end @acset_type PropertyReactionNet(SchPropertyReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet +const OpenPropertyReactionNetOb, OpenPropertyReactionNet = OpenACSetTypes(PropertyReactionNet, :S) +Open(p::PropertyReactionNet{R,C,T}, legs...) where {R,C,T} = OpenPropertyReactionNet{R,C,T}(p, map(l -> FinFunction(l, ns(p)), legs)...) +Open(p::PropertyReactionNet{R,C,T}) where {R,C,T} = OpenPropertyReactionNet{R,C,T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) + @present SchPropertyLabelledReactionNet <: SchLabelledReactionNet begin Prop::AttrType @@ -651,6 +622,60 @@ end @acset_type PropertyLabelledReactionNetUntyped(SchPropertyLabelledReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPropertyPetriNet const PropertyLabelledReactionNet{R,C,T} = PropertyLabelledReactionNetUntyped{R,C,Symbol,T} +const OpenPropertyLabelledReactionNetObUntyped, OpenPropertyLabelledReactionNetUntyped = OpenACSetTypes(PropertyLabelledReactionNetUntyped, :S) +const OpenPropertyLabelledReactionNetOb{R,C,T} = OpenPropertyLabelledReactionNetObUntyped{R,C,Symbol,T} +const OpenPropertyLabelledReactionNet{R,C,T} = OpenPropertyLabelledReactionNetUntyped{R,C,Symbol,T} +Open(p::PropertyLabelledReactionNet{R,C,T}, legs...) where {R,C,T} = begin + s_idx = Dict(sname(p, s) => s for s in 1:ns(p)) + OpenPropertyLabelledReactionNet{R,C,T}(p, map(l -> FinFunction(map(i -> s_idx[i], l), ns(p)), legs)...) +end +Open(p::PropertyLabelledReactionNet{R,C,T}) where {R,C,T} = OpenPropertyLabelledReactionNet{R,C,T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) + +# Add new parent types +const AbstractLabelledPetriNet = Union{LabelledPetriNetUntyped,LabelledPetriNet,LabelledReactionNetUntyped,LabelledReactionNet,PropertyLabelledPetriNetUntyped,PropertyLabelledPetriNet,OpenPropertyLabelledReactionNetUntyped,PropertyLabelledReactionNet} +const AbstractReactionNet = Union{ReactionNet,LabelledReactionNetUntyped,LabelledReactionNet,PropertyReactionNet,OpenPropertyLabelledReactionNetUntyped,PropertyLabelledReactionNet} +const AbstractLabelledReactionNet = typeintersect(AbstractLabelledPetriNet, AbstractReactionNet) + +sname(p::AbstractLabelledPetriNet, s) = subpart(p, s, :sname) +tname(p::AbstractLabelledPetriNet, t) = subpart(p, t, :tname) + +flat_symbol(sym::Symbol)::Symbol = sym +flat_symbol(sym::Tuple)::Symbol = mapreduce(x -> isa(x, Tuple) ? flat_symbol(x) : x, (x, y) -> Symbol(x, "_", y), sym) + +""" flatten_labels(pn::AbstractLabelledPetriNet) + +Takes a labeled Petri net or reaction net and flattens arbitrarily nested labels +on the species and the transitions to a single symbol who's previously nested +parts are separated by `_`. +""" +flatten_labels(pn::AbstractLabelledPetriNet) = + map(pn, Name=flat_symbol) + +""" Concentration of a ReactionNet +""" +concentration(p::AbstractReactionNet, s) = subpart(p, s, :concentration) + +""" Rate of a RectionNet +""" +rate(p::AbstractReactionNet, t) = subpart(p, t, :rate) + +concentrations(p::AbstractReactionNet) = map(s -> concentration(p, s), 1:ns(p)) +rates(p::AbstractReactionNet) = map(t -> rate(p, t), 1:nt(p)) + +""" All concentrations of a ReactionNet +""" +concentrations(p::AbstractLabelledReactionNet) = begin + snames = [sname(p, s) for s in 1:ns(p)] + LVector(; [(snames[s] => concentration(p, s)) for s in 1:ns(p)]...) +end + +""" All rates of a ReactionNet +""" +rates(p::AbstractLabelledReactionNet) = begin + tnames = [tname(p, s) for s in 1:nt(p)] + LVector(; [(tnames[t] => rate(p, t)) for t in 1:nt(p)]...) +end + include("interoperability.jl") include("visualization.jl") include("Epidemiology.jl") From 41df2e991fe4d8dce5097c922dce6db28a7cb167 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 30 Mar 2023 14:24:26 -0400 Subject: [PATCH 04/58] generalize more constructors --- src/AlgebraicPetri.jl | 82 +++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 292f46c7..68ceb70b 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -97,8 +97,8 @@ constructed as follows: PetriNet(3, (1,2)=>(2,2), 2=>3) ``` """ -PetriNet(n::Int, ts::Vararg{Union{Pair,Tuple}}) = begin - p = PetriNet() +function (::Type{T})(n::Int, ts::Vararg{Union{Pair,Tuple}}) where T <: AbstractPetriNet + p = T() add_species!(p, n) add_transitions!(p, length(ts)) for (i, (ins, outs)) in enumerate(ts) @@ -116,6 +116,45 @@ function (::Type{T})(pn::AbstractPetriNet) where T <: AbstractPetriNet pn′ end +""" TransitionMatrices + +This data structure stores the transition matrix of an AbstractPetriNet object. +This is primarily used for constructing the vectorfield representation of the +Petri net. +""" +struct TransitionMatrices + input::Matrix{Int} + output::Matrix{Int} + TransitionMatrices(p::AbstractPetriNet) = begin + input, output = zeros(Int, (nt(p), ns(p))), zeros(Int, (nt(p), ns(p))) + for i in 1:ni(p) + input[subpart(p, i, :it), subpart(p, i, :is)] += 1 + end + for o in 1:no(p) + output[subpart(p, o, :ot), subpart(p, o, :os)] += 1 + end + new(input, output) + end +end + +""" PetriNet(tm::TransitionMatrices) + +Constructs a PetriNet from its TransitionMatrices representation. +""" +function (::Type{T})(tm::TransitionMatrices) where T <: AbstractPetriNet + (m, n) = size(tm.input) + p = T() + add_species!(p, n) + add_transitions!(p, m) + for i in 1:m + for j in 1:n + add_inputs!(p, tm.input[i, j], i, j) + add_outputs!(p, tm.output[i, j], i, j) + end + end + p +end + """ Number of states in a Petri net """ ns(p::AbstractPetriNet) = nparts(p, :S) @@ -231,45 +270,6 @@ inputs(p::AbstractPetriNet, t) = subpart(p, incident(p, t, :it), :is) """ outputs(p::AbstractPetriNet, t) = subpart(p, incident(p, t, :ot), :os) -""" TransitionMatrices - -This data structure stores the transition matrix of an AbstractPetriNet object. -This is primarily used for constructing the vectorfield representation of the -Petri net. -""" -struct TransitionMatrices - input::Matrix{Int} - output::Matrix{Int} - TransitionMatrices(p::AbstractPetriNet) = begin - input, output = zeros(Int, (nt(p), ns(p))), zeros(Int, (nt(p), ns(p))) - for i in 1:ni(p) - input[subpart(p, i, :it), subpart(p, i, :is)] += 1 - end - for o in 1:no(p) - output[subpart(p, o, :ot), subpart(p, o, :os)] += 1 - end - new(input, output) - end -end - -""" PetriNet(tm::TransitionMatrices) - -Constructs a PetriNet from its TransitionMatrices representation. -""" -PetriNet(tm::TransitionMatrices) = begin - (m, n) = size(tm.input) - p = PetriNet() - add_species!(p, n) - add_transitions!(p, m) - for i in 1:m - for j in 1:n - add_inputs!(p, tm.input[i, j], i, j) - add_outputs!(p, tm.output[i, j], i, j) - end - end - p -end - valueat(x::Number, u, t) = x valueat(f::Function, u, t) = try From b0954ccbab3a5d973e1ca540898b189de29e8d03 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 30 Mar 2023 16:27:23 -0400 Subject: [PATCH 05/58] add todo note for simplifying code --- src/AlgebraicPetri.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 68ceb70b..55aa2dc8 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -632,6 +632,8 @@ end Open(p::PropertyLabelledReactionNet{R,C,T}) where {R,C,T} = OpenPropertyLabelledReactionNet{R,C,T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) # Add new parent types +# +# TODO: MOVE TO CODE BASED `has_subpart` TO DISPATCH RATHER THAN UNION TYPES const AbstractLabelledPetriNet = Union{LabelledPetriNetUntyped,LabelledPetriNet,LabelledReactionNetUntyped,LabelledReactionNet,PropertyLabelledPetriNetUntyped,PropertyLabelledPetriNet,OpenPropertyLabelledReactionNetUntyped,PropertyLabelledReactionNet} const AbstractReactionNet = Union{ReactionNet,LabelledReactionNetUntyped,LabelledReactionNet,PropertyReactionNet,OpenPropertyLabelledReactionNetUntyped,PropertyLabelledReactionNet} const AbstractLabelledReactionNet = typeintersect(AbstractLabelledPetriNet, AbstractReactionNet) From c9600a1208821563c9fbf25e3ca28184542044c4 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 4 Apr 2023 16:16:52 -0400 Subject: [PATCH 06/58] generalize more functions to AbstractPetriNets --- src/AlgebraicPetri.jl | 118 +++++++++++++++++++++------------------- src/BilayerNetworks.jl | 56 ++++++++++++------- src/OpenTransitions.jl | 11 ++-- src/SubACSets.jl | 4 +- src/interoperability.jl | 28 +++++----- test/bilayernetworks.jl | 2 +- 6 files changed, 119 insertions(+), 100 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 55aa2dc8..9b66b074 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -86,9 +86,9 @@ Generates on OpenPetriNet with two legs, `n` and `m` """ Open(n, p::AbstractPetriNet, m) = Open(p, n, m) -""" PetriNet(n::Int, ts::Vararg{Union{Pair,Tuple}}) +""" (::AbstractPetriNet)(n::Int, ts::Vararg{Union{Pair,Tuple}}) -Constructs a PetriNet object with `n` states and transitions described by `ts`. +Constructs any AbstractPetriNet object with `n` states and transitions described by `ts`. Transitions are given as `(input_states)=>(output_states)`. A PetriNet modelling the SIR model with 3 states and 2 transitions can be @@ -110,6 +110,14 @@ function (::Type{T})(n::Int, ts::Vararg{Union{Pair,Tuple}}) where T <: AbstractP p end +""" (::AbstractPetriNet)(pn::AbstractPetriNet) + +Cast one type of AbstractPetriNet to another. Any unrepresented parts will be `nothing`. +```@example +pn = PetriNet(3, (1,2)=>(2,2), 2=>3) +labelled_pn = LabelledPetriNet(pn) +``` +""" function (::Type{T})(pn::AbstractPetriNet) where T <: AbstractPetriNet pn′ = T() copy_parts!(pn′, pn) @@ -137,9 +145,9 @@ struct TransitionMatrices end end -""" PetriNet(tm::TransitionMatrices) +""" (::AbstractPetriNet)(tm::TransitionMatrices) -Constructs a PetriNet from its TransitionMatrices representation. +Construct any AbstractPetriNet from a given transition matrice representation. """ function (::Type{T})(tm::TransitionMatrices) where T <: AbstractPetriNet (m, n) = size(tm.input) @@ -240,13 +248,13 @@ add_outputs!(p::AbstractPetriNet, n, t, s; kw...) = add_parts!(p, :O, n; ot=t, o Note that this returns an index if labels are not present in the PetriNet """ -sname(p::AbstractPetriNet, s) = (1:ns(p))[s] +sname(p::AbstractPetriNet, s) = has_subpart(p, :sname) ? subpart(p, s, :sname) : (1:ns(p))[s] """ Name of transition Note that this returns an index if labels are not present in the PetriNet """ -tname(p::AbstractPetriNet, t) = (1:nt(p))[t] +tname(p::AbstractPetriNet, t) = has_subpart(p, :tname) ? subpart(p, t, :tname) : (1:nt(p))[t] """ Names of species in a Petri net @@ -360,6 +368,48 @@ vectorfield_expr(pn::AbstractPetriNet) = begin return mk_function(AlgebraicPetri, fquote) end +flat_symbol(sym::Symbol)::Symbol = sym +flat_symbol(sym::Tuple)::Symbol = mapreduce(x -> isa(x, Tuple) ? flat_symbol(x) : x, (x, y) -> Symbol(x, "_", y), sym) + +""" flatten_labels(pn::AbstractPetriNet) + +Takes a labelled Petri net or reaction net and flattens arbitrarily nested labels +on the species and the transitions to a single symbol who's previously nested +parts are separated by `_`. +""" +flatten_labels(pn::AbstractPetriNet) = + map(pn, Name=flat_symbol) + +""" Concentration of a ReactionNet +""" +concentration(p::AbstractPetriNet, s) = subpart(p, s, :concentration) + +""" Rate of a RectionNet +""" +rate(p::AbstractPetriNet, t) = subpart(p, t, :rate) + +""" All concentrations of a ReactionNet +""" +concentrations(p::AbstractPetriNet) = begin + if has_subpart(p, :sname) + snames = [sname(p, s) for s in 1:ns(p)] + return LVector(; [(snames[s] => concentration(p, s)) for s in 1:ns(p)]...) + else + return map(s -> concentration(p, s), 1:ns(p)) + end +end + +""" All rates of a ReactionNet +""" +rates(p::AbstractPetriNet) = begin + if has_subpart(p, :tname) + tnames = [tname(p, s) for s in 1:nt(p)] + LVector(; [(tnames[t] => rate(p, t)) for t in 1:nt(p)]...) + else + return map(t -> rate(p, t), 1:nt(p)) + end +end + """ ACSet definition for a Petri net with labels on transitions and states. See Catlab.jl documentation for description of the @present syntax. @@ -371,7 +421,8 @@ See Catlab.jl documentation for description of the @present syntax. sname::Attr(S, Name) end -@acset_type LabelledPetriNetUntyped(SchLabelledPetriNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet +@abstract_acset_type AbstractLabelledPetriNet <: AbstractPetriNet +@acset_type LabelledPetriNetUntyped(SchLabelledPetriNet, index=[:it, :is, :ot, :os]) <: AbstractLabelledPetriNet const LabelledPetriNet = LabelledPetriNetUntyped{Symbol} const OpenLabelledPetriNetObUntyped, OpenLabelledPetriNetUntyped = OpenACSetTypes(LabelledPetriNetUntyped, :S) const OpenLabelledPetriNetOb, OpenLabelledPetriNet = OpenLabelledPetriNetObUntyped{Symbol}, OpenLabelledPetriNetUntyped{Symbol} @@ -426,7 +477,8 @@ See Catlab.jl documentation for description of the @present syntax. concentration::Attr(S, Concentration) end -@acset_type ReactionNet(SchReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet +@abstract_acset_type AbstractReactionNet <: AbstractPetriNet +@acset_type ReactionNet(SchReactionNet, index=[:it, :is, :ot, :os]) <: AbstractReactionNet const OpenReactionNetOb, OpenReactionNet = OpenACSetTypes(ReactionNet, :S) Open(p::ReactionNet{R,C}, legs...) where {R,C} = OpenReactionNet{R,C}(p, map(l -> FinFunction(l, ns(p)), legs)...) @@ -472,7 +524,8 @@ See Catlab.jl documentation for description of the @present syntax. sname::Attr(S, Name) end -@acset_type LabelledReactionNetUntyped(SchLabelledReactionNet, index=[:it, :is, :ot, :os]) <: AbstractPetriNet +@abstract_acset_type AbstractLabelledReactionNet <: AbstractPetriNet +@acset_type LabelledReactionNetUntyped(SchLabelledReactionNet, index=[:it, :is, :ot, :os]) <: AbstractLabelledReactionNet const LabelledReactionNet{R,C} = LabelledReactionNetUntyped{R,C,Symbol} const OpenLabelledReactionNetObUntyped, OpenLabelledReactionNetUntyped = OpenACSetTypes(LabelledReactionNetUntyped, :S) const OpenLabelledReactionNetOb{R,C} = OpenLabelledReactionNetObUntyped{R,C,Symbol} @@ -631,53 +684,6 @@ Open(p::PropertyLabelledReactionNet{R,C,T}, legs...) where {R,C,T} = begin end Open(p::PropertyLabelledReactionNet{R,C,T}) where {R,C,T} = OpenPropertyLabelledReactionNet{R,C,T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) -# Add new parent types -# -# TODO: MOVE TO CODE BASED `has_subpart` TO DISPATCH RATHER THAN UNION TYPES -const AbstractLabelledPetriNet = Union{LabelledPetriNetUntyped,LabelledPetriNet,LabelledReactionNetUntyped,LabelledReactionNet,PropertyLabelledPetriNetUntyped,PropertyLabelledPetriNet,OpenPropertyLabelledReactionNetUntyped,PropertyLabelledReactionNet} -const AbstractReactionNet = Union{ReactionNet,LabelledReactionNetUntyped,LabelledReactionNet,PropertyReactionNet,OpenPropertyLabelledReactionNetUntyped,PropertyLabelledReactionNet} -const AbstractLabelledReactionNet = typeintersect(AbstractLabelledPetriNet, AbstractReactionNet) - -sname(p::AbstractLabelledPetriNet, s) = subpart(p, s, :sname) -tname(p::AbstractLabelledPetriNet, t) = subpart(p, t, :tname) - -flat_symbol(sym::Symbol)::Symbol = sym -flat_symbol(sym::Tuple)::Symbol = mapreduce(x -> isa(x, Tuple) ? flat_symbol(x) : x, (x, y) -> Symbol(x, "_", y), sym) - -""" flatten_labels(pn::AbstractLabelledPetriNet) - -Takes a labeled Petri net or reaction net and flattens arbitrarily nested labels -on the species and the transitions to a single symbol who's previously nested -parts are separated by `_`. -""" -flatten_labels(pn::AbstractLabelledPetriNet) = - map(pn, Name=flat_symbol) - -""" Concentration of a ReactionNet -""" -concentration(p::AbstractReactionNet, s) = subpart(p, s, :concentration) - -""" Rate of a RectionNet -""" -rate(p::AbstractReactionNet, t) = subpart(p, t, :rate) - -concentrations(p::AbstractReactionNet) = map(s -> concentration(p, s), 1:ns(p)) -rates(p::AbstractReactionNet) = map(t -> rate(p, t), 1:nt(p)) - -""" All concentrations of a ReactionNet -""" -concentrations(p::AbstractLabelledReactionNet) = begin - snames = [sname(p, s) for s in 1:ns(p)] - LVector(; [(snames[s] => concentration(p, s)) for s in 1:ns(p)]...) -end - -""" All rates of a ReactionNet -""" -rates(p::AbstractLabelledReactionNet) = begin - tnames = [tname(p, s) for s in 1:nt(p)] - LVector(; [(tnames[t] => rate(p, t)) for t in 1:nt(p)]...) -end - include("interoperability.jl") include("visualization.jl") include("Epidemiology.jl") diff --git a/src/BilayerNetworks.jl b/src/BilayerNetworks.jl index 75c054fd..550611e7 100644 --- a/src/BilayerNetworks.jl +++ b/src/BilayerNetworks.jl @@ -73,18 +73,25 @@ function migrate!(bn::AbstractBilayerNetwork, pn::AbstractPetriNet) :infusion=>:os)) end -function migrate!(bn::AbstractLabelledBilayerNetwork, pn::AbstractLabelledPetriNet) - migrate!(bn, pn, - Dict(:Qin=>:S, :Qout=>:S, :Box=>:T, :Win=>:I, :Wn=>:I, :Wa=>:O, :Name=>:Name), - Dict(:arg=>:is, - :call=>:it, - :efflux=>:it, - :effusion=>:is, - :influx=>:ot, - :infusion=>:os, - :parameter=>:tname, - :variable=>:sname, - :tanvar=>:sname)) +function migrate!(bn::AbstractLabelledBilayerNetwork, pn::AbstractPetriNet) + generators = Dict(:Qin=>:S, :Qout=>:S, :Box=>:T, :Win=>:I, :Wn=>:I, :Wa=>:O) + parts = Dict(:arg=>:is, + :call=>:it, + :efflux=>:it, + :effusion=>:is, + :influx=>:ot, + :infusion=>:os) + if :Name in attrtypes(acset_schema(pn)) + generators[:Name] = :Name + end + if has_subpart(pn, :sname) + parts[:variable] = :sname + parts[:tanvar] = :sname + end + if has_subpart(pn, :tname) + parts[:parameter] = :tname + end + migrate!(bn, pn, generators, parts) end @@ -99,17 +106,24 @@ function migrate!(pn::AbstractPetriNet, bn::AbstractBilayerNetwork) :os=>:infusion)) end -function migrate!(pn::AbstractLabelledPetriNet, bn::AbstractLabelledBilayerNetwork) +function migrate!(pn::AbstractPetriNet, bn::AbstractLabelledBilayerNetwork) bnc = copy(bn) balance!(bnc) - migrate!(pn,bnc, - Dict(:S=>:Qin, :T=>:Box, :I=>:Win, :O=>:Wa, :Name=>:Name), - Dict(:is=>:arg, - :it=>:call, - :ot=>:influx, - :os=>:infusion, - :tname=>:parameter, - :sname=>:variable)) + generators = Dict(:S=>:Qin, :T=>:Box, :I=>:Win, :O=>:Wa) + parts = Dict(:is=>:arg, + :it=>:call, + :ot=>:influx, + :os=>:infusion) + if :Name in attrtypes(acset_schema(pn)) + generators[:Name] = :Name + end + if has_subpart(pn, :sname) + parts[:sname] = :variable + end + if has_subpart(pn, :tname) + parts[:tname] = :parameter + end + migrate!(pn, bnc, generators, parts) end diff --git a/src/OpenTransitions.jl b/src/OpenTransitions.jl index 3eac450e..70495c2d 100644 --- a/src/OpenTransitions.jl +++ b/src/OpenTransitions.jl @@ -4,8 +4,7 @@ module OpenTransitions using AlgebraicPetri: - LabelledPetriNetUntyped, PetriNet, AbstractPetriNet, - AbstractLabelledPetriNet, + LabelledPetriNetUntyped, LabelledPetriNet, PetriNet, AbstractPetriNet, ns, nt, tname using Catlab using Catlab.CategoricalAlgebra @@ -37,11 +36,11 @@ OpenT(n, p::AbstractPetriNet, m) = OpenT(p, n, m) const OpenLabelledPetriNetObUntypedT, OpenLabelledPetriNetUntypedT = OpenACSetTypes(LabelledPetriNetUntyped,:T) const OpenLabelledPetriNetObT, OpenLabelledPetriNetT = OpenLabelledPetriNetObUntypedT{Symbol}, OpenLabelledPetriNetUntypedT{Symbol} -OpenT(p::AbstractLabelledPetriNet) = OpenLabelledPetriNetT(p, map(x->FinFunction([x], nt(p)), 1:nt(p))...) -OpenT(p::AbstractLabelledPetriNet, legs...) = begin +OpenT(p::LabelledPetriNet) = OpenLabelledPetriNetT(p, map(x->FinFunction([x], nt(p)), 1:nt(p))...) +OpenT(p::LabelledPetriNet, legs...) = begin t_idx = Dict(tname(p, t)=>t for t in 1:nt(p)) OpenLabelledPetriNetT(p, map(l->FinFunction(map(i->t_idx[i], l), nt(p)), legs)...) end -OpenT(n, p::AbstractLabelledPetriNet, m) = OpenT(p, n, m) +OpenT(n, p::LabelledPetriNet, m) = OpenT(p, n, m) -end \ No newline at end of file +end diff --git a/src/SubACSets.jl b/src/SubACSets.jl index 3c28012b..4750f17f 100644 --- a/src/SubACSets.jl +++ b/src/SubACSets.jl @@ -12,7 +12,7 @@ using AlgebraicPetri concatmap(f,xs) = mapreduce(f, vcat, xs; init =[]) -function strip_names(p::AbstractLabelledPetriNet) +function strip_names(p::AbstractPetriNet) map(p, Name = name -> nothing) end @@ -94,4 +94,4 @@ function mca_help(X::ACSet, Y::ACSet) end end -end \ No newline at end of file +end diff --git a/src/interoperability.jl b/src/interoperability.jl index 3e3a2d46..969ff481 100644 --- a/src/interoperability.jl +++ b/src/interoperability.jl @@ -7,22 +7,22 @@ function __init__() # Interoperability with Petri.jl Petri.Model(p::AbstractPetriNet) = begin ts = TransitionMatrices(p) - t_in = map(i->Dict(k=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) - t_out = map(i->Dict(k=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) - Δ = Dict(i=>t for (i,t) in enumerate(zip(t_in, t_out))) - return Petri.Model(ns(p), Δ) - end + if has_subpart(p, :sname) && has_subpart(p, :tname) + snames = [sname(p, s) for s in 1:ns(p)] + tnames = [tname(p, t) for t in 1:nt(p)] + t_in = map(i->LVector(;[(snames[k]=>v) for (k,v) in enumerate(ts.input[i,:]) if v != 0]...), 1:nt(p)) + t_out = map(i->LVector(;[(snames[k]=>v) for (k,v) in enumerate(ts.output[i,:]) if v != 0]...), 1:nt(p)) + Δ = LVector(;[(tnames[i]=>t) for (i,t) in enumerate(zip(t_in, t_out))]...) + S = collect(values(snames)) + else + t_in = map(i->Dict(k=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) + t_out = map(i->Dict(k=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) + Δ = Dict(i=>t for (i,t) in enumerate(zip(t_in, t_out))) + S = ns(p) + end - Petri.Model(p::Union{AbstractLabelledPetriNet, AbstractLabelledReactionNet}) = begin - snames = [sname(p, s) for s in 1:ns(p)] - tnames = [tname(p, t) for t in 1:nt(p)] - ts = TransitionMatrices(p) - t_in = map(i->LVector(;[(snames[k]=>v) for (k,v) in enumerate(ts.input[i,:]) if v != 0]...), 1:nt(p)) - t_out = map(i->LVector(;[(snames[k]=>v) for (k,v) in enumerate(ts.output[i,:]) if v != 0]...), 1:nt(p)) - - Δ = LVector(;[(tnames[i]=>t) for (i,t) in enumerate(zip(t_in, t_out))]...) - return Petri.Model(collect(values(snames)), Δ) + return Petri.Model(ns(p), Δ) end end diff --git a/test/bilayernetworks.jl b/test/bilayernetworks.jl index 76cb276b..f18720f7 100644 --- a/test/bilayernetworks.jl +++ b/test/bilayernetworks.jl @@ -71,7 +71,7 @@ function roundtrip(pn::AbstractPetriNet, bn::AbstractBilayerNetwork) return roundtrippetri, pn_structure end -function roundtrip(pn::AbstractLabelledPetriNet, bn::AbstractLabelledBilayerNetwork) +function roundtrip(pn::AbstractPetriNet, bn::AbstractLabelledBilayerNetwork) roundtrippetri = LabelledPetriNet() migrate!(roundtrippetri, bn) return roundtrippetri, pn From 8b4d7b9fe21ef5a23daed82cc0e50941db6fa37c Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 5 Apr 2023 09:38:58 -0400 Subject: [PATCH 07/58] add docstrings --- src/AlgebraicPetri.jl | 44 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 9b66b074..f0fe39b7 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -611,8 +611,14 @@ end # PROPERTY PETRI NETS +""" Abstract Type for any PetriNet ACSet with properties. +""" @abstract_acset_type AbstractPropertyPetriNet <: AbstractPetriNet +""" ACSet definition for a PetriNet with properties on transitions and states. + +See Catlab.jl documentation for description of the @present syntax. +""" @present SchPropertyPetriNet <: SchPetriNet begin Prop::AttrType @@ -624,11 +630,26 @@ const OpenPropertyPetriNetOb, OpenPropertyPetriNet = OpenACSetTypes(PropertyPetr Open(p::PropertyPetriNet{T}) where T = OpenPropertyPetriNet{T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) Open(p::PropertyPetriNet{T}, legs...) where T = OpenPropertyPetriNet{T}(p, map(l -> FinFunction(l, ns(p)), legs)...) -sprop(g::AbstractPropertyPetriNet, s) = subpart(g, s, :sprop) -tprop(g::AbstractPropertyPetriNet, t) = subpart(g, t, :tprop) -sprops(p::AbstractPropertyPetriNet) = map(s -> sprop(p, s), 1:ns(p)) -tprops(p::AbstractPropertyPetriNet) = map(t -> tprop(p, t), 1:nt(p)) +""" Property of species +""" +sprop(g::AbstractPetriNet, s) = subpart(g, s, :sprop) + +""" Property of transition +""" +tprop(g::AbstractPetriNet, t) = subpart(g, t, :tprop) + +""" Properties of all species +""" +sprops(p::AbstractPetriNet) = map(s -> sprop(p, s), 1:ns(p)) + +""" Properties of all transitions +""" +tprops(p::AbstractPetriNet) = map(t -> tprop(p, t), 1:nt(p)) + +""" (::AbstractPropertyPetriNet)(pn::AbstractPetriNet, sprops, tprops) +Add properties to the states and transitions of a given Petri Net. +""" function (::Type{T})(pn::AbstractPetriNet, sprops, tprops) where T <: AbstractPropertyPetriNet pn′ = T(pn) map(k -> set_subpart!(pn′, k, :sprop, sprops[k]), keys(sprops)) @@ -636,6 +657,13 @@ function (::Type{T})(pn::AbstractPetriNet, sprops, tprops) where T <: AbstractPr pn′ end +(::Type{T})(pn::AbstractPetriNet, sprops::AbstractDict, tprops::AbstractDict) where T <: AbstractPropertyPetriNet = + T(pn, [sprops[sname(pn, s)] for s in 1:ns(pn)], [tprops[tname(pn, t)] for t in 1:nt(pn)]) + +""" ACSet definition for a LabelledPetriNet with properties on transitions and states. + +See Catlab.jl documentation for description of the @present syntax. +""" @present SchPropertyLabelledPetriNet <: SchLabelledPetriNet begin Prop::AttrType @@ -654,6 +682,10 @@ Open(p::PropertyLabelledPetriNet{T}, legs...) where T = begin OpenPropertyLabelledPetriNet{T}(p, map(l -> FinFunction(map(i -> s_idx[i], l), ns(p)), legs)...) end +""" ACSet definition for a ReactionNet with properties on transitions and states. + +See Catlab.jl documentation for description of the @present syntax. +""" @present SchPropertyReactionNet <: SchReactionNet begin Prop::AttrType @@ -666,6 +698,10 @@ const OpenPropertyReactionNetOb, OpenPropertyReactionNet = OpenACSetTypes(Proper Open(p::PropertyReactionNet{R,C,T}, legs...) where {R,C,T} = OpenPropertyReactionNet{R,C,T}(p, map(l -> FinFunction(l, ns(p)), legs)...) Open(p::PropertyReactionNet{R,C,T}) where {R,C,T} = OpenPropertyReactionNet{R,C,T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) +""" ACSet definition for a LabelledReactionNet with properties on transitions and states. + +See Catlab.jl documentation for description of the @present syntax. +""" @present SchPropertyLabelledReactionNet <: SchLabelledReactionNet begin Prop::AttrType From b1ddcdda622d693ab8ab0e2bf4585f8e2c37d7e6 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 5 Apr 2023 10:49:17 -0400 Subject: [PATCH 08/58] add tests --- test/types.jl | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/types.jl b/test/types.jl index 30d1f4a5..830925da 100644 --- a/test/types.jl +++ b/test/types.jl @@ -129,3 +129,45 @@ for tuple_petri in [tuple_labelled, tuple_rxn] @test tuple_petri′[:, :sname] == [:U_S, :U_I, :U_R] @test tuple_petri′[:, :tname] == [:Q_inf, :Q_rec] end + +# Property Petri Nets +sir_petri = PetriNet(3, ((1, 2), (2, 2)), (2, 3)) +sir_lpetri = LabelledPetriNet([:S, :I, :R], :inf => ((:S, :I), (:I, :I)), :rec => (:I, :R)) +sir_rxn = ReactionNet{Function,Int}([990, 10, 0], (β) => ((1, 2) => (2, 2)), (t -> γ) => (2 => 3)) +sir_lrxn = LabelledReactionNet{Number,Int}((:S => 990, :I => 10, :R => 0), (:inf, 0.001) => ((:S, :I) => (:I, :I)), (:rec, 0.25) => (:I => :R)) + +sir_sprops = [ + Dict(:title => "Susceptible", :unit => "People"), + Dict(:title => "Infected", :unit => "People"), + Dict(:title => "Recovered", :unit => "People"), +] +sir_sprops_dict = Dict(:S => sir_sprops[1], :I => sir_sprops[2], :R => sir_sprops[3]) + +sir_tprops = [ + Dict(:title => "Infection", :description => "An infected person interacts with a suscpetible person and the susceptible person becomes infected."), + Dict(:title => "Recovery", :description => "An infected person recovers from their illness."), +] +sir_tprops_dict = Dict(:inf => sir_tprops[1], :rec => sir_tprops[2]) + +sir_proppetri = PropertyPetriNet{Dict}(sir_petri, sir_sprops, sir_tprops) +@test PetriNet(sir_proppetri) == sir_petri + +@test sir_sprops == sprops(sir_proppetri) +@test sir_tprops == tprops(sir_proppetri) + +sir_proplpetri = PropertyLabelledPetriNet{Dict}(sir_lpetri, sir_sprops_dict, sir_tprops_dict) +@test LabelledPetriNet(sir_proplpetri) == sir_lpetri + +sir_proprxn = PropertyReactionNet{Function,Int,Dict}(sir_rxn, sir_sprops, sir_tprops) +@test ReactionNet{Function,Int}(sir_proprxn) == sir_rxn + +sir_proplrxn = PropertyLabelledReactionNet{Number,Int,Dict}(sir_lrxn, sir_sprops_dict, sir_tprops_dict) +@test LabelledReactionNet{Number,Int}(sir_proplrxn) == sir_lrxn + +for p in [sir_proppetri, sir_proprxn] + @test Open(p, [1], [2], [3]) == Open(p) +end + +for p in [sir_proplpetri, sir_proplrxn] + @test Open(p, [:S], [:I], [:R]) == Open(p) +end From 478d452b3a3ad7eb3e21daf62766f3f8f35b072e Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 5 Apr 2023 11:32:36 -0400 Subject: [PATCH 09/58] bump version to 0.8.7 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 7423aee1..1d23a44c 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AlgebraicPetri" uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" license = "MIT" authors = ["Micah Halter "] -version = "0.8.6" +version = "0.8.7" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" From 32d906fa1adb386f6abd8725d23e53365408fb7b Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 5 Apr 2023 13:51:48 -0400 Subject: [PATCH 10/58] more generalization --- src/ModelingToolkitInterop.jl | 9 ++------- src/TypedPetri.jl | 5 +++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/ModelingToolkitInterop.jl b/src/ModelingToolkitInterop.jl index a57c8e5b..db798dc2 100644 --- a/src/ModelingToolkitInterop.jl +++ b/src/ModelingToolkitInterop.jl @@ -49,12 +49,7 @@ module ModelingToolkitInterop ODESystem(eqs, t, S, r; name=name, kws...) end - function ModelingToolkit.ODEProblem( - p::Union{AbstractReactionNet, AbstractLabelledReactionNet}, - tspan; - name=:PetriNet, - kwargs... - ) + function ModelingToolkit.ODEProblem(p::AbstractPetriNet, tspan; name=:PetriNet, kwargs...) sys = ODESystem(p; name) ODEProblem(sys, p[:,:concentration], tspan, p[:,:rate]; kwargs...) end @@ -70,7 +65,7 @@ module ModelingToolkitInterop default to preserve the bilayer structure. This is useful when one wants to convert symbolic expressions back to a bilayer network. """ - function ModelingToolkit.ODESystem(bn::Union{AbstractLabelledBilayerNetwork,AbstractBilayerNetwork}; name=:BilayerNetwork, simplify = false) + function ModelingToolkit.ODESystem(bn::AbstractBilayerNetwork; name=:BilayerNetwork, simplify = false) t = (@variables t)[1] D = Differential(t) symbolic_vars = map(bn[:variable]) do v diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index c52843b0..704ef004 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -132,7 +132,7 @@ function add_reflexives( type_ind = findfirst(==(ct), type_system[:tname]) is, os = [incident(type_system, type_ind, f) for f in [:it, :ot]] new_t = add_part!(petri, :T; tname=ct) - if petri isa AbstractLabelledReactionNet + if has_subpart(petri, :rate) set_subpart!(petri, new_t, :rate, 1.0) end add_parts!(petri, :I, length(is); is=s_i, it=new_t) @@ -146,7 +146,8 @@ function add_reflexives( codom(typed_petri); type_comps..., Name=x->nothing, - (petri isa AbstractLabelledReactionNet ? [:Rate=>x->nothing, :Concentration=>x->nothing] : [])... + (has_subpart(petri, :rate) ? [:Rate=>x->nothing] : [])..., + (has_subpart(petri, :concentration) ? [:Concentration=>x->nothing] : [])... ) end From 63e5d066f311a0294568ba3ee31853dfb1076c6d Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 6 Apr 2023 12:52:14 -0400 Subject: [PATCH 11/58] allow partially defined metadata dictionaries in constructor --- src/AlgebraicPetri.jl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index f0fe39b7..19729ade 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -657,8 +657,18 @@ function (::Type{T})(pn::AbstractPetriNet, sprops, tprops) where T <: AbstractPr pn′ end -(::Type{T})(pn::AbstractPetriNet, sprops::AbstractDict, tprops::AbstractDict) where T <: AbstractPropertyPetriNet = - T(pn, [sprops[sname(pn, s)] for s in 1:ns(pn)], [tprops[tname(pn, t)] for t in 1:nt(pn)]) +function (::Type{T})(pn::AbstractPetriNet, sprops::AbstractDict, tprops::AbstractDict) where T <: AbstractPropertyPetriNet + pn′ = T(pn) + species = Dict(sname(pn, s)=>s for s in 1:ns(pn)) + for (name, prop) in sprops + set_subpart!(pn′, species[name], :sprop, prop) + end + transitions = Dict(tname(pn, t)=>t for t in 1:nt(pn)) + for (name, prop) in tprops + set_subpart!(pn′, transitions[name], :tprop, prop) + end + pn′ +end """ ACSet definition for a LabelledPetriNet with properties on transitions and states. From 91488afb5978817d04385473614cc4bf2863f1fb Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 18 Apr 2023 13:38:18 -0400 Subject: [PATCH 12/58] add custom separator to flatten_labels --- src/AlgebraicPetri.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 19729ade..56e26fed 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -368,8 +368,8 @@ vectorfield_expr(pn::AbstractPetriNet) = begin return mk_function(AlgebraicPetri, fquote) end -flat_symbol(sym::Symbol)::Symbol = sym -flat_symbol(sym::Tuple)::Symbol = mapreduce(x -> isa(x, Tuple) ? flat_symbol(x) : x, (x, y) -> Symbol(x, "_", y), sym) +flat_symbol(sym::Symbol, sep)::Symbol = sym +flat_symbol(sym::Tuple, sep)::Symbol = mapreduce(x -> isa(x, Tuple) ? flat_symbol(x, sep) : x, (x, y) -> Symbol(x, sep, y), sym) """ flatten_labels(pn::AbstractPetriNet) @@ -377,8 +377,10 @@ Takes a labelled Petri net or reaction net and flattens arbitrarily nested label on the species and the transitions to a single symbol who's previously nested parts are separated by `_`. """ -flatten_labels(pn::AbstractPetriNet) = - map(pn, Name=flat_symbol) +flatten_labels(pn::AbstractPetriNet; attributes=[:Name], sep='_') = begin + f = x->flat_symbol(x, sep) + map(pn; Dict(attr=>f for attr in attributes)...) +end """ Concentration of a ReactionNet """ From 00ff38d5bdafae6289904266b08a3c777bf79321 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 18 Apr 2023 13:38:33 -0400 Subject: [PATCH 13/58] add flatten_labels for ACSetTransformation --- src/AlgebraicPetri.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 56e26fed..def6924d 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -381,6 +381,8 @@ flatten_labels(pn::AbstractPetriNet; attributes=[:Name], sep='_') = begin f = x->flat_symbol(x, sep) map(pn; Dict(attr=>f for attr in attributes)...) end +flatten_labels(act::ACSetTransformation{S,Comp,<:AbstractPetriNet,<:AbstractPetriNet}; attributes=[:Name], sep='_') where {S,Comp} = + ACSetTransformation(flatten_labels(act.dom; attributes=attributes, sep=sep), act.codom; components(act)...) """ Concentration of a ReactionNet """ From 9c6dc6615d74b71b278ff9079fe4848bd771237d Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 18 Apr 2023 14:20:39 -0400 Subject: [PATCH 14/58] add typed_product for more than two typed petri nets --- src/TypedPetri.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index 704ef004..f154291b 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -204,6 +204,10 @@ function typed_product(p1, p2) pb = pullback(p1, p2; product_attrs=true) return first(legs(pb)) ⋅ p1 end +function typed_product(ps::AbstractVector) + pb = pullback(ps; product_attrs=true) + return first(legs(pb)) ⋅ first(ps) +end """ Make typed Petri net with 'identity' transformation between species pairs. From a5b23e650b4fdc83c96b5dc128371d73c9503d66 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 18 Apr 2023 15:40:39 -0400 Subject: [PATCH 15/58] add tests for new functionality --- test/typed_petri.jl | 1 + test/types.jl | 1 + 2 files changed, 2 insertions(+) diff --git a/test/typed_petri.jl b/test/typed_petri.jl index 725a659b..bcaeeafe 100644 --- a/test/typed_petri.jl +++ b/test/typed_petri.jl @@ -57,6 +57,7 @@ typed_sird_aug = add_reflexives( ) stratified = typed_product(typed_quarantine_aug, typed_sird_aug) +@test flatten_labels(stratified).dom == flatten_labels(typed_product([typed_quarantine_aug, typed_sird_aug])).dom @test ns(dom(stratified)) == 8 @test nt(dom(stratified)) == 6 + 4 + 1 @test dom(stratified)[1,:sname] isa Tuple{Symbol, Symbol} diff --git a/test/types.jl b/test/types.jl index 830925da..62055fee 100644 --- a/test/types.jl +++ b/test/types.jl @@ -126,6 +126,7 @@ for tuple_petri in [tuple_labelled, tuple_rxn] tuple_petri′ = tuple_petri |> flatten_labels + @test tuple_petri′ == flatten_labels(tuple_petri′) @test tuple_petri′[:, :sname] == [:U_S, :U_I, :U_R] @test tuple_petri′[:, :tname] == [:Q_inf, :Q_rec] end From c23aa179227b817d950c51ea18faea0dd38b1ad6 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 18 Apr 2023 16:35:35 -0400 Subject: [PATCH 16/58] bump version to 0.8.8 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1d23a44c..39933a82 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AlgebraicPetri" uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" license = "MIT" authors = ["Micah Halter "] -version = "0.8.7" +version = "0.8.8" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" From 9066a627bf35b49484e2a6c817b487546534f8b3 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 20 Apr 2023 12:25:50 -0400 Subject: [PATCH 17/58] add example of stratification of covid models Co-authored-by: p-stokes --- docs/Project.toml | 2 + docs/make.jl | 1 + docs/src/assets/runtime_vs_num_rgns.svg | 61 ++++ examples/covid/stratification/Project.toml | 6 + .../covid/stratification/stratification.jl | 263 ++++++++++++++++++ 5 files changed, 333 insertions(+) create mode 100644 docs/src/assets/runtime_vs_num_rgns.svg create mode 100644 examples/covid/stratification/Project.toml create mode 100644 examples/covid/stratification/stratification.jl diff --git a/docs/Project.toml b/docs/Project.toml index 3f36867e..a3d40be3 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,10 +2,12 @@ AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/docs/make.jl b/docs/make.jl index cc6f2459..e9b776a3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -44,6 +44,7 @@ makedocs( "examples/covid/coexist/coexist.md", "examples/enzymes/enzyme_reactions.md", "examples/covid/bilayerconversion.md", + "examples/covid/stratification/stratification.md", ], "Library Reference" => "api.md", ] diff --git a/docs/src/assets/runtime_vs_num_rgns.svg b/docs/src/assets/runtime_vs_num_rgns.svg new file mode 100644 index 00000000..cb23d7d5 --- /dev/null +++ b/docs/src/assets/runtime_vs_num_rgns.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/covid/stratification/Project.toml b/examples/covid/stratification/Project.toml new file mode 100644 index 00000000..529438b0 --- /dev/null +++ b/examples/covid/stratification/Project.toml @@ -0,0 +1,6 @@ +[deps] +AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" +Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" +DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" +PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" diff --git a/examples/covid/stratification/stratification.jl b/examples/covid/stratification/stratification.jl new file mode 100644 index 00000000..e259836c --- /dev/null +++ b/examples/covid/stratification/stratification.jl @@ -0,0 +1,263 @@ +# # [Stratification of COVID Models](@id stratification_example) +# +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/covid/stratification/stratification.ipynb) + +using AlgebraicPetri, AlgebraicPetri.TypedPetri +using Catlab.Programs, Catlab.Graphics +using Catlab.CategoricalAlgebra +using Catlab.WiringDiagrams +using DisplayAs, Markdown + +# ## Define basic epidemiology model + +# Define the type system for infectious disease models + +const infectious_ontology = LabelledPetriNet( + [:Pop], + :infect => ((:Pop, :Pop) => (:Pop, :Pop)), + :disease => (:Pop => :Pop), + :strata => (:Pop => :Pop) +) + +Graph(infectious_ontology) + +# Define a simple SIRD model with reflexive transitions typed as `:strata` to indicate which states can be stratified +# Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead +# population because they cannote do things such as get vaccinated or travel between regions. + +sird_uwd = @relation () where {(S::Pop, I::Pop, R::Pop, D::Pop)} begin + infect(S, I, I, I) + disease(I, R) + disease(I, D) +end + +sird_model = oapply_typed(infectious_ontology, sird_uwd, [:infection, :recovery, :death]) +sird_model = add_reflexives(sird_model, [[:strata], [:strata], [:strata], []], infectious_ontology) + +Graph(dom(sird_model)) + +# ## Define intervention models + +# ### Masking model + +masking_uwd = @relation () where {(M::Pop, UM::Pop)} begin + disease(M, UM) + disease(UM, M) + infect(M, UM, M, UM) + infect(UM, UM, UM, UM) +end +mask_model = oapply_typed(infectious_ontology, masking_uwd, [:unmask, :mask, :infect_um, :infect_uu]) +mask_model = add_reflexives(mask_model, [[:strata], [:strata]], infectious_ontology) + +Graph(dom(mask_model)) + +# Stratify our SIRD model on this masking model to get a model of SIRD with masking: + +typed_product(sird_model, mask_model) |> dom |> Graph + +# ### Vaccine model + +vax_uwd = @relation () where {(UV::Pop, V::Pop)} begin + strata(UV, V) + infect(V, V, V, V) + infect(V, UV, V, UV) + infect(UV, V, UV, V) + infect(UV, UV, UV, UV) +end +vax_model = oapply_typed(infectious_ontology, vax_uwd, [:vax, :infect_vv, :infect_uv, :infect_vu, :infect_uu]) +vax_model = add_reflexives(vax_model, [[:disease], [:disease]], infectious_ontology) + +Graph(dom(vax_model)) + +# Stratify our SIRD model on this vaccine model to get a model of SIRD with a vaccination rate: + +typed_product(sird_model, vax_model) |> dom |> Graph + +# ### Mask-Vax Model + +mask_vax_uwd = @relation () where {(UV_UM::Pop, UV_M::Pop, V_UM::Pop, V_M::Pop)} begin + strata(UV_UM, UV_M) + strata(UV_M, UV_UM) + strata(V_UM, V_M) + strata(V_M, V_UM) + strata(UV_UM, V_UM) + strata(UV_M, V_M) + infect(V_UM, V_UM, V_UM, V_UM) + infect(V_UM, UV_UM, V_UM, UV_UM) + infect(UV_UM, V_UM, UV_UM, V_UM) + infect(UV_UM, UV_UM, UV_UM, UV_UM) + infect(V_M, V_UM, V_M, V_UM) + infect(V_M, UV_UM, V_M, UV_UM) + infect(UV_M, V_UM, UV_M, V_UM) + infect(UV_M, UV_UM, UV_M, UV_UM) +end +mask_vax_model = oapply_typed( + infectious_ontology, + mask_vax_uwd, + [:mask_uv, :unmask_uv, :mask_v, :unmask_v, :vax_um, :vax_m, :infect_um_vv, :infect_um_uv, :infect_um_vu, :infect_um_uu, :infect_m_vv, :infect_m_uv, :infect_m_vu, :infect_m_uu] +) +mask_vax_model = add_reflexives(mask_vax_model, [[:disease], [:disease], [:disease], [:disease]], infectious_ontology) + +Graph(dom(mask_vax_model)) + +# Stratify our SIRD model on this mask + vaccine model to get a model of SIRD with a vaccination rate and masking policies: + +typed_product(sird_model, mask_vax_model) |> dom |> Graph + +# ## Define geographic models + +# ### Travel model between $N$ regions + +# For this model we can use a julia function to programmatically build up our undirected wiring diagram for defining this model. +# Here we want there to be $N$ regions in which people can travel between each region and people within the same region are able +# to infect other people in the same region. + +function travel_model(n) + uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + junctions = Dict(begin + junction = Symbol("Region$(i)") + junction => add_junction!(uwd, :Pop, variable=junction) + end for i in 1:n) + + pairs = filter(x -> first(x) != last(x), collect(Iterators.product(keys(junctions), keys(junctions)))) + for pair in pairs + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=:strata) + for (rgn, port) in zip(pair, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + end + + act = oapply_typed(infectious_ontology, uwd, [Symbol("$(a)_$(b)") for (a, b) in pairs]) + add_reflexives(act, repeat([[:infect, :disease]], n), infectious_ontology) +end + +Graph(dom(travel_model(2))) + +# Stratify our SIRD model on this travel model with two regions: + +typed_product(sird_model, travel_model(2)) |> dom |> Graph + +# ### Simple Trip model between $N$ regions + +# For this model we can use a julia function to programmatically build up our model where people have the property of living somewhere +# and we are modeling them traveling between locations while maintaining the status of where they live. Here we can actually just +# define the model of having a "Living" status and stratify it with the previously defined travel model to get a model of someone taking a simple trip. + +function living_model(n) + typed_living = pairwise_id_typed_petri(infectious_ontology, :Pop, :infect, [Symbol("Living$(i)") for i in 1:n]) + add_reflexives(typed_living, repeat([[:disease, :strata]], n), infectious_ontology) +end + +Graph(dom(living_model(2))) + +# The resulting simple trip model: + +simple_trip_model = typed_product(travel_model(2), living_model(2)) +Graph(dom(simple_trip_model)) + +# Stratify our SIRD model on this simple trip model between two regions: + +typed_product(sird_model, simple_trip_model) |> dom |> Graph + +# ## Stratification of COVID models + +# we set up a simple helper function to connect the undirected wiring diagrams to our +# infectious disease type system and add the necessary reflexive transitions for stratification. +function oapply_mira_model(uwd) + model = oapply_typed(infectious_ontology, uwd, [Symbol("t$(n)") for n in 1:nboxes(uwd)]) + add_reflexives(model, [repeat([[:strata]], njunctions(uwd)-3)..., [], [:strata],[]], infectious_ontology) +end + +# ### SIDARTHE Model +# +# BIOMD0000000955_miranet + +m1_model = (@relation () where {(S::Pop, I::Pop, D::Pop, A::Pop, R::Pop, T::Pop, H::Pop, E::Pop)} begin + infect(S, D, I, D) + infect(S, A, I, A) + infect(S, R, I, R) + infect(S, I, I, I) + disease(I, D) + disease(I, A) + disease(I, H) + disease(D, R) + disease(D, H) + disease(A, R) + disease(A, H) + disease(A, T) + disease(R, T) + disease(R, H) + disease(T, E) + disease(T, H) +end) |> oapply_mira_model + +Graph(dom(m1_model)) + +# ### SEIAHRD Model +# +# BIOMD0000000960_miranet + +m2_model = (@relation () where {(S::Pop, E::Pop, I::Pop, A::Pop, H::Pop, R::Pop, D::Pop)} begin + infect(S, I, E, I) + infect(S, A, E, A) + infect(S, H, E, H) + disease(E, I) + disease(E, A) + disease(I, H) + disease(I, R) + disease(I, D) + disease(A, R) + disease(A, D) + disease(H, D) + disease(H, R) +end) |> oapply_mira_model + +Graph(dom(m2_model)) + +# ### SEIuIrQRD Model +# +# BIOMD0000000983_miranet + +m3_model = (@relation () where {(S::Pop, E::Pop, Iu::Pop, Ir::Pop, Q::Pop, R::Pop, D::Pop)} begin + infect(S, Ir, E, Ir) + infect(S, Iu, E, Iu) + infect(S, Ir, Q, Ir) + infect(S, Iu, Q, Iu) + disease(Q, Ir) + disease(E, Ir) + disease(E, Iu) + disease(Ir, R) + disease(Iu, R) + disease(Q, S) + disease(Ir, D) +end) |> oapply_mira_model + +Graph(dom(m3_model)) + +# ### Enumerating stratified models +# +# Next we can take all of our epidemiology, intervention, and geography models and easily enumerate +# and calculate the models for every possible stratification combination and investigate the resulting models +# with some set number of regions for the geographic stratification models. + +num_rgns = 5 +disease_models = [("SIRD", sird_model), ("SIDARTHE", m1_model), ("SEIAHRD", m2_model), ("SEIuIrQRD", m3_model)] +policy_models = [nothing, ("Vaccination", vax_model), ("Masking", mask_model), ("Masking + Vaccination", mask_vax_model)] +travel_models = [nothing, ("Travel", travel_model(num_rgns)), ("Simple Trip", typed_product(travel_model(num_rgns), living_model(num_rgns)))] + +table = ["| Model | Inervention | Geography ($(num_rgns) regions) | # of States | # of Transitons |","|:--|$(repeat(":-:|", 4))"] + +for pieces in Iterators.product(disease_models, policy_models, travel_models) + petri = typed_product(last.(collect(filter(x -> !isnothing(x), pieces)))) |> dom + push!(table, "|$(join([isnothing(piece) ? "N/A" : first(piece) for piece in pieces],"|"))|$(ns(petri))|$(nt(petri))|") +end + +Markdown.parse(join(table, "\n")) |> DisplayAs.HTML + +# ## Performance +# +# As we increase the number of regions in our geographic stratification models, the +# number of states and transitions increase polynomially which causes the execution time +# for calculating the final stratified model to also increases polnomially. +# +# ![Runtime vs. Number of Georgraphic Regions](../../../../assets/runtime_vs_num_rgns.svg) From 29165287d0d51118c98619b838e43973c7479932 Mon Sep 17 00:00:00 2001 From: JonathanHallstrom Date: Sat, 22 Apr 2023 11:21:18 +0200 Subject: [PATCH 18/58] Minor spelling fixes --- examples/covid/stratification/stratification.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/covid/stratification/stratification.jl b/examples/covid/stratification/stratification.jl index e259836c..1c24c10d 100644 --- a/examples/covid/stratification/stratification.jl +++ b/examples/covid/stratification/stratification.jl @@ -140,7 +140,7 @@ typed_product(sird_model, travel_model(2)) |> dom |> Graph # ### Simple Trip model between $N$ regions # For this model we can use a julia function to programmatically build up our model where people have the property of living somewhere -# and we are modeling them traveling between locations while maintaining the status of where they live. Here we can actually just +# and we are modelling them travelling between locations while maintaining the status of where they live. Here we can actually just # define the model of having a "Living" status and stratify it with the previously defined travel model to get a model of someone taking a simple trip. function living_model(n) @@ -245,7 +245,7 @@ disease_models = [("SIRD", sird_model), ("SIDARTHE", m1_model), ("SEIAHRD", m2_m policy_models = [nothing, ("Vaccination", vax_model), ("Masking", mask_model), ("Masking + Vaccination", mask_vax_model)] travel_models = [nothing, ("Travel", travel_model(num_rgns)), ("Simple Trip", typed_product(travel_model(num_rgns), living_model(num_rgns)))] -table = ["| Model | Inervention | Geography ($(num_rgns) regions) | # of States | # of Transitons |","|:--|$(repeat(":-:|", 4))"] +table = ["| Model | Intervention | Geography ($(num_rgns) regions) | # of States | # of Transitons |","|:--|$(repeat(":-:|", 4))"] for pieces in Iterators.product(disease_models, policy_models, travel_models) petri = typed_product(last.(collect(filter(x -> !isnothing(x), pieces)))) |> dom @@ -258,6 +258,6 @@ Markdown.parse(join(table, "\n")) |> DisplayAs.HTML # # As we increase the number of regions in our geographic stratification models, the # number of states and transitions increase polynomially which causes the execution time -# for calculating the final stratified model to also increases polnomially. +# for calculating the final stratified model to also increase polynomially. # # ![Runtime vs. Number of Georgraphic Regions](../../../../assets/runtime_vs_num_rgns.svg) From 93ed5b703880f9facedd73889a6a5736752bae29 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Fri, 24 Mar 2023 10:15:51 -0400 Subject: [PATCH 19/58] Move to organization level github actions --- .github/workflows/CompatHelper.yml | 16 ---------- .github/workflows/TagBot.yml | 13 ++++++++ .github/workflows/codecov.yml | 18 ----------- .github/workflows/docs.yml | 27 ---------------- .github/workflows/julia_ci.yml | 50 ++++++++++++++++++++++++++++++ .github/workflows/rebase.yml | 19 ------------ .github/workflows/test.yml | 21 ------------- Project.toml | 2 +- README.md | 6 ++-- src/visualization.jl | 2 +- 10 files changed, 68 insertions(+), 106 deletions(-) delete mode 100644 .github/workflows/CompatHelper.yml delete mode 100644 .github/workflows/codecov.yml delete mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/julia_ci.yml delete mode 100644 .github/workflows/rebase.yml delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml deleted file mode 100644 index da266b9a..00000000 --- a/.github/workflows/CompatHelper.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: CompatHelper -on: - schedule: - - cron: '00 00 * * *' - workflow_dispatch: -jobs: - CompatHelper: - runs-on: ubuntu-latest - steps: - - name: Pkg.add("CompatHelper") - run: julia -e 'using Pkg; Pkg.add("CompatHelper")' - - name: CompatHelper.main() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} - run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index f3896111..90dc1009 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -8,7 +8,18 @@ on: lookback: default: 3 permissions: + actions: read + checks: read contents: write + deployments: read + issues: read + discussions: read + packages: read + pages: read + pull-requests: read + repository-projects: read + security-events: read + statuses: read jobs: TagBot: if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' @@ -17,4 +28,6 @@ jobs: - uses: JuliaRegistries/TagBot@v1 with: token: ${{ secrets.GITHUB_TOKEN }} + # Edit the following line to reflect the actual name of the GitHub Secret containing your private key ssh: ${{ secrets.DOCUMENTER_KEY }} + # ssh: ${{ secrets.NAME_OF_MY_SSH_PRIVATE_KEY_SECRET }} diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml deleted file mode 100644 index 77a90952..00000000 --- a/.github/workflows/codecov.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Code Coverage - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: "1.8" - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-runtest@v1 - - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 815bd6cb..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Documentation - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - env: - # GR backend fix for Plots, discussed in https://github.com/jheinen/GR.jl/issues/422 - GKSwstype: nul - steps: - - uses: actions/checkout@v2 - - name: "Set up Julia" - uses: julia-actions/setup-julia@v1 - with: - version: "1.8" - - name: "Install system dependencies" - run: | - sudo apt-get update - sudo apt-get install graphviz pdf2svg - sudo apt-get install texlive-latex-base texlive-latex-extra texlive-binaries texlive-pictures texlive-luatex - - name: "Install Julia dependencies" - run: julia --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate();' - - name: "Build and deploy docs" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: julia --project=docs docs/make.jl diff --git a/.github/workflows/julia_ci.yml b/.github/workflows/julia_ci.yml new file mode 100644 index 00000000..0052545d --- /dev/null +++ b/.github/workflows/julia_ci.yml @@ -0,0 +1,50 @@ +name: Julia CI/CD + +on: + schedule: + - cron: 0 0 * * * + push: + branches: ["master"] + tags: ["*"] + pull_request: + workflow_dispatch: + inputs: + action: + description: "Action" + required: true + default: "test" + type: choice + options: + - test + - release + version: + description: "Tag and release version:" + required: false + +permissions: + actions: read + checks: read + contents: write + deployments: read + discussions: read + issues: read + packages: read + pages: read + pull-requests: write + repository-projects: read + security-events: read + statuses: read + +jobs: + CI: + if: github.event_name == 'pull_request' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.action == 'test') + uses: AlgebraicJulia/.github/.github/workflows/julia_ci.yml@main + secrets: inherit + CompatHelper: + if: github.event_name == 'schedule' + uses: AlgebraicJulia/.github/.github/workflows/julia_compat.yml@main + secrets: inherit + Release: + if: github.event_name == 'workflow_dispatch' && inputs.action == 'release' && inputs.version != '' + uses: AlgebraicJulia/.github/.github/workflows/julia_release.yml@main + secrets: inherit diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml deleted file mode 100644 index 3ddf46c6..00000000 --- a/.github/workflows/rebase.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Automatic Rebase -on: - issue_comment: - types: [created] -jobs: - rebase: - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') - runs-on: ubuntu-latest - steps: - - name: Checkout the latest code - uses: actions/checkout@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - - name: Automatic Rebase - uses: cirrus-actions/rebase@1.5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index dc6d12cb..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Tests - -on: [push, pull_request] - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - julia_version: ["1.6", "1.7", "1.8"] - os: [ubuntu-latest] - - steps: - - uses: actions/checkout@v2 - - name: "Set up Julia" - uses: julia-actions/setup-julia@v1 - with: - version: ${{ matrix.julia_version }} - - name: "Run tests" - uses: julia-actions/julia-runtest@v1 diff --git a/Project.toml b/Project.toml index 39933a82..ecd6b6f8 100644 --- a/Project.toml +++ b/Project.toml @@ -14,7 +14,7 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" [compat] Catalyst = "^13.0.0" -Catlab = "^0.14.14" +Catlab = "^0.14.16" GeneralizedGenerated = "0.3" LabelledArrays = "^1" Requires = "^1" diff --git a/README.md b/README.md index 6bf07932..a2bed740 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # AlgebraicPetri.jl -[![Documentation](https://github.com/AlgebraicJulia/AlgebraicPetri.jl/workflows/Documentation/badge.svg)](https://algebraicjulia.github.io/AlgebraicPetri.jl/dev/) -![Tests](https://github.com/AlgebraicJulia/AlgebraicPetri.jl/workflows/Tests/badge.svg) -[![Code Coverage](https://codecov.io/gh/AlgebraicJulia/AlgebraicPetri.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/AlgebraicJulia/AlgebraicPetri.jl) +[![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://AlgebraicJulia.github.io/AlgebraicPetri.jl/stable) +[![Development Documentation](https://img.shields.io/badge/docs-dev-blue.svg)](https://AlgebraicJulia.github.io/AlgebraicPetri.jl/dev) +[![CI/CD](https://github.com/AlgebraicJulia/AlgebraicPetri.jl/actions/workflows/julia_ci.yml/badge.svg)](https://github.com/AlgebraicJulia/AlgebraicPetri.jl/actions/workflows/julia_ci.yml) [![DOI](https://zenodo.org/badge/275202510.svg)](https://zenodo.org/badge/latestdoi/275202510) `AlgebraicPetri.jl` is a Julia library for building Petri Net models diff --git a/src/visualization.jl b/src/visualization.jl index 2a4161bf..e04ae976 100644 --- a/src/visualization.jl +++ b/src/visualization.jl @@ -125,7 +125,7 @@ function Graph(m::Multispan{<:AbstractPetriNet}) g = Graphviz.Digraph("G", stmts; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) end -function Graph(p::ACSetTransformation{<:Any, <:Any, <:AbstractPetriNet, <:AbstractPetriNet}) +function Graph(p::StructACSetTransformation{<:Any, <:Any, <:AbstractPetriNet, <:AbstractPetriNet}) Graph(Multispan(p.dom, [p])) end From 438a1703e0529945062ef57a278dfa0611c941c9 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 28 Mar 2023 09:33:05 -0400 Subject: [PATCH 20/58] fix 32 bit compatibility --- src/ModelComparison.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModelComparison.jl b/src/ModelComparison.jl index f5d1db2f..dea97bd5 100644 --- a/src/ModelComparison.jl +++ b/src/ModelComparison.jl @@ -20,7 +20,7 @@ signatures (number of input/output wires). """ function petri_homomorphisms(p1::AbstractPetriNet, p2::AbstractPetriNet; kw...) results = ACSetTransformation[] - sigsTS = Set{Vector{Int64}}() + sigsTS = Set{Vector{Int}}() homs = homomorphisms(PetriNet(p1), PetriNet(p2); kw...) for transform in homs if all([length(inputs(p1, t)) == length(inputs(p2, transform.components[:T](t))) && From fc117545a7de5ffc3a9caaf4d50f784e7a9e8a75 Mon Sep 17 00:00:00 2001 From: p-stokes <92894586+p-stokes@users.noreply.github.com> Date: Mon, 24 Apr 2023 15:09:27 -0400 Subject: [PATCH 21/58] Fixes issue with mca_help not recursing. (#125) Co-authored-by: Micah Halter --- src/SubACSets.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SubACSets.jl b/src/SubACSets.jl index 4750f17f..696ae527 100644 --- a/src/SubACSets.jl +++ b/src/SubACSets.jl @@ -80,14 +80,14 @@ end function mca_help(X::ACSet, Y::ACSet) C = acset_schema(X) #X: C → Set - getsmaller(c) = map(dom, one_removed_subobs(X, c)) + getsmaller(Z,c) = map(dom, one_removed_subobs(Z, c)) # enumerate all sub-acsets X' ↪ X of the acset X: C → Set obtained by removing one point from Xc for some c ∈ C - oneRemovedFromX = concatmap(getsmaller, filter(c -> !isempty(parts(X,c)), objects(C))) + oneRemovedFromX = concatmap(γ -> getsmaller(X,γ), filter(c -> !isempty(parts(X,c)), objects(C))) # keep only those X' ↪ X such that there exists mono X' ↪ Y Y_subs = filter(χ -> exists_mono(χ, Y), oneRemovedFromX) # either terminate or recurse if isempty(Y_subs) - concatmap(χ -> mca_help(χ, Y), Y_subs) + concatmap(χ -> mca_help(χ, Y), oneRemovedFromX) else ω = maximum(map(size,Y_subs)) filter(y -> size(y) == ω, Y_subs) From 78f9b30a5038adc101cf26b918cc556d8f67f24e Mon Sep 17 00:00:00 2001 From: AlgebraicJulia Bot <129184742+algebraicjuliabot@users.noreply.github.com> Date: Mon, 24 Apr 2023 15:10:19 -0400 Subject: [PATCH 22/58] Set version to 0.8.9 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index ecd6b6f8..ba6a2f56 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AlgebraicPetri" uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" license = "MIT" authors = ["Micah Halter "] -version = "0.8.8" +version = "0.8.9" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" From b62914ddfdc390dffa3c8cef2b14022d8e9659a3 Mon Sep 17 00:00:00 2001 From: p-stokes <92894586+p-stokes@users.noreply.github.com> Date: Fri, 5 May 2023 14:42:27 -0400 Subject: [PATCH 23/58] Fix MCA recursion overflowing (#131) * Made test/SubACSets.jl, originally intended as a test for mca, but is currently for dubgging mca. Has mca_help2 that fixes part of the recursion, but one_removed_subobs still needs to be debugged. Uses DataStructures.jl * Adds a copy of Kris's cascade_subobj and a modified version (that removes the subobj rather than trims it) to test/SubACSets.jl * Added new version of mca_help to test/SubACSets.jl. Appears to be working (with rm_cascade_subobj), but could use further checks and cleanup prior to moving to src. * Clarified comment at end of test/SubACSets.jl * Added check for equality before pushing sub-acset to mca_list so it won't return duplicates. Also included new version of strip_names to work on unlabeled Petri nets. * Added strip_attributes, rather that strip_names. Started setting up determination of the morphisms and spans, in addition to the apex, for the mca. * Added mca_hel_rev function to find the corresponding subacsets from the larger mca input acset * Added function to get non-isomorphic mcas to help find other legs of spans. * Began moving new mca functions from test to src * Started adding doc strings to new mca functions. * clean up subacset rewrite and add tests --------- Co-authored-by: Micah Halter --- Project.toml | 12 ++-- src/SubACSets.jl | 144 +++++++++++++++++++++++----------------------- test/SubACSets.jl | 32 +++++++++++ test/runtests.jl | 6 +- 4 files changed, 117 insertions(+), 77 deletions(-) create mode 100644 test/SubACSets.jl diff --git a/Project.toml b/Project.toml index ba6a2f56..87d31a7a 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.8.9" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" GeneralizedGenerated = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -13,12 +14,13 @@ Requires = "ae029012-a4dd-5104-9daa-d747884805df" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" [compat] -Catalyst = "^13.0.0" -Catlab = "^0.14.16" +Catalyst = "13" +Catlab = "0.14.16" +DataStructures = "0.18" GeneralizedGenerated = "0.3" -LabelledArrays = "^1" -Requires = "^1" -StatsBase = "^0.33" +LabelledArrays = "1" +Requires = "1" +StatsBase = "0.33,0.34" julia = "1.6" [extras] diff --git a/src/SubACSets.jl b/src/SubACSets.jl index 696ae527..b0c5fac9 100644 --- a/src/SubACSets.jl +++ b/src/SubACSets.jl @@ -1,49 +1,49 @@ module SubACSets export mca -using Catlab, Catlab.Theories, Catlab.CategoricalAlgebra, Catlab.Graphs, Catlab.CategoricalAlgebra.FinSets -using Catlab.Graphics -using Catlab.CategoricalAlgebra.Diagrams -using Catlab.CategoricalAlgebra.FreeDiagrams -using Catlab.ACSetInterface -import Catlab.CategoricalAlgebra.FinCats: FreeCatGraph, FinDomFunctor, collect_ob, collect_hom -using Catlab.Programs -using AlgebraicPetri +using Catlab.CategoricalAlgebra +using DataStructures -concatmap(f,xs) = mapreduce(f, vcat, xs; init =[]) - -function strip_names(p::AbstractPetriNet) - map(p, Name = name -> nothing) -end - -function strip_names(p::ACSetTransformation) - init = NamedTuple([k=>collect(v) for (k,v) in pairs(components(p))]) - homomorphism(strip_names(dom(p)), strip_names(codom(p)), initial=init) -end - -# the smaller acset is the "pattern" -function normalize_order(X::ACSet, Y::ACSet) - size(X) ≤ size(Y) ? (X,Y) : (Y,X) -end +""" + rm_cascade_subobj(X::ACSet, rm_subs) -# given an acset X: C→Set and an object c ∈ C, compute all possible X' ↪ X which -# are given by removing a single element from the set Xc -function one_removed_subobs(X::ACSet, c) - C = acset_schema(X) - subs = [filter(j -> j != i, parts(X,c)) for i ∈ parts(X,c)] - build_sub(sub) = hom( - # need double negation to remove dangling edges - ¬¬Subobject( - X, - NamedTuple( - zip( - objects(C), - [o == c ? sub : parts(X, o) for o ∈ objects(C)] - ) - ) - ) - ) - map(build_sub, subs) +Deletes parts from an ACSet in cascading fashion, e.g. deleting a vertex deletes its edges +rm_subs is a NamedTuple or Dict of parts to be removed. +""" +function rm_cascade_subobj(X::ACSet, rm_subs) + # HACK: Remove this once Catlab makes cascading delete default + # https://github.com/AlgebraicJulia/Catlab.jl/pull/605 (old PR) + S = acset_schema(X) + subs = Dict([k => Set(parts(X, k)) for k ∈ objects(S)]) + rm_subs = Dict([k => Set(v) for (k, v) ∈ pairs(rm_subs)]) + while !isempty(rm_subs) + curr_c = first(rm_subs)[1] + if isempty(rm_subs[curr_c]) + delete!(rm_subs, curr_c) + else + curr_part = pop!(rm_subs[curr_c]) + if curr_part ∈ subs[curr_c] + delete!(subs[curr_c], curr_part) + for (f, c, d) ∈ homs(S) + if d == curr_c && c ∈ keys(subs) + for test_part ∈ subs[c] + if X[test_part, f] == curr_part + if c ∈ keys(rm_subs) + push!(rm_subs[c], test_part) + else + rm_subs[c] = Set([test_part]) + end + end + end + end + end + end + if isempty(rm_subs[curr_c]) + delete!(rm_subs, curr_c) + end + end + end + dom(hom(Subobject(X, NamedTuple(k => collect(v) for (k, v) ∈ subs)))) end """ @@ -53,45 +53,47 @@ Defintion: let 𝐺: C → 𝐒et be a C-set, we define the _size_ of 𝐺 to be * a Petri net P is |PT| + |PS| + |PI| + |PO| (num transitions + num species + num input arcs + num output arcs). """ -function size(X::ACSet) - foldl(+, [length(parts(X, oₛ)) for oₛ ∈ objects(acset_schema(X))]) +size(X::ACSet) = foldl(+, [length(parts(X, oₛ)) for oₛ ∈ objects(acset_schema(X))]) + +function strip_attributes(p::ACSet) + attributes = attrtypes(acset_schema(p)) + isempty(attributes) ? p : map(p; Dict(attr => (x -> nothing) for attr ∈ attributes)...) end +# Ask: "does there exists a mono X ↪ Y ?" +exists_mono(X::ACSet, Y::ACSet)::Bool = + is_homomorphic(X, strip_attributes(Y); monic=true, type_components=(Name=x -> nothing,)) -"""Get all monomorphisms from an acset X to an acset Y """ -monos(X::ACSet, Y::ACSet) = - homomorphism(X, strip_names(Y); monic = true, type_components=(Name=x->nothing,),) + mca(XX::ACSet, YY::ACSet) -"""Ask: "does there exists a mono X ↪ Y ?" -""" -exists_mono(X::ACSet,Y::ACSet)::Bool = - is_homomorphic(X, strip_names(Y); monic = true, type_components=(Name=x->nothing,),) - - -"""Brute-force implementation of Maximum Common Acset (MCA). -Input: two Acsets a₁ and a₂ -Task : find all a with with |a| maximum possible such that there is a monic span of Acset a₁ ← a → a₂. +Computes the maximimum common subacsets between XX and YY, i.e., find all a with with |a| maximum possible such that there is a monic span of Acset a₁ ← a → a₂. """ function mca(XX::ACSet, YY::ACSet) - (X,Y) = normalize_order(XX,YY) - exists_mono(X,Y) ? [X] : mca_help(X, Y) -end + (X, Y) = size(XX) ≤ size(YY) ? (XX, YY) : (YY, XX) # normalize order + + X_subs = BinaryHeap(Base.By(size, Base.Order.Reverse), [X]) + mca_list = Set{ACSet}() -function mca_help(X::ACSet, Y::ACSet) - C = acset_schema(X) #X: C → Set - getsmaller(Z,c) = map(dom, one_removed_subobs(Z, c)) - # enumerate all sub-acsets X' ↪ X of the acset X: C → Set obtained by removing one point from Xc for some c ∈ C - oneRemovedFromX = concatmap(γ -> getsmaller(X,γ), filter(c -> !isempty(parts(X,c)), objects(C))) - # keep only those X' ↪ X such that there exists mono X' ↪ Y - Y_subs = filter(χ -> exists_mono(χ, Y), oneRemovedFromX) - # either terminate or recurse - if isempty(Y_subs) - concatmap(χ -> mca_help(χ, Y), oneRemovedFromX) - else - ω = maximum(map(size,Y_subs)) - filter(y -> size(y) == ω, Y_subs) + while !isempty(X_subs) && (isempty(mca_list) || size(first(mca_list)) <= size(first(X_subs))) + curr_X_sub = pop!(X_subs) + C = acset_schema(curr_X_sub) #X: C → Set + if exists_mono(curr_X_sub, Y) + push!(mca_list, curr_X_sub) + else + indiv_parts = [] + for c ∈ objects(C) + for p ∈ parts(curr_X_sub, c) + push!(indiv_parts, NamedTuple([c => [p]])) + end + end + new_X_subs = mapreduce(γ -> rm_cascade_subobj(curr_X_sub, γ), vcat, indiv_parts; init=[]) + for new_sub ∈ new_X_subs + push!(X_subs, new_sub) + end + end end + mca_list end end diff --git a/test/SubACSets.jl b/test/SubACSets.jl new file mode 100644 index 00000000..3d6c5d8b --- /dev/null +++ b/test/SubACSets.jl @@ -0,0 +1,32 @@ +using Test + +using AlgebraicPetri, AlgebraicPetri.SubACSets + +m1 = LabelledPetriNet( + [:X3, :Y3, :W3, :Z3], + :f3 => (:X3 => (:W3, :Y3, :Z3)) +) + +m2 = LabelledPetriNet( + [:X4, :W4, :Y4, :Z4], + :f4 => ((:W4, :X4, :Y4) => :Z4) +) + +sub_acsets = mca(m1, m2) + +@test sub_acsets == Set([ + LabelledPetriNet( + [:X3, :Y3, :W3, :Z3], + :f3 => (:X3 => :Z3) + ), + LabelledPetriNet( + [:X3, :Y3, :W3, :Z3], + :f3 => (:X3 => :W3) + ), + LabelledPetriNet( + [:X3, :Y3, :W3, :Z3], + :f3 => (:X3 => :Y3) + ) +]) + +@test Set(PetriNet.(sub_acsets)) == mca(PetriNet(m1), PetriNet(m2)) diff --git a/test/runtests.jl b/test/runtests.jl index 77971a1d..4ab91a65 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -57,4 +57,8 @@ end @testset "Rewriting" begin include("rewriting.jl") -end \ No newline at end of file +end + +@testset "SubACSets" begin + include("SubACSets.jl") +end From 8a648019d6d8239e8ce949b6867f108bda21e619 Mon Sep 17 00:00:00 2001 From: AlgebraicJulia Bot <129184742+algebraicjuliabot@users.noreply.github.com> Date: Fri, 5 May 2023 14:43:19 -0400 Subject: [PATCH 24/58] Set version to 0.8.10 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 87d31a7a..b7892032 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AlgebraicPetri" uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" license = "MIT" authors = ["Micah Halter "] -version = "0.8.9" +version = "0.8.10" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" From 9015dae8bae8ffa69169ed2fd8fcbb61f828414a Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 9 May 2023 16:43:55 -0400 Subject: [PATCH 25/58] refactor(docs): move examples to docs and clean up random environments (#134) Signed-off-by: Micah Halter --- .gitignore | 5 - docs/.gitignore | 2 + {examples => docs/literate}/covid/_covid.jl | 0 .../literate}/covid/_generate_figs.jl | 0 .../literate}/covid/bilayerconversion.jl | 0 .../literate}/covid/chime/README.md | 0 .../literate}/covid/chime/chime-cset.jl | 0 .../literate}/covid/chime/chime.jl | 0 .../literate}/covid/chime/chime.json | 0 .../covid/chime/cset-json-schema.pdf | Bin .../covid/chime/cset-json-schema.rmd | 0 .../literate}/covid/chime/ode-chime.png | Bin .../literate}/covid/chime/sde-chime.png | Bin .../literate}/covid/chime/sir.png | Bin .../covid/coexist/3gen_coexist_petri.svg | 0 .../covid/coexist/3gen_coexist_wd.svg | 0 .../literate}/covid/coexist/coexist.jl | 0 .../literate}/covid/coexist/coexist.json | 0 .../literate}/covid/coexist/coexist_wd.svg | 0 .../literate}/covid/crossexposure_wd.svg | 0 .../literate}/covid/epidemiology.jl | 0 .../covid/stratification/stratification.jl | 0 .../literate}/enzymes/enzyme_reactions.jl | 0 .../literate}/predation/lotka-volterra.jl | 0 docs/make.jl | 51 +- examples/covid/Project.toml | 9 - examples/covid/chime/Manifest.toml | 918 ------------------ examples/covid/chime/Project.toml | 8 - examples/covid/stratification/Project.toml | 6 - examples/enzymes/Project.toml | 5 - examples/predation/Project.toml | 6 - 31 files changed, 30 insertions(+), 980 deletions(-) create mode 100644 docs/.gitignore rename {examples => docs/literate}/covid/_covid.jl (100%) rename {examples => docs/literate}/covid/_generate_figs.jl (100%) rename {examples => docs/literate}/covid/bilayerconversion.jl (100%) rename {examples => docs/literate}/covid/chime/README.md (100%) rename {examples => docs/literate}/covid/chime/chime-cset.jl (100%) rename {examples => docs/literate}/covid/chime/chime.jl (100%) rename {examples => docs/literate}/covid/chime/chime.json (100%) rename {examples => docs/literate}/covid/chime/cset-json-schema.pdf (100%) rename {examples => docs/literate}/covid/chime/cset-json-schema.rmd (100%) rename {examples => docs/literate}/covid/chime/ode-chime.png (100%) rename {examples => docs/literate}/covid/chime/sde-chime.png (100%) rename {examples => docs/literate}/covid/chime/sir.png (100%) rename {examples => docs/literate}/covid/coexist/3gen_coexist_petri.svg (100%) rename {examples => docs/literate}/covid/coexist/3gen_coexist_wd.svg (100%) rename {examples => docs/literate}/covid/coexist/coexist.jl (100%) rename {examples => docs/literate}/covid/coexist/coexist.json (100%) rename {examples => docs/literate}/covid/coexist/coexist_wd.svg (100%) rename {examples => docs/literate}/covid/crossexposure_wd.svg (100%) rename {examples => docs/literate}/covid/epidemiology.jl (100%) rename {examples => docs/literate}/covid/stratification/stratification.jl (100%) rename {examples => docs/literate}/enzymes/enzyme_reactions.jl (100%) rename {examples => docs/literate}/predation/lotka-volterra.jl (100%) delete mode 100644 examples/covid/Project.toml delete mode 100644 examples/covid/chime/Manifest.toml delete mode 100644 examples/covid/chime/Project.toml delete mode 100644 examples/covid/stratification/Project.toml delete mode 100644 examples/enzymes/Project.toml delete mode 100644 examples/predation/Project.toml diff --git a/.gitignore b/.gitignore index d512117e..d43b31a2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,6 @@ deps/downloads/ deps/usr/ deps/src/ -# Build artifacts for creating documentation generated by the Documenter package -docs/build/ -docs/site/ -docs/src/examples - # Editor/IDE specific ignores .vscode/ diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..cff0b76e --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +build/ +src/generated/ diff --git a/examples/covid/_covid.jl b/docs/literate/covid/_covid.jl similarity index 100% rename from examples/covid/_covid.jl rename to docs/literate/covid/_covid.jl diff --git a/examples/covid/_generate_figs.jl b/docs/literate/covid/_generate_figs.jl similarity index 100% rename from examples/covid/_generate_figs.jl rename to docs/literate/covid/_generate_figs.jl diff --git a/examples/covid/bilayerconversion.jl b/docs/literate/covid/bilayerconversion.jl similarity index 100% rename from examples/covid/bilayerconversion.jl rename to docs/literate/covid/bilayerconversion.jl diff --git a/examples/covid/chime/README.md b/docs/literate/covid/chime/README.md similarity index 100% rename from examples/covid/chime/README.md rename to docs/literate/covid/chime/README.md diff --git a/examples/covid/chime/chime-cset.jl b/docs/literate/covid/chime/chime-cset.jl similarity index 100% rename from examples/covid/chime/chime-cset.jl rename to docs/literate/covid/chime/chime-cset.jl diff --git a/examples/covid/chime/chime.jl b/docs/literate/covid/chime/chime.jl similarity index 100% rename from examples/covid/chime/chime.jl rename to docs/literate/covid/chime/chime.jl diff --git a/examples/covid/chime/chime.json b/docs/literate/covid/chime/chime.json similarity index 100% rename from examples/covid/chime/chime.json rename to docs/literate/covid/chime/chime.json diff --git a/examples/covid/chime/cset-json-schema.pdf b/docs/literate/covid/chime/cset-json-schema.pdf similarity index 100% rename from examples/covid/chime/cset-json-schema.pdf rename to docs/literate/covid/chime/cset-json-schema.pdf diff --git a/examples/covid/chime/cset-json-schema.rmd b/docs/literate/covid/chime/cset-json-schema.rmd similarity index 100% rename from examples/covid/chime/cset-json-schema.rmd rename to docs/literate/covid/chime/cset-json-schema.rmd diff --git a/examples/covid/chime/ode-chime.png b/docs/literate/covid/chime/ode-chime.png similarity index 100% rename from examples/covid/chime/ode-chime.png rename to docs/literate/covid/chime/ode-chime.png diff --git a/examples/covid/chime/sde-chime.png b/docs/literate/covid/chime/sde-chime.png similarity index 100% rename from examples/covid/chime/sde-chime.png rename to docs/literate/covid/chime/sde-chime.png diff --git a/examples/covid/chime/sir.png b/docs/literate/covid/chime/sir.png similarity index 100% rename from examples/covid/chime/sir.png rename to docs/literate/covid/chime/sir.png diff --git a/examples/covid/coexist/3gen_coexist_petri.svg b/docs/literate/covid/coexist/3gen_coexist_petri.svg similarity index 100% rename from examples/covid/coexist/3gen_coexist_petri.svg rename to docs/literate/covid/coexist/3gen_coexist_petri.svg diff --git a/examples/covid/coexist/3gen_coexist_wd.svg b/docs/literate/covid/coexist/3gen_coexist_wd.svg similarity index 100% rename from examples/covid/coexist/3gen_coexist_wd.svg rename to docs/literate/covid/coexist/3gen_coexist_wd.svg diff --git a/examples/covid/coexist/coexist.jl b/docs/literate/covid/coexist/coexist.jl similarity index 100% rename from examples/covid/coexist/coexist.jl rename to docs/literate/covid/coexist/coexist.jl diff --git a/examples/covid/coexist/coexist.json b/docs/literate/covid/coexist/coexist.json similarity index 100% rename from examples/covid/coexist/coexist.json rename to docs/literate/covid/coexist/coexist.json diff --git a/examples/covid/coexist/coexist_wd.svg b/docs/literate/covid/coexist/coexist_wd.svg similarity index 100% rename from examples/covid/coexist/coexist_wd.svg rename to docs/literate/covid/coexist/coexist_wd.svg diff --git a/examples/covid/crossexposure_wd.svg b/docs/literate/covid/crossexposure_wd.svg similarity index 100% rename from examples/covid/crossexposure_wd.svg rename to docs/literate/covid/crossexposure_wd.svg diff --git a/examples/covid/epidemiology.jl b/docs/literate/covid/epidemiology.jl similarity index 100% rename from examples/covid/epidemiology.jl rename to docs/literate/covid/epidemiology.jl diff --git a/examples/covid/stratification/stratification.jl b/docs/literate/covid/stratification/stratification.jl similarity index 100% rename from examples/covid/stratification/stratification.jl rename to docs/literate/covid/stratification/stratification.jl diff --git a/examples/enzymes/enzyme_reactions.jl b/docs/literate/enzymes/enzyme_reactions.jl similarity index 100% rename from examples/enzymes/enzyme_reactions.jl rename to docs/literate/enzymes/enzyme_reactions.jl diff --git a/examples/predation/lotka-volterra.jl b/docs/literate/predation/lotka-volterra.jl similarity index 100% rename from examples/predation/lotka-volterra.jl rename to docs/literate/predation/lotka-volterra.jl diff --git a/docs/make.jl b/docs/make.jl index e9b776a3..55a83217 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,28 +1,33 @@ using Documenter using Literate +const literate_dir = joinpath(@__DIR__, "literate") +const generated_dir = joinpath(@__DIR__, "src", "generated") + @info "Loading AlgebraicPetri" using AlgebraicPetri -# Set Literate.jl config if not being compiled on recognized service. -config = Dict{String,String}() -if !(haskey(ENV, "GITHUB_ACTIONS") || haskey(ENV, "GITLAB_CI")) - config["nbviewer_root_url"] = "https://nbviewer.jupyter.org/github/AlgebraicJulia/AlgebraicPetri.jl/blob/gh-pages/dev" - config["repo_root_url"] = "https://github.com/AlgebraicJulia/AlgebraicPetri.jl/blob/master/docs" -end +const no_literate = "--no-literate" in ARGS +if !no_literate + @info "Building Literate.jl docs" -const literate_dir = joinpath(@__DIR__, "..", "examples") -const generated_dir = joinpath(@__DIR__, "src", "examples") + # Set Literate.jl config if not being compiled on recognized service. + config = Dict{String,String}() + if !(haskey(ENV, "GITHUB_ACTIONS") || haskey(ENV, "GITLAB_CI")) + config["nbviewer_root_url"] = "https://nbviewer.jupyter.org/github/AlgebraicJulia/AlgebraicPetri.jl/blob/gh-pages/dev" + config["repo_root_url"] = "https://github.com/AlgebraicJulia/AlgebraicPetri.jl/blob/master/docs" + end -for (root, dirs, files) in walkdir(literate_dir) - out_dir = joinpath(generated_dir, relpath(root, literate_dir)) - for file in files - f,l = splitext(file) - if l == ".jl" && !startswith(f, "_") - Literate.markdown(joinpath(root, file), out_dir; - config=config, documenter=true, credit=false) - Literate.notebook(joinpath(root, file), out_dir; - execute=true, documenter=true, credit=false) + for (root, dirs, files) in walkdir(literate_dir) + out_dir = joinpath(generated_dir, relpath(root, literate_dir)) + for file in files + f,l = splitext(file) + if l == ".jl" && !startswith(f, "_") + Literate.markdown(joinpath(root, file), out_dir; + config=config, documenter=true, credit=false) + Literate.notebook(joinpath(root, file), out_dir; + execute=true, documenter=true, credit=false) + end end end end @@ -39,12 +44,12 @@ makedocs( pages = Any[ "AlgebraicPetri.jl" => "index.md", "Examples" => Any[ - "examples/predation/lotka-volterra.md", - "examples/covid/epidemiology.md", - "examples/covid/coexist/coexist.md", - "examples/enzymes/enzyme_reactions.md", - "examples/covid/bilayerconversion.md", - "examples/covid/stratification/stratification.md", + "generated/predation/lotka-volterra.md", + "generated/covid/epidemiology.md", + "generated/covid/coexist/coexist.md", + "generated/enzymes/enzyme_reactions.md", + "generated/covid/bilayerconversion.md", + "generated/covid/stratification/stratification.md", ], "Library Reference" => "api.md", ] diff --git a/examples/covid/Project.toml b/examples/covid/Project.toml deleted file mode 100644 index 3a255c94..00000000 --- a/examples/covid/Project.toml +++ /dev/null @@ -1,9 +0,0 @@ -[deps] -AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" -JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" diff --git a/examples/covid/chime/Manifest.toml b/examples/covid/chime/Manifest.toml deleted file mode 100644 index 50258cbc..00000000 --- a/examples/covid/chime/Manifest.toml +++ /dev/null @@ -1,918 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -[[Adapt]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "42c42f2221906892ceb765dbcb1a51deeffd86d7" -uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "2.3.0" - -[[AlgebraicPetri]] -deps = ["AutoHashEquals", "Catlab", "LabelledArrays", "LinearAlgebra", "Petri"] -path = "../../.." -uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -version = "0.4.1" - -[[ArnoldiMethod]] -deps = ["DelimitedFiles", "LinearAlgebra", "Random", "SparseArrays", "StaticArrays", "Test"] -git-tree-sha1 = "2b6845cea546604fb4dca4e31414a6a59d39ddcd" -uuid = "ec485272-7323-5ecc-a04f-4719b315124d" -version = "0.0.4" - -[[ArrayInterface]] -deps = ["LinearAlgebra", "Requires", "SparseArrays"] -git-tree-sha1 = "920136b6b8ae5bd28a3c45d68e55421dec156d7f" -uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "2.13.6" - -[[Artifacts]] -deps = ["Pkg"] -git-tree-sha1 = "c30985d8821e0cd73870b17b0ed0ce6dc44cb744" -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" -version = "1.3.0" - -[[AutoHashEquals]] -git-tree-sha1 = "45bb6705d93be619b81451bb2006b7ee5d4e4453" -uuid = "15f4f7f2-30c1-5605-9d31-71845cf9641f" -version = "0.2.0" - -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e" -uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.6+5" - -[[CanonicalTraits]] -deps = ["MLStyle"] -git-tree-sha1 = "fe3d23a57c0c9d9b99d7e65890a36c3de6b14906" -uuid = "a603d957-0e48-4f86-8fbd-0b7bc66df689" -version = "0.2.3" - -[[Catlab]] -deps = ["AutoHashEquals", "Compat", "Compose", "DataStructures", "FunctionWrappers", "GeneralizedGenerated", "JSON", "LightGraphs", "LightXML", "LinearAlgebra", "Logging", "MLStyle", "MetaGraphs", "Parameters", "Pkg", "PrettyTables", "Random", "Reexport", "Requires", "SparseArrays", "StaticArrays", "Statistics", "StructArrays"] -git-tree-sha1 = "8e028a374c82f2e3929ab2a60401d3ac80054384" -uuid = "134e5e36-593f-5add-ad60-77f754baafbe" -version = "0.9.1" - -[[ChainRulesCore]] -deps = ["LinearAlgebra", "MuladdMacro", "SparseArrays"] -git-tree-sha1 = "aebbda0a7c644bd8739b34f2a1b1e48f114aab49" -uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "0.9.17" - -[[CodecZlib]] -deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" -uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.0" - -[[ColorSchemes]] -deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random", "StaticArrays"] -git-tree-sha1 = "5d472aa8908568bc198564db06983913a6c2c8e7" -uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.10.1" - -[[ColorTypes]] -deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "4bffea7ed1a9f0f3d1a131bbcd4b925548d75288" -uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.10.9" - -[[Colors]] -deps = ["ColorTypes", "FixedPointNumbers", "InteractiveUtils", "Reexport"] -git-tree-sha1 = "008d6bc68dea6beb6303fdc37188cb557391ebf2" -uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" -version = "0.12.4" - -[[CommonSubexpressions]] -deps = ["MacroTools", "Test"] -git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" -uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" -version = "0.3.0" - -[[Compat]] -deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "f76e41cf110de7176a657c72409e722cfc86fbb6" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.20.0" - -[[CompilerSupportLibraries_jll]] -deps = ["Libdl", "Pkg"] -git-tree-sha1 = "7c4f882c41faa72118841185afc58a2eb00ef612" -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "0.3.3+0" - -[[Compose]] -deps = ["Base64", "Colors", "DataStructures", "Dates", "IterTools", "JSON", "LinearAlgebra", "Measures", "Printf", "Random", "Requires", "Statistics", "UUIDs"] -git-tree-sha1 = "a2b4df8e2dc688f2d63b5cfcc00c773218fa9e7f" -uuid = "a81c6b42-2e10-5240-aca2-a61377ecd94b" -version = "0.9.1" - -[[Contour]] -deps = ["StaticArrays"] -git-tree-sha1 = "d05a3a25b762720d40246d5bedf518c9c2614ef5" -uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" -version = "0.5.5" - -[[CpuId]] -deps = ["Markdown", "Test"] -git-tree-sha1 = "f0464e499ab9973b43c20f8216d088b61fda80c6" -uuid = "adafc99b-e345-5852-983c-f28acb93d879" -version = "0.2.2" - -[[Crayons]] -git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d" -uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" -version = "4.0.4" - -[[DataAPI]] -git-tree-sha1 = "176e23402d80e7743fc26c19c681bfb11246af32" -uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" -version = "1.3.0" - -[[DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "db07bb22795762895b60e44d62b34b16c982a687" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.7" - -[[DataValueInterfaces]] -git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" -uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" -version = "1.0.0" - -[[Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[DelimitedFiles]] -deps = ["Mmap"] -uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" - -[[DiffEqBase]] -deps = ["ArrayInterface", "ChainRulesCore", "DataStructures", "Distributed", "DocStringExtensions", "FunctionWrappers", "IterativeSolvers", "IteratorInterfaceExtensions", "LabelledArrays", "LinearAlgebra", "Logging", "MuladdMacro", "Parameters", "Printf", "RecipesBase", "RecursiveArrayTools", "RecursiveFactorization", "Requires", "Roots", "SparseArrays", "StaticArrays", "Statistics", "SuiteSparse", "TableTraits", "Tables", "TreeViews", "ZygoteRules"] -git-tree-sha1 = "2457d3b710e2767a8eab5d4d7983ae6a902e9335" -uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.48.0" - -[[DiffEqCallbacks]] -deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "OrdinaryDiffEq", "RecipesBase", "RecursiveArrayTools", "StaticArrays"] -git-tree-sha1 = "c252e7a153d902f7c535feb3d296fdd9812049c3" -uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" -version = "2.14.1" - -[[DiffEqJump]] -deps = ["ArrayInterface", "Compat", "DataStructures", "DiffEqBase", "FunctionWrappers", "LinearAlgebra", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "StaticArrays", "TreeViews", "UnPack"] -git-tree-sha1 = "68c389b108388d09f01065cf6d6df426f126d5a0" -uuid = "c894b116-72e5-5b58-be3c-e6d8d4ac2b12" -version = "6.10.1" - -[[DiffEqNoiseProcess]] -deps = ["DiffEqBase", "Distributions", "LinearAlgebra", "PoissonRandom", "Random", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "Requires", "ResettableStacks", "StaticArrays", "Statistics"] -git-tree-sha1 = "1ea45d69ee4c9f9f7da6069947929bf3705a543f" -uuid = "77a26b50-5914-5dd7-bc55-306e6241c503" -version = "5.4.0" - -[[DiffResults]] -deps = ["StaticArrays"] -git-tree-sha1 = "da24935df8e0c6cf28de340b958f6aac88eaa0cc" -uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" -version = "1.0.2" - -[[DiffRules]] -deps = ["NaNMath", "Random", "SpecialFunctions"] -git-tree-sha1 = "eb0c34204c8410888844ada5359ac8b96292cfd1" -uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" -version = "1.0.1" - -[[Distances]] -deps = ["LinearAlgebra", "Statistics"] -git-tree-sha1 = "a5b88815e6984e9f3256b6ca0dc63109b16a506f" -uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" -version = "0.9.2" - -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[Distributions]] -deps = ["FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "StaticArrays", "Statistics", "StatsBase", "StatsFuns"] -git-tree-sha1 = "164a5b8d81743dbb9b60d6e45b4e9c0f3b8a6caf" -uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.24.0" - -[[DocStringExtensions]] -deps = ["LibGit2", "Markdown", "Pkg", "Test"] -git-tree-sha1 = "50ddf44c53698f5e784bbebb3f4b21c5807401b1" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.3" - -[[EarCut_jll]] -deps = ["Libdl", "Pkg"] -git-tree-sha1 = "eabac56550a7d7e0be499125673fbff560eb8b20" -uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" -version = "2.1.5+0" - -[[ExponentialUtilities]] -deps = ["LinearAlgebra", "Printf", "Requires", "SparseArrays"] -git-tree-sha1 = "4e7db935d55d4a11acb74856ee6cb113a7808c6f" -uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18" -version = "1.8.0" - -[[FFMPEG]] -deps = ["FFMPEG_jll", "x264_jll"] -git-tree-sha1 = "9a73ffdc375be61b0e4516d83d880b265366fe1f" -uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" -version = "0.4.0" - -[[FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "LibVPX_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "3cc57ad0a213808473eafef4845a74766242e05f" -uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "4.3.1+4" - -[[FastClosures]] -git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" -uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" -version = "0.3.2" - -[[FillArrays]] -deps = ["LinearAlgebra", "Random", "SparseArrays"] -git-tree-sha1 = "502b3de6039d5b78c76118423858d981349f3823" -uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "0.9.7" - -[[FiniteDiff]] -deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"] -git-tree-sha1 = "a78ee56e4636c20c2db9ccde8afe57065f6ab387" -uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.7.0" - -[[FixedPointNumbers]] -deps = ["Statistics"] -git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" -uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.8.4" - -[[Formatting]] -deps = ["Printf"] -git-tree-sha1 = "a0c901c29c0e7c763342751c0a94211d56c0de5c" -uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" -version = "0.4.1" - -[[ForwardDiff]] -deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "NaNMath", "Random", "SpecialFunctions", "StaticArrays"] -git-tree-sha1 = "1d090099fb82223abc48f7ce176d3f7696ede36d" -uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.12" - -[[FreeType2_jll]] -deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "cbd58c9deb1d304f5a245a0b7eb841a2560cfec6" -uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.10.1+5" - -[[FriBidi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "0d20aed5b14dd4c9a2453c1b601d08e1149679cc" -uuid = "559328eb-81f9-559d-9380-de523a88c83c" -version = "1.0.5+6" - -[[FunctionWrappers]] -git-tree-sha1 = "e4813d187be8c7b993cb7f85cbf2b7bfbaadc694" -uuid = "069b7b12-0de2-55c6-9aab-29f3d0a68a2e" -version = "1.1.1" - -[[GR]] -deps = ["Base64", "DelimitedFiles", "HTTP", "JSON", "LinearAlgebra", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"] -git-tree-sha1 = "cd0f34bd097d4d5eb6bbe01778cf8a7ed35f29d9" -uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.52.0" - -[[GeneralizedGenerated]] -deps = ["CanonicalTraits", "DataStructures", "JuliaVariables", "MLStyle"] -git-tree-sha1 = "50e0ed8fbcd56ae2e65b9aa73394f20b30269b2d" -uuid = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb" -version = "0.2.7" - -[[GenericSVD]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "62909c3eda8a25b5673a367d1ad2392ebb265211" -uuid = "01680d73-4ee2-5a08-a1aa-533608c188bb" -version = "0.3.0" - -[[GeometryBasics]] -deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] -git-tree-sha1 = "876a906eab3be990fdcbfe1e43bb3a76f4776f72" -uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -version = "0.3.3" - -[[GeometryTypes]] -deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "StaticArrays"] -git-tree-sha1 = "34bfa994967e893ab2f17b864eec221b3521ba4d" -uuid = "4d00f742-c7ba-57c2-abde-4428a4b178cb" -version = "0.8.3" - -[[Grisu]] -git-tree-sha1 = "03d381f65183cb2d0af8b3425fde97263ce9a995" -uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" -version = "1.0.0" - -[[HTTP]] -deps = ["Base64", "Dates", "IniFile", "MbedTLS", "Sockets"] -git-tree-sha1 = "c7ec02c4c6a039a98a15f955462cd7aea5df4508" -uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "0.8.19" - -[[Inflate]] -git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c" -uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" -version = "0.1.2" - -[[IniFile]] -deps = ["Test"] -git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" -uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" -version = "0.5.0" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[IterTools]] -git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18" -uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" -version = "1.3.0" - -[[IterativeSolvers]] -deps = ["LinearAlgebra", "Printf", "Random", "RecipesBase", "SparseArrays"] -git-tree-sha1 = "3b7e2aac8c94444947facea7cc7ca91c49169be0" -uuid = "42fd0dbc-a981-5370-80f2-aaf504508153" -version = "0.8.4" - -[[IteratorInterfaceExtensions]] -git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" -uuid = "82899510-4779-5014-852e-03e436cf321d" -version = "1.0.0" - -[[JLD2]] -deps = ["CodecZlib", "DataStructures", "MacroTools", "Mmap", "Pkg", "Printf", "Requires", "UUIDs"] -git-tree-sha1 = "1b8168c14939e43c7c4d2c9e8f0ddd8718965430" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.2.4" - -[[JLLWrappers]] -git-tree-sha1 = "7cec881362e5b4e367ff0279dd99a06526d51a55" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.1.2" - -[[JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.1" - -[[JuliaVariables]] -deps = ["MLStyle", "NameResolution"] -git-tree-sha1 = "e0fcfa0a2f6122fbe13603764c5310dde00c5593" -uuid = "b14d175d-62b4-44ba-8fb7-3064adc8c3ec" -version = "0.2.3" - -[[LAME_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "df381151e871f41ee86cee4f5f6fd598b8a68826" -uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" -version = "3.100.0+3" - -[[LaTeXStrings]] -git-tree-sha1 = "c7aebfecb1a60d59c0fe023a68ec947a208b1e6b" -uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -version = "1.2.0" - -[[LabelledArrays]] -deps = ["ArrayInterface", "LinearAlgebra", "MacroTools", "StaticArrays"] -git-tree-sha1 = "5e04374019448f8509349948ab504f117e3b575a" -uuid = "2ee39098-c373-598a-b85f-a56591580800" -version = "1.3.0" - -[[Latexify]] -deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] -git-tree-sha1 = "829b033e31573b8ffdd14e0d47154fd3ddc7abbf" -uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.14.0" - -[[LibGit2]] -deps = ["Printf"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[LibVPX_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "85fcc80c3052be96619affa2fe2e6d2da3908e11" -uuid = "dd192d2f-8180-539f-9fb4-cc70b1dcf69a" -version = "1.9.0+1" - -[[Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[Libiconv_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "8e924324b2e9275a51407a4e06deb3455b1e359f" -uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.16.0+7" - -[[LightGraphs]] -deps = ["ArnoldiMethod", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] -git-tree-sha1 = "a0d4bcea4b9c056da143a5ded3c2b7f7740c2d41" -uuid = "093fc24a-ae57-5d10-9952-331d41423f4d" -version = "1.3.0" - -[[LightXML]] -deps = ["Libdl", "XML2_jll"] -git-tree-sha1 = "e129d9391168c677cd4800f5c0abb1ed8cb3794f" -uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" -version = "0.9.0" - -[[LineSearches]] -deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] -git-tree-sha1 = "d6e6b2ed397a402a22e474a3f1859c8c1db82c8c" -uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" -version = "7.1.0" - -[[LinearAlgebra]] -deps = ["Libdl"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[LoopVectorization]] -deps = ["DocStringExtensions", "LinearAlgebra", "OffsetArrays", "SIMDPirates", "SLEEFPirates", "UnPack", "VectorizationBase"] -git-tree-sha1 = "3242a8f411e19eda9adc49d0b877681975c11375" -uuid = "bdcacae8-1622-11e9-2a5c-532679323890" -version = "0.8.26" - -[[MLStyle]] -git-tree-sha1 = "937eda9ce36fcce082a42edd7181c8d23f4eb550" -uuid = "d8e11817-5142-5d16-987a-aa16d5891078" -version = "0.4.6" - -[[MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "f7d2e3f654af75f01ec49be82c231c382214223a" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.5" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "426a6978b03a97ceb7ead77775a1da066343ec6e" -uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.2" - -[[MbedTLS_jll]] -deps = ["Libdl", "Pkg"] -git-tree-sha1 = "c0b1286883cac4e2b617539de41111e0776d02e8" -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.16.8+0" - -[[Measures]] -git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" -uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" -version = "0.3.1" - -[[MetaGraphs]] -deps = ["JLD2", "LightGraphs", "Random"] -git-tree-sha1 = "df1706b656e11e7bcf5997a51501e40fab84f567" -uuid = "626554b9-1ddb-594c-aa3c-2596fe9399a5" -version = "0.6.6" - -[[Missings]] -deps = ["DataAPI"] -git-tree-sha1 = "ed61674a0864832495ffe0a7e889c0da76b0f4c8" -uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" -version = "0.4.4" - -[[Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[MuladdMacro]] -git-tree-sha1 = "c6190f9a7fc5d9d5915ab29f2134421b12d24a68" -uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -version = "0.2.2" - -[[NLSolversBase]] -deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] -git-tree-sha1 = "39d6bc45e99c96e6995cbddac02877f9b61a1dd1" -uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" -version = "7.7.1" - -[[NLsolve]] -deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] -git-tree-sha1 = "650f266dcb5a24b4095fdab92f0137c0f4ee9392" -uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" -version = "4.4.1" - -[[NaNMath]] -git-tree-sha1 = "c84c576296d0e2fbb3fc134d3e09086b3ea617cd" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "0.3.4" - -[[NameResolution]] -deps = ["PrettyPrint"] -git-tree-sha1 = "1a0fa0e9613f46c9b8c11eee38ebb4f590013c5e" -uuid = "71a1bf82-56d0-4bbc-8a3c-48b961074391" -version = "0.1.5" - -[[OffsetArrays]] -git-tree-sha1 = "a416e2f267e2c8729f25bcaf1ce19d2893faf393" -uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.3.1" - -[[Ogg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "a42c0f138b9ebe8b58eba2271c5053773bde52d0" -uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.4+2" - -[[OpenSSL_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "71bbbc616a1d710879f5a1021bcba65ffba6ce58" -uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "1.1.1+6" - -[[OpenSpecFun_jll]] -deps = ["CompilerSupportLibraries_jll", "Libdl", "Pkg"] -git-tree-sha1 = "d51c416559217d974a1113522d5919235ae67a87" -uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.3+3" - -[[Opus_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "f9d57f4126c39565e05a2b0264df99f497fc6f37" -uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.3.1+3" - -[[OrderedCollections]] -git-tree-sha1 = "16c08bf5dba06609fe45e30860092d6fa41fde7b" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.3.1" - -[[OrdinaryDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "ExponentialUtilities", "FastClosures", "FiniteDiff", "ForwardDiff", "GenericSVD", "LinearAlgebra", "Logging", "MacroTools", "MuladdMacro", "NLsolve", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "50724f6881234caa4f928473f50ce966b08aa4ed" -uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "5.43.0" - -[[PDMats]] -deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse", "Test"] -git-tree-sha1 = "95a4038d1011dfdbde7cecd2ad0ac411e53ab1bc" -uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" -version = "0.10.1" - -[[Parameters]] -deps = ["OrderedCollections", "UnPack"] -git-tree-sha1 = "38b2e970043613c187bd56a995fe2e551821eb4a" -uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" -version = "0.12.1" - -[[Parsers]] -deps = ["Dates"] -git-tree-sha1 = "6fa4202675c05ba0f8268a6ddf07606350eda3ce" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.0.11" - -[[Petri]] -deps = ["AutoHashEquals", "Catlab", "DiffEqBase", "DiffEqJump", "OrdinaryDiffEq", "SparseArrays", "SteadyStateDiffEq", "StochasticDiffEq"] -git-tree-sha1 = "363ff2f68331502604b80be72196c658dc0789cb" -uuid = "4259d249-1051-49fa-8328-3f8ab9391c33" -version = "1.2.3" - -[[Pkg]] -deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[PlotThemes]] -deps = ["PlotUtils", "Requires", "Statistics"] -git-tree-sha1 = "c6f5ea535551b3b16835134697f0c65d06c94b91" -uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "2.0.0" - -[[PlotUtils]] -deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] -git-tree-sha1 = "4e098f88dad9a2b518b83124a116be1c49e2b2bf" -uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.0.7" - -[[Plots]] -deps = ["Base64", "Contour", "Dates", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "GeometryTypes", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"] -git-tree-sha1 = "f4425bbd5f313b074d6ce3b86d80c0ad16bf7326" -uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.6.12" - -[[PoissonRandom]] -deps = ["Random", "Statistics", "Test"] -git-tree-sha1 = "44d018211a56626288b5d3f8c6497d28c26dc850" -uuid = "e409e4f3-bfea-5376-8464-e040bb5c01ab" -version = "0.4.0" - -[[PrettyPrint]] -git-tree-sha1 = "632eb4abab3449ab30c5e1afaa874f0b98b586e4" -uuid = "8162dcfd-2161-5ef2-ae6c-7681170c5f98" -version = "0.2.0" - -[[PrettyTables]] -deps = ["Crayons", "Formatting", "Parameters", "Reexport", "Tables"] -git-tree-sha1 = "8458dc04a493ae5c2fed3796c1d3117972c69694" -uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" -version = "0.9.1" - -[[Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[QuadGK]] -deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "12fbe86da16df6679be7521dfb39fbc861e1dc7b" -uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.4.1" - -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[RandomNumbers]] -deps = ["Random", "Requires"] -git-tree-sha1 = "441e6fc35597524ada7f85e13df1f4e10137d16f" -uuid = "e6cf234a-135c-5ec9-84dd-332b85af5143" -version = "1.4.0" - -[[RecipesBase]] -git-tree-sha1 = "6ee6c35fe69e79e17c455a386c1ccdc66d9f7da4" -uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -version = "1.1.0" - -[[RecipesPipeline]] -deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] -git-tree-sha1 = "4a325c9bcc2d8e62a8f975b9666d0251d53b63b9" -uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" -version = "0.1.13" - -[[RecursiveArrayTools]] -deps = ["ArrayInterface", "LinearAlgebra", "RecipesBase", "Requires", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "639b3c4c7bcdc42be3ce69c4919eac17be73242b" -uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" -version = "2.7.2" - -[[RecursiveFactorization]] -deps = ["LinearAlgebra", "LoopVectorization", "VectorizationBase"] -git-tree-sha1 = "4ca0bdad1d69abbd59c35af89a9a2ab6cd5ef0f1" -uuid = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" -version = "0.1.4" - -[[Reexport]] -deps = ["Pkg"] -git-tree-sha1 = "7b1d07f411bc8ddb7977ec7f377b97b158514fe0" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "0.2.0" - -[[Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "28faf1c963ca1dc3ec87f166d92982e3c4a1f66d" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.1.0" - -[[ResettableStacks]] -deps = ["StaticArrays"] -git-tree-sha1 = "d19e9c93de6020a96dbb2820567c78d0ab8f7248" -uuid = "ae5879a3-cd67-5da8-be7f-38c6eb64a37b" -version = "1.0.0" - -[[Rmath]] -deps = ["Random", "Rmath_jll"] -git-tree-sha1 = "86c5647b565873641538d8f812c04e4c9dbeb370" -uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" -version = "0.6.1" - -[[Rmath_jll]] -deps = ["Libdl", "Pkg"] -git-tree-sha1 = "d76185aa1f421306dec73c057aa384bad74188f0" -uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" -version = "0.2.2+1" - -[[Roots]] -deps = ["Printf"] -git-tree-sha1 = "1211c7c1928c1ed29cdcef65979b7a791e3b9fbe" -uuid = "f2b01f46-fcfa-551c-844a-d8ac1e96c665" -version = "1.0.5" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[SIMDPirates]] -deps = ["VectorizationBase"] -git-tree-sha1 = "450d163d3279a1d35e3aad3352a5167ef21b84a4" -uuid = "21efa798-c60a-11e8-04d3-e1a92915a26a" -version = "0.8.25" - -[[SLEEFPirates]] -deps = ["Libdl", "SIMDPirates", "VectorizationBase"] -git-tree-sha1 = "67ae90a18aa8c22bf159318300e765fbd89ddf6e" -uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" -version = "0.5.5" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" - -[[Showoff]] -deps = ["Dates", "Grisu"] -git-tree-sha1 = "ee010d8f103468309b8afac4abb9be2e18ff1182" -uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" -version = "0.3.2" - -[[SimpleTraits]] -deps = ["InteractiveUtils", "MacroTools"] -git-tree-sha1 = "daf7aec3fe3acb2131388f93a4c409b8c7f62226" -uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" -version = "0.9.3" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[SortingAlgorithms]] -deps = ["DataStructures", "Random", "Test"] -git-tree-sha1 = "03f5898c9959f8115e30bc7226ada7d0df554ddd" -uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" -version = "0.3.1" - -[[SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[SparseDiffTools]] -deps = ["Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "LightGraphs", "LinearAlgebra", "Requires", "SparseArrays", "VertexSafeGraphs"] -git-tree-sha1 = "69de355cb5e2b9a0e89f383c1762bba5ae70b580" -uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804" -version = "1.10.0" - -[[SpecialFunctions]] -deps = ["OpenSpecFun_jll"] -git-tree-sha1 = "d8d8b8a9f4119829410ecd706da4cc8594a1e020" -uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "0.10.3" - -[[StaticArrays]] -deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "016d1e1a00fabc556473b07161da3d39726ded35" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "0.12.4" - -[[Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[StatsBase]] -deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics"] -git-tree-sha1 = "7bab7d4eb46b225b35179632852b595a3162cb61" -uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.33.2" - -[[StatsFuns]] -deps = ["Rmath", "SpecialFunctions"] -git-tree-sha1 = "04a5a8e6ab87966b43f247920eab053fd5fdc925" -uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -version = "0.9.5" - -[[SteadyStateDiffEq]] -deps = ["DiffEqBase", "DiffEqCallbacks", "LinearAlgebra", "NLsolve", "Reexport"] -git-tree-sha1 = "75f258513b7ef8b235876f4cf146577ffd545094" -uuid = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f" -version = "1.5.1" - -[[StochasticDiffEq]] -deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqJump", "DiffEqNoiseProcess", "FillArrays", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "09c24c310da843a3c6b41984089f2a28c301d3b1" -uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" -version = "6.26.0" - -[[StructArrays]] -deps = ["Adapt", "DataAPI", "Tables"] -git-tree-sha1 = "8099ed9fb90b6e754d6ba8c6ed8670f010eadca0" -uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" -version = "0.4.4" - -[[SuiteSparse]] -deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] -uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" - -[[TableTraits]] -deps = ["IteratorInterfaceExtensions"] -git-tree-sha1 = "b1ad568ba658d8cbb3b892ed5380a6f3e781a81e" -uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" -version = "1.0.0" - -[[Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] -git-tree-sha1 = "24a584cf65e2cfabdadc21694fb69d2e74c82b44" -uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.1.0" - -[[Test]] -deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[TranscodingStreams]] -deps = ["Random", "Test"] -git-tree-sha1 = "7c53c35547de1c5b9d46a4797cf6d8253807108c" -uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.9.5" - -[[TreeViews]] -deps = ["Test"] -git-tree-sha1 = "8d0d7a3fe2f30d6a7f833a5f19f7c7a5b396eae6" -uuid = "a2a6695c-b41b-5b7d-aed9-dbfdeacea5d7" -version = "0.3.0" - -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[UnPack]] -git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" -uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" -version = "1.0.2" - -[[Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[VectorizationBase]] -deps = ["CpuId", "Libdl", "LinearAlgebra"] -git-tree-sha1 = "03e2fbb479a1ea350398195b6fbf439bae0f8260" -uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.12.33" - -[[VertexSafeGraphs]] -deps = ["LightGraphs"] -git-tree-sha1 = "b9b450c99a3ca1cc1c6836f560d8d887bcbe356e" -uuid = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f" -version = "0.1.2" - -[[XML2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "be0db24f70aae7e2b89f2f3092e93b8606d659a6" -uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.9.10+3" - -[[Zlib_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "320228915c8debb12cb434c59057290f0834dbf6" -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.2.11+18" - -[[ZygoteRules]] -deps = ["MacroTools"] -git-tree-sha1 = "b3b4882cc9accf6731a08cc39543fbc6b669dca8" -uuid = "700de1a5-db45-46bc-99cf-38207098b444" -version = "0.2.0" - -[[libass_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "acc685bcf777b2202a904cdcb49ad34c2fa1880c" -uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" -version = "0.14.0+4" - -[[libfdk_aac_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "7a5780a0d9c6864184b3a2eeeb833a0c871f00ab" -uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" -version = "0.1.6+4" - -[[libvorbis_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] -git-tree-sha1 = "fa14ac25af7a4b8a7f61b287a124df7aab601bcd" -uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.6+6" - -[[x264_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "d713c1ce4deac133e3334ee12f4adff07f81778f" -uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" -version = "2020.7.14+2" - -[[x265_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "487da2f8f2f0c8ee0e83f39d13037d6bbf0a45ab" -uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" -version = "3.0.0+3" diff --git a/examples/covid/chime/Project.toml b/examples/covid/chime/Project.toml deleted file mode 100644 index c8a257f4..00000000 --- a/examples/covid/chime/Project.toml +++ /dev/null @@ -1,8 +0,0 @@ -[deps] -AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" -JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/examples/covid/stratification/Project.toml b/examples/covid/stratification/Project.toml deleted file mode 100644 index 529438b0..00000000 --- a/examples/covid/stratification/Project.toml +++ /dev/null @@ -1,6 +0,0 @@ -[deps] -AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" -DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6" -Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" -PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" diff --git a/examples/enzymes/Project.toml b/examples/enzymes/Project.toml deleted file mode 100644 index 22d43b63..00000000 --- a/examples/enzymes/Project.toml +++ /dev/null @@ -1,5 +0,0 @@ -[deps] -AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" -DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/examples/predation/Project.toml b/examples/predation/Project.toml deleted file mode 100644 index 864972b0..00000000 --- a/examples/predation/Project.toml +++ /dev/null @@ -1,6 +0,0 @@ -[deps] -AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" From 085efac06d3b37bde0a061b7d8240847cbe88279 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 10 May 2023 21:29:20 -0400 Subject: [PATCH 26/58] perf: use native package extensions in julia 1.9+ (#135) --- Project.toml | 18 ++-- ext/AlgebraicPetriCatalystExt.jl | 43 +++++++++ ext/AlgebraicPetriModelingToolkitExt.jl | 114 ++++++++++++++++++++++++ ext/AlgebraicPetriPetriExt.jl | 29 ++++++ src/AlgebraicPetri.jl | 5 +- src/CatalystInterop.jl | 39 -------- src/ModelingToolkitInterop.jl | 113 ----------------------- src/interoperability.jl | 30 +------ 8 files changed, 206 insertions(+), 185 deletions(-) create mode 100644 ext/AlgebraicPetriCatalystExt.jl create mode 100644 ext/AlgebraicPetriModelingToolkitExt.jl create mode 100644 ext/AlgebraicPetriPetriExt.jl delete mode 100644 src/CatalystInterop.jl delete mode 100644 src/ModelingToolkitInterop.jl diff --git a/Project.toml b/Project.toml index b7892032..2fc4fd3b 100644 --- a/Project.toml +++ b/Project.toml @@ -13,17 +13,25 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Requires = "ae029012-a4dd-5104-9daa-d747884805df" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +[weakdeps] +Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" +ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" +Requires = "ae029012-a4dd-5104-9daa-d747884805df" # makes sure Requires isn't a dependency for Julia v1.9+ + +[extensions] +AlgebraicPetriPetriExt = "Petri" +AlgebraicPetriCatalystExt = "Catalyst" +AlgebraicPetriModelingToolkitExt = "ModelingToolkit" + [compat] Catalyst = "13" Catlab = "0.14.16" DataStructures = "0.18" GeneralizedGenerated = "0.3" LabelledArrays = "1" +ModelingToolkit = "8" +Petri = "1" Requires = "1" StatsBase = "0.33,0.34" julia = "1.6" - -[extras] -Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" -Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" diff --git a/ext/AlgebraicPetriCatalystExt.jl b/ext/AlgebraicPetriCatalystExt.jl new file mode 100644 index 00000000..adcc7722 --- /dev/null +++ b/ext/AlgebraicPetriCatalystExt.jl @@ -0,0 +1,43 @@ +module AlgebraicPetriCatalystExt + +using AlgebraicPetri +using Catlab.CategoricalAlgebra +# TODO: Remove after dropping support for Dict(snames[k]=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) + t_out = map(i->Dict(snames[k]=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) + Δ = Dict(tnames[i]=>t for (i,t) in enumerate(zip(t_in, t_out))) + S = collect(values(snames)) + else + t_in = map(i->Dict(k=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) + t_out = map(i->Dict(k=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) + Δ = Dict(i=>t for (i,t) in enumerate(zip(t_in, t_out))) + S = ns(p) + end + + return Petri.Model(ns(p), Δ) +end + +end diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index def6924d..2847af00 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -734,7 +734,6 @@ Open(p::PropertyLabelledReactionNet{R,C,T}, legs...) where {R,C,T} = begin end Open(p::PropertyLabelledReactionNet{R,C,T}) where {R,C,T} = OpenPropertyLabelledReactionNet{R,C,T}(p, map(x -> FinFunction([x], ns(p)), 1:ns(p))...) -include("interoperability.jl") include("visualization.jl") include("Epidemiology.jl") include("BilayerNetworks.jl") @@ -742,4 +741,8 @@ include("ModelComparison.jl") include("SubACSets.jl") include("TypedPetri.jl") include("OpenTransitions.jl") + +# TODO: Remove after dropping support for LVector(;[(snames[k]=>v) for (k,v) in enumerate(ts.input[i,:]) if v != 0]...), 1:nt(p)) - t_out = map(i->LVector(;[(snames[k]=>v) for (k,v) in enumerate(ts.output[i,:]) if v != 0]...), 1:nt(p)) - Δ = LVector(;[(tnames[i]=>t) for (i,t) in enumerate(zip(t_in, t_out))]...) - S = collect(values(snames)) - else - t_in = map(i->Dict(k=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) - t_out = map(i->Dict(k=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) - Δ = Dict(i=>t for (i,t) in enumerate(zip(t_in, t_out))) - S = ns(p) - end - - return Petri.Model(ns(p), Δ) - end - end - - @require Catalyst="479239e8-5488-4da2-87a7-35f2df7eef83" include("CatalystInterop.jl") - @require ModelingToolkit="961ee093-0014-501f-94e3-6117800e7a78" include("ModelingToolkitInterop.jl") + @require Petri="4259d249-1051-49fa-8328-3f8ab9391c33" include("../ext/AlgebraicPetriPetriExt.jl") + @require Catalyst="479239e8-5488-4da2-87a7-35f2df7eef83" include("../ext/AlgebraicPetriCatalystExt.jl") + @require ModelingToolkit="961ee093-0014-501f-94e3-6117800e7a78" include("../ext/AlgebraicPetriModelingToolkitExt.jl") end From c89c621454c3aad029962fc0de4c2448f0ca5bb4 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Fri, 12 May 2023 11:36:36 -0400 Subject: [PATCH 27/58] fix: allow vector field functions to work with more types (#136) Allow `vectorfield_expr` to work with other indexable types (#139) * comprehensions not allowed in generated * fix vectorfield_expr * vector for rates contains union types of float or function * remove commented-out code * get rid of files that snuck in asdf --- Project.toml | 1 - src/AlgebraicPetri.jl | 62 ++++++++++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/Project.toml b/Project.toml index 2fc4fd3b..5f82457c 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,6 @@ Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" GeneralizedGenerated = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Requires = "ae029012-a4dd-5104-9daa-d747884805df" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 2847af00..da21c59a 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -25,7 +25,6 @@ using Catlab.CategoricalAlgebra.FinSets using Catlab.Present using Catlab.Theories using LabelledArrays -using LinearAlgebra: mul! using GeneralizedGenerated: mk_function vectorify(n::AbstractVector) = n @@ -297,8 +296,8 @@ passed to the DifferentialEquations.jl solver package. vectorfield(pn::AbstractPetriNet) = begin tm = TransitionMatrices(pn) dt = tm.output - tm.input - f(du, u, p, t) = begin - rates = zeros(eltype(du), nt(pn)) + (du, u, p, t) -> begin + rates = zeros(valtype(du), nt(pn)) u_m = [u[sname(pn, i)] for i in 1:ns(pn)] p_m = [p[tname(pn, i)] for i in 1:nt(pn)] for i in 1:nt(pn) @@ -307,9 +306,8 @@ vectorfield(pn::AbstractPetriNet) = begin for j in 1:ns(pn) du[sname(pn, j)] = sum(rates[i] * dt[i, j] for i in 1:nt(pn); init=0.0) end - return du + du end - return f end """ vectorfield_expr(pn::AbstractPetriNet) @@ -323,19 +321,53 @@ passed to the DifferentialEquations.jl solver package. vectorfield_expr(pn::AbstractPetriNet) = begin fquote = Expr(:function, Expr(:tuple, :du, :u, :p, :t)) fcode = Expr[] + num_t = nt(pn) + + # generate vector of rate constants for each transition p_ix = [tname(pn, i) for i in 1:nt(pn)] push!(fcode, :( - p_m = p[$(p_ix)] + p_m = Vector{Union{Float64,Function}}(undef,$(num_t)) )) - for i in 1:nt(pn) + for i in 1:num_t + if eltype(p_ix) <: Symbol + push!(fcode, :( + p_m[$(i)] = p[$(Meta.quot(p_ix[i]))] + )) + else + push!(fcode, :( + p_m[$(i)] = p[$(p_ix[i])] + )) + end + end + + # for each transition, calculate its firing intensity + for i in 1:num_t is_ix = subpart(pn, incident(pn, i, :it), :is) # input places is_pn_ix = [sname(pn, j) for j in is_ix] os_ix = subpart(pn, incident(pn, i, :ot), :os) # output places os_pn_ix = [sname(pn, j) for j in os_ix] + + # generate vector of markings just for t's inputs and calc rate + n_input = length(is_pn_ix) + push!(fcode, :( + inputs = zeros($(n_input)) + )) + for j in 1:n_input + if eltype(is_pn_ix) <: Symbol + push!(fcode, :( + inputs[$(j)] = u[$(Meta.quot(is_pn_ix[j]))] + )) + else + push!(fcode, :( + inputs[$(j)] = u[$(is_pn_ix[j])] + )) + end + end push!(fcode, :( - rate = valueat(p_m[$(i)], u, t) * prod(u[$(is_pn_ix)]) + rate = valueat(p_m[$(i)], u, t) * prod(inputs) )) - # need quote node for subsetting du + + # transition decreases inputs and increases output marking if eltype(os_pn_ix) <: Symbol for j in os_pn_ix push!(fcode, :( @@ -388,7 +420,7 @@ flatten_labels(act::ACSetTransformation{S,Comp,<:AbstractPetriNet,<:AbstractPetr """ concentration(p::AbstractPetriNet, s) = subpart(p, s, :concentration) -""" Rate of a RectionNet +""" Rate of a ReactionNet """ rate(p::AbstractPetriNet, t) = subpart(p, t, :rate) @@ -396,10 +428,9 @@ rate(p::AbstractPetriNet, t) = subpart(p, t, :rate) """ concentrations(p::AbstractPetriNet) = begin if has_subpart(p, :sname) - snames = [sname(p, s) for s in 1:ns(p)] - return LVector(; [(snames[s] => concentration(p, s)) for s in 1:ns(p)]...) + LVector(; [(sname(p, s) => concentration(p, s)) for s in 1:ns(p)]...) else - return map(s -> concentration(p, s), 1:ns(p)) + map(s -> concentration(p, s), 1:ns(p)) end end @@ -407,10 +438,9 @@ end """ rates(p::AbstractPetriNet) = begin if has_subpart(p, :tname) - tnames = [tname(p, s) for s in 1:nt(p)] - LVector(; [(tnames[t] => rate(p, t)) for t in 1:nt(p)]...) + LVector(; [(tname(p, t) => rate(p, t)) for t in 1:nt(p)]...) else - return map(t -> rate(p, t), 1:nt(p)) + map(t -> rate(p, t), 1:nt(p)) end end From 94e7fefb8f662a431758ac560f644e82e953af6b Mon Sep 17 00:00:00 2001 From: p-stokes <92894586+p-stokes@users.noreply.github.com> Date: Mon, 15 May 2023 12:19:31 -0400 Subject: [PATCH 28/58] Changed prim_petri to fix issue when type system has multiple states. (#143) --- src/TypedPetri.jl | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index f154291b..94e3cd3a 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -19,16 +19,14 @@ function prim_petri(type_system, transition) t = add_transition!(prim) s_map = Int[] for i in inputs(type_system, transition) - s = is(type_system, i) - s′ = add_species!(prim) - push!(s_map, s) - add_input!(prim, 1, s′) + i′ = add_species!(prim) + push!(s_map, i) + add_input!(prim, 1, i′) end - for i in outputs(type_system, transition) - s = os(type_system, i) - s′ = add_species!(prim) - push!(s_map, s) - add_output!(prim, 1, s′) + for o in outputs(type_system, transition) + o′ = add_species!(prim) + push!(s_map, o) + add_output!(prim, 1, o′) end ACSetTransformation( prim, From b2b4edc53aa26dc95124899484001a414d8fa908 Mon Sep 17 00:00:00 2001 From: AlgebraicJulia Bot <129184742+algebraicjuliabot@users.noreply.github.com> Date: Mon, 15 May 2023 12:20:20 -0400 Subject: [PATCH 29/58] Set version to 0.8.11 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 5f82457c..43554dde 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AlgebraicPetri" uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" license = "MIT" authors = ["Micah Halter "] -version = "0.8.10" +version = "0.8.11" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" From d6a4cf2955692d30993408888417231dad52dc07 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Mon, 15 May 2023 13:32:21 -0400 Subject: [PATCH 30/58] clean up tests (#144) Co-authored-by: p-stokes --- ...{bilayernetworks.jl => BilayerNetworks.jl} | 4 + test/CatalystInterop.jl | 10 - test/{epidemiology.jl => Epidemiology.jl} | 12 +- ...{modelcomparison.jl => ModelComparison.jl} | 11 +- test/ModelingToolkitInterop.jl | 47 ----- test/OpenTransitions.jl | 181 ++++++++++++++++++ test/SubACSets.jl | 4 + test/{typed_petri.jl => TypedPetri.jl} | 4 + test/algebraicpetri/AlgebraicPetri.jl | 17 ++ test/{ => algebraicpetri}/core.jl | 10 +- test/{ => algebraicpetri}/petri.jl | 16 +- test/algebraicpetri/rewriting.jl | 92 +++++++++ test/{ => algebraicpetri}/types.jl | 11 +- test/ext/AlgebraicPetriCatalystExt.jl | 12 ++ test/ext/AlgebraicPetriModelingToolkitExt.jl | 49 +++++ test/ext/AlgebraicPetriPetriExt.jl | 15 ++ test/ext/extensions.jl | 13 ++ test/opentransitions.jl | 180 ----------------- test/rewriting.jl | 90 --------- test/runtests.jl | 57 ++---- 20 files changed, 452 insertions(+), 383 deletions(-) rename test/{bilayernetworks.jl => BilayerNetworks.jl} (99%) delete mode 100644 test/CatalystInterop.jl rename test/{epidemiology.jl => Epidemiology.jl} (52%) rename test/{modelcomparison.jl => ModelComparison.jl} (93%) delete mode 100644 test/ModelingToolkitInterop.jl create mode 100644 test/OpenTransitions.jl rename test/{typed_petri.jl => TypedPetri.jl} (99%) create mode 100644 test/algebraicpetri/AlgebraicPetri.jl rename test/{ => algebraicpetri}/core.jl (73%) rename test/{ => algebraicpetri}/petri.jl (87%) create mode 100644 test/algebraicpetri/rewriting.jl rename test/{ => algebraicpetri}/types.jl (98%) create mode 100644 test/ext/AlgebraicPetriCatalystExt.jl create mode 100644 test/ext/AlgebraicPetriModelingToolkitExt.jl create mode 100644 test/ext/AlgebraicPetriPetriExt.jl create mode 100644 test/ext/extensions.jl delete mode 100644 test/opentransitions.jl delete mode 100644 test/rewriting.jl diff --git a/test/bilayernetworks.jl b/test/BilayerNetworks.jl similarity index 99% rename from test/bilayernetworks.jl rename to test/BilayerNetworks.jl index f18720f7..04e6f41b 100644 --- a/test/bilayernetworks.jl +++ b/test/BilayerNetworks.jl @@ -1,3 +1,5 @@ +module TestBilayerNetworks + using Test using AlgebraicPetri @@ -231,3 +233,5 @@ end bn_error = "Mass action does not allow species $(bnsir_migrate_break[2, :variable]) to be "* "removed without contributing to the rate." @test_throws ErrorException(bn_error) migrate!(edge_sir, bnsir_migrate_break) + +end diff --git a/test/CatalystInterop.jl b/test/CatalystInterop.jl deleted file mode 100644 index 3241e50d..00000000 --- a/test/CatalystInterop.jl +++ /dev/null @@ -1,10 +0,0 @@ -module CatalystTest - using AlgebraicPetri - using Catalyst - using Test - - # Test with SIR model - sir = PetriNet(3, (1,2)=>(2,2), (2)=>(3)) - sir_rxn = ReactionSystem(sir) - @test sir_rxn isa ReactionSystem -end diff --git a/test/epidemiology.jl b/test/Epidemiology.jl similarity index 52% rename from test/epidemiology.jl rename to test/Epidemiology.jl index 1fdbbae2..0c0ff813 100644 --- a/test/epidemiology.jl +++ b/test/Epidemiology.jl @@ -1,3 +1,11 @@ +module TestEpidemiology + +using Test +using AlgebraicPetri +using AlgebraicPetri.Epidemiology +using Catlab.Programs +using Catlab.CategoricalAlgebra + sir_petri = LabelledPetriNet([:S,:I,:R], :inf=>((:S,:I)=>(:I,:I)), :rec=>(:I=>:R)) sir = infection ⋅ recovery @@ -9,4 +17,6 @@ sir_relation = @relation (s,i,r) begin recovery(i,r) end -@test apex(oapply_epi(sir_relation)) == sir_petri \ No newline at end of file +@test apex(oapply_epi(sir_relation)) == sir_petri + +end diff --git a/test/modelcomparison.jl b/test/ModelComparison.jl similarity index 93% rename from test/modelcomparison.jl rename to test/ModelComparison.jl index 0480e9b5..3d63f8e3 100644 --- a/test/modelcomparison.jl +++ b/test/ModelComparison.jl @@ -1,3 +1,9 @@ +module TestModelComparison + +using Test +using AlgebraicPetri, AlgebraicPetri.ModelComparison +using Catlab.CategoricalAlgebra + SIRD = LabelledReactionNet{Float64, Float64}([:S=>0.0, :I=>0.0, :R=>0.0, :D=>0.0], (:inf=>0.0)=>((:S,:I)=>(:I,:I)), (:rec=>0.0)=>(:I=>:R), @@ -10,7 +16,7 @@ models = [SIR, SIRD] AlgebraicPetri.ModelComparison.compare(A::Subobject, B::Subobject) = compare(dom(hom(A)), dom(hom(B))) -@testset "Subobjects" begin + for pn in [models, ReactionNet{Float64, Float64}.([SIR, SIRD]), LabelledPetriNet.(models), @@ -47,4 +53,5 @@ for pn in [models, @test A ∧ ¬(¬(A)) == ¬(¬(A)) @test implies((A∧B), A) == A∨B end -end \ No newline at end of file + +end diff --git a/test/ModelingToolkitInterop.jl b/test/ModelingToolkitInterop.jl deleted file mode 100644 index 458b250c..00000000 --- a/test/ModelingToolkitInterop.jl +++ /dev/null @@ -1,47 +0,0 @@ -module ModelingToolkitInterop - using Test - using ModelingToolkit - using ModelingToolkit: unwrap, term - using AlgebraicPetri - using AlgebraicPetri.Epidemiology - using AlgebraicPetri.BilayerNetworks - - using Catlab - using Catlab.CategoricalAlgebra - import Catlab.CategoricalAlgebra: migrate! - using Catlab.WiringDiagrams - using Catlab.Programs.RelationalPrograms - - # Define SIR Model - sir = @relation (s, i, r) begin - infection(s, i) - recovery(i, r) - end - - # Convert to Epidemiology petri net - psir = apex(oapply_epi(sir)) - - # Create empty bilayer network - bnsir = LabelledBilayerNetwork() - # migrate petri model to bilayer network - migrate!(bnsir, psir) - - @variables t S(t) I(t) R(t) - @parameters inf rec - D = Differential(t) - ϕ1 = inf * S * I - ϕ2 = rec * I - plus(x, y) = term(+, unwrap(x), unwrap(y); type = Real) - minus(x, y) = term(-, unwrap(x), unwrap(y); type = Real) - minus(x) = term(-, unwrap(x); type = Real) - eqs = [D(S) ~ -ϕ1, D(I) ~ ϕ1 + ϕ1 - (ϕ1 + ϕ2), D(R) ~ ϕ2] - eqs2 = [D(S) ~ minus(ϕ1), D(I) ~ minus(plus(ϕ1, ϕ1), plus(ϕ1, ϕ2)), D(R) ~ ϕ2] - bilayer_example = ODESystem(eqs2, t, name=:BilayerNetwork) - simp_bilayer_example = ODESystem(eqs, t, name=:BilayerNetwork) - petri_example = ODESystem(eqs, t, name=:PetriNet) - - @test ODESystem(psir) == petri_example - @test ODESystem(bnsir) == bilayer_example - @test ODESystem(bnsir, simplify = true) == simp_bilayer_example - @test typeof(ODESystem(PetriNet(psir))) == ODESystem # Sanity check that non-labelled Petri Nets resolve correctly -end diff --git a/test/OpenTransitions.jl b/test/OpenTransitions.jl new file mode 100644 index 00000000..1ac4770e --- /dev/null +++ b/test/OpenTransitions.jl @@ -0,0 +1,181 @@ +module TestOpenTransitions + +using Test +using AlgebraicPetri +using AlgebraicPetri.OpenTransitions +using Catlab, Catlab.CategoricalAlgebra, Catlab.Programs, Catlab.WiringDiagrams + +# tests with unlabeled PN + +# merge along 1 transition, specify legs +annihilation = OpenT(PetriNet(1, 1=>()), [1]) +creation = OpenT(PetriNet(1, ()=>1), [1]) + +join_pattern = @relation (T,) begin + X(T) + Y(T) +end + +joined_pn = oapply(join_pattern, + Dict( + :X => annihilation, + :Y => creation + ) +) + +@test ns(apex(joined_pn)) == 2 +@test nt(apex(joined_pn)) == 1 +@test subpart(apex(joined_pn), :it) == [1] +@test subpart(apex(joined_pn), :is) == [1] +@test subpart(apex(joined_pn), :ot) == [1] +@test subpart(apex(joined_pn), :os) == [2] +@test nparts(apex(joined_pn), :O) == 1 +@test nparts(apex(joined_pn), :I) == 1 + +# merge along 1 transition, do not specify legs +annihilation = OpenT(PetriNet(1, 1=>())) +creation = OpenT(PetriNet(1, ()=>1)) + +joined_pn = oapply(join_pattern, + Dict( + :X => annihilation, + :Y => creation + ) +) + +@test ns(apex(joined_pn)) == 2 +@test nt(apex(joined_pn)) == 1 +@test subpart(apex(joined_pn), :it) == [1] +@test subpart(apex(joined_pn), :is) == [1] +@test subpart(apex(joined_pn), :ot) == [1] +@test subpart(apex(joined_pn), :os) == [2] +@test nparts(apex(joined_pn), :O) == 1 +@test nparts(apex(joined_pn), :I) == 1 + +# merge along 2 transitions +annihilation = OpenT(PetriNet(1, 1=>(), 1=>()), [1], [2]) +creation = OpenT(PetriNet(1, ()=>1, ()=>1), [1], [2]) + +join_pattern = @relation (T1,T2) begin + X(T1,T2) + Y(T1,T2) +end + +joined_pn = oapply(join_pattern, + Dict( + :X => annihilation, + :Y => creation + ) +) + +@test length(legs(joined_pn)) == 2 +@test ns(apex(joined_pn)) == 2 +@test nt(apex(joined_pn)) == 2 +@test subpart(apex(joined_pn), :it) == [1,2] +@test subpart(apex(joined_pn), :is) == [1,1] +@test subpart(apex(joined_pn), :ot) == [1,2] +@test subpart(apex(joined_pn), :os) == [2,2] + +# tests with labeled PN + +# merge along 1 transition, specify legs +annihilation = OpenT( + LabelledPetriNet([:X], + :T => (:X => ()) + ), [:T] +) + +creation = OpenT( + LabelledPetriNet([:X], + :T => (() => :X) + ), [:T] +) + +join_pattern = @relation (T,) begin + X(T) + Y(T) +end + +joined_pn = oapply(join_pattern, + Dict( + :X => annihilation, + :Y => creation + ) +) + +@test apex(joined_pn) isa LabelledPetriNet +@test ns(apex(joined_pn)) == 2 +@test nt(apex(joined_pn)) == 1 +@test subpart(apex(joined_pn), :it) == [1] +@test subpart(apex(joined_pn), :is) == [1] +@test subpart(apex(joined_pn), :ot) == [1] +@test subpart(apex(joined_pn), :os) == [2] +@test nparts(apex(joined_pn), :O) == 1 +@test nparts(apex(joined_pn), :I) == 1 + +# merge along 1 transition, do not specify legs +annihilation = OpenT( + LabelledPetriNet([:X], + :T => (:X => ()) + ) +) + +creation = OpenT( + LabelledPetriNet([:X], + :T => (() => :X) + ) +) + +joined_pn = oapply(join_pattern, + Dict( + :X => annihilation, + :Y => creation + ) +) + +@test apex(joined_pn) isa LabelledPetriNet +@test ns(apex(joined_pn)) == 2 +@test nt(apex(joined_pn)) == 1 +@test subpart(apex(joined_pn), :it) == [1] +@test subpart(apex(joined_pn), :is) == [1] +@test subpart(apex(joined_pn), :ot) == [1] +@test subpart(apex(joined_pn), :os) == [2] +@test nparts(apex(joined_pn), :O) == 1 +@test nparts(apex(joined_pn), :I) == 1 + +# merge along 2 transitions +annihilation = OpenT( + LabelledPetriNet([:X], + :T1 => (:X=>()), + :T2 => (:X=>()) + ), [:T1], [:T2] +) +creation = OpenT( + LabelledPetriNet([:X], + :T1 => (()=>:X), + :T2 => (()=>:X) + ), [:T1], [:T2] +) + +join_pattern = @relation (T1,T2) begin + X(T1,T2) + Y(T1,T2) +end + +joined_pn = oapply(join_pattern, + Dict( + :X => annihilation, + :Y => creation + ) +) + +@test apex(joined_pn) isa LabelledPetriNet +@test length(legs(joined_pn)) == 2 +@test ns(apex(joined_pn)) == 2 +@test nt(apex(joined_pn)) == 2 +@test subpart(apex(joined_pn), :it) == [1,2] +@test subpart(apex(joined_pn), :is) == [1,1] +@test subpart(apex(joined_pn), :ot) == [1,2] +@test subpart(apex(joined_pn), :os) == [2,2] + +end diff --git a/test/SubACSets.jl b/test/SubACSets.jl index 3d6c5d8b..6e5544e6 100644 --- a/test/SubACSets.jl +++ b/test/SubACSets.jl @@ -1,3 +1,5 @@ +module TestSubACSets + using Test using AlgebraicPetri, AlgebraicPetri.SubACSets @@ -30,3 +32,5 @@ sub_acsets = mca(m1, m2) ]) @test Set(PetriNet.(sub_acsets)) == mca(PetriNet(m1), PetriNet(m2)) + +end diff --git a/test/typed_petri.jl b/test/TypedPetri.jl similarity index 99% rename from test/typed_petri.jl rename to test/TypedPetri.jl index bcaeeafe..b7cc027d 100644 --- a/test/typed_petri.jl +++ b/test/TypedPetri.jl @@ -1,3 +1,5 @@ +module TestTypedPetri + using Test using AlgebraicPetri, AlgebraicPetri.TypedPetri @@ -94,3 +96,5 @@ typed_age_aug = add_reflexives( ) stratified = typed_product(typed_age_aug, typed_sird) + +end diff --git a/test/algebraicpetri/AlgebraicPetri.jl b/test/algebraicpetri/AlgebraicPetri.jl new file mode 100644 index 00000000..596c2693 --- /dev/null +++ b/test/algebraicpetri/AlgebraicPetri.jl @@ -0,0 +1,17 @@ +using Test + +@testset "Core" begin + include("core.jl") +end + +@testset "Types" begin + include("types.jl") +end + +@testset "Petri" begin + include("petri.jl") +end + +@testset "Rewriting" begin + include("rewriting.jl") +end diff --git a/test/core.jl b/test/algebraicpetri/core.jl similarity index 73% rename from test/core.jl rename to test/algebraicpetri/core.jl index 4a60aee2..a40869ae 100644 --- a/test/core.jl +++ b/test/algebraicpetri/core.jl @@ -1,3 +1,9 @@ +module TestCore + +using Test +using AlgebraicPetri +using Catlab.CategoricalAlgebra + p1 = codom(Open([1], PetriNet(1), [1])) p2 = codom(Open([1,2], PetriNet(2), [1,2])) pc1 = id(p1) @@ -11,4 +17,6 @@ pc2 = id(p2) @test dom(mcopy(p1)) == p1 @test codom(mcopy(p1)) == p1 ⊗ p1 @test dom(delete(p1)) == p1 -@test codom(delete(p1)) == munit(OpenPetriNetOb) \ No newline at end of file +@test codom(delete(p1)) == munit(OpenPetriNetOb) + +end diff --git a/test/petri.jl b/test/algebraicpetri/petri.jl similarity index 87% rename from test/petri.jl rename to test/algebraicpetri/petri.jl index f06f23f2..8b8e9777 100644 --- a/test/petri.jl +++ b/test/algebraicpetri/petri.jl @@ -1,5 +1,9 @@ -using Catlab.Graphs -using Catlab.Graphics.Graphviz +module TestPetri + +using Test +using AlgebraicPetri +using Catlab.CategoricalAlgebra +using Catlab.Graphs, Catlab.Graphics.Graphviz f = Open([1, 2], PetriNet(4, (1,3), (2,4)), [3, 4]) @@ -40,7 +44,7 @@ lrn′ = Open([:I], LabelledReactionNet{Number,Int}([:I=>10, :R=>0], ((:rec=>.25 @test lrn == lrn′ death_petri = Open(PetriNet(1, 1=>())); -@test Graph(death_petri) isa Graph +@test AlgebraicPetri.Graph(death_petri) isa Graphviz.Graph # Test visualization of nested subgraphs SIR = LabelledReactionNet{Float64, Float64}([:S=>1.0, :I=>0.0, :R=>0.0], @@ -53,5 +57,7 @@ edge_attrs = Attributes(:splines=>"splines") g = Graphviz.Digraph("G", stmts1; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) stmts2 = Vector{Statement}([AlgebraicPetri.tagged_subgraph(g; post="_2")]) g2 = Graphviz.Digraph("G", stmts2; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) -@test g2 isa Graph -@test g2.stmts[1].stmts[1].stmts[1].name == "1_s1_2" \ No newline at end of file +@test g2 isa Graphviz.Graph +@test g2.stmts[1].stmts[1].stmts[1].name == "1_s1_2" + +end diff --git a/test/algebraicpetri/rewriting.jl b/test/algebraicpetri/rewriting.jl new file mode 100644 index 00000000..5427abd5 --- /dev/null +++ b/test/algebraicpetri/rewriting.jl @@ -0,0 +1,92 @@ +module TestRewriting + +using AlgebraicPetri +using AlgebraicRewriting +using Catlab, Catlab.CategoricalAlgebra +using Test + +const homomorphism = CategoricalAlgebra.homomorphism +const is_isomorphic = CategoricalAlgebra.is_isomorphic + +sir = LabelledReactionNet{Float64, Float64}( + [:S=>100, :I=>1, :R=>0], + (:inf,.03)=>((:S,:I)=>(:I,:I)), + (:rec,.25)=>(:I=>:R) +) + +seir = LabelledReactionNet{Float64, Float64}( + [:S=>100,:I=>1,:E=>1,:R=>0], + (:inf,.03)=>((:S,:I)=>(:I,:I)), + (:rec,.25)=>(:I=>:R), + (:inc,.1)=>(:E=>:I), + (:exp,.1)=>((:S,:I)=>(:E,:I)) +) + +# seir test +Rg = LabelledReactionNet{Float64, Float64}( + [:S=>100,:I=>1,:E=>1], + (:exp,.1)=>((:S, :I)=>(:E, :I)), + (:inc,.1)=>(:E => :I) +) +Lg = LabelledReactionNet{Float64, Float64}( + [:S=>100,:I=>1], +) + +L = homomorphism(Lg, Lg) +R = homomorphism(Lg, Rg) +m = homomorphism(Lg, sir) + +@test is_isomorphic(seir, rewrite_match(Rule{:DPO}(L,R), m)) + +# seirs test +Lg = LabelledReactionNet{Float64, Float64}( + [:S=>100,:I=>1], +) +Rg = LabelledReactionNet{Float64, Float64}( + [:S=>100,:I=>1], + (:sus,.1)=>(:I=>:S) +) + +L = homomorphism(Lg, Lg) +R = homomorphism(Lg, Rg) +m = homomorphism(Lg, seir) + +seirs = rewrite_match(Rule{:DPO}(L,R), m) + +@test nt(seirs) == nt(seir) + 1 +@test ns(seirs) == ns(seir) + +sus_ix = only(incident(seirs, :sus, :tname)) +sus_input = only(seirs[incident(seirs, sus_ix, :it), :is]) +sus_output = only(seirs[incident(seirs, sus_ix, :ot), :os]) + +@test seirs[sus_input,:sname] == :I +@test seirs[sus_output,:sname] == :S + +# seird test + +Lg = LabelledReactionNet{Float64, Float64}( + [:I=>1], +) +Rg = LabelledReactionNet{Float64, Float64}( + [:I=>1,:D=>0], + (:die,.1)=>(:I=>:D) +) + +L = homomorphism(Lg, Lg) +R = homomorphism(Lg, Rg) +m = homomorphism(Lg, seir) + +seird = rewrite_match(Rule{:DPO}(L,R), m) + +@test nt(seird) == nt(seir) + 1 +@test ns(seird) == ns(seir) + 1 + +die_ix = only(incident(seird, :die, :tname)) +die_input = only(seird[incident(seird, die_ix, :it), :is]) +die_output = only(seird[incident(seird, die_ix, :ot), :os]) + +@test seird[die_input,:sname] == :I +@test seird[die_output,:sname] == :D + +end diff --git a/test/types.jl b/test/algebraicpetri/types.jl similarity index 98% rename from test/types.jl rename to test/algebraicpetri/types.jl index 62055fee..9c493842 100644 --- a/test/types.jl +++ b/test/algebraicpetri/types.jl @@ -1,5 +1,10 @@ +module TestTypes + +using Test +using AlgebraicPetri +using Catlab.CategoricalAlgebra +using LabelledArrays using Tables -import Petri sir_petri = PetriNet(3, ((1, 2), (2, 2)), (2, 3)) sir_lpetri = LabelledPetriNet([:S, :I, :R], :inf => ((:S, :I), (:I, :I)), :rec => (:I, :R)) @@ -52,8 +57,6 @@ open_sir_rxn = Open([1, 2], sir_rxn, [3]) open_sir_lrxn = Open([:S, :I], sir_lrxn, [:R]) @test sir_tpetri == sir_petri -@test Petri.Model(sir_petri) == Petri.Model(sir_rxn) -@test Petri.Model(sir_lpetri) == Petri.Model(sir_lrxn) @test typeof(Graph(sir_petri)) == Graph @test typeof(Graph(sir_lpetri)) == Graph @@ -172,3 +175,5 @@ end for p in [sir_proplpetri, sir_proplrxn] @test Open(p, [:S], [:I], [:R]) == Open(p) end + +end diff --git a/test/ext/AlgebraicPetriCatalystExt.jl b/test/ext/AlgebraicPetriCatalystExt.jl new file mode 100644 index 00000000..1bfc52bd --- /dev/null +++ b/test/ext/AlgebraicPetriCatalystExt.jl @@ -0,0 +1,12 @@ +module TestAlgebraicPetriCatalystExt + +using Test +using AlgebraicPetri +using Catalyst + +# Test with SIR model +sir = PetriNet(3, (1,2)=>(2,2), (2)=>(3)) +sir_rxn = ReactionSystem(sir) +@test sir_rxn isa ReactionSystem + +end diff --git a/test/ext/AlgebraicPetriModelingToolkitExt.jl b/test/ext/AlgebraicPetriModelingToolkitExt.jl new file mode 100644 index 00000000..3a30c97d --- /dev/null +++ b/test/ext/AlgebraicPetriModelingToolkitExt.jl @@ -0,0 +1,49 @@ +module TestAlgebraicPetriModelingToolkitExt + +using Test +using ModelingToolkit +using ModelingToolkit: unwrap, term +using AlgebraicPetri +using AlgebraicPetri.Epidemiology +using AlgebraicPetri.BilayerNetworks + +using Catlab +using Catlab.CategoricalAlgebra +import Catlab.CategoricalAlgebra: migrate! +using Catlab.WiringDiagrams +using Catlab.Programs.RelationalPrograms + +# Define SIR Model +sir = @relation (s, i, r) begin + infection(s, i) + recovery(i, r) +end + +# Convert to Epidemiology petri net +psir = apex(oapply_epi(sir)) + +# Create empty bilayer network +bnsir = LabelledBilayerNetwork() +# migrate petri model to bilayer network +migrate!(bnsir, psir) + +@variables t S(t) I(t) R(t) +@parameters inf rec +D = Differential(t) +ϕ1 = inf * S * I +ϕ2 = rec * I +plus(x, y) = term(+, unwrap(x), unwrap(y); type = Real) +minus(x, y) = term(-, unwrap(x), unwrap(y); type = Real) +minus(x) = term(-, unwrap(x); type = Real) +eqs = [D(S) ~ -ϕ1, D(I) ~ ϕ1 + ϕ1 - (ϕ1 + ϕ2), D(R) ~ ϕ2] +eqs2 = [D(S) ~ minus(ϕ1), D(I) ~ minus(plus(ϕ1, ϕ1), plus(ϕ1, ϕ2)), D(R) ~ ϕ2] +bilayer_example = ODESystem(eqs2, t, name=:BilayerNetwork) +simp_bilayer_example = ODESystem(eqs, t, name=:BilayerNetwork) +petri_example = ODESystem(eqs, t, name=:PetriNet) + +@test ODESystem(psir) == petri_example +@test ODESystem(bnsir) == bilayer_example +@test ODESystem(bnsir, simplify = true) == simp_bilayer_example +@test typeof(ODESystem(PetriNet(psir))) == ODESystem # Sanity check that non-labelled Petri Nets resolve correctly + +end diff --git a/test/ext/AlgebraicPetriPetriExt.jl b/test/ext/AlgebraicPetriPetriExt.jl new file mode 100644 index 00000000..db7a50c8 --- /dev/null +++ b/test/ext/AlgebraicPetriPetriExt.jl @@ -0,0 +1,15 @@ +module TestAlgebraicPetriPetriExt + +using Test +using AlgebraicPetri +import Petri + +sir_petri = PetriNet(3, ((1, 2), (2, 2)), (2, 3)) +sir_lpetri = LabelledPetriNet([:S, :I, :R], :inf => ((:S, :I), (:I, :I)), :rec => (:I, :R)) +sir_rxn = ReactionNet{Number,Int}([990, 10, 0], (0.001, ((1, 2) => (2, 2))), (0.25, (2 => 3))) +sir_lrxn = LabelledReactionNet{Number,Int}((:S => 990, :I => 10, :R => 0), (:inf, 0.001) => ((:S, :I) => (:I, :I)), (:rec, 0.25) => (:I => :R)) + +@test Petri.Model(sir_petri) == Petri.Model(sir_rxn) +@test Petri.Model(sir_lpetri) == Petri.Model(sir_lrxn) + +end diff --git a/test/ext/extensions.jl b/test/ext/extensions.jl new file mode 100644 index 00000000..38b626d9 --- /dev/null +++ b/test/ext/extensions.jl @@ -0,0 +1,13 @@ +using Test + +@testset "Petri Package Extension" begin + include("AlgebraicPetriPetriExt.jl") +end + +@testset "Catalyst Package Extension" begin + include("AlgebraicPetriCatalystExt.jl") +end + +@testset "ModelingToolkit Package Extension" begin + include("AlgebraicPetriModelingToolkitExt.jl") +end diff --git a/test/opentransitions.jl b/test/opentransitions.jl deleted file mode 100644 index cc65f21a..00000000 --- a/test/opentransitions.jl +++ /dev/null @@ -1,180 +0,0 @@ -module OpenTransitionsTest - using AlgebraicPetri - using AlgebraicPetri.OpenTransitions - using Catlab, Catlab.CategoricalAlgebra, Catlab.Programs, Catlab.WiringDiagrams - using Test - - # tests with unlabeled PN - - # merge along 1 transition, specify legs - annihilation = OpenT(PetriNet(1, 1=>()), [1]) - creation = OpenT(PetriNet(1, ()=>1), [1]) - - join_pattern = @relation (T,) begin - X(T) - Y(T) - end - - joined_pn = oapply(join_pattern, - Dict( - :X => annihilation, - :Y => creation - ) - ) - - @test ns(apex(joined_pn)) == 2 - @test nt(apex(joined_pn)) == 1 - @test subpart(apex(joined_pn), :it) == [1] - @test subpart(apex(joined_pn), :is) == [1] - @test subpart(apex(joined_pn), :ot) == [1] - @test subpart(apex(joined_pn), :os) == [2] - @test nparts(apex(joined_pn), :O) == 1 - @test nparts(apex(joined_pn), :I) == 1 - - # merge along 1 transition, do not specify legs - annihilation = OpenT(PetriNet(1, 1=>())) - creation = OpenT(PetriNet(1, ()=>1)) - - joined_pn = oapply(join_pattern, - Dict( - :X => annihilation, - :Y => creation - ) - ) - - @test ns(apex(joined_pn)) == 2 - @test nt(apex(joined_pn)) == 1 - @test subpart(apex(joined_pn), :it) == [1] - @test subpart(apex(joined_pn), :is) == [1] - @test subpart(apex(joined_pn), :ot) == [1] - @test subpart(apex(joined_pn), :os) == [2] - @test nparts(apex(joined_pn), :O) == 1 - @test nparts(apex(joined_pn), :I) == 1 - - # merge along 2 transitions - annihilation = OpenT(PetriNet(1, 1=>(), 1=>()), [1], [2]) - creation = OpenT(PetriNet(1, ()=>1, ()=>1), [1], [2]) - - join_pattern = @relation (T1,T2) begin - X(T1,T2) - Y(T1,T2) - end - - joined_pn = oapply(join_pattern, - Dict( - :X => annihilation, - :Y => creation - ) - ) - - @test length(legs(joined_pn)) == 2 - @test ns(apex(joined_pn)) == 2 - @test nt(apex(joined_pn)) == 2 - @test subpart(apex(joined_pn), :it) == [1,2] - @test subpart(apex(joined_pn), :is) == [1,1] - @test subpart(apex(joined_pn), :ot) == [1,2] - @test subpart(apex(joined_pn), :os) == [2,2] - - # tests with labeled PN - - # merge along 1 transition, specify legs - annihilation = OpenT( - LabelledPetriNet([:X], - :T => (:X => ()) - ), [:T] - ) - - creation = OpenT( - LabelledPetriNet([:X], - :T => (() => :X) - ), [:T] - ) - - join_pattern = @relation (T,) begin - X(T) - Y(T) - end - - joined_pn = oapply(join_pattern, - Dict( - :X => annihilation, - :Y => creation - ) - ) - - @test apex(joined_pn) isa LabelledPetriNet - @test ns(apex(joined_pn)) == 2 - @test nt(apex(joined_pn)) == 1 - @test subpart(apex(joined_pn), :it) == [1] - @test subpart(apex(joined_pn), :is) == [1] - @test subpart(apex(joined_pn), :ot) == [1] - @test subpart(apex(joined_pn), :os) == [2] - @test nparts(apex(joined_pn), :O) == 1 - @test nparts(apex(joined_pn), :I) == 1 - - # merge along 1 transition, do not specify legs - annihilation = OpenT( - LabelledPetriNet([:X], - :T => (:X => ()) - ) - ) - - creation = OpenT( - LabelledPetriNet([:X], - :T => (() => :X) - ) - ) - - joined_pn = oapply(join_pattern, - Dict( - :X => annihilation, - :Y => creation - ) - ) - - @test apex(joined_pn) isa LabelledPetriNet - @test ns(apex(joined_pn)) == 2 - @test nt(apex(joined_pn)) == 1 - @test subpart(apex(joined_pn), :it) == [1] - @test subpart(apex(joined_pn), :is) == [1] - @test subpart(apex(joined_pn), :ot) == [1] - @test subpart(apex(joined_pn), :os) == [2] - @test nparts(apex(joined_pn), :O) == 1 - @test nparts(apex(joined_pn), :I) == 1 - - # merge along 2 transitions - annihilation = OpenT( - LabelledPetriNet([:X], - :T1 => (:X=>()), - :T2 => (:X=>()) - ), [:T1], [:T2] - ) - creation = OpenT( - LabelledPetriNet([:X], - :T1 => (()=>:X), - :T2 => (()=>:X) - ), [:T1], [:T2] - ) - - join_pattern = @relation (T1,T2) begin - X(T1,T2) - Y(T1,T2) - end - - joined_pn = oapply(join_pattern, - Dict( - :X => annihilation, - :Y => creation - ) - ) - - @test apex(joined_pn) isa LabelledPetriNet - @test length(legs(joined_pn)) == 2 - @test ns(apex(joined_pn)) == 2 - @test nt(apex(joined_pn)) == 2 - @test subpart(apex(joined_pn), :it) == [1,2] - @test subpart(apex(joined_pn), :is) == [1,1] - @test subpart(apex(joined_pn), :ot) == [1,2] - @test subpart(apex(joined_pn), :os) == [2,2] - -end \ No newline at end of file diff --git a/test/rewriting.jl b/test/rewriting.jl deleted file mode 100644 index 43c2043f..00000000 --- a/test/rewriting.jl +++ /dev/null @@ -1,90 +0,0 @@ -module RewritingTest - using AlgebraicPetri - using AlgebraicRewriting - using Catlab, Catlab.CategoricalAlgebra - using Test - - const homomorphism = CategoricalAlgebra.homomorphism - const is_isomorphic = CategoricalAlgebra.is_isomorphic - - sir = LabelledReactionNet{Float64, Float64}( - [:S=>100, :I=>1, :R=>0], - (:inf,.03)=>((:S,:I)=>(:I,:I)), - (:rec,.25)=>(:I=>:R) - ) - - seir = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1,:E=>1,:R=>0], - (:inf,.03)=>((:S,:I)=>(:I,:I)), - (:rec,.25)=>(:I=>:R), - (:inc,.1)=>(:E=>:I), - (:exp,.1)=>((:S,:I)=>(:E,:I)) - ) - - # seir test - Rg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1,:E=>1], - (:exp,.1)=>((:S, :I)=>(:E, :I)), - (:inc,.1)=>(:E => :I) - ) - Lg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1], - ) - - L = homomorphism(Lg, Lg) - R = homomorphism(Lg, Rg) - m = homomorphism(Lg, sir) - - @test is_isomorphic(seir, rewrite_match(Rule{:DPO}(L,R), m)) - - # seirs test - Lg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1], - ) - Rg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1], - (:sus,.1)=>(:I=>:S) - ) - - L = homomorphism(Lg, Lg) - R = homomorphism(Lg, Rg) - m = homomorphism(Lg, seir) - - seirs = rewrite_match(Rule{:DPO}(L,R), m) - - @test nt(seirs) == nt(seir) + 1 - @test ns(seirs) == ns(seir) - - sus_ix = only(incident(seirs, :sus, :tname)) - sus_input = only(seirs[incident(seirs, sus_ix, :it), :is]) - sus_output = only(seirs[incident(seirs, sus_ix, :ot), :os]) - - @test seirs[sus_input,:sname] == :I - @test seirs[sus_output,:sname] == :S - - # seird test - - Lg = LabelledReactionNet{Float64, Float64}( - [:I=>1], - ) - Rg = LabelledReactionNet{Float64, Float64}( - [:I=>1,:D=>0], - (:die,.1)=>(:I=>:D) - ) - - L = homomorphism(Lg, Lg) - R = homomorphism(Lg, Rg) - m = homomorphism(Lg, seir) - - seird = rewrite_match(Rule{:DPO}(L,R), m) - - @test nt(seird) == nt(seir) + 1 - @test ns(seird) == ns(seir) + 1 - - die_ix = only(incident(seird, :die, :tname)) - die_input = only(seird[incident(seird, die_ix, :it), :is]) - die_output = only(seird[incident(seird, die_ix, :ot), :os]) - - @test seird[die_input,:sname] == :I - @test seird[die_output,:sname] == :D -end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 4ab91a65..5bff4877 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,64 +1,33 @@ using Test -using LabelledArrays -using AlgebraicPetri -using AlgebraicPetri.Epidemiology -using AlgebraicPetri.ModelComparison -using AlgebraicPetri.OpenTransitions -using Catlab.Theories -using Catlab.CategoricalAlgebra -using Catlab.CategoricalAlgebra.FinSets -using Catlab.Programs -using AlgebraicRewriting - -@testset "Core" begin - include("core.jl") -end - -@testset "Types" begin - include("types.jl") +@testset "AlgebraicPetri" begin + include("algebraicpetri/AlgebraicPetri.jl") end -@testset "Petri" begin - include("petri.jl") +@testset "BilayerNetworks" begin + include("BilayerNetworks.jl") end @testset "Epidemiology" begin - include("epidemiology.jl") -end - -@testset "TypedPetris" begin - include("typed_petri.jl") -end - -@testset "BilayerNetworks" begin - include("bilayernetworks.jl") + include("Epidemiology.jl") end @testset "ModelComparison" begin - include("modelcomparison.jl") + include("ModelComparison.jl") end -@testset "Catalyst Interop" begin - include("CatalystInterop.jl") +@testset "OpenTransitions" begin + include("OpenTransitions.jl") end -@testset "ModelingToolkit Interop" begin - include("ModelingToolkitInterop.jl") +@testset "SubACSets" begin + include("SubACSets.jl") end @testset "TypedPetris" begin - include("typed_petri.jl") -end - -@testset "OpenTransitions" begin - include("opentransitions.jl") -end - -@testset "Rewriting" begin - include("rewriting.jl") + include("TypedPetri.jl") end -@testset "SubACSets" begin - include("SubACSets.jl") +@testset "Package Extensions" begin + include("ext/extensions.jl") end From 5811ec6f78aba18da15e464c927fe1bef90cfc52 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 17 May 2023 12:56:45 -0400 Subject: [PATCH 31/58] cleanup!: drop support for julia <1.9 and remove requires (#145) This is paving the way for the upcoming v0.9 release along with Catlab v0.15 which will remove Julia Date: Wed, 17 May 2023 13:47:25 -0400 Subject: [PATCH 32/58] fix: use AlgebraicJuliaBot for making release tags --- .github/workflows/TagBot.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index 90dc1009..3cf9b495 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -27,7 +27,4 @@ jobs: steps: - uses: JuliaRegistries/TagBot@v1 with: - token: ${{ secrets.GITHUB_TOKEN }} - # Edit the following line to reflect the actual name of the GitHub Secret containing your private key - ssh: ${{ secrets.DOCUMENTER_KEY }} - # ssh: ${{ secrets.NAME_OF_MY_SSH_PRIVATE_KEY_SECRET }} + token: ${{ secrets.RELEASE_TOKEN }} From a2988732b0acb5aec2fab9d184b1ae48da5c33d5 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 17 May 2023 14:47:10 -0400 Subject: [PATCH 33/58] refactor!: move to `to_graphviz` for visualization (#147) * cleanup!: move to using to_graphviz_property_graph for visualization * fix: update tests for new graphviz API * fix: update docs for new graphviz API --- Project.toml | 2 - docs/literate/covid/_covid.jl | 4 +- docs/literate/covid/_generate_figs.jl | 13 +- docs/literate/covid/bilayerconversion.jl | 12 +- docs/literate/covid/chime/chime-cset.jl | 3 +- docs/literate/covid/chime/chime.jl | 2 +- docs/literate/covid/coexist/coexist.jl | 4 +- docs/literate/covid/epidemiology.jl | 8 +- .../covid/stratification/stratification.jl | 34 +-- docs/literate/predation/lotka-volterra.jl | 12 +- src/visualization.jl | 288 +++++++++--------- test/BilayerNetworks.jl | 5 +- test/ModelComparison.jl | 8 +- test/algebraicpetri/petri.jl | 22 +- test/algebraicpetri/types.jl | 14 +- test/ext/AlgebraicPetriModelingToolkitExt.jl | 2 +- 16 files changed, 209 insertions(+), 224 deletions(-) diff --git a/Project.toml b/Project.toml index 848641e7..3eabeae5 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,6 @@ Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" GeneralizedGenerated = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" -StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" [weakdeps] Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" @@ -29,5 +28,4 @@ GeneralizedGenerated = "0.3" LabelledArrays = "1" ModelingToolkit = "8" Petri = "1" -StatsBase = "0.33,0.34" julia = "1.9" diff --git a/docs/literate/covid/_covid.jl b/docs/literate/covid/_covid.jl index 1efbebbc..94ee0b75 100644 --- a/docs/literate/covid/_covid.jl +++ b/docs/literate/covid/_covid.jl @@ -61,7 +61,7 @@ seird_city = to_hom_expr(FreeBiproductCategory, seird_city) display_wd(seird_city) # - -Graph(decoration(F(seird_city))) +to_graphviz(decoration(F(seird_city))) # create a multi-city SEIRD models @@ -72,7 +72,7 @@ pc_seird_3 = F(seird_3) p_seird_3 = decoration(pc_seird_3) display_wd(seird_3) # - -Graph(p_seird_3) +to_graphviz(p_seird_3) # Define time frame and initial parameters diff --git a/docs/literate/covid/_generate_figs.jl b/docs/literate/covid/_generate_figs.jl index 62d8ae93..e3b4b637 100644 --- a/docs/literate/covid/_generate_figs.jl +++ b/docs/literate/covid/_generate_figs.jl @@ -2,6 +2,7 @@ include("epidemiology.jl") using OrdinaryDiffEq +using Catlab.Graphics using Catlab.Graphics.Graphviz: run_graphviz # + @@ -41,7 +42,7 @@ end # - save_wd(sir, "sir.svg") -save_graph(Graph(p_sir), "sir_graph.svg") +save_graph(to_graphviz(p_sir), "sir_graph.svg") # define initial states and transition rates u0 = [10.0, 1, 0] @@ -53,7 +54,7 @@ sol = OrdinaryDiffEq.solve(prob,Tsit5()) splot(sol, "sir_soln.svg") save_wd(seir, "seir.svg") -save_graph(Graph(p_seir), "seir_graph.svg") +save_graph(to_graphviz(p_seir), "seir_graph.svg") # define initial states and transition rates u0 = [10.0, 1, 0, 0] @@ -65,7 +66,7 @@ sol = OrdinaryDiffEq.solve(prob,Tsit5()) splot(sol, "seir_soln.svg") save_wd(seird, "seird.svg") -save_graph(Graph(p_seird), "seird_graph.svg") +save_graph(to_graphviz(p_seird), "seird_graph.svg") # define initial states and transition rates u0 = [10.0, 1, 0, 0, 0] @@ -78,16 +79,16 @@ splot(sol, "seird_soln.svg") include("covid.jl") -[save_graph(Graph(Petri.Model(decoration(p))), pname) for (p,pname) in [(spontaneous_petri, "spont.svg"), +[save_graph(to_graphviz(Petri.Model(decoration(p))), pname) for (p,pname) in [(spontaneous_petri, "spont.svg"), (transmission_petri, "transmission.svg"), (exposure_petri, "exposure.svg"), (travel_petri, "travel.svg")]] save_wd(seird_city, "seird_city.svg") -save_graph(Graph(Petri.Model(decoration(F(seird_city)))), "seird_graph.svg") +save_graph(to_graphviz(Petri.Model(decoration(F(seird_city)))), "seird_graph.svg") save_wd(seird_3, "seird_3.svg") -save_graph(Graph(p_seird_3), "seird_3_graph.svg") +save_graph(to_graphviz(p_seird_3), "seird_3_graph.svg") pltdims = [4,9, 14] # Define time frame, 3 months diff --git a/docs/literate/covid/bilayerconversion.jl b/docs/literate/covid/bilayerconversion.jl index b2d992d5..0f88fe55 100644 --- a/docs/literate/covid/bilayerconversion.jl +++ b/docs/literate/covid/bilayerconversion.jl @@ -43,7 +43,7 @@ display_uwd(sir) # Extract the Petri network form of the model. psir = apex(oapply_epi(sir)) psir -Graph(psir) +to_graphviz(psir) #- # Convert the Petri network into a bilayer network and draw it. @@ -106,7 +106,7 @@ bnrt,pnstr = roundtrip(pseir, bnseir) display_uwd(sir) -Graph(psir) +to_graphviz(psir) #- to_graphviz(bnsir) @@ -115,7 +115,7 @@ to_graphviz(bnsir) to_graphviz(bnseir) #- -Graph(bnrt) +to_graphviz(bnrt) #- qm = @relation (s,q) begin @@ -140,7 +140,7 @@ semantics = Dict( :quarrec => spontaneous_petri(:Q, :R, :qr) ) pn_quar = oapply(qm, semantics) |> apex -Graph(pn_quar) +to_graphviz(pn_quar) #- bnquar = LabelledBilayerNetwork() @@ -159,7 +159,7 @@ display_uwd(qm) #- pn_quar = oapply(qm, semantics) |> apex -Graph(pn_quar) +to_graphviz(pn_quar) #- bnquar = LabelledBilayerNetwork() @@ -168,7 +168,7 @@ to_graphviz(bnquar) #- quarrt = LabelledPetriNet() -migrate!(quarrt, bnquar) |> Graph +migrate!(quarrt, bnquar) |> to_graphviz bnquar #- diff --git a/docs/literate/covid/chime/chime-cset.jl b/docs/literate/covid/chime/chime-cset.jl index 5846f355..b7e130c5 100644 --- a/docs/literate/covid/chime/chime-cset.jl +++ b/docs/literate/covid/chime/chime-cset.jl @@ -3,6 +3,7 @@ using OrdinaryDiffEq using Plots using Catlab.Meta using Catlab.CategoricalAlgebra +using Catlab.Graphics using JSON import OrdinaryDiffEq: ODEProblem @@ -27,7 +28,7 @@ end sir_cset= LabelledReactionNet{Function, Float64}((:S=>990, :I=>10, :R=>0), (:inf, β)=>((:S, :I)=>(:I,:I)), (:rec, t->γ)=>(:I=>:R)) -Graph(sir_cset) +to_graphviz(sir_cset) prob = ODEProblem(sir_cset, (17.0, 120.0)) sol = OrdinaryDiffEq.solve(prob,Tsit5()) diff --git a/docs/literate/covid/chime/chime.jl b/docs/literate/covid/chime/chime.jl index 7bc0a489..2f0e30dd 100644 --- a/docs/literate/covid/chime/chime.jl +++ b/docs/literate/covid/chime/chime.jl @@ -20,7 +20,7 @@ display_uwd(sir) #- p_sir = apex(oapply_epi(sir)); -Graph(p_sir) +to_graphviz(p_sir) u0 = LVector(S=990, I=10, R=0); t_span = (17.0,120.0) diff --git a/docs/literate/covid/coexist/coexist.jl b/docs/literate/covid/coexist/coexist.jl index 090aede1..06741575 100644 --- a/docs/literate/covid/coexist/coexist.jl +++ b/docs/literate/covid/coexist/coexist.jl @@ -164,8 +164,8 @@ end; display_uwd(threeNCoexist) #- threeNCoexist_algpetri = apex(F_tcx(threeNCoexist)) -Graph(threeNCoexist_algpetri); -save_fig(Graph(threeNCoexist_algpetri), "3ncoexist_petri", "svg"); # hide +to_graphviz(threeNCoexist_algpetri); +save_fig(to_graphviz(threeNCoexist_algpetri), "3ncoexist_petri", "svg"); # hide # ![3-generation COEXIST model petri net](3ncoexist_petri.svg) diff --git a/docs/literate/covid/epidemiology.jl b/docs/literate/covid/epidemiology.jl index 00e39821..54bf0360 100644 --- a/docs/literate/covid/epidemiology.jl +++ b/docs/literate/covid/epidemiology.jl @@ -27,7 +27,7 @@ end display_uwd(sir) #- p_sir = apex(oapply_epi(sir)) -Graph(p_sir) +to_graphviz(p_sir) # define initial states and transition rates, then # create, solve, and visualize ODE problem @@ -53,7 +53,7 @@ end display_uwd(seir) #- p_seir = apex(oapply_epi(seir)) -Graph(p_seir) +to_graphviz(p_seir) # define initial states and transition rates, then # create, solve, and visualize ODE problem @@ -78,7 +78,7 @@ end display_uwd(seird) #- p_seird = apex(oapply_epi(seird)) -Graph(p_seird) +to_graphviz(p_seird) # define initial states and transition rates, then # create, solve, and visualize ODE problem @@ -89,4 +89,4 @@ p = LVector(exp=0.9, ill=0.2, rec=0.5, death=0.1); prob = ODEProblem(vectorfield(p_seird),u0,(0.0,15.0),p); sol = solve(prob,Tsit5()) -plot(sol) \ No newline at end of file +plot(sol) diff --git a/docs/literate/covid/stratification/stratification.jl b/docs/literate/covid/stratification/stratification.jl index 1c24c10d..6a3b561e 100644 --- a/docs/literate/covid/stratification/stratification.jl +++ b/docs/literate/covid/stratification/stratification.jl @@ -19,7 +19,7 @@ const infectious_ontology = LabelledPetriNet( :strata => (:Pop => :Pop) ) -Graph(infectious_ontology) +to_graphviz(infectious_ontology) # Define a simple SIRD model with reflexive transitions typed as `:strata` to indicate which states can be stratified # Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead @@ -34,7 +34,7 @@ end sird_model = oapply_typed(infectious_ontology, sird_uwd, [:infection, :recovery, :death]) sird_model = add_reflexives(sird_model, [[:strata], [:strata], [:strata], []], infectious_ontology) -Graph(dom(sird_model)) +to_graphviz(dom(sird_model)) # ## Define intervention models @@ -49,11 +49,11 @@ end mask_model = oapply_typed(infectious_ontology, masking_uwd, [:unmask, :mask, :infect_um, :infect_uu]) mask_model = add_reflexives(mask_model, [[:strata], [:strata]], infectious_ontology) -Graph(dom(mask_model)) +to_graphviz(dom(mask_model)) # Stratify our SIRD model on this masking model to get a model of SIRD with masking: -typed_product(sird_model, mask_model) |> dom |> Graph +typed_product(sird_model, mask_model) |> dom |> to_graphviz # ### Vaccine model @@ -67,11 +67,11 @@ end vax_model = oapply_typed(infectious_ontology, vax_uwd, [:vax, :infect_vv, :infect_uv, :infect_vu, :infect_uu]) vax_model = add_reflexives(vax_model, [[:disease], [:disease]], infectious_ontology) -Graph(dom(vax_model)) +to_graphviz(dom(vax_model)) # Stratify our SIRD model on this vaccine model to get a model of SIRD with a vaccination rate: -typed_product(sird_model, vax_model) |> dom |> Graph +typed_product(sird_model, vax_model) |> dom |> to_graphviz # ### Mask-Vax Model @@ -98,11 +98,11 @@ mask_vax_model = oapply_typed( ) mask_vax_model = add_reflexives(mask_vax_model, [[:disease], [:disease], [:disease], [:disease]], infectious_ontology) -Graph(dom(mask_vax_model)) +to_graphviz(dom(mask_vax_model)) # Stratify our SIRD model on this mask + vaccine model to get a model of SIRD with a vaccination rate and masking policies: -typed_product(sird_model, mask_vax_model) |> dom |> Graph +typed_product(sird_model, mask_vax_model) |> dom |> to_graphviz # ## Define geographic models @@ -131,11 +131,11 @@ function travel_model(n) add_reflexives(act, repeat([[:infect, :disease]], n), infectious_ontology) end -Graph(dom(travel_model(2))) +to_graphviz(dom(travel_model(2))) # Stratify our SIRD model on this travel model with two regions: -typed_product(sird_model, travel_model(2)) |> dom |> Graph +typed_product(sird_model, travel_model(2)) |> dom |> to_graphviz # ### Simple Trip model between $N$ regions @@ -148,16 +148,16 @@ function living_model(n) add_reflexives(typed_living, repeat([[:disease, :strata]], n), infectious_ontology) end -Graph(dom(living_model(2))) +to_graphviz(dom(living_model(2))) # The resulting simple trip model: simple_trip_model = typed_product(travel_model(2), living_model(2)) -Graph(dom(simple_trip_model)) +to_graphviz(dom(simple_trip_model)) # Stratify our SIRD model on this simple trip model between two regions: -typed_product(sird_model, simple_trip_model) |> dom |> Graph +typed_product(sird_model, simple_trip_model) |> dom |> to_graphviz # ## Stratification of COVID models @@ -191,7 +191,7 @@ m1_model = (@relation () where {(S::Pop, I::Pop, D::Pop, A::Pop, R::Pop, T::Pop, disease(T, H) end) |> oapply_mira_model -Graph(dom(m1_model)) +to_graphviz(dom(m1_model)) # ### SEIAHRD Model # @@ -212,7 +212,7 @@ m2_model = (@relation () where {(S::Pop, E::Pop, I::Pop, A::Pop, H::Pop, R::Pop, disease(H, R) end) |> oapply_mira_model -Graph(dom(m2_model)) +to_graphviz(dom(m2_model)) # ### SEIuIrQRD Model # @@ -232,7 +232,7 @@ m3_model = (@relation () where {(S::Pop, E::Pop, Iu::Pop, Ir::Pop, Q::Pop, R::Po disease(Ir, D) end) |> oapply_mira_model -Graph(dom(m3_model)) +to_graphviz(dom(m3_model)) # ### Enumerating stratified models # @@ -260,4 +260,4 @@ Markdown.parse(join(table, "\n")) |> DisplayAs.HTML # number of states and transitions increase polynomially which causes the execution time # for calculating the final stratified model to also increase polynomially. # -# ![Runtime vs. Number of Georgraphic Regions](../../../../assets/runtime_vs_num_rgns.svg) +# ![Runtime vs. Number of Georgraphic Regions](../../../assets/runtime_vs_num_rgns.svg) diff --git a/docs/literate/predation/lotka-volterra.jl b/docs/literate/predation/lotka-volterra.jl index 31dc14dd..0880d8e8 100644 --- a/docs/literate/predation/lotka-volterra.jl +++ b/docs/literate/predation/lotka-volterra.jl @@ -18,13 +18,13 @@ display_uwd(ex) = to_graphviz(ex, box_labels=:name, junction_labels=:variable, e # #### Step 1: Define the building block Petri nets needed to construct the model birth_petri = Open(PetriNet(1, 1=>(1,1))); -Graph(birth_petri) +to_graphviz(birth_petri) #- predation_petri = Open(PetriNet(2, (1,2)=>(2,2))); -Graph(predation_petri) +to_graphviz(predation_petri) #- death_petri = Open(PetriNet(1, 1=>())); -Graph(death_petri) +to_graphviz(death_petri) # #### Step 2: Generate models using a relational syntax @@ -38,7 +38,7 @@ display_uwd(lotka_volterra) #- lv_dict = Dict(:birth=>birth_petri, :predation=>predation_petri, :death=>death_petri); lotka_petri = apex(oapply(lotka_volterra, lv_dict)) -Graph(lotka_petri) +to_graphviz(lotka_petri) # Generate appropriate vector fields, define parameters, and visualize solution @@ -61,7 +61,7 @@ end display_uwd(dual_lv) #- dual_lv_petri = apex(oapply(dual_lv, lv_dict)) -Graph(dual_lv_petri) +to_graphviz(dual_lv_petri) # Generate a new solver, provide parameters, and analyze results @@ -69,4 +69,4 @@ u0 = [100, 10, 2]; p = [.3, .015, .7, .017, .35]; prob = ODEProblem(vectorfield(dual_lv_petri),u0,(0.0,100.0),p); sol = solve(prob,Tsit5(),abstol=1e-6); -plot(sol) \ No newline at end of file +plot(sol) diff --git a/src/visualization.jl b/src/visualization.jl index e04ae976..69295177 100644 --- a/src/visualization.jl +++ b/src/visualization.jl @@ -1,177 +1,163 @@ -using Catlab.CategoricalAlgebra -using Catlab.Graphics.Graphviz -import Catlab.Graphics.Graphviz: Graph, Subgraph -import Base.Iterators: flatten -using StatsBase - -export Graph - -########################### -# Base Graph Construction # -########################### -def_states(p, s; pos="") = ("s$s", Attributes(:label=>"$(sname(p, s))", - :shape=>"circle", - :color=>"#6C9AC3", - :pos=>pos)) -def_trans(p, t; pos="") = ("t$t", Attributes(:label=>"$(tname(p, t))", - :shape=>"square", - :color=>"#E28F41", - :pos=>pos)) -def_inpts(p, s, t, i) = (["s$s", "t$t"],Attributes(:labelfontsize=>"6")) -def_otpts(p, s, t, o) = (["t$t", "s$s"],Attributes(:labelfontsize=>"6")) - -function Graph(p::AbstractPetriNet; make_states::Function=def_states, - make_trans::Function=def_trans, make_inpts::Function=def_inpts, - make_otpts::Function=def_otpts, name="G", prog="dot", - positions=Dict(:T=>fill("", nt(p)), :S=>fill("", ns(p))), kw...) - - graph_attrs = :graph_attrs ∈ keys(kw) ? Attributes(kw[:graph_attrs]) : - Attributes(:rankdir=>"LR") - node_attrs = :node_attrs ∈ keys(kw) ? Attributes(kw[:node_attrs]) : - Attributes(:shape=>"plain", - :style=>"filled", - :color=>"white") - edge_attrs = :edge_attrs ∈ keys(kw) ? Attributes(kw[:edge_attrs]) : - Attributes(:splines=>"splines") - - statenodes = [Node(make_states(p,s; pos=positions[:S][s])...) for s in 1:ns(p)] - transnodes = [Node(make_trans(p,t; pos=positions[:T][t])...) for t in 1:nt(p)] - stmts = vcat(statenodes, transnodes) - - i_edges = map(1:ni(p)) do i - Edge(make_inpts(p, is(p, i), it(p, i), i)...) - end |> collect - o_edges = map(1:no(p)) do o - Edge(make_otpts(p, os(p, o), ot(p, o), o)...) - end |> collect - edges = vcat(i_edges, o_edges) - - # Add count labels if no labels provided - if all(!(:label ∈ keys(e.attrs)) for e in edges) - edge_vals = countmap(edges) - edges = map(filter((v)->v[2] != 0, collect(edge_vals))) do v - attrs = v[1].attrs - attrs[:label] = "$(v[2])" - Edge(v[1].path, attrs) - end |> collect +using Catlab.CategoricalAlgebra, Catlab.Graphics.Graphviz +using Catlab.Graphs: PropertyGraph + +import Catlab.Graphics.Graphviz: Subgraph +import Catlab.Graphics: to_graphviz, to_graphviz_property_graph + +const GRAPH_ATTRS = Dict(:rankdir=>"LR") +const NODE_ATTRS = Dict(:shape => "plain", :style=>"filled") +const EDGE_ATTRS = Dict(:splines=>"splines") + + +# Single Petri Nets +################### + +to_graphviz(pn::Union{ + AbstractPetriNet, + Subobject{<:AbstractPetriNet}, + StructuredMulticospan{<:StructuredCospans.AbstractDiscreteACSet{<:AbstractPetriNet}}, + }; kw...) = + to_graphviz(to_graphviz_property_graph(pn; kw...)) + +function to_graphviz_property_graph(pn::AbstractPetriNet; + prog::AbstractString="dot", graph_attrs::AbstractDict=Dict(), + node_attrs::AbstractDict=Dict(), edge_attrs::AbstractDict=Dict(), name::AbstractString="G", kw...) + pg = PropertyGraph{Any}(; name = name, prog = prog, + graph = merge!(GRAPH_ATTRS, graph_attrs), + node = merge!(NODE_ATTRS, node_attrs), + edge = merge!(EDGE_ATTRS, edge_attrs), + ) + S_vtx = Dict(map(parts(pn, :S)) do s + s => add_vertex!(pg; label="$(sname(pn, s))", shape="circle", color="#6C9AC3") + end) + T_vtx = Dict(map(parts(pn, :T)) do t + t => add_vertex!(pg; label="$(tname(pn, t))", shape="square", color="#E28F41") + end) + + edges = Dict{Tuple{Int,Int}, Int}() + map(parts(pn, :I)) do i + edge = (S_vtx[pn[i, :is]], T_vtx[pn[i, :it]]) + edges[edge] = get(edges, edge, 0) + 1 + end + map(parts(pn, :O)) do o + edge = (T_vtx[pn[o, :ot]], S_vtx[pn[o, :os]]) + edges[edge] = get(edges, edge, 0) + 1 + end + for ((src, tgt),count) in edges + add_edge!(pg, src, tgt, label="$(count)") end - stmts = vcat(stmts, edges) - g = Graphviz.Digraph(name, stmts; prog=prog, - graph_attrs=graph_attrs, - node_attrs=node_attrs, - edge_attrs=edge_attrs) - return g + pg end - -#################### -# Subgraph Drawing # -#################### -add_label(n::Node, pre, post) = Node("$pre$(n.name)$post", n.attrs) -add_label(e::Edge, pre, post) = begin - path = map(e.path) do n_id - NodeID("$pre$(n_id.name)$post", n_id.port, n_id.anchor) +function to_graphviz_property_graph(so::Subobject{<:AbstractPetriNet}; + prog::AbstractString="dot", graph_attrs::AbstractDict=Dict(), + node_attrs::AbstractDict=Dict(), edge_attrs::AbstractDict=Dict(), + name::AbstractString="G", lw::Number=3.0, kw...) + pn = ob(so) + comps = hom(so).components + sts = comps[:S].func + trans = comps[:T].func + inps = comps[:I].func + otps = comps[:O].func + + pg = PropertyGraph{Any}(; name = name, prog = prog, + graph = merge!(GRAPH_ATTRS, graph_attrs), + node = merge!(NODE_ATTRS, node_attrs), + edge = merge!(EDGE_ATTRS, edge_attrs), + ) + S_vtx = Dict(map(parts(pn, :S)) do s + s => add_vertex!(pg; + label="$(sname(pn, s))", + shape="circle", + fillcolor="#6C9AC3", + penwidth = s ∈ sts ? "$lw" : "0.0" + ) + end) + T_vtx = Dict(map(parts(pn, :T)) do t + t => add_vertex!(pg; + label="$(tname(pn, t))", + shape="square", + fillcolor="#E28F41", + penwidth = t ∈ trans ? "$lw" : "0.0" + ) + end) + + edges = Dict{Tuple{Int,Int}, Tuple{Int,Number}}() + map(parts(pn, :I)) do i + edge = (S_vtx[pn[i, :is]], T_vtx[pn[i, :it]]) + (count, weight) = get(edges, edge, (0,1)) + edges[edge] = (count + 1, i ∈ inps ? lw : weight) end - Edge(path, e.attrs) -end -add_label(g::Subgraph, pre, post) = begin - stmts = map(g.stmts) do st - add_label(st, pre, post) + map(parts(pn, :O)) do o + edge = (T_vtx[pn[o, :ot]], S_vtx[pn[o, :os]]) + (count, weight) = get(edges, edge, (0,1)) + edges[edge] = (count + 1, o ∈ otps ? lw : weight) end - name = "$pre$(g.name)$post" - Subgraph(name, stmts, g.graph_attrs, g.node_attrs, g.edge_attrs) -end - -function tagged_subgraph(g::Graph; pre="", post="") - stmts = map(g.stmts) do st - add_label(st, pre, post) + for ((src, tgt),(count,weight)) in edges + add_edge!(pg, src, tgt, label="$(count)", penwidth="$(weight)") end - Subgraph(g.name, stmts, g.graph_attrs, g.node_attrs, g.edge_attrs) -end -function Subgraph(p::AbstractPetriNet; pre="", post="", kw...) - tagged_subgraph(Graph(p; kw...); pre=pre, post=post) + pg end -###################### -# Specialized Graphs # -###################### -function Graph(m::Multispan{<:AbstractPetriNet}) - apex = Subgraph(m.apex; name="clusterApex", pre="ap_") +to_graphviz_property_graph(op::StructuredMulticospan{<:StructuredCospans.AbstractDiscreteACSet{<:AbstractPetriNet}}; kw...) = + to_graphviz_property_graph(apex(op); kw...) - leg_graphs = map(enumerate(m.legs)) do (i, l) - Subgraph(l.codom; name="clusterLeg$i", pre="leg$(i)_") - end +# Petri Nets Multi-spans +######################## - graph_attrs = Attributes(:rankdir=>"LR") - node_attrs = Attributes(:shape=>"plain", :style=>"filled", :color=>"white") - edge_attrs = Attributes(:splines=>"splines") +function to_graphviz(m::Multispan{<:AbstractPetriNet}; + prog::AbstractString="dot", graph_attrs::AbstractDict=Dict(), + node_attrs::AbstractDict=Dict(), edge_attrs::AbstractDict=Dict(), + name::AbstractString="G", kw...) + apex = Subgraph(m.apex; name="clusterApex", pre="ap_", prog=prog, graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) - t_edges = map(enumerate(m.legs)) do (i, l) - map(1:nt(m.apex)) do t - Edge(["\"ap_t$t\"", "\"leg$(i)_t$(l.components[:T](t))\""], - Attributes(:constraint=>"false", :style=>"dotted")) - end + leg_graphs = map(enumerate(m.legs)) do (i, l) + Subgraph(l.codom; name="clusterLeg$i", pre="leg$(i)_", prog=prog, graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) end s_edges = map(enumerate(m.legs)) do (i, l) map(1:ns(m.apex)) do s - Edge(["\"ap_s$s\"", "\"leg$(i)_s$(l.components[:S](s))\""], + Edge(["\"ap_n$s\"", "\"leg$(i)_n$(l.components[:S](s))\""], Attributes(:constraint=>"false", :style=>"dotted")) end end - stmts = vcat([apex], leg_graphs, t_edges..., s_edges...) - g = Graphviz.Digraph("G", stmts; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) -end - -function Graph(p::StructACSetTransformation{<:Any, <:Any, <:AbstractPetriNet, <:AbstractPetriNet}) - Graph(Multispan(p.dom, [p])) -end -function Graph(so::Subobject{<:AbstractPetriNet}; lw = 3.0, kw...) - p = ob(so) - maps = hom(so) - sts = maps.components[:S].func - trans = maps.components[:T].func - inps = maps.components[:I].func - otps = maps.components[:O].func - sns = sname(p, sts) - tns = tname(p, trans) - mkstate(p,s; kw...) = begin - ds = def_states(p,s; kw...) - attrs = ds[2] - attrs[:fillcolor] = "#6C9AC3" - attrs[:color] = "black" - attrs[:penwidth] = s ∈ sts ? "$lw" : "0.0" - (ds[1], attrs) - end - mktrans(p,t; kw...) = begin - dt = def_trans(p,t; kw...) - attrs = dt[2] - attrs[:fillcolor] = "#E28F41" - attrs[:color] = "black" - attrs[:penwidth] = t ∈ trans ? "$lw" : "0.0" - (dt[1], attrs) + t_edges = map(enumerate(m.legs)) do (i, l) + map(1:nt(m.apex)) do t + Edge(["\"ap_n$(t+ns(m.apex))\"", "\"leg$(i)_n$(l.components[:T](t)+ns(l.codom))\""], + Attributes(:constraint=>"false", :style=>"dotted")) + end end - mkinpts(p, s, t, i) = begin - (["s$s", "t$t"], - Attributes(:labelfontsize=>"6", - :penwidth=>(i ∈ inps ? "$lw" : "1.0"))) - end + g = Digraph(name, vcat([apex], leg_graphs, t_edges..., s_edges...); prog=prog, + graph_attrs = merge!(GRAPH_ATTRS, graph_attrs), + node_attrs = merge!(NODE_ATTRS, node_attrs), + edge_attrs = merge!(EDGE_ATTRS, edge_attrs) + ) +end - mkotpts(p, s, t, o) = begin - (["t$t", "s$s"], - Attributes(:labelfontsize=>"6", - :penwidth=>(o ∈ otps ? "$lw" : "1.0"))) - end +to_graphviz(p::StructACSetTransformation{<:Any, <:Any, <:AbstractPetriNet, <:AbstractPetriNet}; kw...) = + to_graphviz(Multispan(p.dom, [p]); kw...) - Graph(p; make_states=mkstate, make_trans=mktrans, make_inpts=mkinpts, make_otpts=mkotpts, - node_attrs = Attributes(:shape=>"plain", :style=>"filled, solid", :color=>"white"), - kw...) -end +# Subgraph Extensions +##################### -function Graph(op::Union{OpenPetriNet, OpenLabelledPetriNetUntyped, OpenReactionNet, OpenLabelledReactionNetUntyped}) - Graph(apex(op)) -end +add_label(n::Node, pre, post) = Node("$pre$(n.name)$post", n.attrs) +add_label(e::Edge, pre, post) = Edge(map(e.path) do n_id + NodeID("$pre$(n_id.name)$post", n_id.port, n_id.anchor) + end, e.attrs) +add_label(g::Subgraph, pre, post) = Subgraph("$pre$(g.name)$post", + map(g.stmts) do st + add_label(st, pre, post) + end, + g.graph_attrs, g.node_attrs, g.edge_attrs) + +tagged_subgraph(g::Graph; pre="", post="") = Subgraph(g.name, + map(g.stmts) do st + add_label(st, pre, post) + end, + g.graph_attrs, g.node_attrs, g.edge_attrs) + +Subgraph(p::AbstractPetriNet; pre="", post="", kw...) = tagged_subgraph(to_graphviz(p; kw...); pre=pre, post=post) diff --git a/test/BilayerNetworks.jl b/test/BilayerNetworks.jl index 04e6f41b..6cf83ecc 100644 --- a/test/BilayerNetworks.jl +++ b/test/BilayerNetworks.jl @@ -31,7 +31,6 @@ display_uwd(sir) psir = apex(oapply_epi(sir)) psir -Graph(psir) # Convert the Petri network into a bilayer network and draw it. # This model uses a computation graph to express the computation of the vector field of the Petri net. @@ -41,8 +40,8 @@ lab_bnsir = LabelledBilayerNetwork() migrate!(bnsir, psir) migrate!(lab_bnsir, psir) bnsir -@test typeof(to_graphviz(bnsir)) == Graph -@test typeof(to_graphviz(lab_bnsir)) == Graph +@test to_graphviz(bnsir) isa Graphics.Graphviz.Graph +@test to_graphviz(lab_bnsir) isa Graphics.Graphviz.Graph bnsir_test = @acset BilayerNetwork begin Qin = 3 diff --git a/test/ModelComparison.jl b/test/ModelComparison.jl index 3d63f8e3..e9af9a70 100644 --- a/test/ModelComparison.jl +++ b/test/ModelComparison.jl @@ -2,7 +2,7 @@ module TestModelComparison using Test using AlgebraicPetri, AlgebraicPetri.ModelComparison -using Catlab.CategoricalAlgebra +using Catlab.CategoricalAlgebra, Catlab.Graphics SIRD = LabelledReactionNet{Float64, Float64}([:S=>0.0, :I=>0.0, :R=>0.0, :D=>0.0], (:inf=>0.0)=>((:S,:I)=>(:I,:I)), @@ -26,12 +26,12 @@ for pn in [models, @test apex(c_res) == pn[1] @test length(legs(c_res)) == 2 - @test Graph(legs(c_res)[1]) isa Graph - @test Graph(c_res) isa Graph + @test to_graphviz(legs(c_res)[1]) isa Graphics.Graphviz.Graph + @test to_graphviz(c_res) isa Graphics.Graphviz.Graph so = Subobject.(legs(c_res)) for s in so - @test Graph(s) isa Graph + @test to_graphviz(s) isa Graphics.Graphviz.Graph @test codom(hom(s)) == pn[2] end diff --git a/test/algebraicpetri/petri.jl b/test/algebraicpetri/petri.jl index 8b8e9777..2efd98ff 100644 --- a/test/algebraicpetri/petri.jl +++ b/test/algebraicpetri/petri.jl @@ -3,7 +3,7 @@ module TestPetri using Test using AlgebraicPetri using Catlab.CategoricalAlgebra -using Catlab.Graphs, Catlab.Graphics.Graphviz +using Catlab.Graphs, Catlab.Graphics f = Open([1, 2], PetriNet(4, (1,3), (2,4)), [3, 4]) @@ -44,20 +44,20 @@ lrn′ = Open([:I], LabelledReactionNet{Number,Int}([:I=>10, :R=>0], ((:rec=>.25 @test lrn == lrn′ death_petri = Open(PetriNet(1, 1=>())); -@test AlgebraicPetri.Graph(death_petri) isa Graphviz.Graph +@test to_graphviz(death_petri) isa Graphics.Graphviz.Graph # Test visualization of nested subgraphs SIR = LabelledReactionNet{Float64, Float64}([:S=>1.0, :I=>0.0, :R=>0.0], (:inf=>0.5)=>((:S,:I)=>(:I,:I)), (:rec=>0.1)=>(:I=>:R)) -stmts1 = Vector{Statement}([AlgebraicPetri.Subgraph(SIR; pre="1_")]) -graph_attrs = Attributes(:rankdir=>"LR") -node_attrs = Attributes(:shape=>"plain", :style=>"filled", :color=>"white") -edge_attrs = Attributes(:splines=>"splines") -g = Graphviz.Digraph("G", stmts1; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) -stmts2 = Vector{Statement}([AlgebraicPetri.tagged_subgraph(g; post="_2")]) -g2 = Graphviz.Digraph("G", stmts2; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) -@test g2 isa Graphviz.Graph -@test g2.stmts[1].stmts[1].stmts[1].name == "1_s1_2" +stmts1 = Vector{Graphics.Graphviz.Statement}([AlgebraicPetri.Subgraph(SIR; pre="1_")]) +graph_attrs = Graphics.Graphviz.Attributes(:rankdir=>"LR") +node_attrs = Graphics.Graphviz.Attributes(:shape=>"plain", :style=>"filled", :color=>"white") +edge_attrs = Graphics.Graphviz.Attributes(:splines=>"splines") +g = Graphics.Graphviz.Digraph("G", stmts1; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) +stmts2 = Vector{Graphics.Graphviz.Statement}([AlgebraicPetri.tagged_subgraph(g; post="_2")]) +g2 = Graphics.Graphviz.Digraph("G", stmts2; graph_attrs=graph_attrs, node_attrs=node_attrs, edge_attrs=edge_attrs) +@test g2 isa Graphics.Graphviz.Graph +@test g2.stmts[1].stmts[1].stmts[1].name == "1_n1_2" end diff --git a/test/algebraicpetri/types.jl b/test/algebraicpetri/types.jl index 9c493842..441a8f63 100644 --- a/test/algebraicpetri/types.jl +++ b/test/algebraicpetri/types.jl @@ -2,7 +2,7 @@ module TestTypes using Test using AlgebraicPetri -using Catlab.CategoricalAlgebra +using Catlab.CategoricalAlgebra, Catlab.Graphics using LabelledArrays using Tables @@ -58,12 +58,12 @@ open_sir_lrxn = Open([:S, :I], sir_lrxn, [:R]) @test sir_tpetri == sir_petri -@test typeof(Graph(sir_petri)) == Graph -@test typeof(Graph(sir_lpetri)) == Graph -@test typeof(Graph(sir_rxn)) == Graph -@test typeof(Graph(open_sir_rxn)) == Graph -@test typeof(Graph(sir_lrxn)) == Graph -@test typeof(Graph(open_sir_lrxn)) == Graph +@test to_graphviz(sir_petri) isa Graphics.Graphviz.Graph +@test to_graphviz(sir_lpetri) isa Graphics.Graphviz.Graph +@test to_graphviz(sir_rxn) isa Graphics.Graphviz.Graph +@test to_graphviz(open_sir_rxn) isa Graphics.Graphviz.Graph +@test to_graphviz(sir_lrxn) isa Graphics.Graphviz.Graph +@test to_graphviz(open_sir_lrxn) isa Graphics.Graphviz.Graph @test inputs(sir_petri, 1) == [1, 2] @test outputs(sir_petri, 1) == [2, 2] diff --git a/test/ext/AlgebraicPetriModelingToolkitExt.jl b/test/ext/AlgebraicPetriModelingToolkitExt.jl index 3a30c97d..e78c1e6b 100644 --- a/test/ext/AlgebraicPetriModelingToolkitExt.jl +++ b/test/ext/AlgebraicPetriModelingToolkitExt.jl @@ -44,6 +44,6 @@ petri_example = ODESystem(eqs, t, name=:PetriNet) @test ODESystem(psir) == petri_example @test ODESystem(bnsir) == bilayer_example @test ODESystem(bnsir, simplify = true) == simp_bilayer_example -@test typeof(ODESystem(PetriNet(psir))) == ODESystem # Sanity check that non-labelled Petri Nets resolve correctly +@test ODESystem(PetriNet(psir)) isa ODESystem # Sanity check that non-labelled Petri Nets resolve correctly end From 856d7638d5f3e6a8564728ac39f8b37177ac961c Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 18 May 2023 14:52:05 -0400 Subject: [PATCH 34/58] docs: fix LabelledReactionNet docstring (#149) --- src/AlgebraicPetri.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index ad106768..28cbd6cc 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -585,7 +585,7 @@ initial population of 10 susceptible, 1 infected, 0 recovered and an infection rate of 0.5 and recovery rate of 0.1 can be constructed as follows: ```@example -ReactionNet{Float64, Float64}([:S=>10,:I=>1,:R=>0], (:inf=>0.5)=>((1,2)=>(2,2)), (:rec=>0.1)=>(2=>3)) +LabelledReactionNet{Float64, Float64}([:S=>10,:I=>1,:R=>0], (:inf=>0.5)=>((:S,:I)=>(:I,:I)), (:rec=>0.1)=>(:I=>:R)) ``` """ LabelledReactionNet{R,C}(n::Union{AbstractVector,Tuple}, ts::Vararg{Union{Pair,Tuple}}) where {R,C} = begin From 0b4259296fcb1966f5b465fed930bcb4b343d1b4 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 23 May 2023 15:05:42 -0400 Subject: [PATCH 35/58] feat: add package extension for OrdinaryDiffEq (#150) --- Project.toml | 5 ++++- ext/AlgebraicPetriOrdinaryDiffEqExt.jl | 9 +++++++++ test/Project.toml | 1 + test/ext/AlgebraicPetriOrdinaryDiffEqExt.jl | 15 +++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 ext/AlgebraicPetriOrdinaryDiffEqExt.jl create mode 100644 test/ext/AlgebraicPetriOrdinaryDiffEqExt.jl diff --git a/Project.toml b/Project.toml index 3eabeae5..784b29ab 100644 --- a/Project.toml +++ b/Project.toml @@ -13,12 +13,14 @@ LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" [weakdeps] Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" [extensions] -AlgebraicPetriPetriExt = "Petri" AlgebraicPetriCatalystExt = "Catalyst" AlgebraicPetriModelingToolkitExt = "ModelingToolkit" +AlgebraicPetriOrdinaryDiffEqExt = "OrdinaryDiffEq" +AlgebraicPetriPetriExt = "Petri" [compat] Catalyst = "13" @@ -27,5 +29,6 @@ DataStructures = "0.18" GeneralizedGenerated = "0.3" LabelledArrays = "1" ModelingToolkit = "8" +OrdinaryDiffEq = "6" Petri = "1" julia = "1.9" diff --git a/ext/AlgebraicPetriOrdinaryDiffEqExt.jl b/ext/AlgebraicPetriOrdinaryDiffEqExt.jl new file mode 100644 index 00000000..c09f0ecc --- /dev/null +++ b/ext/AlgebraicPetriOrdinaryDiffEqExt.jl @@ -0,0 +1,9 @@ +module AlgebraicPetriOrdinaryDiffEqExt + +using AlgebraicPetri +import OrdinaryDiffEq: ODEProblem + +ODEProblem(m::AbstractPetriNet, u0, tspan, β) = ODEProblem(vectorfield(m), u0, tspan, β) +ODEProblem(m::AbstractPetriNet, tspan) = ODEProblem(vectorfield(m), concentrations(m), tspan, rates(m)) + +end diff --git a/test/Project.toml b/test/Project.toml index 93604f4a..4f101e76 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -5,6 +5,7 @@ Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/ext/AlgebraicPetriOrdinaryDiffEqExt.jl b/test/ext/AlgebraicPetriOrdinaryDiffEqExt.jl new file mode 100644 index 00000000..41d47b4b --- /dev/null +++ b/test/ext/AlgebraicPetriOrdinaryDiffEqExt.jl @@ -0,0 +1,15 @@ +module TestAlgebraicPetriOrdinaryDiffEqExt + +using Test +using AlgebraicPetri +using OrdinaryDiffEq + +sir_petri = PetriNet(3, ((1, 2), (2, 2)), (2, 3)) +sir_rxn = ReactionNet{Number,Int}([990, 10, 0], (0.001, ((1, 2) => (2, 2))), (0.25, (2 => 3))) + +sol_petri = solve(ODEProblem(sir_petri, [990, 10, 0], (0,100.0), [0.001, 0.25]), Tsit5()) +sol_rxn = solve(ODEProblem(sir_rxn, (0,100.0)), Tsit5()) + +@test sol_petri.u == sol_rxn.u + +end From 4a9d16eb6904f2fe73696d6834695dec5064b956 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 24 May 2023 09:38:41 -0400 Subject: [PATCH 36/58] ci: change default branch from master to main --- .github/workflows/julia_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/julia_ci.yml b/.github/workflows/julia_ci.yml index 0052545d..9dabe35f 100644 --- a/.github/workflows/julia_ci.yml +++ b/.github/workflows/julia_ci.yml @@ -4,7 +4,7 @@ on: schedule: - cron: 0 0 * * * push: - branches: ["master"] + branches: ["main"] tags: ["*"] pull_request: workflow_dispatch: From db11d3773085e5d5a0ed2bb9e9b02f29b047043e Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 16 May 2023 13:59:17 -0400 Subject: [PATCH 37/58] cleanup!: SubACSets upstreamed to Catlab --- Project.toml | 2 - .../chime/{chime-cset.jl => _chime-cset.jl} | 0 .../covid/chime/{chime.jl => _chime.jl} | 0 src/AlgebraicPetri.jl | 8 +- src/SubACSets.jl | 99 ------------------- test/SubACSets.jl | 36 ------- test/runtests.jl | 4 - 7 files changed, 3 insertions(+), 146 deletions(-) rename docs/literate/covid/chime/{chime-cset.jl => _chime-cset.jl} (100%) rename docs/literate/covid/chime/{chime.jl => _chime.jl} (100%) delete mode 100644 src/SubACSets.jl delete mode 100644 test/SubACSets.jl diff --git a/Project.toml b/Project.toml index 784b29ab..cdeacc4d 100644 --- a/Project.toml +++ b/Project.toml @@ -6,7 +6,6 @@ version = "0.8.11" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" -DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" GeneralizedGenerated = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" @@ -25,7 +24,6 @@ AlgebraicPetriPetriExt = "Petri" [compat] Catalyst = "13" Catlab = "0.14.16" -DataStructures = "0.18" GeneralizedGenerated = "0.3" LabelledArrays = "1" ModelingToolkit = "8" diff --git a/docs/literate/covid/chime/chime-cset.jl b/docs/literate/covid/chime/_chime-cset.jl similarity index 100% rename from docs/literate/covid/chime/chime-cset.jl rename to docs/literate/covid/chime/_chime-cset.jl diff --git a/docs/literate/covid/chime/chime.jl b/docs/literate/covid/chime/_chime.jl similarity index 100% rename from docs/literate/covid/chime/chime.jl rename to docs/literate/covid/chime/_chime.jl diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 28cbd6cc..9d85a58a 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -2,17 +2,16 @@ """ module AlgebraicPetri -export SchPetriNet, PetriNet, OpenPetriNetOb, AbstractPetriNet, ns, nt, ni, no, - os, ot, is, it, +export SchPetriNet, PetriNet, OpenPetriNetOb, AbstractPetriNet, + ns, nt, ni, no, os, ot, is, it, add_species!, add_transition!, add_transitions!, add_input!, add_inputs!, add_output!, add_outputs!, inputs, outputs, - TransitionMatrices, vectorfield, vectorfield_expr, + TransitionMatrices, vectorfield, vectorfield_expr, flatten_labels, SchLabelledPetriNet, LabelledPetriNet, AbstractLabelledPetriNet, sname, tname, snames, tnames, SchReactionNet, ReactionNet, AbstractReactionNet, concentration, concentrations, rate, rates, SchLabelledReactionNet, LabelledReactionNet, AbstractLabelledReactionNet, Open, OpenPetriNet, OpenLabelledPetriNet, OpenReactionNet, OpenLabelledReactionNet, OpenPetriNetOb, OpenLabelledPetriNetOb, OpenReactionNetOb, OpenLabelledReactionNetOb, - mca, flatten_labels, AbstractPropertyPetriNet, sprop, tprop, sprops, tprops, SchPropertyPetriNet, SchPropertyLabelledPetriNet, SchPropertyReactionNet, SchPropertyLabelledReactionNet, PropertyPetriNet, PropertyLabelledPetriNet, PropertyReactionNet, PropertyLabelledReactionNet, @@ -768,7 +767,6 @@ include("visualization.jl") include("Epidemiology.jl") include("BilayerNetworks.jl") include("ModelComparison.jl") -include("SubACSets.jl") include("TypedPetri.jl") include("OpenTransitions.jl") diff --git a/src/SubACSets.jl b/src/SubACSets.jl deleted file mode 100644 index b0c5fac9..00000000 --- a/src/SubACSets.jl +++ /dev/null @@ -1,99 +0,0 @@ -module SubACSets -export mca - -using Catlab.CategoricalAlgebra -using DataStructures - -""" - rm_cascade_subobj(X::ACSet, rm_subs) - -Deletes parts from an ACSet in cascading fashion, e.g. deleting a vertex deletes its edges -rm_subs is a NamedTuple or Dict of parts to be removed. -""" -function rm_cascade_subobj(X::ACSet, rm_subs) - # HACK: Remove this once Catlab makes cascading delete default - # https://github.com/AlgebraicJulia/Catlab.jl/pull/605 (old PR) - S = acset_schema(X) - subs = Dict([k => Set(parts(X, k)) for k ∈ objects(S)]) - rm_subs = Dict([k => Set(v) for (k, v) ∈ pairs(rm_subs)]) - while !isempty(rm_subs) - curr_c = first(rm_subs)[1] - if isempty(rm_subs[curr_c]) - delete!(rm_subs, curr_c) - else - curr_part = pop!(rm_subs[curr_c]) - if curr_part ∈ subs[curr_c] - delete!(subs[curr_c], curr_part) - for (f, c, d) ∈ homs(S) - if d == curr_c && c ∈ keys(subs) - for test_part ∈ subs[c] - if X[test_part, f] == curr_part - if c ∈ keys(rm_subs) - push!(rm_subs[c], test_part) - else - rm_subs[c] = Set([test_part]) - end - end - end - end - end - end - if isempty(rm_subs[curr_c]) - delete!(rm_subs, curr_c) - end - end - end - dom(hom(Subobject(X, NamedTuple(k => collect(v) for (k, v) ∈ subs)))) -end - -""" -Defintion: let 𝐺: C → 𝐒et be a C-set, we define the _size_ of 𝐺 to be ∑_{c ∈ C} -|𝐺c|. For example, under this definition, the size of: - * a graph G is |GE| + |GV| (num edges + num vertices) - * a Petri net P is |PT| + |PS| + |PI| + |PO| (num transitions + num species + - num input arcs + num output arcs). -""" -size(X::ACSet) = foldl(+, [length(parts(X, oₛ)) for oₛ ∈ objects(acset_schema(X))]) - -function strip_attributes(p::ACSet) - attributes = attrtypes(acset_schema(p)) - isempty(attributes) ? p : map(p; Dict(attr => (x -> nothing) for attr ∈ attributes)...) -end - -# Ask: "does there exists a mono X ↪ Y ?" -exists_mono(X::ACSet, Y::ACSet)::Bool = - is_homomorphic(X, strip_attributes(Y); monic=true, type_components=(Name=x -> nothing,)) - -""" - mca(XX::ACSet, YY::ACSet) - -Computes the maximimum common subacsets between XX and YY, i.e., find all a with with |a| maximum possible such that there is a monic span of Acset a₁ ← a → a₂. -""" -function mca(XX::ACSet, YY::ACSet) - (X, Y) = size(XX) ≤ size(YY) ? (XX, YY) : (YY, XX) # normalize order - - X_subs = BinaryHeap(Base.By(size, Base.Order.Reverse), [X]) - mca_list = Set{ACSet}() - - while !isempty(X_subs) && (isempty(mca_list) || size(first(mca_list)) <= size(first(X_subs))) - curr_X_sub = pop!(X_subs) - C = acset_schema(curr_X_sub) #X: C → Set - if exists_mono(curr_X_sub, Y) - push!(mca_list, curr_X_sub) - else - indiv_parts = [] - for c ∈ objects(C) - for p ∈ parts(curr_X_sub, c) - push!(indiv_parts, NamedTuple([c => [p]])) - end - end - new_X_subs = mapreduce(γ -> rm_cascade_subobj(curr_X_sub, γ), vcat, indiv_parts; init=[]) - for new_sub ∈ new_X_subs - push!(X_subs, new_sub) - end - end - end - mca_list -end - -end diff --git a/test/SubACSets.jl b/test/SubACSets.jl deleted file mode 100644 index 6e5544e6..00000000 --- a/test/SubACSets.jl +++ /dev/null @@ -1,36 +0,0 @@ -module TestSubACSets - -using Test - -using AlgebraicPetri, AlgebraicPetri.SubACSets - -m1 = LabelledPetriNet( - [:X3, :Y3, :W3, :Z3], - :f3 => (:X3 => (:W3, :Y3, :Z3)) -) - -m2 = LabelledPetriNet( - [:X4, :W4, :Y4, :Z4], - :f4 => ((:W4, :X4, :Y4) => :Z4) -) - -sub_acsets = mca(m1, m2) - -@test sub_acsets == Set([ - LabelledPetriNet( - [:X3, :Y3, :W3, :Z3], - :f3 => (:X3 => :Z3) - ), - LabelledPetriNet( - [:X3, :Y3, :W3, :Z3], - :f3 => (:X3 => :W3) - ), - LabelledPetriNet( - [:X3, :Y3, :W3, :Z3], - :f3 => (:X3 => :Y3) - ) -]) - -@test Set(PetriNet.(sub_acsets)) == mca(PetriNet(m1), PetriNet(m2)) - -end diff --git a/test/runtests.jl b/test/runtests.jl index 5bff4877..9855240d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,10 +20,6 @@ end include("OpenTransitions.jl") end -@testset "SubACSets" begin - include("SubACSets.jl") -end - @testset "TypedPetris" begin include("TypedPetri.jl") end From 64e2dfd3dc7b671f6980171ac13dac1bbcf5f9a7 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 23 May 2023 12:33:26 -0400 Subject: [PATCH 38/58] fix: Update to new ACSetTtransformation API --- src/TypedPetri.jl | 71 +++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index 94e3cd3a..88f19b25 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -28,13 +28,11 @@ function prim_petri(type_system, transition) push!(s_map, o) add_output!(prim, 1, o′) end - ACSetTransformation( + LooseACSetTransformation( + (S=s_map, T=[transition], O=incident(type_system, transition, :ot), I=incident(type_system, transition, :it)), + (), prim, - type_system, - S=s_map, - T=[transition], - O=incident(type_system, transition, :ot), - I=incident(type_system, transition, :it), + type_system ) end @@ -48,13 +46,11 @@ function prim_cospan(type_system, transition) feet = [FinSet(1) for s in 1:ns(p)] structured_feet = [PetriNet(1) for s in 1:ns(p)] legs = [ - ACSetTransformation( + LooseACSetTransformation( + (S = [s], T = Int[], I = Int[], O = Int[]), + (), structured_feet[s], - p, - S = [s], - T = Int[], - I = Int[], - O = Int[], + p ) for s in 1:ns(p) ] @@ -84,11 +80,11 @@ function oapply_typed(type_system::LabelledPetriNet, uwd, tnames::Vector{Symbol} ) ) labelled_petri = LabelledPetriNet(unlabelled_map.dom, uwd[:variable], tnames) - ACSetTransformation( + LooseACSetTransformation( + unlabelled_map.components, + (Name=x->nothing,), labelled_petri, - type_system; - unlabelled_map.components..., - Name=name->nothing + type_system ) end @@ -124,7 +120,7 @@ function add_reflexives( type_system::AbstractPetriNet ) petri = deepcopy(dom(typed_petri)) - type_comps = Dict([k=>collect(v) for (k,v) in pairs(deepcopy(components(typed_petri)))]) + type_comps = Dict(k=>collect(v) for (k,v) in pairs(deepcopy(components(typed_petri)))) for (s_i,cts) in enumerate(reflexive_transitions) for ct in cts type_ind = findfirst(==(ct), type_system[:tname]) @@ -139,13 +135,11 @@ function add_reflexives( append!(type_comps[:I], is); append!(type_comps[:O], os); end end - ACSetTransformation( + LooseACSetTransformation( + type_comps, + (Name=x->nothing, (has_subpart(petri, :rate) ? [:Rate=>x->nothing] : [])..., (has_subpart(petri, :concentration) ? [:Concentration=>x->nothing] : [])...), petri, - codom(typed_petri); - type_comps..., - Name=x->nothing, - (has_subpart(petri, :rate) ? [:Rate=>x->nothing] : [])..., - (has_subpart(petri, :concentration) ? [:Concentration=>x->nothing] : [])... + codom(typed_petri) ) end @@ -178,13 +172,15 @@ function add_params( end pn end - ACSetTransformation( + LooseACSetTransformation( + NamedTuple(map(objects(acset_schema(domain))) do ob + ob => components(typed_petri)[ob] + end), + NamedTuple(map(attrtypes(acset_schema(domain))) do attrtype + attrtype => x->nothing + end), domain, - typing; - components(typed_petri)..., - Name=x->nothing, - Rate=x->nothing, - Concentration=x->nothing + typing, ) end @@ -214,16 +210,17 @@ Assumes a single species type and a single transition type. function pairwise_id_typed_petri(type_net, stype, ttype, args...; codom_net=nothing) # TODO: this keyword parameter is a workaround. It should be removed and fixed later. net = pairwise_id_petri(args...) - type_components = Dict(type => (x -> nothing) - for type in attrtypes(acset_schema(net))) + type_components = NamedTuple(map(attrtypes(acset_schema(net))) do type + type => x->nothing + end) s = only(incident(type_net, stype, :sname)) t = only(incident(type_net, ttype, :tname)) - ACSetTransformation(net, isnothing(codom_net) ? type_net : codom_net; - S = repeat([s], ns(net)), - T = repeat([t], nt(net)), - I = repeat(incident(type_net, t, :it), nt(net)), - O = repeat(incident(type_net, t, :ot), nt(net)), - type_components...) + LooseACSetTransformation( + (S = repeat([s], ns(net)), T = repeat([t], nt(net)), I = repeat(incident(type_net, t, :it), nt(net)), O = repeat(incident(type_net, t, :ot), nt(net))), + type_components, + net, + isnothing(codom_net) ? type_net : codom_net + ) end """ Make Petri net with 'identity' transformation between all species pairs. From 31499b6b8139a63ce4e30f249983cb9532fc4e8e Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 23 May 2023 12:36:56 -0400 Subject: [PATCH 39/58] chore(test): comment out tests for external packages that need to be updated --- test/ModelComparison.jl | 35 +++++++++++++-------------- test/algebraicpetri/AlgebraicPetri.jl | 7 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/test/ModelComparison.jl b/test/ModelComparison.jl index e9af9a70..11783f0e 100644 --- a/test/ModelComparison.jl +++ b/test/ModelComparison.jl @@ -32,26 +32,25 @@ for pn in [models, so = Subobject.(legs(c_res)) for s in so @test to_graphviz(s) isa Graphics.Graphviz.Graph - @test codom(hom(s)) == pn[2] + @test ob(s) == pn[2] end - @test dom(hom(~foldl(∨, so) ∨ foldl(∨, so))) == pn[2] - A,B = so - @test implies(A, B) == ¬(A) ∨ B - @test ¬(A ∧ B) == ¬(A) ∨ ¬(B) - @test ¬(A ∧ B) != ¬(A) ∨ B - # modus ponens holds only up to inclusion, not equality. - @test length(compare(A ∧ implies(A,B), B)) > 0 - # this is an equivalent check because X ∧ B == X iff X ↪ B - @test (A ∧ implies(A,B)) == B ∧ (A ∧ implies(A,B)) - - @test length(compare(B ∧ implies(B,A), A)) > 0 - @test (B ∧ implies(B,A)) == A ∧ (B ∧ implies(B,A)) - - @test ¬(A ∨ (¬B)) == ¬(A) ∧ ¬(¬(B)) - @test ¬(A ∨ (¬B)) == ¬(A) ∧ B - @test A ∧ ¬(¬(A)) == ¬(¬(A)) - @test implies((A∧B), A) == A∨B + # TODO: Uncomment after Subobject logic support is fixed + # @test dom(hom(~foldl(∨, so) ∨ foldl(∨, so))) == pn[2] + # A,B = so + # @test implies(A, B) == ¬(A) ∨ B + # @test ¬(A ∧ B) == ¬(A) ∨ ¬(B) + # @test ¬(A ∧ B) != ¬(A) ∨ B + # # modus ponens holds only up to inclusion, not equality. + # @test length(compare(A ∧ implies(A,B), B)) > 0 + # # this is an equivalent check because X ∧ B == X iff X ↪ B + # @test (A ∧ implies(A,B)) == B ∧ (A ∧ implies(A,B)) + # @test length(compare(B ∧ implies(B,A), A)) > 0 + # @test (B ∧ implies(B,A)) == A ∧ (B ∧ implies(B,A)) + # @test ¬(A ∨ (¬B)) == ¬(A) ∧ ¬(¬(B)) + # @test ¬(A ∨ (¬B)) == ¬(A) ∧ B + # @test A ∧ ¬(¬(A)) == ¬(¬(A)) + # @test implies((A∧B), A) == A∨B end end diff --git a/test/algebraicpetri/AlgebraicPetri.jl b/test/algebraicpetri/AlgebraicPetri.jl index 596c2693..a1fac1cd 100644 --- a/test/algebraicpetri/AlgebraicPetri.jl +++ b/test/algebraicpetri/AlgebraicPetri.jl @@ -12,6 +12,7 @@ end include("petri.jl") end -@testset "Rewriting" begin - include("rewriting.jl") -end +# TODO: Uncomment once AlgebraicRewriting has been updated +# @testset "Rewriting" begin +# include("rewriting.jl") +# end From 689bff78db8f5b6fd4339d60524821d8f228446b Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 23 May 2023 13:44:17 -0400 Subject: [PATCH 40/58] docs: add max_common_subobject example --- docs/literate/covid/max_common_subobject.jl | 68 +++++++++++++++++++ .../{stratification => }/stratification.jl | 0 docs/make.jl | 3 +- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 docs/literate/covid/max_common_subobject.jl rename docs/literate/covid/{stratification => }/stratification.jl (100%) diff --git a/docs/literate/covid/max_common_subobject.jl b/docs/literate/covid/max_common_subobject.jl new file mode 100644 index 00000000..1f0920e9 --- /dev/null +++ b/docs/literate/covid/max_common_subobject.jl @@ -0,0 +1,68 @@ +# # [Maximum Common Sub C-Set](@id max_common_subobject) +# +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/covid/max_common_subobject.ipynb) + +using AlgebraicPetri +using Catlab.CategoricalAlgebra, Catlab.Graphics + +# ### Define epidemiology models + +# #### SIR + +sir = LabelledPetriNet([:S, :I, :R], + :inf => ((:S, :I) => (:I, :I)), + :rec => (:I => :R) + ) +to_graphviz(sir) + +# #### SIRD + +sird = LabelledPetriNet([:S, :I, :R, :D], + :inf => ((:S, :I) => (:I, :I)), + :rec => (:I => :R), + :death => (:R => :D) + ) +to_graphviz(sird) + +# #### SEIR + +seir = LabelledPetriNet([:S, :E, :I, :R], + :exp => ((:S, :I) => (:E, :I)), + :ill => (:E => :I), + :rec => (:I => :R) + ) +to_graphviz(seir) + +# #### SEIRD + +seird = LabelledPetriNet([:S, :E, :I, :R, :D], + :exp => ((:S, :I) => (:E, :I)), + :ill => (:E => :I), + :rec => (:I => :R), + :death => (:R => :D) + ) +to_graphviz(seird) + +# ### Calculate the Maximum Common C-Set + +sub, morphisms = maximum_common_subobject(sir, sird, seir, seird) |> collect |> first + +to_graphviz(sub) + +# ### Visualize Sub C-Sets + +# #### SIR + +first(morphisms[1])(sub) |> to_graphviz + +# #### SIRD + +first(morphisms[2])(sub) |> to_graphviz + +# #### SEIR + +first(morphisms[3])(sub) |> to_graphviz + +# #### SEIRD + +first(morphisms[4])(sub) |> to_graphviz diff --git a/docs/literate/covid/stratification/stratification.jl b/docs/literate/covid/stratification.jl similarity index 100% rename from docs/literate/covid/stratification/stratification.jl rename to docs/literate/covid/stratification.jl diff --git a/docs/make.jl b/docs/make.jl index 55a83217..668dfb3b 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -49,7 +49,8 @@ makedocs( "generated/covid/coexist/coexist.md", "generated/enzymes/enzyme_reactions.md", "generated/covid/bilayerconversion.md", - "generated/covid/stratification/stratification.md", + "generated/covid/stratification.md", + "generated/covid/max_common_subobject.md", ], "Library Reference" => "api.md", ] From 31829e3750283cd10284692ee8c044ed469c10bb Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 23 May 2023 14:28:01 -0400 Subject: [PATCH 41/58] docs: update old example jupyter notebook links to new location --- docs/literate/covid/_covid.jl | 2 +- docs/literate/covid/coexist/coexist.jl | 2 +- docs/literate/covid/epidemiology.jl | 2 +- docs/literate/covid/stratification.jl | 2 +- docs/literate/enzymes/enzyme_reactions.jl | 2 +- docs/literate/predation/lotka-volterra.jl | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/literate/covid/_covid.jl b/docs/literate/covid/_covid.jl index 94ee0b75..c9e953e7 100644 --- a/docs/literate/covid/_covid.jl +++ b/docs/literate/covid/_covid.jl @@ -1,6 +1,6 @@ # # [Multi-City COVID-19 Model](@id covid_example) # -#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/covid/covid.ipynb) +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/covid/covid.ipynb) using AlgebraicPetri using AlgebraicPetri.Epidemiology diff --git a/docs/literate/covid/coexist/coexist.jl b/docs/literate/covid/coexist/coexist.jl index 06741575..2d6e28d2 100644 --- a/docs/literate/covid/coexist/coexist.jl +++ b/docs/literate/covid/coexist/coexist.jl @@ -1,6 +1,6 @@ # # [COEXIST Multi-Generational COVID Model](@id coexist_example) # -#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/covid/coexist/coexist.ipynb) +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/covid/coexist/coexist.ipynb) using AlgebraicPetri diff --git a/docs/literate/covid/epidemiology.jl b/docs/literate/covid/epidemiology.jl index 54bf0360..276a960e 100644 --- a/docs/literate/covid/epidemiology.jl +++ b/docs/literate/covid/epidemiology.jl @@ -1,6 +1,6 @@ # # [Basic Epidemiology Models](@id epidemiology_example) # -#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/covid/epidemiology.ipynb) +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/covid/epidemiology.ipynb) using AlgebraicPetri using AlgebraicPetri.Epidemiology diff --git a/docs/literate/covid/stratification.jl b/docs/literate/covid/stratification.jl index 6a3b561e..1046e207 100644 --- a/docs/literate/covid/stratification.jl +++ b/docs/literate/covid/stratification.jl @@ -1,6 +1,6 @@ # # [Stratification of COVID Models](@id stratification_example) # -#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/covid/stratification/stratification.ipynb) +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/covid/stratification.ipynb) using AlgebraicPetri, AlgebraicPetri.TypedPetri using Catlab.Programs, Catlab.Graphics diff --git a/docs/literate/enzymes/enzyme_reactions.jl b/docs/literate/enzymes/enzyme_reactions.jl index 78c24f34..4ac06ff6 100644 --- a/docs/literate/enzymes/enzyme_reactions.jl +++ b/docs/literate/enzymes/enzyme_reactions.jl @@ -1,6 +1,6 @@ # # [Cathepsin Enzyme Reactions](@id enzyme_example) # -#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/enzymes/enzyme_reactions.ipynb) +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/enzymes/enzyme_reactions.ipynb) using AlgebraicPetri using Catlab.Programs diff --git a/docs/literate/predation/lotka-volterra.jl b/docs/literate/predation/lotka-volterra.jl index 0880d8e8..7f1ec6a1 100644 --- a/docs/literate/predation/lotka-volterra.jl +++ b/docs/literate/predation/lotka-volterra.jl @@ -1,6 +1,6 @@ # # [Lotka-Volterra Model](@id predation_example) # -#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/examples/predation/lotka-volterra.ipynb) +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/predation/lotka-volterra.ipynb) using AlgebraicPetri From 2d3362e8b65f58e912c370213e79c71ac7934fa5 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Tue, 23 May 2023 14:58:20 -0400 Subject: [PATCH 42/58] revert: reenable AlgebraicRewriting tests after testing with new branch Refs: 3c53d583 --- test/algebraicpetri/AlgebraicPetri.jl | 7 +++---- test/algebraicpetri/rewriting.jl | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/algebraicpetri/AlgebraicPetri.jl b/test/algebraicpetri/AlgebraicPetri.jl index a1fac1cd..596c2693 100644 --- a/test/algebraicpetri/AlgebraicPetri.jl +++ b/test/algebraicpetri/AlgebraicPetri.jl @@ -12,7 +12,6 @@ end include("petri.jl") end -# TODO: Uncomment once AlgebraicRewriting has been updated -# @testset "Rewriting" begin -# include("rewriting.jl") -# end +@testset "Rewriting" begin + include("rewriting.jl") +end diff --git a/test/algebraicpetri/rewriting.jl b/test/algebraicpetri/rewriting.jl index 5427abd5..fe27d9d9 100644 --- a/test/algebraicpetri/rewriting.jl +++ b/test/algebraicpetri/rewriting.jl @@ -5,9 +5,6 @@ using AlgebraicRewriting using Catlab, Catlab.CategoricalAlgebra using Test -const homomorphism = CategoricalAlgebra.homomorphism -const is_isomorphic = CategoricalAlgebra.is_isomorphic - sir = LabelledReactionNet{Float64, Float64}( [:S=>100, :I=>1, :R=>0], (:inf,.03)=>((:S,:I)=>(:I,:I)), From 9cc82e62ec4f8077728851996b0f87ef8c646b2f Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Wed, 31 May 2023 12:02:51 -0400 Subject: [PATCH 43/58] fix: add new required catlab imports after ACSets.jl migration --- src/TypedPetri.jl | 1 + test/Epidemiology.jl | 2 +- test/algebraicpetri/core.jl | 1 + test/algebraicpetri/petri.jl | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index 88f19b25..fd37e94a 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -4,6 +4,7 @@ export prim_petri, strip_names, prim_cospan, oapply_typed, typed_product, using Catlab using Catlab.CategoricalAlgebra +using Catlab.Theories using Catlab.WiringDiagrams using AlgebraicPetri using AlgebraicPetri: LabelledPetriNetUntyped, OpenLabelledPetriNetUntyped, LabelledReactionNetUntyped diff --git a/test/Epidemiology.jl b/test/Epidemiology.jl index 0c0ff813..e2eb860f 100644 --- a/test/Epidemiology.jl +++ b/test/Epidemiology.jl @@ -4,7 +4,7 @@ using Test using AlgebraicPetri using AlgebraicPetri.Epidemiology using Catlab.Programs -using Catlab.CategoricalAlgebra +using Catlab.CategoricalAlgebra, Catlab.Theories sir_petri = LabelledPetriNet([:S,:I,:R], :inf=>((:S,:I)=>(:I,:I)), :rec=>(:I=>:R)) diff --git a/test/algebraicpetri/core.jl b/test/algebraicpetri/core.jl index a40869ae..a8ec78fb 100644 --- a/test/algebraicpetri/core.jl +++ b/test/algebraicpetri/core.jl @@ -2,6 +2,7 @@ module TestCore using Test using AlgebraicPetri +using Catlab.Theories using Catlab.CategoricalAlgebra p1 = codom(Open([1], PetriNet(1), [1])) diff --git a/test/algebraicpetri/petri.jl b/test/algebraicpetri/petri.jl index 2efd98ff..8534b82f 100644 --- a/test/algebraicpetri/petri.jl +++ b/test/algebraicpetri/petri.jl @@ -2,7 +2,7 @@ module TestPetri using Test using AlgebraicPetri -using Catlab.CategoricalAlgebra +using Catlab.CategoricalAlgebra, Catlab.Theories using Catlab.Graphs, Catlab.Graphics f = Open([1, 2], PetriNet(4, (1,3), (2,4)), [3, 4]) From 9ba53d3df3a98033140a5b4e0b2ce8ff1aee1741 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 1 Jun 2023 10:20:10 -0400 Subject: [PATCH 44/58] fix: update to new ACSetTransformation syntax --- src/AlgebraicPetri.jl | 2 +- src/visualization.jl | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 9d85a58a..6666232a 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -412,7 +412,7 @@ flatten_labels(pn::AbstractPetriNet; attributes=[:Name], sep='_') = begin f = x->flat_symbol(x, sep) map(pn; Dict(attr=>f for attr in attributes)...) end -flatten_labels(act::ACSetTransformation{S,Comp,<:AbstractPetriNet,<:AbstractPetriNet}; attributes=[:Name], sep='_') where {S,Comp} = +flatten_labels(act::ACSetTransformation; attributes=[:Name], sep='_') = ACSetTransformation(flatten_labels(act.dom; attributes=attributes, sep=sep), act.codom; components(act)...) """ Concentration of a ReactionNet diff --git a/src/visualization.jl b/src/visualization.jl index 69295177..35dd8883 100644 --- a/src/visualization.jl +++ b/src/visualization.jl @@ -138,8 +138,7 @@ function to_graphviz(m::Multispan{<:AbstractPetriNet}; ) end -to_graphviz(p::StructACSetTransformation{<:Any, <:Any, <:AbstractPetriNet, <:AbstractPetriNet}; kw...) = - to_graphviz(Multispan(p.dom, [p]); kw...) +to_graphviz(p::ACSetTransformation; kw...) = to_graphviz(Multispan(p.dom, [p]); kw...) # Subgraph Extensions ##################### From a85a2eb9dd9ba920f228f893961d1cc24a219c63 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 15 Jun 2023 09:43:24 -0400 Subject: [PATCH 45/58] chore(test): remove algebraicrewriting tests --- test/Project.toml | 1 - test/algebraicpetri/AlgebraicPetri.jl | 4 -- test/algebraicpetri/rewriting.jl | 89 --------------------------- 3 files changed, 94 deletions(-) delete mode 100644 test/algebraicpetri/rewriting.jl diff --git a/test/Project.toml b/test/Project.toml index 4f101e76..7021d076 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,6 +1,5 @@ [deps] AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" -AlgebraicRewriting = "725a01d3-f174-5bbd-84e1-b9417bad95d9" Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" diff --git a/test/algebraicpetri/AlgebraicPetri.jl b/test/algebraicpetri/AlgebraicPetri.jl index 596c2693..ea8ac928 100644 --- a/test/algebraicpetri/AlgebraicPetri.jl +++ b/test/algebraicpetri/AlgebraicPetri.jl @@ -11,7 +11,3 @@ end @testset "Petri" begin include("petri.jl") end - -@testset "Rewriting" begin - include("rewriting.jl") -end diff --git a/test/algebraicpetri/rewriting.jl b/test/algebraicpetri/rewriting.jl deleted file mode 100644 index fe27d9d9..00000000 --- a/test/algebraicpetri/rewriting.jl +++ /dev/null @@ -1,89 +0,0 @@ -module TestRewriting - -using AlgebraicPetri -using AlgebraicRewriting -using Catlab, Catlab.CategoricalAlgebra -using Test - -sir = LabelledReactionNet{Float64, Float64}( - [:S=>100, :I=>1, :R=>0], - (:inf,.03)=>((:S,:I)=>(:I,:I)), - (:rec,.25)=>(:I=>:R) -) - -seir = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1,:E=>1,:R=>0], - (:inf,.03)=>((:S,:I)=>(:I,:I)), - (:rec,.25)=>(:I=>:R), - (:inc,.1)=>(:E=>:I), - (:exp,.1)=>((:S,:I)=>(:E,:I)) -) - -# seir test -Rg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1,:E=>1], - (:exp,.1)=>((:S, :I)=>(:E, :I)), - (:inc,.1)=>(:E => :I) -) -Lg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1], -) - -L = homomorphism(Lg, Lg) -R = homomorphism(Lg, Rg) -m = homomorphism(Lg, sir) - -@test is_isomorphic(seir, rewrite_match(Rule{:DPO}(L,R), m)) - -# seirs test -Lg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1], -) -Rg = LabelledReactionNet{Float64, Float64}( - [:S=>100,:I=>1], - (:sus,.1)=>(:I=>:S) -) - -L = homomorphism(Lg, Lg) -R = homomorphism(Lg, Rg) -m = homomorphism(Lg, seir) - -seirs = rewrite_match(Rule{:DPO}(L,R), m) - -@test nt(seirs) == nt(seir) + 1 -@test ns(seirs) == ns(seir) - -sus_ix = only(incident(seirs, :sus, :tname)) -sus_input = only(seirs[incident(seirs, sus_ix, :it), :is]) -sus_output = only(seirs[incident(seirs, sus_ix, :ot), :os]) - -@test seirs[sus_input,:sname] == :I -@test seirs[sus_output,:sname] == :S - -# seird test - -Lg = LabelledReactionNet{Float64, Float64}( - [:I=>1], -) -Rg = LabelledReactionNet{Float64, Float64}( - [:I=>1,:D=>0], - (:die,.1)=>(:I=>:D) -) - -L = homomorphism(Lg, Lg) -R = homomorphism(Lg, Rg) -m = homomorphism(Lg, seir) - -seird = rewrite_match(Rule{:DPO}(L,R), m) - -@test nt(seird) == nt(seir) + 1 -@test ns(seird) == ns(seir) + 1 - -die_ix = only(incident(seird, :die, :tname)) -die_input = only(seird[incident(seird, die_ix, :it), :is]) -die_output = only(seird[incident(seird, die_ix, :ot), :os]) - -@test seird[die_input,:sname] == :I -@test seird[die_output,:sname] == :D - -end From a22fd3a03722d280a81861d91e259a91f08f66e0 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 15 Jun 2023 10:29:39 -0400 Subject: [PATCH 46/58] cleanup!: Drop interoperability with Petri.jl --- Project.toml | 3 --- ext/AlgebraicPetriPetriExt.jl | 28 ---------------------------- test/Project.toml | 1 - test/ext/AlgebraicPetriPetriExt.jl | 15 --------------- test/ext/extensions.jl | 4 ---- 5 files changed, 51 deletions(-) delete mode 100644 ext/AlgebraicPetriPetriExt.jl delete mode 100644 test/ext/AlgebraicPetriPetriExt.jl diff --git a/Project.toml b/Project.toml index cdeacc4d..050c1616 100644 --- a/Project.toml +++ b/Project.toml @@ -13,13 +13,11 @@ LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" [extensions] AlgebraicPetriCatalystExt = "Catalyst" AlgebraicPetriModelingToolkitExt = "ModelingToolkit" AlgebraicPetriOrdinaryDiffEqExt = "OrdinaryDiffEq" -AlgebraicPetriPetriExt = "Petri" [compat] Catalyst = "13" @@ -28,5 +26,4 @@ GeneralizedGenerated = "0.3" LabelledArrays = "1" ModelingToolkit = "8" OrdinaryDiffEq = "6" -Petri = "1" julia = "1.9" diff --git a/ext/AlgebraicPetriPetriExt.jl b/ext/AlgebraicPetriPetriExt.jl deleted file mode 100644 index 5ac57687..00000000 --- a/ext/AlgebraicPetriPetriExt.jl +++ /dev/null @@ -1,28 +0,0 @@ -module AlgebraicPetriPetriExt - -using AlgebraicPetri -using Catlab.CategoricalAlgebra - -import Petri - -Petri.Model(p::AbstractPetriNet) = begin - ts = TransitionMatrices(p) - - if has_subpart(p, :sname) && has_subpart(p, :tname) - snames = [sname(p, s) for s in 1:ns(p)] - tnames = [tname(p, t) for t in 1:nt(p)] - t_in = map(i->Dict(snames[k]=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) - t_out = map(i->Dict(snames[k]=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) - Δ = Dict(tnames[i]=>t for (i,t) in enumerate(zip(t_in, t_out))) - S = collect(values(snames)) - else - t_in = map(i->Dict(k=>v for (k,v) in enumerate(ts.input[i,:]) if v != 0), 1:nt(p)) - t_out = map(i->Dict(k=>v for (k,v) in enumerate(ts.output[i,:]) if v != 0), 1:nt(p)) - Δ = Dict(i=>t for (i,t) in enumerate(zip(t_in, t_out))) - S = ns(p) - end - - return Petri.Model(ns(p), Δ) -end - -end diff --git a/test/Project.toml b/test/Project.toml index 7021d076..193de05f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -5,6 +5,5 @@ Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/ext/AlgebraicPetriPetriExt.jl b/test/ext/AlgebraicPetriPetriExt.jl deleted file mode 100644 index db7a50c8..00000000 --- a/test/ext/AlgebraicPetriPetriExt.jl +++ /dev/null @@ -1,15 +0,0 @@ -module TestAlgebraicPetriPetriExt - -using Test -using AlgebraicPetri -import Petri - -sir_petri = PetriNet(3, ((1, 2), (2, 2)), (2, 3)) -sir_lpetri = LabelledPetriNet([:S, :I, :R], :inf => ((:S, :I), (:I, :I)), :rec => (:I, :R)) -sir_rxn = ReactionNet{Number,Int}([990, 10, 0], (0.001, ((1, 2) => (2, 2))), (0.25, (2 => 3))) -sir_lrxn = LabelledReactionNet{Number,Int}((:S => 990, :I => 10, :R => 0), (:inf, 0.001) => ((:S, :I) => (:I, :I)), (:rec, 0.25) => (:I => :R)) - -@test Petri.Model(sir_petri) == Petri.Model(sir_rxn) -@test Petri.Model(sir_lpetri) == Petri.Model(sir_lrxn) - -end diff --git a/test/ext/extensions.jl b/test/ext/extensions.jl index 38b626d9..99886a2a 100644 --- a/test/ext/extensions.jl +++ b/test/ext/extensions.jl @@ -1,9 +1,5 @@ using Test -@testset "Petri Package Extension" begin - include("AlgebraicPetriPetriExt.jl") -end - @testset "Catalyst Package Extension" begin include("AlgebraicPetriCatalystExt.jl") end From 534381f7cc0d49be17a0437aec61e1a9eb15c4b7 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 15 Jun 2023 10:29:58 -0400 Subject: [PATCH 47/58] fix: Update to new Catlab exports and bump version --- Project.toml | 2 +- docs/Project.toml | 1 - docs/literate/covid/coexist/{coexist.jl => _coexist.jl} | 0 docs/make.jl | 1 - src/AlgebraicPetri.jl | 4 ---- src/BilayerNetworks.jl | 2 -- src/Epidemiology.jl | 3 --- src/ModelComparison.jl | 1 - src/OpenTransitions.jl | 1 - src/TypedPetri.jl | 3 --- src/visualization.jl | 4 ++-- 11 files changed, 3 insertions(+), 19 deletions(-) rename docs/literate/covid/coexist/{coexist.jl => _coexist.jl} (100%) diff --git a/Project.toml b/Project.toml index 050c1616..f5213547 100644 --- a/Project.toml +++ b/Project.toml @@ -21,7 +21,7 @@ AlgebraicPetriOrdinaryDiffEqExt = "OrdinaryDiffEq" [compat] Catalyst = "13" -Catlab = "0.14.16" +Catlab = "0.15" GeneralizedGenerated = "0.3" LabelledArrays = "1" ModelingToolkit = "8" diff --git a/docs/Project.toml b/docs/Project.toml index a3d40be3..151e73d0 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -9,6 +9,5 @@ LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Petri = "4259d249-1051-49fa-8328-3f8ab9391c33" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" diff --git a/docs/literate/covid/coexist/coexist.jl b/docs/literate/covid/coexist/_coexist.jl similarity index 100% rename from docs/literate/covid/coexist/coexist.jl rename to docs/literate/covid/coexist/_coexist.jl diff --git a/docs/make.jl b/docs/make.jl index 668dfb3b..b04b0ffb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -46,7 +46,6 @@ makedocs( "Examples" => Any[ "generated/predation/lotka-volterra.md", "generated/covid/epidemiology.md", - "generated/covid/coexist/coexist.md", "generated/enzymes/enzyme_reactions.md", "generated/covid/bilayerconversion.md", "generated/covid/stratification.md", diff --git a/src/AlgebraicPetri.jl b/src/AlgebraicPetri.jl index 6666232a..743b769e 100644 --- a/src/AlgebraicPetri.jl +++ b/src/AlgebraicPetri.jl @@ -19,10 +19,6 @@ export SchPetriNet, PetriNet, OpenPetriNetOb, AbstractPetriNet, OpenPropertyPetriNetOb, OpenPropertyLabelledPetriNetOb, OpenPropertyReactionNetOb, OpenPropertyLabelledReactionNetOb using Catlab -using Catlab.CategoricalAlgebra -using Catlab.CategoricalAlgebra.FinSets -using Catlab.Present -using Catlab.Theories using LabelledArrays using GeneralizedGenerated: mk_function diff --git a/src/BilayerNetworks.jl b/src/BilayerNetworks.jl index 550611e7..33487114 100644 --- a/src/BilayerNetworks.jl +++ b/src/BilayerNetworks.jl @@ -2,8 +2,6 @@ module BilayerNetworks using AlgebraicPetri using Catlab -using Catlab.CategoricalAlgebra -using Catlab.Graphics import Catlab.CategoricalAlgebra: migrate! export ThBilayerNetwork, AbstractBilayerNetwork, BilayerNetwork, diff --git a/src/Epidemiology.jl b/src/Epidemiology.jl index 101d4316..e1224753 100644 --- a/src/Epidemiology.jl +++ b/src/Epidemiology.jl @@ -5,9 +5,6 @@ module Epidemiology using AlgebraicPetri using Catlab -using Catlab.Theories -using Catlab.WiringDiagrams -using Catlab.CategoricalAlgebra.FinSets export oapply_epi, infection, exposure, illness, recovery, death diff --git a/src/ModelComparison.jl b/src/ModelComparison.jl index dea97bd5..600aebb7 100644 --- a/src/ModelComparison.jl +++ b/src/ModelComparison.jl @@ -5,7 +5,6 @@ module ModelComparison using AlgebraicPetri using Catlab -using Catlab.CategoricalAlgebra import Catlab.CategoricalAlgebra: Subobject export petri_homomorphisms, compare, PetriSubobject diff --git a/src/OpenTransitions.jl b/src/OpenTransitions.jl index 70495c2d..f0a5988d 100644 --- a/src/OpenTransitions.jl +++ b/src/OpenTransitions.jl @@ -7,7 +7,6 @@ using AlgebraicPetri: LabelledPetriNetUntyped, LabelledPetriNet, PetriNet, AbstractPetriNet, ns, nt, tname using Catlab -using Catlab.CategoricalAlgebra export OpenLabelledPetriNetObT, OpenLabelledPetriNetT, OpenT, OpenPetriNetObT, OpenPetriNetT diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index fd37e94a..656d7962 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -3,9 +3,6 @@ export prim_petri, strip_names, prim_cospan, oapply_typed, typed_product, add_params, add_reflexives, pairwise_id_petri, pairwise_id_typed_petri using Catlab -using Catlab.CategoricalAlgebra -using Catlab.Theories -using Catlab.WiringDiagrams using AlgebraicPetri using AlgebraicPetri: LabelledPetriNetUntyped, OpenLabelledPetriNetUntyped, LabelledReactionNetUntyped diff --git a/src/visualization.jl b/src/visualization.jl index 35dd8883..dc2f7b7f 100644 --- a/src/visualization.jl +++ b/src/visualization.jl @@ -1,5 +1,5 @@ -using Catlab.CategoricalAlgebra, Catlab.Graphics.Graphviz -using Catlab.Graphs: PropertyGraph +using Catlab, Catlab.Graphics.Graphviz +using Catlab.Graphics.Graphviz: Graph import Catlab.Graphics.Graphviz: Subgraph import Catlab.Graphics: to_graphviz, to_graphviz_property_graph From cbc2631f35c1886791b192f7e9a936877640850e Mon Sep 17 00:00:00 2001 From: AlgebraicJulia Bot <129184742+algebraicjuliabot@users.noreply.github.com> Date: Thu, 15 Jun 2023 11:40:11 -0400 Subject: [PATCH 48/58] Set version to 0.9.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index f5213547..8af41266 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AlgebraicPetri" uuid = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b" license = "MIT" authors = ["Micah Halter "] -version = "0.8.11" +version = "0.9.0" [deps] Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" From 0afbc1a8adadef581aa37777a9c097f6d93342e0 Mon Sep 17 00:00:00 2001 From: Micah Halter Date: Thu, 29 Jun 2023 14:32:51 -0400 Subject: [PATCH 49/58] fix: uncomment tests now that Catlab v0.15.1 supports them again --- Project.toml | 2 +- test/ModelComparison.jl | 31 +++++++++++++++---------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Project.toml b/Project.toml index 8af41266..1cf77d2f 100644 --- a/Project.toml +++ b/Project.toml @@ -21,7 +21,7 @@ AlgebraicPetriOrdinaryDiffEqExt = "OrdinaryDiffEq" [compat] Catalyst = "13" -Catlab = "0.15" +Catlab = "0.15.1" GeneralizedGenerated = "0.3" LabelledArrays = "1" ModelingToolkit = "8" diff --git a/test/ModelComparison.jl b/test/ModelComparison.jl index 11783f0e..04720e76 100644 --- a/test/ModelComparison.jl +++ b/test/ModelComparison.jl @@ -35,22 +35,21 @@ for pn in [models, @test ob(s) == pn[2] end - # TODO: Uncomment after Subobject logic support is fixed - # @test dom(hom(~foldl(∨, so) ∨ foldl(∨, so))) == pn[2] - # A,B = so - # @test implies(A, B) == ¬(A) ∨ B - # @test ¬(A ∧ B) == ¬(A) ∨ ¬(B) - # @test ¬(A ∧ B) != ¬(A) ∨ B - # # modus ponens holds only up to inclusion, not equality. - # @test length(compare(A ∧ implies(A,B), B)) > 0 - # # this is an equivalent check because X ∧ B == X iff X ↪ B - # @test (A ∧ implies(A,B)) == B ∧ (A ∧ implies(A,B)) - # @test length(compare(B ∧ implies(B,A), A)) > 0 - # @test (B ∧ implies(B,A)) == A ∧ (B ∧ implies(B,A)) - # @test ¬(A ∨ (¬B)) == ¬(A) ∧ ¬(¬(B)) - # @test ¬(A ∨ (¬B)) == ¬(A) ∧ B - # @test A ∧ ¬(¬(A)) == ¬(¬(A)) - # @test implies((A∧B), A) == A∨B + @test dom(hom(~foldl(∨, so) ∨ foldl(∨, so))) == pn[2] + A,B = so + @test implies(A, B) == ¬(A) ∨ B + @test ¬(A ∧ B) == ¬(A) ∨ ¬(B) + @test ¬(A ∧ B) != ¬(A) ∨ B + # modus ponens holds only up to inclusion, not equality. + @test length(compare(A ∧ implies(A,B), B)) > 0 + # this is an equivalent check because X ∧ B == X iff X ↪ B + @test (A ∧ implies(A,B)) == B ∧ (A ∧ implies(A,B)) + @test length(compare(B ∧ implies(B,A), A)) > 0 + @test (B ∧ implies(B,A)) == A ∧ (B ∧ implies(B,A)) + @test ¬(A ∨ (¬B)) == ¬(A) ∧ ¬(¬(B)) + @test ¬(A ∨ (¬B)) == ¬(A) ∧ B + @test A ∧ ¬(¬(A)) == ¬(¬(A)) + @test implies((A∧B), A) == A∨B end end From 35fb5b39633ab60e17d18fae044011b1340f1b39 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Mon, 10 Jul 2023 14:55:28 -0700 Subject: [PATCH 50/58] BUG: Don't assume colimit preserves order of states in `oapply_typed`. --- docs/literate/covid/stratification.jl | 24 +++++++++++++----------- src/TypedPetri.jl | 12 +++++++++--- test/TypedPetri.jl | 4 ++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/docs/literate/covid/stratification.jl b/docs/literate/covid/stratification.jl index 1046e207..fe5bb5c7 100644 --- a/docs/literate/covid/stratification.jl +++ b/docs/literate/covid/stratification.jl @@ -25,7 +25,7 @@ to_graphviz(infectious_ontology) # Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead # population because they cannote do things such as get vaccinated or travel between regions. -sird_uwd = @relation () where {(S::Pop, I::Pop, R::Pop, D::Pop)} begin +sird_uwd = @relation (S,I,R,D) where (S::Pop, I::Pop, R::Pop, D::Pop) begin infect(S, I, I, I) disease(I, R) disease(I, D) @@ -40,7 +40,7 @@ to_graphviz(dom(sird_model)) # ### Masking model -masking_uwd = @relation () where {(M::Pop, UM::Pop)} begin +masking_uwd = @relation (M,UM) where (M::Pop, UM::Pop) begin disease(M, UM) disease(UM, M) infect(M, UM, M, UM) @@ -57,7 +57,7 @@ typed_product(sird_model, mask_model) |> dom |> to_graphviz # ### Vaccine model -vax_uwd = @relation () where {(UV::Pop, V::Pop)} begin +vax_uwd = @relation (UV,V) where (UV::Pop, V::Pop) begin strata(UV, V) infect(V, V, V, V) infect(V, UV, V, UV) @@ -75,7 +75,7 @@ typed_product(sird_model, vax_model) |> dom |> to_graphviz # ### Mask-Vax Model -mask_vax_uwd = @relation () where {(UV_UM::Pop, UV_M::Pop, V_UM::Pop, V_M::Pop)} begin +mask_vax_uwd = @relation (UV_UM,UV_M,V_UM,V_M) where (UV_UM::Pop, UV_M::Pop, V_UM::Pop, V_M::Pop) begin strata(UV_UM, UV_M) strata(UV_M, UV_UM) strata(V_UM, V_M) @@ -113,11 +113,13 @@ typed_product(sird_model, mask_vax_model) |> dom |> to_graphviz # to infect other people in the same region. function travel_model(n) - uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + uwd = RelationDiagram(repeat([:Pop], n)) junctions = Dict(begin - junction = Symbol("Region$(i)") - junction => add_junction!(uwd, :Pop, variable=junction) - end for i in 1:n) + variable = Symbol("Region$(i)") + junction = add_junction!(uwd, :Pop, variable=variable) + set_junction!(uwd, port, junction, outer=true) + variable => junction + end for (i, port) in enumerate(ports(uwd, outer=true))) pairs = filter(x -> first(x) != last(x), collect(Iterators.product(keys(junctions), keys(junctions)))) for pair in pairs @@ -172,7 +174,7 @@ end # # BIOMD0000000955_miranet -m1_model = (@relation () where {(S::Pop, I::Pop, D::Pop, A::Pop, R::Pop, T::Pop, H::Pop, E::Pop)} begin +m1_model = (@relation (S,I,D,A,R,T,H,E) where (S::Pop, I::Pop, D::Pop, A::Pop, R::Pop, T::Pop, H::Pop, E::Pop) begin infect(S, D, I, D) infect(S, A, I, A) infect(S, R, I, R) @@ -197,7 +199,7 @@ to_graphviz(dom(m1_model)) # # BIOMD0000000960_miranet -m2_model = (@relation () where {(S::Pop, E::Pop, I::Pop, A::Pop, H::Pop, R::Pop, D::Pop)} begin +m2_model = (@relation (S,E,I,A,H,R,D) where (S::Pop, E::Pop, I::Pop, A::Pop, H::Pop, R::Pop, D::Pop) begin infect(S, I, E, I) infect(S, A, E, A) infect(S, H, E, H) @@ -218,7 +220,7 @@ to_graphviz(dom(m2_model)) # # BIOMD0000000983_miranet -m3_model = (@relation () where {(S::Pop, E::Pop, Iu::Pop, Ir::Pop, Q::Pop, R::Pop, D::Pop)} begin +m3_model = (@relation (S,E,Iu,Ir,Q,R,D) where (S::Pop, E::Pop, Iu::Pop, Ir::Pop, Q::Pop, R::Pop, D::Pop) begin infect(S, Ir, E, Ir) infect(S, Iu, E, Iu) infect(S, Ir, Q, Ir) diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index 656d7962..3873c8f5 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -63,6 +63,8 @@ colimiting the transitions together, and returns the ACSetTransformation from that Petri net to the type system. """ function oapply_typed(type_system::LabelledPetriNet, uwd, tnames::Vector{Symbol}) + junction(uwd, outer=true) == junctions(uwd) || + error("Outer ports of UWD must coincide with junctions in `oapply_typed`") type_system′ = PetriNet(type_system) prim_cospan_data = Dict( tname(type_system, t) => prim_cospan(type_system′, t) @@ -74,12 +76,16 @@ function oapply_typed(type_system::LabelledPetriNet, uwd, tnames::Vector{Symbol} colim, Multicospan( type_system′, - [prim_cospan_data[subpart(uwd, b, :name)][2] for b in 1:nboxes(uwd)] + [prim_cospan_data[uwd[b, :name]][2] for b in boxes(uwd)] ) ) - labelled_petri = LabelledPetriNet(unlabelled_map.dom, uwd[:variable], tnames) + state_labels = Vector{Symbol}(undef, njunctions(uwd)) + for (j, leg) in zip(junctions(uwd), legs(petri)) + state_labels[only(collect(leg[:S]))] = uwd[j, :variable] + end + labelled_petri = LabelledPetriNet(dom(unlabelled_map), state_labels, tnames) LooseACSetTransformation( - unlabelled_map.components, + components(unlabelled_map), (Name=x->nothing,), labelled_petri, type_system diff --git a/test/TypedPetri.jl b/test/TypedPetri.jl index b7cc027d..eed1bcb3 100644 --- a/test/TypedPetri.jl +++ b/test/TypedPetri.jl @@ -14,7 +14,7 @@ const infectious_ontology = LabelledPetriNet( :strata=>(:Pop=>:Pop) ) -sird_uwd = @relation () where (S::Pop, I::Pop, R::Pop, D::Pop) begin +sird_uwd = @relation (S,I,R,D) where (S::Pop, I::Pop, R::Pop, D::Pop) begin infect(S,I,I,I) # inf disease(I,R) # recover disease(I,D) # die @@ -35,7 +35,7 @@ typed_sird = add_params( # SIRD-with-quarantine model. -quarantine_uwd = @relation () where (Q::Pop, NQ::Pop) begin +quarantine_uwd = @relation (Q,NQ) where (Q::Pop, NQ::Pop) begin strata(Q,NQ) # enter quarantine strata(NQ,Q) # exit quarantine end From b72368ee1707f7ca35754e65b80a48d23b0f02f8 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Tue, 11 Jul 2023 16:41:37 -0700 Subject: [PATCH 51/58] CLEANUP: Ensure that fix to `oapply_typed` is backwards compatible. --- src/TypedPetri.jl | 9 +++++++-- test/TypedPetri.jl | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/TypedPetri.jl b/src/TypedPetri.jl index 3873c8f5..83ba86c1 100644 --- a/src/TypedPetri.jl +++ b/src/TypedPetri.jl @@ -63,8 +63,13 @@ colimiting the transitions together, and returns the ACSetTransformation from that Petri net to the type system. """ function oapply_typed(type_system::LabelledPetriNet, uwd, tnames::Vector{Symbol}) - junction(uwd, outer=true) == junctions(uwd) || - error("Outer ports of UWD must coincide with junctions in `oapply_typed`") + if junction(uwd, outer=true) != junctions(uwd) + # XXX: This could be considered a user error, but for the sake of backwards + # compatibility, we will fix it for them. + uwd = copy(uwd) + rem_parts!(uwd, :OuterPort, parts(uwd, :OuterPort)) + add_parts!(uwd, :OuterPort, njunctions(uwd), outer_junction=junctions(uwd)) + end type_system′ = PetriNet(type_system) prim_cospan_data = Dict( tname(type_system, t) => prim_cospan(type_system′, t) diff --git a/test/TypedPetri.jl b/test/TypedPetri.jl index eed1bcb3..cd7311e9 100644 --- a/test/TypedPetri.jl +++ b/test/TypedPetri.jl @@ -25,6 +25,15 @@ typed_sird_no_params = oapply_typed(infectious_ontology, sird_uwd, @test ns(dom(typed_sird_no_params)) == 4 @test nt(dom(typed_sird_no_params)) == 3 +# Backwards compatibility: allow UWDs with no outer ports. +sird_uwd_no_outer = @relation () where (S::Pop, I::Pop, R::Pop, D::Pop) begin + infect(S,I,I,I) # inf + disease(I,R) # recover + disease(I,D) # die +end +@test oapply_typed(infectious_ontology, sird_uwd_no_outer, + [:inf, :recover, :die]) == typed_sird_no_params + typed_sird = add_params( oapply_typed(infectious_ontology, sird_uwd, [:inf, :recover, :die]), Dict(:S => 1.0, :I => 1.0, :R => 0.0, :D => 0.0), From 9adb553fcd8a62c9480d4d54ec5513df9916868d Mon Sep 17 00:00:00 2001 From: p-stokes Date: Fri, 7 Jul 2023 21:38:35 -0400 Subject: [PATCH 52/58] Started doc page for multi-strain model example. --- docs/literate/covid/disease_strains.jl | 247 +++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 docs/literate/covid/disease_strains.jl diff --git a/docs/literate/covid/disease_strains.jl b/docs/literate/covid/disease_strains.jl new file mode 100644 index 00000000..700f2dd6 --- /dev/null +++ b/docs/literate/covid/disease_strains.jl @@ -0,0 +1,247 @@ +# # [Multiple-Strain Model of COVID and Vaccines](@id multistrain_example) +# +#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/covid/disease_strains.ipynb) + +using AlgebraicPetri, AlgebraicPetri.TypedPetri +using Catlab.Programs, Catlab.Graphics +using Catlab.CategoricalAlgebra +using Catlab.WiringDiagrams +using DisplayAs, Markdown + +# This example presents models incorporating multiple strains of disease and vaccine type. +# Importantly, it shows why stratification by strain is different from other stratifications, e.g. geography, age, or other strata, and requires using a different type system. + +# ## Define basic epidemiology model + +# We start by defining our basic type system for infectious disease models + +const infectious_ontology = LabelledPetriNet( + [:Pop], + :infect => ((:Pop, :Pop) => (:Pop, :Pop)), + :disease => (:Pop => :Pop), + :strata => (:Pop => :Pop) +) + +to_graphviz(infectious_ontology) + +# We define a simple SIRD model with reflexive transitions typed as `:strata` to indicate which states can be stratified +# Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead +# population because they cannote do things such as get vaccinated or travel between regions. + +sird_uwd = @relation () where {(S::Pop, I::Pop, R::Pop, D::Pop)} begin + infect(S, I, I, I) + disease(I, R) + disease(I, D) +end + +sird_model = oapply_typed(infectious_ontology, sird_uwd, [:infection, :recovery, :death]) +sird_model = add_reflexives(sird_model, [[:strata], [:strata], [:strata], []], infectious_ontology) + +to_graphviz(dom(sird_model)) + +# ## Define a multi-strain model + +# Here we define a model of multiple strains of disease infection. +# In this model, uninfected individuals can become infected by indivuals carrying one of the strains. +# This model can be typed the `infectious_ontology`. +# We add reflexives of `:disease` and `:strata` for the strain states but only `:strata` for the uninfected state. + +function strain_model(n) + uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + junction = :Uninfected + junctions[junction] = add_junction!(uwd, :Pop, variable=junction) + for i in 1:n + junction = Symbol("Strain$(i)") + junctions[junction] = add_junction!(uwd, :Pop, variable=junction) + end + strains = filter((x) -> x != Symbol("Uninfected"), keys(junctions)) + for s in strains + pair = (:Uninfected, s, s, s) + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=:infect) + for (rgn, port) in zip(pair, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + end + act = oapply_typed(infectious_ontology, uwd, [Symbol("inf_$(b)") for b in strains]) + add_reflexives(act, vcat([[:strata]],repeat([[:disease,:strata]], n)), infectious_ontology) +end + +to_graphviz(dom(strain_model(2))) + +# ## Stratify the SIRD model for two strains + +typed_product(sird_model, strain_model(2)) |> dom |> to_graphviz + +# Unfortunately, stratification of these models does not produce the desired result. +# There are quite a few extraneous states and transitions. +# The primary issue is the asymmetry in the role of the uninfected population. +# We can address this be changing the type system. + +# ## Define a new type system and corresponding epidemiology and multi-strain models + +# The new type system has separate states for uninfected and infected to account for the asymmetry in their role in infection +# and in the corresponding asymmetry in the intended stratification. +# Accordingly, the `:Inf` state has `:disease` and `:strataI` transitions. +# The `:Uninf` state only has an additional "strata" transition, `:strataU`, but note this transition is distinct from that for the `:Inf` state. + +const strain_ontology = LabelledPetriNet( + [:Uninf, :Inf], + :infect => ((:Uninf, :Inf) => (:Inf, :Inf)), + :disease => (:Inf => :Inf), + :strataI => (:Inf => :Inf), + :strataU => (:Uninf => :Uninf) +) + +to_graphviz(strain_ontology) + +# We now reform the SIRD and multi-strain models using the new type system +sird_for_strains_uwd = @relation () where {(S::Uninf, I::Inf, R::Inf, D::Inf)} begin + infect(S, I, I, I) + disease(I, R) + disease(I, D) +end +sird_for_strains_model = oapply_typed(strain_ontology, sird_for_strains_uwd, [:infection, :recovery, :death]) +sird_for_strains_model = add_reflexives(sird_for_strains_model, [[:strataU], [:strataI], [:strataI], []], strain_ontology) + +to_graphviz(dom(sird_for_strains_model)) + +function strain_model(n) + uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + junction = :Uninfected + junctions[junction] = add_junction!(uwd, :Uninf, variable=junction) + for i in 1:n + junction = Symbol("Strain$(i)") + junctions[junction] = add_junction!(uwd, :Inf, variable=junction) + end + strains = filter((x) -> x != Symbol("Uninfected"), keys(junctions)) + for s in strains + pair = (:Uninfected, s, s, s) + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=:infect) + for (rgn, port) in zip(pair, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + end + act = oapply_typed(strain_ontology, uwd, [Symbol("inf_$(b)") for b in strains]) + add_reflexives(act, vcat([[:strataU]],repeat([[:disease,:strataI]], n)), strain_ontology) +end + +to_graphviz(dom(strain_model(2))) + +# When we now stratify we get the desired model. + +sird_strain = typed_product(sird_for_strains_model, strain_model(2)) |> dom |> to_graphviz + +to_graphviz(dom(strain_model(2))) + +# ## Post composition: Typing the type system + +# In some instances we may want to relate models typed to different type systems. +# For example, we usually type our `simple_trip` model of geographic regions to the `infectious_ontology` s.t. we can stratify a disease model by geographic regions, +# but the multi-strain disease model above is typed by the new `strain_ontology`. + +# Crucially, we can accomplish this IF there is an appropriate morphism (map) between the type systems because post-composition by a morphism of type systems is functorial. +# In this case there is a morphism from `strain_ontology` to `infectious_ontology`, so we can form the morphism + +# ### Morphism from `strain_ontology` to `infectious_ontology` + +strain_ont_uwd = @relation () where {(Uninf::Pop, Inf::Pop)} begin + infect(Uninf, Inf, Inf, Inf) + disease(Inf, Inf) + strata(Inf, Inf) + strata(Uninf, Uninf) +end +strain_ont_act = oapply_typed(infectious_ontology,strain_ont_uwd,[:infect,:disease,:strataI,:strataU]) + + +# ### Vaccine model + +vax_uwd = @relation () where {(UV::Pop, V::Pop)} begin + strata(UV, V) + infect(V, V, V, V) + infect(V, UV, V, UV) + infect(UV, V, UV, V) + infect(UV, UV, UV, UV) +end +vax_model = oapply_typed(infectious_ontology, vax_uwd, [:vax, :infect_vv, :infect_uv, :infect_vu, :infect_uu]) +vax_model = add_reflexives(vax_model, [[:disease], [:disease]], infectious_ontology) + +to_graphviz(dom(vax_model)) + +# Stratify our SIRD model on this vaccine model to get a model of SIRD with a vaccination rate: + +typed_product(sird_model, vax_model) |> dom |> to_graphviz + + +# Stratify our SIRD model on this mask + vaccine model to get a model of SIRD with a vaccination rate and masking policies: + +typed_product(sird_model, mask_vax_model) |> dom |> to_graphviz + +# ## Define geographic models + +# ### Travel model between $N$ regions + +# For this model we can use a julia function to programmatically build up our undirected wiring diagram for defining this model. +# Here we want there to be $N$ regions in which people can travel between each region and people within the same region are able +# to infect other people in the same region. + +function travel_model(n) + uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + junctions = Dict(begin + junction = Symbol("Region$(i)") + junction => add_junction!(uwd, :Pop, variable=junction) + end for i in 1:n) + + pairs = filter(x -> first(x) != last(x), collect(Iterators.product(keys(junctions), keys(junctions)))) + for pair in pairs + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=:strata) + for (rgn, port) in zip(pair, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + end + + act = oapply_typed(infectious_ontology, uwd, [Symbol("$(a)_$(b)") for (a, b) in pairs]) + add_reflexives(act, repeat([[:infect, :disease]], n), infectious_ontology) +end + +to_graphviz(dom(travel_model(2))) + +# Stratify our SIRD model on this travel model with two regions: + +typed_product(sird_model, travel_model(2)) |> dom |> to_graphviz + +# ### Simple Trip model between $N$ regions + +# For this model we can use a julia function to programmatically build up our model where people have the property of living somewhere +# and we are modelling them travelling between locations while maintaining the status of where they live. Here we can actually just +# define the model of having a "Living" status and stratify it with the previously defined travel model to get a model of someone taking a simple trip. + +function living_model(n) + typed_living = pairwise_id_typed_petri(infectious_ontology, :Pop, :infect, [Symbol("Living$(i)") for i in 1:n]) + add_reflexives(typed_living, repeat([[:disease, :strata]], n), infectious_ontology) +end + +to_graphviz(dom(living_model(2))) + +# The resulting simple trip model: + +simple_trip_model = typed_product(travel_model(2), living_model(2)) +to_graphviz(dom(simple_trip_model)) + +# Stratify our SIRD model on this simple trip model between two regions: + +typed_product(sird_model, simple_trip_model) |> dom |> to_graphviz + + + +test = typed_product(sird_for_strains_model, strain_model(2)) +test2 = typed_product(compose(test,strain_ont_act),simple_trip_model) + +# ## Stratification of COVID models + +# we set up a simple helper function to connect the undirected wiring diagrams to our +# infectious disease type system and add the necessary reflexive transitions for stratification. +function oapply_mira_model(uwd) + model = oapply_typed(infectious_ontology, uwd, [Symbol("t$(n)") for n in 1:nboxes(uwd)]) + add_reflexives(model, [repeat([[:strata]], njunctions(uwd)-3)..., [], [:strata],[]], infectious_ontology) +end + From 0b744f02bb351b2af08b9ec57d0ecb1a08a81d2c Mon Sep 17 00:00:00 2001 From: p-stokes Date: Fri, 7 Jul 2023 23:44:30 -0400 Subject: [PATCH 53/58] Added model of vaccination with multiple vaccine types. --- docs/literate/covid/disease_strains.jl | 83 +++++++++++++++----------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/docs/literate/covid/disease_strains.jl b/docs/literate/covid/disease_strains.jl index 700f2dd6..3a0ca6f4 100644 --- a/docs/literate/covid/disease_strains.jl +++ b/docs/literate/covid/disease_strains.jl @@ -26,7 +26,7 @@ to_graphviz(infectious_ontology) # We define a simple SIRD model with reflexive transitions typed as `:strata` to indicate which states can be stratified # Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead -# population because they cannote do things such as get vaccinated or travel between regions. +# population because they cannot do things such as get vaccinated or travel between regions. sird_uwd = @relation () where {(S::Pop, I::Pop, R::Pop, D::Pop)} begin infect(S, I, I, I) @@ -39,6 +39,51 @@ sird_model = add_reflexives(sird_model, [[:strata], [:strata], [:strata], []], i to_graphviz(dom(sird_model)) +# ## Define a model of multiple vaccine types + +# We define a model of vaccination with multiple vaccine types. +# In this model, vaccination transitions are typed as `:strata`. +# Note that the `:infect` transitions must be included to enable cross-infection between different vax types. + +function vax_model(n) + uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + junction = :Unvaxxed + junctions = Dict(junction => add_junction!(uwd, :Pop, variable=junction)) + for i in 1:n + junction = Symbol("VaxType$(i)") + junctions[junction] = add_junction!(uwd, :Pop, variable=junction) + end + strains = filter((x) -> x != Symbol("Unvaxxed"), keys(junctions)) + for s in strains + pair = (:Unvaxxed, s) + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=:strata) + for (rgn, port) in zip(pair, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + end + tnames = [Symbol("vax_$(b)") for b in strains] + + pairs = collect(Iterators.product(keys(junctions), keys(junctions))) + for pair in pairs + ins_outs = (pair[1], pair[2], pair[1], pair[2]) + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in ins_outs], name=:infect) + for (rgn, port) in zip(ins_outs, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + push!(tnames,Symbol("inf_$(pair[1])_$(pair[2])")) + end + act = oapply_typed(infectious_ontology, uwd, tnames) + add_reflexives(act, repeat([[:disease]], n+1), infectious_ontology) +end + +to_graphviz(dom(vax_model(2))) + +# ## Stratify the SIRD model with vaccinations for two vaccine types + +# We can now stratify the two typed models. + +typed_product(sird_model, vax_model(2)) |> dom |> to_graphviz + # ## Define a multi-strain model # Here we define a model of multiple strains of disease infection. @@ -152,31 +197,7 @@ strain_ont_uwd = @relation () where {(Uninf::Pop, Inf::Pop)} begin end strain_ont_act = oapply_typed(infectious_ontology,strain_ont_uwd,[:infect,:disease,:strataI,:strataU]) - -# ### Vaccine model - -vax_uwd = @relation () where {(UV::Pop, V::Pop)} begin - strata(UV, V) - infect(V, V, V, V) - infect(V, UV, V, UV) - infect(UV, V, UV, V) - infect(UV, UV, UV, UV) -end -vax_model = oapply_typed(infectious_ontology, vax_uwd, [:vax, :infect_vv, :infect_uv, :infect_vu, :infect_uu]) -vax_model = add_reflexives(vax_model, [[:disease], [:disease]], infectious_ontology) - -to_graphviz(dom(vax_model)) - -# Stratify our SIRD model on this vaccine model to get a model of SIRD with a vaccination rate: - -typed_product(sird_model, vax_model) |> dom |> to_graphviz - - -# Stratify our SIRD model on this mask + vaccine model to get a model of SIRD with a vaccination rate and masking policies: - -typed_product(sird_model, mask_vax_model) |> dom |> to_graphviz - -# ## Define geographic models +# ### Define geographic models # ### Travel model between $N$ regions @@ -232,16 +253,6 @@ to_graphviz(dom(simple_trip_model)) typed_product(sird_model, simple_trip_model) |> dom |> to_graphviz - test = typed_product(sird_for_strains_model, strain_model(2)) test2 = typed_product(compose(test,strain_ont_act),simple_trip_model) -# ## Stratification of COVID models - -# we set up a simple helper function to connect the undirected wiring diagrams to our -# infectious disease type system and add the necessary reflexive transitions for stratification. -function oapply_mira_model(uwd) - model = oapply_typed(infectious_ontology, uwd, [Symbol("t$(n)") for n in 1:nboxes(uwd)]) - add_reflexives(model, [repeat([[:strata]], njunctions(uwd)-3)..., [], [:strata],[]], infectious_ontology) -end - From 52079b2d08a116da53800fd0f1465c2cef378394 Mon Sep 17 00:00:00 2001 From: p-stokes Date: Sat, 8 Jul 2023 15:56:41 -0400 Subject: [PATCH 54/58] Fixed issue with initializing junctions dictionaries. Doc will build now. --- docs/literate/covid/disease_strains.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/literate/covid/disease_strains.jl b/docs/literate/covid/disease_strains.jl index 3a0ca6f4..fe4339bf 100644 --- a/docs/literate/covid/disease_strains.jl +++ b/docs/literate/covid/disease_strains.jl @@ -91,10 +91,10 @@ typed_product(sird_model, vax_model(2)) |> dom |> to_graphviz # This model can be typed the `infectious_ontology`. # We add reflexives of `:disease` and `:strata` for the strain states but only `:strata` for the uninfected state. -function strain_model(n) +function strain_model′(n) uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() junction = :Uninfected - junctions[junction] = add_junction!(uwd, :Pop, variable=junction) + junctions = Dict(junction => add_junction!(uwd, :Pop, variable=junction)) for i in 1:n junction = Symbol("Strain$(i)") junctions[junction] = add_junction!(uwd, :Pop, variable=junction) @@ -111,11 +111,11 @@ function strain_model(n) add_reflexives(act, vcat([[:strata]],repeat([[:disease,:strata]], n)), infectious_ontology) end -to_graphviz(dom(strain_model(2))) +to_graphviz(dom(strain_model′(2))) # ## Stratify the SIRD model for two strains -typed_product(sird_model, strain_model(2)) |> dom |> to_graphviz +typed_product(sird_model, strain_model′(2)) |> dom |> to_graphviz # Unfortunately, stratification of these models does not produce the desired result. # There are quite a few extraneous states and transitions. @@ -153,7 +153,7 @@ to_graphviz(dom(sird_for_strains_model)) function strain_model(n) uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() junction = :Uninfected - junctions[junction] = add_junction!(uwd, :Uninf, variable=junction) + junctions = Dict(junction => add_junction!(uwd, :Pop, variable=junction)) for i in 1:n junction = Symbol("Strain$(i)") junctions[junction] = add_junction!(uwd, :Inf, variable=junction) From 00256ca010227046c2663994edf22d8b73f1f3ab Mon Sep 17 00:00:00 2001 From: p-stokes Date: Sat, 8 Jul 2023 20:20:12 -0400 Subject: [PATCH 55/58] Refined/edited text of example. Added stratification of mulit-strain and multi-vax. --- docs/literate/covid/disease_strains.jl | 83 +++++++++++++++----------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/docs/literate/covid/disease_strains.jl b/docs/literate/covid/disease_strains.jl index fe4339bf..e453d67b 100644 --- a/docs/literate/covid/disease_strains.jl +++ b/docs/literate/covid/disease_strains.jl @@ -9,11 +9,11 @@ using Catlab.WiringDiagrams using DisplayAs, Markdown # This example presents models incorporating multiple strains of disease and vaccine type. -# Importantly, it shows why stratification by strain is different from other stratifications, e.g. geography, age, or other strata, and requires using a different type system. +# Importantly, it shows why stratification by disease strain is different from other stratifications, e.g. geography or age, and requires using a different type system. # ## Define basic epidemiology model -# We start by defining our basic type system for infectious disease models +# We start by defining our basic type system for infectious disease models. const infectious_ontology = LabelledPetriNet( [:Pop], @@ -24,7 +24,7 @@ const infectious_ontology = LabelledPetriNet( to_graphviz(infectious_ontology) -# We define a simple SIRD model with reflexive transitions typed as `:strata` to indicate which states can be stratified +# We define a simple SIRD model with reflexive transitions typed as `:strata` to indicate which states can be stratified. # Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead # population because they cannot do things such as get vaccinated or travel between regions. @@ -41,7 +41,7 @@ to_graphviz(dom(sird_model)) # ## Define a model of multiple vaccine types -# We define a model of vaccination with multiple vaccine types. +# We also define a model of vaccination with multiple vaccine types. # In this model, vaccination transitions are typed as `:strata`. # Note that the `:infect` transitions must be included to enable cross-infection between different vax types. @@ -80,11 +80,11 @@ to_graphviz(dom(vax_model(2))) # ## Stratify the SIRD model with vaccinations for two vaccine types -# We can now stratify the two typed models. +# We can now stratify the two typed models to get a model of SIRD with vaccination by multiple possible vaccine types. typed_product(sird_model, vax_model(2)) |> dom |> to_graphviz -# ## Define a multi-strain model +# ## Define a model of multiple disease strains # Here we define a model of multiple strains of disease infection. # In this model, uninfected individuals can become infected by indivuals carrying one of the strains. @@ -115,17 +115,17 @@ to_graphviz(dom(strain_model′(2))) # ## Stratify the SIRD model for two strains -typed_product(sird_model, strain_model′(2)) |> dom |> to_graphviz - # Unfortunately, stratification of these models does not produce the desired result. # There are quite a few extraneous states and transitions. # The primary issue is the asymmetry in the role of the uninfected population. -# We can address this be changing the type system. +# We can address this by changing the type system. + +typed_product(sird_model, strain_model′(2)) |> dom |> to_graphviz -# ## Define a new type system and corresponding epidemiology and multi-strain models +# ## Define a new type system and corresponding disease and multi-strain models # The new type system has separate states for uninfected and infected to account for the asymmetry in their role in infection -# and in the corresponding asymmetry in the intended stratification. +# and for the corresponding asymmetry in the intended stratification. # Accordingly, the `:Inf` state has `:disease` and `:strataI` transitions. # The `:Uninf` state only has an additional "strata" transition, `:strataU`, but note this transition is distinct from that for the `:Inf` state. @@ -139,7 +139,7 @@ const strain_ontology = LabelledPetriNet( to_graphviz(strain_ontology) -# We now reform the SIRD and multi-strain models using the new type system +# We now reform the SIRD model using the new type system. sird_for_strains_uwd = @relation () where {(S::Uninf, I::Inf, R::Inf, D::Inf)} begin infect(S, I, I, I) disease(I, R) @@ -150,6 +150,8 @@ sird_for_strains_model = add_reflexives(sird_for_strains_model, [[:strataU], [:s to_graphviz(dom(sird_for_strains_model)) +# And similarly reform the multi-strain model. + function strain_model(n) uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() junction = :Uninfected @@ -174,18 +176,18 @@ to_graphviz(dom(strain_model(2))) # When we now stratify we get the desired model. -sird_strain = typed_product(sird_for_strains_model, strain_model(2)) |> dom |> to_graphviz +sird_strain = typed_product(sird_for_strains_model, strain_model(2)) -to_graphviz(dom(strain_model(2))) +to_graphviz(dom(sird_strain)) -# ## Post composition: Typing the type system +# ## Post-composition: Typing the type system -# In some instances we may want to relate models typed to different type systems. -# For example, we usually type our `simple_trip` model of geographic regions to the `infectious_ontology` s.t. we can stratify a disease model by geographic regions, +# In some instances, we may want to relate models typed to different type systems. +# For example, we usually type our `simple_trip` model of geographic regions to the `infectious_ontology` such that we can stratify a disease model by geographic regions, # but the multi-strain disease model above is typed by the new `strain_ontology`. # Crucially, we can accomplish this IF there is an appropriate morphism (map) between the type systems because post-composition by a morphism of type systems is functorial. -# In this case there is a morphism from `strain_ontology` to `infectious_ontology`, so we can form the morphism +# In this case, there is a morphism from `strain_ontology` to `infectious_ontology`, so we can form the morphism # ### Morphism from `strain_ontology` to `infectious_ontology` @@ -197,12 +199,15 @@ strain_ont_uwd = @relation () where {(Uninf::Pop, Inf::Pop)} begin end strain_ont_act = oapply_typed(infectious_ontology,strain_ont_uwd,[:infect,:disease,:strataI,:strataU]) -# ### Define geographic models +to_graphviz(strain_ont_act) + +# ### Define simple-trip geographic model of $N$ regions -# ### Travel model between $N$ regions +# To demonstrate stratification utilizing post-composition to re-type the models, we use the simple-trip geographic model. +# This model is comprises a travel model and a living model. -# For this model we can use a julia function to programmatically build up our undirected wiring diagram for defining this model. -# Here we want there to be $N$ regions in which people can travel between each region and people within the same region are able +# **Travel model between $N$ regions**\n +# In this model, there are $N$ regions which people can travel between. People within the same region are able # to infect other people in the same region. function travel_model(n) @@ -226,15 +231,11 @@ end to_graphviz(dom(travel_model(2))) -# Stratify our SIRD model on this travel model with two regions: +# This model could itself be stratified with the SIRD model, but we want to model +# persons travelling between locations while maintaining the status of where they live. -typed_product(sird_model, travel_model(2)) |> dom |> to_graphviz - -# ### Simple Trip model between $N$ regions - -# For this model we can use a julia function to programmatically build up our model where people have the property of living somewhere -# and we are modelling them travelling between locations while maintaining the status of where they live. Here we can actually just -# define the model of having a "Living" status and stratify it with the previously defined travel model to get a model of someone taking a simple trip. +# **Living model of $N$ regions**\n +# In this model, people have the property of "Living" somewhere. function living_model(n) typed_living = pairwise_id_typed_petri(infectious_ontology, :Pop, :infect, [Symbol("Living$(i)") for i in 1:n]) @@ -243,16 +244,28 @@ end to_graphviz(dom(living_model(2))) -# The resulting simple trip model: +# **Simple trip model of $N$ regions**\n +# We can stratify the living model with the travel model to get a model of someone taking a simple trip. simple_trip_model = typed_product(travel_model(2), living_model(2)) + to_graphviz(dom(simple_trip_model)) -# Stratify our SIRD model on this simple trip model between two regions: +# ### Stratify SIRD-multi-strain and simple-trip models + +# Now, to stratify our multi-strain SIRD model with the simple-trip, we first retype the multi-strain model +# to the `infectious_ontology` by composing with the morphism we defined. + +sird_strain_retyped = compose(sird_strain,strain_ont_act) + +# We can now stratify. + +sird_strain_trip = typed_product(sird_strain_retyped,simple_trip_model) -typed_product(sird_model, simple_trip_model) |> dom |> to_graphviz +to_graphviz(dom(sird_strain_trip)) +# ## Define a multi-strain SIRD model with vaccination by multiple vaccine types -test = typed_product(sird_for_strains_model, strain_model(2)) -test2 = typed_product(compose(test,strain_ont_act),simple_trip_model) +sird_strain_vax = typed_product(sird_strain_retyped,vax_model(2)) +to_graphviz(dom(sird_strain_vax)) From 0af941c90ddee5c6cd7d63f0c196c5556ba8e832 Mon Sep 17 00:00:00 2001 From: p-stokes Date: Sat, 8 Jul 2023 21:31:33 -0400 Subject: [PATCH 56/58] Added new multi-strain example to doc builder in make.jl --- docs/make.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/make.jl b/docs/make.jl index b04b0ffb..9aeac834 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -49,6 +49,7 @@ makedocs( "generated/enzymes/enzyme_reactions.md", "generated/covid/bilayerconversion.md", "generated/covid/stratification.md", + "generated/covid/disease_strains.md", "generated/covid/max_common_subobject.md", ], "Library Reference" => "api.md", From d25fb55dd644e5508e242fe5cf8fdf1caa763ed4 Mon Sep 17 00:00:00 2001 From: p-stokes Date: Sun, 9 Jul 2023 14:54:11 -0400 Subject: [PATCH 57/58] Added further example of re-stratifying sird-strain-vax model with the simple trip, which again requires re-typing to an augmented type system. --- docs/literate/covid/disease_strains.jl | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/docs/literate/covid/disease_strains.jl b/docs/literate/covid/disease_strains.jl index e453d67b..04b70716 100644 --- a/docs/literate/covid/disease_strains.jl +++ b/docs/literate/covid/disease_strains.jl @@ -266,6 +266,94 @@ to_graphviz(dom(sird_strain_trip)) # ## Define a multi-strain SIRD model with vaccination by multiple vaccine types +# We can similarly stratify the multi-strain SIRD model with the multi-vax model. + sird_strain_vax = typed_product(sird_strain_retyped,vax_model(2)) to_graphviz(dom(sird_strain_vax)) + +# ## Re-stratify the multi-strain multi-vax SIRD model with the simple trip model + +# If we would like to re-stratify our SIRD-strain-vax model with the simple trip model, we again face a difficulty. +# Both the "vaccination" transitions of the first model and the "travel" transitions of the second +# are currently typed to the `:strata` transition of the `infectious_ontology` type system. +# To appropriately stratify, we need an additional "strata" transition to distinguish +# between the two types of transitions. +# We can again use post-compostion to overcome the difficulty. + +# ### Define an augmented version of the `infectious_ontology` type system with an additional "strata" transition + +const aug_inf_ontology = LabelledPetriNet( + [:nPop], + :ninfect => ((:nPop, :nPop) => (:nPop, :nPop)), + :ndisease => (:nPop => :nPop), + :nstrata => (:nPop => :nPop), + :nstrata2 => (:nPop => :nPop) +) + +to_graphviz(aug_inf_ontology) + +# ### Define morphisms from the original type system to the new augmented type system + +# We form one morphism that maps the `:strata` transition to `:nstrata`. +# This morphism will serve to re-type the SIRD-strain-vax model. + +function retype_inf_ont(strata_map) + uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + junction = :Pop + junctions = Dict(junction => add_junction!(uwd, :nPop, variable=junction)) + + boxes = [:ninfect, :ndisease, strata_map] + for bname in boxes + if bname == :ninfect + pair = (:Pop, :Pop, :Pop, :Pop) + else + pair = (:Pop, :Pop) + end + box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=bname) + for (rgn, port) in zip(pair, ports(uwd, box)) + set_junction!(uwd, port, junctions[rgn]) + end + end + + act = oapply_typed(aug_inf_ontology, uwd, [:infect, :disease, :strata]) +end + +inf_ont_act = retype_inf_ont(:nstrata) + +to_graphviz(inf_ont_act) + +# We form another morphism that maps the `:strata` transition to `:nstrata2`. +# This morphism will serve to re-type the simple trip model. + +rgn_ont_act = retype_inf_ont(:nstrata2) + +to_graphviz(rgn_ont_act) + +# ### Add reflexive transitions + +# To finish preparing for stratification, we need to add the new reflexive transitions to the component models. +# To the SIRD-strain-vax model, we add an `:nstrata2` tranisiton to each state that does not represent +# a portion of the population that is deceased (because deceased individuals cannot travel). + +sird_strain_vax_retyped = flatten_labels(compose(sird_strain_vax,inf_ont_act)) +reflx = [[:nstrata2]] +for ii in 2:ns(dom(sird_strain_vax_retyped)) + if split(String(dom(sird_strain_vax_retyped)[ii,:sname]),"_")[1] == "D" + push!(reflx,[]) + else + push!(reflx,[:nstrata2]) + end +end +aug_sird_strain_vax = add_reflexives(sird_strain_vax_retyped, reflx, aug_inf_ontology); + +# To the simple trip model, we add an `:nstrata` tranisiton for each state. + +simple_trip_retyped = flatten_labels(compose(simple_trip_model,rgn_ont_act)) +aug_trip = add_reflexives(simple_trip_retyped, repeat([[:nstrata]],ns(dom(simple_trip_retyped))), aug_inf_ontology); + +# ### Stratify the SIRD-strain-vax and simple trip models + +sird_strain_vax_trip = typed_product([aug_sird_strain_vax,aug_trip]) + +to_graphviz(dom(sird_strain_vax_trip)) From 43da719f648b5a6f64458252469aad79faad65a8 Mon Sep 17 00:00:00 2001 From: p-stokes Date: Thu, 13 Jul 2023 13:21:11 -0400 Subject: [PATCH 58/58] Updated multistrain example to use new version of oapply_typed. --- docs/literate/covid/disease_strains.jl | 79 +++++++++++++++++--------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/docs/literate/covid/disease_strains.jl b/docs/literate/covid/disease_strains.jl index 04b70716..a9592217 100644 --- a/docs/literate/covid/disease_strains.jl +++ b/docs/literate/covid/disease_strains.jl @@ -28,7 +28,7 @@ to_graphviz(infectious_ontology) # Here we add reflexive transitions to the susceptible, infected, and recovered populations but we leave out the dead # population because they cannot do things such as get vaccinated or travel between regions. -sird_uwd = @relation () where {(S::Pop, I::Pop, R::Pop, D::Pop)} begin +sird_uwd = @relation (S,I,R,D) where (S::Pop, I::Pop, R::Pop, D::Pop) begin infect(S, I, I, I) disease(I, R) disease(I, D) @@ -46,13 +46,21 @@ to_graphviz(dom(sird_model)) # Note that the `:infect` transitions must be included to enable cross-infection between different vax types. function vax_model(n) - uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() - junction = :Unvaxxed - junctions = Dict(junction => add_junction!(uwd, :Pop, variable=junction)) + uwd = RelationDiagram(repeat([:Pop], n+1)) + + variable = :Unvaxxed + junction = add_junction!(uwd, :Pop, variable=variable) + port = ports(uwd, outer=true)[1] + set_junction!(uwd, port, junction, outer=true) + junctions = Dict(variable => junction) for i in 1:n - junction = Symbol("VaxType$(i)") - junctions[junction] = add_junction!(uwd, :Pop, variable=junction) + variable = Symbol("VaxType$(i)") + junction = add_junction!(uwd, :Pop, variable=variable) + port = ports(uwd, outer=true)[i+1] + set_junction!(uwd, port, junction, outer=true) + junctions[variable] = junction end + strains = filter((x) -> x != Symbol("Unvaxxed"), keys(junctions)) for s in strains pair = (:Unvaxxed, s) @@ -92,12 +100,18 @@ typed_product(sird_model, vax_model(2)) |> dom |> to_graphviz # We add reflexives of `:disease` and `:strata` for the strain states but only `:strata` for the uninfected state. function strain_model′(n) - uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() - junction = :Uninfected - junctions = Dict(junction => add_junction!(uwd, :Pop, variable=junction)) + uwd = RelationDiagram(repeat([:Pop], n+1)) + variable = :Uninfected + junction = add_junction!(uwd, :Pop, variable=variable) + port = ports(uwd, outer=true)[1] + set_junction!(uwd, port, junction, outer=true) + junctions = Dict(variable => junction) for i in 1:n - junction = Symbol("Strain$(i)") - junctions[junction] = add_junction!(uwd, :Pop, variable=junction) + variable = Symbol("Strain$(i)") + junction = add_junction!(uwd, :Pop, variable=variable) + port = ports(uwd, outer=true)[i+1] + set_junction!(uwd, port, junction, outer=true) + junctions[variable] = junction end strains = filter((x) -> x != Symbol("Uninfected"), keys(junctions)) for s in strains @@ -140,7 +154,7 @@ const strain_ontology = LabelledPetriNet( to_graphviz(strain_ontology) # We now reform the SIRD model using the new type system. -sird_for_strains_uwd = @relation () where {(S::Uninf, I::Inf, R::Inf, D::Inf)} begin +sird_for_strains_uwd = @relation (S,I,R,D) where (S::Uninf, I::Inf, R::Inf, D::Inf) begin infect(S, I, I, I) disease(I, R) disease(I, D) @@ -153,12 +167,18 @@ to_graphviz(dom(sird_for_strains_model)) # And similarly reform the multi-strain model. function strain_model(n) - uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() - junction = :Uninfected - junctions = Dict(junction => add_junction!(uwd, :Pop, variable=junction)) + uwd = RelationDiagram(vcat([:Uninf],repeat([:Inf], n))) + variable = :Uninfected + junction = add_junction!(uwd, :Uninf, variable=variable) + port = ports(uwd, outer=true)[1] + set_junction!(uwd, port, junction, outer=true) + junctions = Dict(variable => junction) for i in 1:n - junction = Symbol("Strain$(i)") - junctions[junction] = add_junction!(uwd, :Inf, variable=junction) + variable = Symbol("Strain$(i)") + junction = add_junction!(uwd, :Inf, variable=variable) + port = ports(uwd, outer=true)[i+1] + set_junction!(uwd, port, junction, outer=true) + junctions[variable] = junction end strains = filter((x) -> x != Symbol("Uninfected"), keys(junctions)) for s in strains @@ -191,7 +211,7 @@ to_graphviz(dom(sird_strain)) # ### Morphism from `strain_ontology` to `infectious_ontology` -strain_ont_uwd = @relation () where {(Uninf::Pop, Inf::Pop)} begin +strain_ont_uwd = @relation (Uninf,Inf) where (Uninf::Pop, Inf::Pop) begin infect(Uninf, Inf, Inf, Inf) disease(Inf, Inf) strata(Inf, Inf) @@ -211,12 +231,14 @@ to_graphviz(strain_ont_act) # to infect other people in the same region. function travel_model(n) - uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() + uwd = RelationDiagram(repeat([:Pop], n)) junctions = Dict(begin - junction = Symbol("Region$(i)") - junction => add_junction!(uwd, :Pop, variable=junction) - end for i in 1:n) - + variable = Symbol("Region$(i)") + junction = add_junction!(uwd, :Pop, variable=variable) + set_junction!(uwd, port, junction, outer=true) + variable => junction + end for (i, port) in enumerate(ports(uwd, outer=true))) + pairs = filter(x -> first(x) != last(x), collect(Iterators.product(keys(junctions), keys(junctions)))) for pair in pairs box = add_box!(uwd, [junction_type(uwd, junctions[p]) for p in pair], name=:strata) @@ -299,10 +321,13 @@ to_graphviz(aug_inf_ontology) # This morphism will serve to re-type the SIRD-strain-vax model. function retype_inf_ont(strata_map) - uwd = RelationalPrograms.TypedUnnamedRelationDiagram{Symbol,Symbol,Symbol}() - junction = :Pop - junctions = Dict(junction => add_junction!(uwd, :nPop, variable=junction)) - + uwd = RelationDiagram([:nPop]) + variable = :Pop + junction = add_junction!(uwd, :nPop, variable=variable) + port = ports(uwd, outer=true)[1] + set_junction!(uwd, port, junction, outer=true) + junctions = Dict(variable => junction) + boxes = [:ninfect, :ndisease, strata_map] for bname in boxes if bname == :ninfect