Code Monkey home page Code Monkey logo

algebraicpetri.jl's People

Contributors

algebraicjuliabot avatar anandijain avatar bosonbaas avatar chrisrackauckas avatar epatters avatar github-actions[bot] avatar jonathanhallstrom avatar jpfairbanks avatar mehalter avatar olynch avatar p-stokes avatar pitmonticone avatar slwu89 avatar tylerhanks avatar yingboma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

algebraicpetri.jl's Issues

`vectorfield_expr` only works with LabelledArrays

We are working on removing LabelledArrays as a package dependency and all of our internal tooling should work with any sort of indexable type for labelled petri nets. While making a PR to remove this dependency from AlgebraicPetri I noticed that the new vectorfield_expr outputs a function that strictly relies on LabelledArrays

using AlgebraicPetri

# Define some random model

sir_lpetri = LabelledPetriNet([:S, :I, :R], :inf => ((:S, :I), (:I, :I)), :rec => (:I, :R))

# Define some parameters and stuff as dictionaries

initial_concentrations = Dict(:S => 990, :I => 10, :R => 0)
model_rates = Dict(:inf => 0.001, :rec => 0.25)

# This works

du = Dict(:S=>0.0, :I=>0.0, :R=>0.0)
out = vectorfield(sir_lpetri)(du, initial_concentrations, model_rates, 0.01)

# This does not

du_expr = Dict(:S=>0.0, :I=>0.0, :R=>0.0)
out = vectorfield_expr(sir_lpetri)(du, initial_concentrations, model_rates, 0.01)

# vectorfield_expr only works with LVectors from LabelledArrays, it should work with Dictionaries/Named Tuples/etc.

using LabelledArrays

du_expr = LVector(;Dict(:S=>0.0, :I=>0.0, :R=>0.0)...)
out = vectorfield_expr(sir_lpetri)(du, LVector(;initial_concentrations...), LVector(;model_rates...), 0.01)

@slwu89 pinging since you did this implementation maybe you have a good idea of how to resolve this. It looks like the function relies on the shorthand of like du_expr[[:S,:I]] to index multiple keys at one time which we shouldn't be reliant on.

Type piracy in visualization functions

The visualization module has lots of type piracies. For example, the Graph constructor is defined for Multispan, Subobject, and ACSetTransformation, but AlgebraicPetri doesn't own any of these types, nor are the methods defined here general enough for those types.

Use color to distinguish morphisms of Petri nets

When looking at morphisms $\phi: P \to P_{type}$ its often the case that $P_{type}$ will only have a small number of transitions and places. In that case, it would be nice to use color to visualize the data of the morphism, rather than edges, which do rather strange things with the graph placement algorithm and get somewhat unreadable for even moderately sized petri nets (see ex from docs):

plot_37

Issues when running stratified model

Hi @mehalter!

I'm trying to implement this simple multigroup model using AlgebraicPetri, and (probably due to my lack of understanding), have run into issues.

  1. Firstly, when I use typed_product, my recovery rate disappears. How do I keep it in my stratified model?
  2. Secondly, how can I set/access the rates and concentrations in a combined model? As is, concentrations and rates throws an error, as the keys are tuples rather than symbols.
using AlgebraicPetri
using AlgebraicPetri.TypedPetri
using Catlab.Programs
using Catlab.Graphics
using Catlab.CategoricalAlgebra
using Catlab.WiringDiagrams
using GraphViz
using LabelledArrays
using OrdinaryDiffEq
using Plots

display_uwd(ex) = to_graphviz(ex, box_labels=:name, junction_labels=:variable, edge_attrs=Dict(:len=>".75"));

infectious_ontology = LabelledPetriNet(
  [:Pop],
  :infect => ((:Pop, :Pop)=>(:Pop, :Pop)), 
  :disease => (:Pop => :Pop),
  :strata => (:Pop => :Pop)
)

