Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a function already to generate Petri.Model from LabelledPetriNet? #177

Closed
sdwfrost opened this issue Sep 26, 2024 · 5 comments
Closed

Comments

@sdwfrost
Copy link

As it says in the title, I have a problem where I want to convert a LabelledPetriNet to Petri.Model - I couldn't seem to find any conversion code - am I missing something?

@mehalter
Copy link
Member

Do you mean integration with Petri.jl? I believe all integration with Petri.jl was removed because this package really just supercedes it. It supports all of the features that are in Petri.jl

@sdwfrost
Copy link
Author

I wanted to generate SDEs and jump processes as well as the vector field; I didn't see this functionality in AlgebraicPetri.jl

@sdwfrost
Copy link
Author

(I also want to add in a conversion to a discrete-time stochastic solver along the same lines of Gemlib). I suspect that I'll have to extend the model specification to split out discrete and continuous states, so I can lower to a PDMP https://docs.sciml.ai/JumpProcesses/stable/tutorials/jump_diffusion/)

@slwu89
Copy link
Member

slwu89 commented Sep 27, 2024

@sdwfrost you're right, the only simulation functionality available "natively" in AlgPetri right now is the ODE interpretation of the Petri net, as seen in these two functions for the vector field:

""" vectorfield(pn::AbstractPetriNet)
Generates a Julia function which calculates the 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(pn::AbstractPetriNet) = begin
tm = TransitionMatrices(pn)
dt = tm.output - tm.input
(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)
rates[i] = valueat(p_m[i], u, t) * prod(u_m[j]^tm.input[i, j] for j in 1:ns(pn))
end
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
du
end
end
""" vectorfield_expr(pn::AbstractPetriNet)
Generates a Julia expression which is then evaluated that calculates the
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
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 = Vector{Union{Float64,Function}}(undef,$(num_t))
))
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(inputs)
))
# transition decreases inputs and increases output marking
if eltype(os_pn_ix) <: Symbol
for j in os_pn_ix
push!(fcode, :(
du[$(Meta.quot(j))] += rate
))
end
for j in is_pn_ix
push!(fcode, :(
du[$(Meta.quot(j))] -= rate
))
end
else
# dont need quote nodes
for j in os_pn_ix
push!(fcode, :(
du[$(j)] += rate
))
end
for j in is_pn_ix
push!(fcode, :(
du[$(j)] -= rate
))
end
end
end
push!(fcode, :(
return du
))
push!(fquote.args, Expr(:block, fcode...))
return mk_function(AlgebraicPetri, fquote)
end

I wrote the vectorfield_expr method with the intention of putting in a CTMC interpretation as well, but alas did not get around to it. But the logic is there, see the comments in the code, referring to "firing intensity" = )

Also anything generating code like that could (and should) be done more elegantly with https://github.com/AlgebraicJulia/CompTime.jl but that package did not exist at the time.

@sdwfrost
Copy link
Author

Thanks @slwu89 - if the idea is to develop AlgebraicPetri further (rather than integrate more tightly with Petri.jl), I'll close this issue and open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants