# YPetri

`YPetri`

is a domain model and a simulator of dynamical systems. It was inspired by the problems from the field of modelling of biochemical pathways, but on purpose, YPetri is not specific to biochemistry. As a matter of separation of concerns, YPetri caters solely to the two main concerns of modelling, model specification and simulation, excelling in the first one. YPetri implements a novel universal Petri net type, that integrating discrete/continous, deterministic/stochastic, timed/timeless and stoichiometric/nonstoichiometric dichotomies commonly seen in extended Petri nets. YPetri allows specification of any kind of dynamical system whatsoever.

## Usage

`YPetri`

provides a *domain* *specific* *language* (DSL) that can be loaded by:

```
require 'y_petri'
include YPetri
```

(As a matter of terminology, DSLs used in modelling are sometimes termed *domain* *specific* *modelling* *languages* (DSMLs). This term is popular especially in engineering.) Petri net places can now be created:

```
A = Place()
B = Place()
places.names # you can shorten this to #pn
#=> [:A, :B]
# Setting their marking:
A.marking = 2
B.marking = 5
```

And transitions:

```
A2B = Transition stoichiometry: { A: -1, B: 1 } #=> #<Transition: A2B (tS) >
A2B.stoichiometry #=> [-1, 1]
A2B.s #=> {:A=>-1, :B=>1}
A2B.arcs.names #=> [:A, :B]
A2B.timeless? #=> true
A2B.enabled? #=> true
```

Explanation of the keywords: *arcs*, *enabled* are standard Petri net terms,
*stoichiometry* means arcs with the amount of tokens to add / take from the
connected places when the transition fires, *timeless* means that firing of
the transition is not defined in time.

We can now play the *token* *game*:

```
places.map &:marking #=> [2, 5]
A2B.fire!
places.map &:marking #=> [1, 6]
A2B.fire!
places.map &:marking #=> [0, 7]
```

## Advanced usage

A Petri net is mostly used as a wiring diagram of some real-world system. Such
Petri net can then be used to generate its simulation -- represented by
`YPetri::Simulation`

class. A Petri net consisting of only *timed* transitions
can be used to generate (implicitly or explicitly) a system of ordinary
differential equations (ODE). A simulation generated from such Petri net can
then be used to solve (eg.) the initial value problem by numeric methods:

```
# Start a fresh irb session!
require 'y_petri'
include YPetri
A = Place default_marking: 0.5
B = Place default_marking: 0.5
A_pump = Transition s: { A: -1 }, rate: proc { 0.005 }
B_decay = Transition s: { B: -1 }, rate: 0.05
net #=> #<Net: name: Top, 2pp, 2tt >
run!
```

Simulation can now be accessed through `simulation`

DSL method:

```
simulation #=> #<Simulation: time: 60, pp: 2, tt: 2, oid: -XXXXXXXXX>
simulation.settings #=> {:method=>:pseudo_euler, :guarded=>false, :step=>0.1, :sampling=>5, :time=>0..60}
print_recording
```

If you have `gnuplot`

gem installed properly, you can view plots:

```
plot_state
plot_flux
```

## Gillespie method

To try out another simulation method, Gillespie algorithm, open a fresh session and type:

```
require 'y_petri'
require 'sy'
require 'mathn'
include YPetri
A = Place m!: 10
B = Place m!: 10
AB = Place m!: 0
AB_association = Transition s: { A: -1, B: -1, AB: 1 }, rate: 0.1
AB_dissociation = Transition s: { AB: -1, A: 1, B: 1 }, rate: 0.1
A2B = Transition s: { A: -1, B: 1 }, rate: 0.05
B2A = Transition s: { A: 1, B: -1 }, rate: 0.07
set_step 1
set_target_time 50
set_sampling 1
set_simulation_method :gillespie
run!
print_recording
```

Again, you can visualize the results using `gnuplot`

gem:

```
plot_state
```

So much for the demo for now! Thanks for trying YPetri!

## Contributing

- Fork it
- Create your feature branch (
`git checkout -b my-new-feature`

) - Commit your changes (
`git commit -am 'Added some feature'`

) - Push to the branch (
`git push origin my-new-feature`

) - Create new Pull Request core_ext/array/