sir_relation = @relation () where {(S::Pop, I::Pop, R::Pop)} begin
    infect(S, I, I, I)
    disease(I, R)
end
display_uwd(sir_relation)

sir_model = oapply_typed(infectious_ontology, sir_relation, [:infection, :recovery])
sir_model = add_params(sir_model,
                       Dict(:S => 0.99, :I => 0.01, :R => 0.0),
                       Dict(:infection => 0.5, :recovery => 0.25))
sir_pn = dom(sir_model)
sir_prob = ODEProblem(vectorfield(sir_pn), concentrations(sir_pn), (0.0, 40.0), rates(sir_pn))
sir_sol = solve(sir_prob, Rosenbrock32())
plot(sir_sol)

risk_relation = @relation () where {(H::Pop, L::Pop)} begin
  infect(H, H, H, H)
  infect(L, L, L, L)
  infect(H, L, H, L)
  infect(L, H, L, H)
end
risk_model = oapply_typed(infectious_ontology, risk_relation, [:infect_hh, :infect_ll, :infect_hl, :infect_lh])
risk_model = add_params(risk_model,
                        Dict(:H => 500.0, :L => 500.0),
                        Dict(:infect_hh => 1.0, :infect_ll => 1.0, :infect_hl => 1.0, :infect_lh => 1.0))

sir_model = add_reflexives(sir_model, [[:strata], [:strata], [:strata]], infectious_ontology)
risk_model = add_reflexives(risk_model, [[:strata], [:strata]], infectious_ontology)
sir_risk = typed_product(sir_model, risk_model)
sir_risk_pn = dom(sir_risk)
sir_risk_pn

oapply_typed results in wrong wiring

This simple SEIR example gives a wiring from I to R in the UWD (correct) but from E to R in the labelled Petri net.

using AlgebraicPetri,AlgebraicPetri.TypedPetri
using Catlab, Catlab.CategoricalAlgebra, Catlab.Programs
using Catlab.WiringDiagrams, Catlab.Graphics
using AlgebraicDynamics.UWDDynam


epi_transitions = LabelledPetriNet(
  [:Pop],
  :infection=>((:Pop, :Pop)=>(:Pop, :Pop)),
  :progression=>(:Pop=>:Pop),
  :recovery=>(:Pop=>:Pop)
)

seir_uwd = @relation () where (S::Pop, E::Pop, I::Pop, R::Pop) begin
    infection(S, I, E, I)
    progression(E, I)
    recovery(I, R)
end
to_graphviz(seir_uwd, box_labels=:name, junction_labels=:variable)

seir_acst = oapply_typed(epi_transitions, seir_uwd, [, , ])
seir_lpn = dom(seir_acst)
Graph(seir_lpn)

@jpfairbanks found that changing the order to (S::Pop, I::Pop, E::Pop, R::Pop) in the @relation fixed this.

Adding reflexive transitions to an already stratified model doesn't work because the transition names are tuples

Adding reflexive transitions to an already stratified model doesn't work because the transition names are tuples. This prevents doing multiple stratifications in the straightforward, iterative way. (There is a work around by adding the extra reflexive transitions to the initial model in the beginning before the first stratification, but this impairs a general model building/exploration workflow.) The code below sets up and attempts multiple stratification, but errors at trying to augment the already stratified model with reflexive transitions.

Note that the available flatten_labels function does not work in this case because the stratified model is already typed and, hence, an ACSetTransformation, not a LabelledPetriNet.

using AlgebraicPetri, AlgebraicPetri.TypedPetri
using Catlab.Programs, Catlab.Graphics
using Catlab.CategoricalAlgebra

const infectious_ontology = LabelledPetriNet(
    [:Pop],
    :infect => ((:Pop, :Pop) => (:Pop, :Pop)),
    :disease => (:Pop => :Pop),
    :strata => (:Pop => :Pop)
)

Graph(infectious_ontology)

sir_uwd = @relation () where (S::Pop, I::Pop, R::Pop) begin
    infect(S, I, I, I)
    disease(I, R)
