y_petri 2.1.18 → 2.1.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +83 -16
- data/lib/y_petri/net/data_set.rb +8 -0
- data/lib/y_petri/simulation.rb +1 -1
- data/lib/y_petri/version.rb +1 -1
- data/test/simulation_test.rb +4 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 925fd4bc4059984743c3a79a05161f8318bb664b
|
4
|
+
data.tar.gz: 9df7ce42d2a6d90d196b9b0325ce9f547892b228
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6e49798a1982ffee6b72a5fe210cce73cb30a2dfa32b745cad5d5be27160600cecb6449a786bcff335dfa3b49d3132655c35fb88094716df430c3b66e43c0b9
|
7
|
+
data.tar.gz: 56705a76926aa07e3116038dd216427d4bc07dfc512422d9fc354087b8103e6e67a3722f5b80cbec7075a7d194c77bc1dde1ae57e8005f40f03c5a78cc7c6c4a
|
data/README.md
CHANGED
@@ -1,26 +1,93 @@
|
|
1
1
|
# YPetri
|
2
2
|
|
3
|
-
|
3
|
+
`YPetri` is a domain model and a simulator of _functional_ _Petri_ _nets_,
|
4
|
+
a family of Petri nets, whose transitions have functions attached to them.
|
4
5
|
|
5
|
-
##
|
6
|
-
|
7
|
-
Add this line to your application's Gemfile:
|
8
|
-
|
9
|
-
gem 'y_petri'
|
10
|
-
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
6
|
+
## Usage
|
14
7
|
|
15
|
-
|
8
|
+
`YPetri` provides a _domain_ _specific_ _language_ (DSL), that can be loaded by:
|
9
|
+
```ruby
|
10
|
+
require 'y_petri'
|
11
|
+
include YPetri
|
12
|
+
```
|
13
|
+
Now, one can create places:
|
14
|
+
```ruby
|
15
|
+
A = Place()
|
16
|
+
B = Place()
|
17
|
+
places.names # you can shorten this to #pn
|
18
|
+
#=> [:A, :B]
|
19
|
+
# Setting their marking:
|
20
|
+
A.marking = 2
|
21
|
+
B.marking = 5
|
22
|
+
```
|
23
|
+
And transitions:
|
24
|
+
```ruby
|
25
|
+
A2B = Transition stoichiometry: { A: -1, B: 1 }
|
26
|
+
#=> #<Transition: A2B (tS) >
|
27
|
+
A2B.stoichiometry
|
28
|
+
#=> [-1, 1]
|
29
|
+
A2B.s
|
30
|
+
#=> {:A=>-1, :B=>1}
|
31
|
+
A2B.arcs.names
|
32
|
+
#=> [:A, :B]
|
33
|
+
A2B.timeless?
|
34
|
+
#=> true
|
35
|
+
A2B.enabled?
|
36
|
+
#=> true
|
37
|
+
```
|
38
|
+
Explanation of the keywords: _arcs_, _enabled_ are standard Petri net terms,
|
39
|
+
_stoichiometry_ means arcs with the amount of tokens to add / take from the
|
40
|
+
connected places when the transition fires, _timeless_ means that firing of
|
41
|
+
the transition is not defined in time.
|
16
42
|
|
17
|
-
|
43
|
+
We can now play the _token_ _game_:
|
44
|
+
```ruby
|
45
|
+
places.map &:marking
|
46
|
+
#=> [2, 5]
|
47
|
+
A2B.fire!
|
48
|
+
places.map &:marking
|
49
|
+
#=> [1, 6]
|
50
|
+
A2B.fire!
|
51
|
+
places.map &:marking
|
52
|
+
#=> [0, 7]
|
53
|
+
```
|
18
54
|
|
19
|
-
##
|
55
|
+
## Advanced usage
|
20
56
|
|
21
|
-
|
22
|
-
|
23
|
-
|
57
|
+
A Petri net is mostly used as a wiring diagram of some real-world system. Such
|
58
|
+
Petri net can then be used to generate (implicitly or explicitly) a more specific
|
59
|
+
simulation of that real-world system. This is represented by `YPetri::Simulation`
|
60
|
+
class. If a Petri net with only _timed_ transitions is considered, it can then
|
61
|
+
be used to generate (implicitly or explicitly) a system of ordinary differential
|
62
|
+
equations (ODE). A Simulation class instance generated from such Petri net can
|
63
|
+
then be used to eg. solve the initial value problem by numeric integration of the
|
64
|
+
ODE system using one of the available numerical methods:
|
65
|
+
```ruby
|
66
|
+
# Start a fresh irb session!
|
67
|
+
require 'y_petri'
|
68
|
+
include YPetri
|
69
|
+
A = Place default_marking: 0.5
|
70
|
+
B = Place default_marking: 0.5
|
71
|
+
A_pump = Transition s: { A: -1 }, rate: proc { 0.005 }
|
72
|
+
B_decay = Transition s: { B: -1 }, rate: 0.05
|
73
|
+
net
|
74
|
+
#=> #<Net: name: Top, 2pp, 2tt >
|
75
|
+
run!
|
76
|
+
```
|
77
|
+
Simulation can now be accessed through `simulation` DSL method:
|
78
|
+
```ruby
|
79
|
+
simulation
|
80
|
+
#=> #<Simulation: time: 60, pp: 2, tt: 2, oid: -XXXXXXXXX>
|
81
|
+
simulation.settings
|
82
|
+
#=> {:method=>:pseudo_euler, :guarded=>false, :step=>0.1, :sampling=>5, :time=>0..60}
|
83
|
+
print_recording
|
84
|
+
```
|
85
|
+
If you have `gnuplot` gem installed properly, you can view plots:
|
86
|
+
```ruby
|
87
|
+
plot_state
|
88
|
+
plot_flux
|
89
|
+
```
|
90
|
+
So much for the demo for now! Thanks for trying YPetri!
|
24
91
|
|
25
92
|
## Contributing
|
26
93
|
|
data/lib/y_petri/net/data_set.rb
CHANGED
@@ -252,4 +252,12 @@ class YPetri::Net::DataSet < Hash
|
|
252
252
|
def inspect
|
253
253
|
to_s
|
254
254
|
end
|
255
|
+
|
256
|
+
# Pretty print the dataset.
|
257
|
+
#
|
258
|
+
def print precision: 4, distance: precision + 4
|
259
|
+
features.labels.print_as_line precision: precision, distance: distance
|
260
|
+
puts '-' * features.size * distance
|
261
|
+
records.each.print_as_line precision: precision, distance: distance
|
262
|
+
end
|
255
263
|
end # YPetri::Net::Dataset
|
data/lib/y_petri/simulation.rb
CHANGED
data/lib/y_petri/version.rb
CHANGED
data/test/simulation_test.rb
CHANGED
@@ -119,7 +119,7 @@ describe YPetri::Simulation do
|
|
119
119
|
@sim.ts_tt.first.domain.names.must_equal []
|
120
120
|
@sim.timed?.must_equal false
|
121
121
|
@sim.m.must_equal [1, 2]
|
122
|
-
@sim.
|
122
|
+
@sim.p_m.must_equal( { A: 1, B: 2 } )
|
123
123
|
@sim.recording.must_equal( { 0 => [1, 2]} )
|
124
124
|
@sim.simulation_method.must_equal :pseudo_euler
|
125
125
|
@sim.core.must_be_kind_of YPetri::Core
|
@@ -133,7 +133,7 @@ describe YPetri::Simulation do
|
|
133
133
|
cl = @sim.send( :transitions ).ts.delta_closure
|
134
134
|
cl.call.must_equal Matrix[ [1], [0] ]
|
135
135
|
@sim.step!
|
136
|
-
@sim.
|
136
|
+
@sim.p_m.must_equal( { A: 2, B: 2 } ) # marking of A goes up by 1
|
137
137
|
@sim.recording.must_equal( { 0 => [1, 2], 1 => [2, 2] } )
|
138
138
|
end
|
139
139
|
end
|
@@ -277,7 +277,8 @@ describe "timeless simulation" do
|
|
277
277
|
.must_equal [2.5, 4.5]
|
278
278
|
-> { ds.interpolate( 1.5 ) }.must_raise TypeError
|
279
279
|
ds.reconstruct( event: 2 )
|
280
|
-
.
|
280
|
+
.p_m.must_equal( { U: 2.5, V: 4.5 } )
|
281
|
+
ds.reconstruct( event: 2 ).must_respond_to( :pm )
|
281
282
|
ds.marking.slice( 2..4 ).series
|
282
283
|
.must_equal [[2.5, 2.5, 2.5], [4.5, 5.5, 6.5]]
|
283
284
|
ds.marking.slice( 2..4 )
|