end

to_graphviz(sir_uwd, box_labels = :name, junction_labels = :variable)

tnames = [:beta, :gamma]
typed_sir = oapply_typed(infectious_ontology, sir_uwd, tnames)
Graph(dom(typed_sir))

N = 2
snames = [Symbol("Age$i") for i in 1:N]

typed_age = pairwise_id_typed_petri(infectious_ontology, :Pop, :infect, snames)

Graph(dom(typed_age))

typed_age_aug = add_reflexives(
    typed_age,
    repeat([[:disease]], N),
    infectious_ontology
)

Graph(dom(typed_age_aug))

typed_sir_aug = add_reflexives(
    typed_sir,
    [[:strata], [:strata], [:strata]],
    infectious_ontology
)

Graph(dom(typed_sir_aug))

typed_sir_age = typed_product(typed_sir_aug, typed_age_aug)

Graph(dom(typed_sir_age))

M = 2
snames = [Symbol("Country$i") for i in 1:M]

# Need a function like `pairwise_id_typed_petri` but without identity
travel_uwd = @relation () where (Country1::Pop, Country2::Pop) begin
    strata(Country1, Country2)
    strata(Country2, Country1)
end

to_graphviz(travel_uwd, box_labels = :name, junction_labels = :variable)

typed_travel = oapply_typed(infectious_ontology, travel_uwd, [:Country1_Country2, :Country2_Country1])

Graph(dom(typed_travel))

# Augment the travel model with reflexives

typed_travel_aug = add_reflexives(
    typed_travel,
    repeat([[:infect, :disease]], M),
    infectious_ontology
)

typed_sir_age_aug = add_reflexives(
    typed_sir_age,
    repeat([[:strata]], 3 * N),
    # [[], [], [], [], [], []],
    infectious_ontology
)

Graph(dom(typed_sir_age_aug))

typed_sir_age_travel = typed_product(typed_sir_age_aug, typed_travel_aug)

Graph(dom(typed_sir_age_travel))

Inefficiency in `vectorfield` function

The vectorfield function currently iterates through each element of the transition matrix, making each evaluation be O(ST) for number of states S and number of transitions T. This can cause significant slowdown on large sparse PetriNets, and could be improved by using a sparse representation of the transition matrix.

Generated Vectorfield Function

I've noticed that the function returned from vectorfield can tend to be unstable when working with a combination of ForwardDiff and functions as rates. I feel like this can be improved and optimized by constructing a specialized function expression instead of returning a single function that works with a wide range of parameter types.

PetriFunctor Design

For the design of the PetriFunctors, I think we want to have something like the following:

abstract AbstractFunctor end # this type should be imported from Catlab.
abstract AbstractLaxitor end # this type should be imported from Catlab.

struct PetriDecorator <: AbstractFunctor end

struct PetriLaxitor <: AbstractLaxitor end

struct LaxMonoidalFunctor{Ftr, Lxr} <: AbstractFunctor 
  F::Ftr
  L::Lxr
end

D = LaxMonoidal(PetriDecorator(), PetriLaxitor())

"""we follow FinOrd's lead in taking the skeleton of FinSet so we work with Petri nets 
where the state space is a single Int n rather than the range 1:n.
A functor from FinOrd to Set has an objects part, which given an object n in FinOrd 
(a natural number) should return a representation of F(n)::Set, sets can be represented as
a predicate that takes an element and returns true if the element is in the set. Here we take
any julia value and test whether it is a Petri net on n states.
"""
function (pd::PetriDecorator)(n::FinOrdOb) begin
   return p -> typeof(p) == Petri.Model && (p.S == n)
end

"""mapping a FinOrdFunc over the transitions of a Petri net means renumbering the states 
incident to a transition where the transitions of a petri net are stored as a list of tuples of lists. 
This could be easily adapted for storing transitions in a list of pairs of multisets.
"""
map(f::Function, ts::Vector{Tuple{Vector{Int}, Vector{Int}}) = [(f.(t[1]), f.(t[2])) for t in ts]

"""
A functor from FinOrd to Set has a hom part, which given a hom f in FinOrd 
(a function n::Int->m::Int) should return a representation of F(f)::F(n)->F(m), 
here we implement this as a function that takes a Petri net of size n to a Petri net of size m,
such that the transitions are mapped appropriately.
"""
function (pd::PetriDecorator)(f::FinOrdFunc)
  return (p::Petri.Model) -> Petri.Model(codom(f), map(f, p.Δ))
end

"""the laxitor takes a pair of decorations and returns the coproduct decoration. For Petri nets, it encodes
the idea that you shift the states of q up by the number of states in p.
"""
(l::PetriLaxitor)(p::Petri.Model, q::Petri.Model) = Petri.Model(p.S+q.S, hcat(p.Δ, map(x->x+p.S, q.Δ)))

Then the compose/otimes operation for petri decorated cospans can be implemented in terms of these functions and the universal contructions in catlab.categorical_algebra. We use the empty structs because there is no information in the functor here it just tells us how we want to lift FinOrdObs and FinOrdFuncs up to functions that operate on Petri.Models.

Once we implement the C-Set approach, the definitions of the function (pd::PetriDecorator)(f::FinOrdFunc) and (l::PetriLaxitor)(p::Petri.Model, q::Petri.Model) can be inferred from the definition of C-Sets, but for now we code it up manually as part of the "code that understands math" aspect of partially symbolic computing.

ReactionNet documentation example

the SIR example construction in the docstring for LabelledReactionNet errors for me.

ReactionNet{Float64, Float64}([:S=>10,:I=>1,:R=>0],
    (:inf=>0.5)=>((1,2)=>(2,2)),
    (:rec=>0.1)=>(2=>3))

ERROR: MethodError: Cannot `convert` an object of type Pair{Symbol, Int64} to an object of type Float64

All the other code examples in AlgebraicPetri.jl work for me, though, as well as the SIR example from the tests:

LabelledReactionNet{Float64, Float64}([:S=>1.0, :I=>0.0, :R=>0.0],
    (:inf=>0.5)=>((:S,:I)=>(:I,:I)),
    (:rec=>0.1)=>(:I=>:R))

`prim_petri` of TypedPetri.jl not labeling types of states correctly

This issue arose from the following example with multiple states in the type system. As seen in the example, all states wind up being typed to the :Pop state type. I think if lines 22 and 28 in prim_petri were replaced with s=i it would address the issue.

const ontology = LabelledPetriNet(
    [:Pop, :Vac],
    :infect => ((:Pop, :Pop) => (:Pop, :Pop)),
    :disease => (:Pop => :Pop),
    :strata => (:Pop => :Pop),
    :vaccinate => ((:Pop, :Vac) => :Pop),
    :produce => (() => :Vac),
)
Graph(ontology)
sirv_uwd = @relation () where (S::Pop, I::Pop, R::Pop, vaccine::Vac, V::Pop) begin
    infect(S, I, I, I)
    disease(I, R)
    vaccinate(S, vaccine, V)
    produce(vaccine)
end
to_graphviz(sirv_uwd, box_labels = :name, junction_labels = :variable)

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

Potential Catalyst Breaking Update

With the update of Catalyst.jl from 6.13 to 6.14, it appears that using arrays to index symbol arrays is no longer supported. This breaks the CatalystInterop tooling.

Test Issue

This is an issue to test the ASKEM integration workflow.

SDE version of Petri Semantics

It would be awesome to have an SDE model of PetriNets with the interface

pn = Petri.Model(...)
p, cb = SDEProblem(pn, u0, params, tspan)
solve(p, callback=cb)

suggestions for documentation improvement

Just collecting some things I found confusing that I plan to make one or more PRs to address in the future

`one_removed_subobs` does not remove arcs from Petri net

When trying to remove input or output arcs from a Petri net, the function one_removed_subobs fails to remove the part and returns the original Petri net. This leads to problems with the mca recursion because some subACSets are not decreasing in size.

m3 = LabelledPetriNet(
  [:X,:Y,:W,:Z],
  :f=>(:X=>(:W, :Y, :Z))
)
m3 == dom(one_removed_subobs(m3,:I)[1])

Tests for DPO rewriting of Petri nets

The following tests were removed from @kris-brown's AlgebraicJulia/Catlab.jl#425 to avoid code duplication from this repo. This issue is a reminder to add the tests here once the DPO feature is merged and released in Catlab. Actually, I only see one @test below, so the test assertions should probably be bulked up a bit too.

sir=EpiRxnNet((:S=>100, :I=>1, :R=>0),
              (:inf,.03)=>((:S,:I)=>(:I,:I)),
              (:rec,.25)=>(:I=>:R));

seir = EpiRxnNet((: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)));
Rg = EpiRxnNet((:S=>100,:I=>1,:E=>1),
               (:exp,.1)=>((:S, :I)=>(:E, :I)),
               (:inc,.1)=>(:E => :I))
Lg = EpiRxnNet((:S=>100,:I=>1),)

L=ACSetTransformation(Lg,Lg,S=[1,2]);
R=ACSetTransformation(Lg,Rg,S=[1,2]);
m=ACSetTransformation(Lg, sir,S=[1,2]);
@test is_isomorphic(seir, rewrite_match(L,R,m))

Lg = EpiRxnNet((:S=>100,:I=>1),)
Rg = EpiRxnNet((:S=>100,:I=>1), (:sus,.1)=>(:I=>:S))
L=ACSetTransformation(Lg,Lg,S=[1,2]);
R=ACSetTransformation(Lg,Rg,S=[1,2]);
m=ACSetTransformation(Lg, seir,S=[1,2]);
seirs = rewrite_match(L,R,m)

Lg = EpiRxnNet((:I=>1),)
Rg = EpiRxnNet((:I=>1,:D=>0), (:die,.1)=>(:I=>:D))
L=ACSetTransformation(Lg,Lg,S=[1]);
R=ACSetTransformation(Lg,Rg,S=[1]);
m=ACSetTransformation(Lg, seir,S=[2]);
seird = rewrite_match(L,R,m)

Method error in enzyme_reactions.jl

I was trying to clean up #104 to get it merged when I found a very odd method error arising from the call to solve here https://github.com/AlgebraicJulia/AlgebraicPetri.jl/blob/master/examples/enzymes/enzyme_reactions.jl#L251 (also occurs for other calls to solve in that file). The error is very long, I'll paste it at the end of this post (without the stacktrace, which is even longer).

Here's my environment info:

julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 32 × AMD Ryzen 9 5950X 16-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, znver3)
  Threads: 1 on 32 virtual cores
Environment:
  LD_LIBRARY_PATH = /app/lib
  JULIA_EDITOR = code
  JULIA_NUM_THREADS = 

(@v1.8) pkg> st
Status `~/.julia/environments/v1.8/Project.toml`
  [4f99eebe] AlgebraicPetri v0.8.4 `../../../Desktop/git/AlgebraicPetri.jl`
  [134e5e36] Catlab v0.14.14
  [31a5f54b] Debugger v0.7.8
  [0c46a032] DifferentialEquations v7.7.0
  [aa1ae85d] JuliaInterpreter v0.9.22
  [91a5bcdd] Plots v1.38.5
  [295af30f] Revise v3.5.1
  [3c863552] Graphviz_jll v2.50.0+1

The error:

ERROR: MethodError: Cannot `convert` an object of type 
  LinearSolve.LinearCache{LabelledArrays.LArray{Float64{},2,Array{Float64{},2},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},SciMLBase.NullParameters{},RFLUFactorization{true,true},Tuple{LinearAlgebra.LU{Float64{},LabelledArrays.LArray{Float64, 2, Matrix{Float64}, (:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},Array{Int64{},1}},Array{Int64{},1}},LinearSolve.InvPreconditioner{LinearAlgebra.Diagonal{Float64{},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)}}},LinearAlgebra.Diagonal{Float64{},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)}},Float64{},true} to an object of type 
  LinearSolve.LinearCache{LabelledArrays.LArray{Float64{},2,Array{Float64{},2},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)},SciMLBase.NullParameters{},RFLUFactorization{true,true},Tuple{LinearAlgebra.LU{Float64{},Matrix{Float64},Array{Int64{},1}},Array{Int64{},1}},LinearSolve.InvPreconditioner{LinearAlgebra.Diagonal{Float64{},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)}}},LinearAlgebra.Diagonal{Float64{},LabelledArrays.LArray{Float64{},1,Array{Float64{},1},(:K, :Kinact, :KK, :Kdeg, :KKinact, :S, :Sinact, :SS, :Sdeg, :SSinact, :L, :Linact, :LL, :Ldeg, :LLinact, :KS, :KSinact, :KL, :KLinact, :SK, :SKinact, :SL, :SLinact, :LK, :LKinact, :LS, :LSinact, :E, :KE, :Edeg, :SE, :LE)}},Float64{},true}
Closest candidates are:
  convert(::Type{T}, ::T) where T at ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/base/Base.jl:61
  LinearSolve.LinearCache{TA, Tb, Tu, Tp, Talg, Tc, Tl, Tr, Ttol, issq}(::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any) where {TA, Tb, Tu, Tp, Talg, Tc, Tl, Tr, Ttol, issq} at ~/.julia/packages/LinearSolve/7ER8k/src/common.jl:9

Food Webs

A food web is like a petri net where the species are species of organisms and the transitions of consumption events. We should be able to represent them with Dynamical systems based on a conservation of biomass principle. AlgPetri should be able to support the hierarchical definition of a FoodWeb.

image

Howard Odom (UNC grad, UF Prof) had a theory of ecological systems theory back in the 1970s, which is very compatible with modern ACT approaches. We could implement these diagrams using Decorated Cospans to describe large ecosystems as interacting subsystems.

A good start would be implementing a foodweb as a petrinet (or general open dynamical system connected by resource sharing). Then we could show that you can do Trophic Species Reduction, which merges species if they have the same set of preditors and prey as a symbolic simplification in the resulting category.

Update Catlab

Fix interface with Catlab to match the new Catlab v0.7.3 changes. Mainly FinOrd is now FinSet

Gluing along transitions

Hi AlgPetri team,

I'm interested in gluing PNs along transitions. This is especially useful in modeling manufacturing, logistics, and supply chain systems, see an example below for informal "gluing" of 2 kanban production cells together along the transition $exitCell_{i}$ and $enterCell_{i+1}$, with the resulting PN using the label $enterCell_{i+1}$ for that transition which is the result of the gluing operation. A single kanban cell is on the top figure and a system of 2 joined cells is on the bottom.
Screen Shot 2023-01-26 at 2 24 32 PM
Screen Shot 2023-01-26 at 2 24 43 PM

A simply hacky proof of concept is below...I'm really curious to hear if this functionality could be developed into a PR that I can work on to add this feature to the package! Thanks.

using Catlab, Catlab.CategoricalAlgebra, Catlab.WiringDiagrams, Catlab.Programs, Catlab.Graphics
using AlgebraicPetri
draw(uwd::AbstractUWD; kwargs...) = to_graphviz(uwd, junction_labels=:variable, box_labels=:name; kwargs...);

const OpenLabelledPetriNetObUntypedT, OpenLabelledPetriNetUntypedT = OpenACSetTypes(AlgebraicPetri.LabelledPetriNetUntyped,:T)
const OpenLabelledPetriNetObT, OpenLabelledPetriNetT = OpenLabelledPetriNetObUntypedT{Symbol}, OpenLabelledPetriNetUntypedT{Symbol}
OpenT(p::AbstractLabelledPetriNet, 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

annihilation = LabelledPetriNet([:X],
    :T => (:X => ())
)

creation = LabelledPetriNet([:X],
    :T => (() => :X)
)

annihilation_o = OpenT(annihilation, [:T])
creation_o = OpenT(creation, [:T])

join_pattern = @relation (Event,) begin
    X(Event)
    Y(Event)
end

joined_pn = oapply(join_pattern,
    Dict(
        :X => annihilation_o,
        :Y => creation_o
    )
)

Graph(annihilation)
Graph(creation)
draw(join_pattern)
Graph(apex(joined_pn))

ACSetTransformation Wrapper to type LabelledPetriNet

Writing a wrapper for ACSetTransformation similar to oapply_typed that takes a LabelledPetriNet instead of a uwd
Given:

  1. LabelledPetriNet (SIR for example)
  2. LabelledPetriNet/Type System/Ontology,
  3. some sort of mapping (not sure what format you will require but ideally it is based off of the id's rather than the indexes)

Output: typed petrinet

Example visual if helpful Below

Sample.of.how.I.want.to.type.mov

`mca` not searching in order of size

mca currently searches by taking the list of subACSets formed by removing a single part from each object of the smaller input ACSet. It then looks for a mono from each subACSet in the list into the larger input ACSet. If it finds any monos, it returns the largest ones, otherwise it recurses on the list of subACSets.

Unfortunately, at each round the subACSets in the list can be of varying size, and if it finds a mono for one of the smaller subACSets, it will terminate without further searching the larger subACSets.

For example, in the following mca returns the four separate nodes, rather than a vector of isomorphic cases of the single transition with a single input and single output.

m3 = LabelledPetriNet(
  [:X,:Y,:W,:Z],
  :f=>(:X=>(:W, :Y, :Z))
)
m4 = LabelledPetriNet(
  [:X,:W,:Y,:Z],
  :f=>((:W, :X, :Y)=>:Z)
)
test = mca(m3,m4)

naive questions on removing edges and states

i am in the process of reading through the RxNet paper (i don't really know CT)

right now, im just recreating tons and tons of petri nets with one or two edges different and its starting to get cumbersome.
i wrote two helpers that made it easy to add transitions and get out the (n, ts) tuple used to construct the LabelledPetriNet

one problem i kept running into was not being able to easily remove edges/states.
maybe it doesn't fit Catlabs philosophy or something, but my thought was, if we are creating sets of models to compare, it would be nice to "only store the diff", instead of lugging around a bunch of copies. in the example below, i wanted to start from the most basic SIR model and progressively work up to SEIRHD. im able to get part of the way there but I didn't see anything related to deleting transitions and species. id love some help on this.

at some point, i want to build some tools to be able to ask questions like "compare the death counts of all the models that take :mutation => (:R=>:S) into account"

thanks for the amazing package!

function add_things!(p::AbstractLabelledPetriNet, ts::Vararg{Union{Pair,Tuple}})
    n = snames(p)
    state_idx = AlgebraicPetri.state_dict(n)
    for (name, (ins, outs)) in ts
        i = add_transition!(p, tname=name)
        ins = AlgebraicPetri.vectorify(ins)
        outs = AlgebraicPetri.vectorify(outs)
        add_inputs!(p, length(ins), repeat([i], length(ins)),
            map(x -> state_idx[x], collect(ins)))
        add_outputs!(p, length(outs), repeat([i], length(outs)),
            map(x -> state_idx[x], collect(outs)))
    end
    p
end

function get_things(p)
    is_ = inputs.((p,), 1:nt(p))
    os_ = outputs.((p,), 1:nt(p))
    tns = tnames(p)
    sns = snames(p)
    (sns, [tns[i] => (sns[is_[i]] => sns[os_[i]]) for i in 1:nt(p)])
end

sir_n = [:S, :I, :R]
sir_t = [:exp => ((:S, :I) => (:I, :I)), :rec => (:I => :R)]
sir = LabelledPetriNet(
    sir_n, sir_t...
)

sird = deepcopy(sir)
add_species!(sird; sname=:D)
@test has_species(sird, :D)
add_things!(sird, :death => (:I => :D))

n, ts = get_things(sird)
@test LabelledPetriNet(n, ts...) == sird

# how do i split I into I and E? 
seird = LabelledPetriNet(
    [:S, :E, :I, :R, :D],
    :exp => ([:S, :I] => [:E, :I]),
    :conv => (:E => :I),
    :rec => (:I => :R),
    :death => (:I => :D)
)

Add Examples to Documentation

Examples for subobject algebras and parameter estimation with Catalyst should be added to the AlgebraicPetri documentation.

AlgebraicPetri v0.9

TODO

  • Revert commented out tests after regressions are resolved (#151):
    • ModelComparison: Need to wait until Subobject regression is fixed
  • Update Project.toml [compat] entries for (#151):
    • Catlab
    • AlgebraicRewriting
  • Make sure tests are passing once Catlab is released
  • Change default branch and update branch protection to main
  • Tag new release v0.9

Precompilation warnings in package extensions

When precompiling the OrdinaryDiffEq and ModelingToolkit extensions, I get the following warnings:

  2 dependencies had warnings during precompilation:
┌ AlgebraicPetriModelingToolkitExt [64666759-9bd1-54ef-b315-8c08f09f6f3d]
│  WARNING: Method definition (::Type{SciMLBase.ODEProblem{uType, tType, isinplace, P, F, K, PT} where PT where K where F where P where isinplace where tType where uType})(AlgebraicPetri.AbstractPetriNet{S, Ts, P} where P where Ts where S, Any) in module AlgebraicPetriOrdinaryDiffEqExt at /home/epatters/Local/algjulia/algpetri/ext/AlgebraicPetriOrdinaryDiffEqExt.jl:7 overwritten in module AlgebraicPetriModelingToolkitExt at /home/epatters/Local/algjulia/algpetri/ext/AlgebraicPetriModelingToolkitExt.jl:47.
│    ** incremental compilation may be fatally broken for this module **
└  
┌ AlgebraicPetriCatalystExt [77e4b18c-d989-5097-a0f2-659ba3bbce58]
│  WARNING: Method definition (::Type{SciMLBase.ODEProblem{uType, tType, isinplace, P, F, K, PT} where PT where K where F where P where isinplace where tType where uType})(AlgebraicPetri.AbstractPetriNet{S, Ts, P} where P where Ts where S, Any) in module AlgebraicPetriOrdinaryDiffEqExt at /home/epatters/Local/algjulia/algpetri/ext/AlgebraicPetriOrdinaryDiffEqExt.jl:7 overwritten in module AlgebraicPetriModelingToolkitExt at /home/epatters/Local/algjulia/algpetri/ext/AlgebraicPetriModelingToolkitExt.jl:47.
│    ** incremental compilation may be fatally broken for this module **
│  
│  WARNING: Method definition (::Type{SciMLBase.ODEProblem{uType, tType, isinplace, P, F, K, PT} where PT where K where F where P where isinplace where tType where uType})(AlgebraicPetri.AbstractPetriNet{S, Ts, P} where P where Ts where S, Any) in module AlgebraicPetriOrdinaryDiffEqExt at /home/epatters/Local/algjulia/algpetri/ext/AlgebraicPetriOrdinaryDiffEqExt.jl:7 overwritten in module AlgebraicPetriModelingToolkitExt at /home/epatters/Local/algjulia/algpetri/ext/AlgebraicPetriModelingToolkitExt.jl:47.
│    ** incremental compilation may be fatally broken for this module **

This is on Catlab v0.15.5.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.