y_petri 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/lib/y_petri/demonstrator.rb +164 -0
- data/lib/y_petri/demonstrator_2.rb +176 -0
- data/lib/y_petri/demonstrator_3.rb +150 -0
- data/lib/y_petri/demonstrator_4.rb +217 -0
- data/lib/y_petri/manipulator.rb +598 -0
- data/lib/y_petri/net.rb +458 -0
- data/lib/y_petri/place.rb +189 -0
- data/lib/y_petri/simulation.rb +1313 -0
- data/lib/y_petri/timed_simulation.rb +281 -0
- data/lib/y_petri/transition.rb +921 -0
- data/lib/y_petri/version.rb +3 -0
- data/lib/y_petri/workspace/instance_methods.rb +254 -0
- data/lib/y_petri/workspace/parametrized_subclassing.rb +26 -0
- data/lib/y_petri/workspace.rb +16 -0
- data/lib/y_petri.rb +141 -0
- data/test/simple_manual_examples.rb +28 -0
- data/test/y_petri_graph.png +0 -0
- data/test/y_petri_test.rb +1521 -0
- data/y_petri.gemspec +21 -0
- metadata +112 -0
@@ -0,0 +1,1521 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'minitest/spec'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require_relative '../lib/y_petri' # tested component itself
|
7
|
+
# require 'y_petri'
|
8
|
+
|
9
|
+
# require 'sy'
|
10
|
+
|
11
|
+
include Pyper if require 'pyper'
|
12
|
+
|
13
|
+
# **************************************************************************
|
14
|
+
# Test of Place class, part I.
|
15
|
+
# **************************************************************************
|
16
|
+
#
|
17
|
+
describe ::YPetri::Place do
|
18
|
+
before do
|
19
|
+
# skip "to speed up testing"
|
20
|
+
@pç = pç = Class.new ::YPetri::Place
|
21
|
+
@p = pç.new! default_marking: 3.2,
|
22
|
+
marking: 1.1,
|
23
|
+
quantum: 0.1,
|
24
|
+
name: "P1"
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "place behavior" do
|
28
|
+
before do
|
29
|
+
@p.m = 1.1
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have constant magic included" do
|
33
|
+
assert_respond_to @p, :name
|
34
|
+
assert_equal @p.name, :P1
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have own marking and be able to update it" do
|
38
|
+
assert_equal 1.1, @p.marking
|
39
|
+
assert_equal 0.1, @p.quantum
|
40
|
+
assert_equal :P1, @p.name
|
41
|
+
@p.add 1
|
42
|
+
assert_equal 2.1, @p.value # alias for #marking
|
43
|
+
@p.subtract 0.5
|
44
|
+
assert_equal 1.6, @p.m
|
45
|
+
@p.reset_marking
|
46
|
+
assert_equal 3.2, @p.marking
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should respond to the arc getters" do
|
50
|
+
# #action_arcs & aliases
|
51
|
+
assert_equal [], @p.upstream_arcs
|
52
|
+
assert_equal [], @p.upstream_transitions
|
53
|
+
assert_equal [], @p.ϝ
|
54
|
+
# #test_arcs & aliases
|
55
|
+
assert_equal [], @p.downstream_arcs
|
56
|
+
assert_equal [], @p.downstream_transitions
|
57
|
+
# #arcs & aliasesnn
|
58
|
+
assert_equal [], @p.arcs
|
59
|
+
assert_equal [], @p.connectivity
|
60
|
+
# #precedents & aliases
|
61
|
+
assert_equal [], @p.precedents
|
62
|
+
assert_equal [], @p.upstream_places
|
63
|
+
# #dependents & aliases
|
64
|
+
assert_equal [], @p.dependents
|
65
|
+
assert_equal [], @p.downstream_places
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should respond to register and fire conn. transitions methods" do
|
69
|
+
assert_respond_to @p, :fire_upstream!
|
70
|
+
assert_respond_to @p, :fire_downstream!
|
71
|
+
assert_respond_to @p, :fire_upstream_recursively
|
72
|
+
assert_respond_to @p, :fire_downstream_recursively
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# **************************************************************************
|
78
|
+
# Test of Transition class, part I.
|
79
|
+
# **************************************************************************
|
80
|
+
#
|
81
|
+
describe ::YPetri::Transition do
|
82
|
+
before do
|
83
|
+
# skip "to speed up testing"
|
84
|
+
@ç = ç = Class.new ::YPetri::Transition
|
85
|
+
@pç = pç = Class.new ::YPetri::Place
|
86
|
+
[ ç, pç ].each { |ç|
|
87
|
+
ç.class_exec {
|
88
|
+
define_method :Place do pç end
|
89
|
+
define_method :Transition do ç end
|
90
|
+
private :Place, :Transition
|
91
|
+
}
|
92
|
+
}
|
93
|
+
@p1 = pç.new default_marking: 1.0
|
94
|
+
@p2 = pç.new default_marking: 2.0
|
95
|
+
@p3 = pç.new default_marking: 3.0
|
96
|
+
@p4 = pç.new default_marking: 4.0
|
97
|
+
@p5 = pç.new default_marking: 5.0
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "1. timeless nonstoichiometric (ts) transitions" do
|
101
|
+
|
102
|
+
# Note that timeless nonstoichiometric transitions require a function
|
103
|
+
# block, and thus are always functional
|
104
|
+
|
105
|
+
before do
|
106
|
+
@t1 = @ç.new codomain: [ @p1, @p3 ], domain: @p2, action: λ { |a| [ a, a ] }
|
107
|
+
# saying that the trans. is timed saves the day here:
|
108
|
+
@t2 = @ç.new codomain: [ @p1, @p3 ], action: λ { |t| [ t, t ] }, timed: true
|
109
|
+
# Only with domain is 1-ary closure allowed to be timeless:
|
110
|
+
@t3 = @ç.new codomain: [ @p1, @p3 ], action: λ { |t| [ t, t ] }, timed: false, domain: [ @p2 ]
|
111
|
+
# With nullary action closure, timeless is implied, so this is allowed
|
112
|
+
@t4 = @ç.new action: λ { [ 0.5, 0.5 ] }, codomain: [ @p1, @p3 ]
|
113
|
+
# ... also for stoichiometric variety
|
114
|
+
@t5 = @ç.new action: λ { 0.5 }, codomain: [ @p1, @p3 ], s: [ 1, 1 ]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should raise errors for bad parameters" do
|
118
|
+
# omitting the domain should raise ArgumentError about too much ambiguity:
|
119
|
+
assert_raises AErr do @ç.new codomain: [ @p1, @p3 ], action: λ { |t| [ t, t ] } end
|
120
|
+
# saying that the transition is timeless points to a conflict:
|
121
|
+
assert_raises AErr do @ç.new codomain: [ @p1, @p3 ], action: λ { |t| [ t, t ] }, timeless: true end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should initi and perform" do
|
125
|
+
assert_equal [ @p2 ], @t1.domain
|
126
|
+
assert_equal [ @p1, @p3 ], @t1.action_arcs
|
127
|
+
assert @t1.functional?
|
128
|
+
assert @t1.timeless?
|
129
|
+
assert @t2.timed?
|
130
|
+
assert [@t3, @t4, @t5].all? { |t| t.timeless? }
|
131
|
+
assert @t2.rateless?
|
132
|
+
# that's enough, now let's flex them:
|
133
|
+
@t1.fire!
|
134
|
+
assert_equal [3, 5], [ @p1.marking, @p3.marking ]
|
135
|
+
@t3.fire!
|
136
|
+
assert_equal [5, 7], [ @p1.marking, @p3.marking ]
|
137
|
+
@t4.fire!
|
138
|
+
assert_equal [5.5, 7.5], [ @p1.marking, @p3.marking ]
|
139
|
+
@t5.fire!
|
140
|
+
assert_equal [6, 8], [ @p1.marking, @p3.marking ]
|
141
|
+
# now t2 for firing requires delta time
|
142
|
+
@t2.fire! 1
|
143
|
+
assert_equal [7, 9], [ @p1.marking, @p3.marking ]
|
144
|
+
@t2.fire! 0.1
|
145
|
+
assert_equal [7.1, 9.1], [@p1.marking, @p3.marking ]
|
146
|
+
# let's change @p2 marking
|
147
|
+
@p2.marking = 0.1
|
148
|
+
@t1.fire!
|
149
|
+
assert_in_epsilon 7.2, @p1.marking, 1e-9
|
150
|
+
assert_in_epsilon 9.2, @p3.marking, 1e-9
|
151
|
+
# let's test #domain_marking, #codomain_marking, #zero_action
|
152
|
+
assert_equal [ @p1.marking, @p3.marking ], @t1.codomain_marking
|
153
|
+
assert_equal [ @p2.marking ], @t1.domain_marking
|
154
|
+
assert_equal [ 0, 0 ], @t1.zero_action
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "2. timed rateless non-stoichiometric (Tsr) transitions" do
|
159
|
+
#LATER: To save time, I omit the full test suite.
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "3. timeless stoichiometric (tS) transitions" do
|
163
|
+
describe "functionless tS transitions" do
|
164
|
+
|
165
|
+
# For transitions with no function given (ie. functionless), it is
|
166
|
+
# required that their stoichiometric vector be given and their action
|
167
|
+
# closure is then automatically generated from the stoichio. vector
|
168
|
+
|
169
|
+
before do
|
170
|
+
# timeless transition with stoichiometric vector only, as hash
|
171
|
+
@ftS1 = @ç.new stoichiometry: { @p1 => 1 }
|
172
|
+
# timeless transition with stoichiometric vector as array + codomain
|
173
|
+
@ftS2 = @ç.new stoichiometry: 1, codomain: @p1
|
174
|
+
# :stoichiometric_vector is aliased as :sv
|
175
|
+
@ftS3 = @ç.new s: 1, codomain: @p1
|
176
|
+
# :codomain is aliased as :action_arcs
|
177
|
+
@ftS4 = @ç.new s: 1, action_arcs: @p1
|
178
|
+
# dropping of square brackets around size 1 vectors is optional
|
179
|
+
@ftS5 = @ç.new s: [ 1 ], downstream: [ @p1 ]
|
180
|
+
# another alias for :codomain is :downstream_places
|
181
|
+
@ftS6 = @ç.new s: [ 1 ], downstream_places: [ @p1 ]
|
182
|
+
# and now, all of the above transitions...
|
183
|
+
@tt = @ftS1, @ftS2, @ftS3, @ftS4, @ftS5, @ftS6
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should work" do
|
187
|
+
# ...should be the same, having a single action arc:
|
188
|
+
assert @tt.all?{ |t| t.action_arcs == [ @p1 ] }
|
189
|
+
# timeless:
|
190
|
+
assert @tt.all?{ |t| t.timeless? }
|
191
|
+
# rateless:
|
192
|
+
assert @tt.all?{ |t| t.rateless? }
|
193
|
+
assert @tt.all?{ |t| not t.has_rate? }
|
194
|
+
# no assignment action
|
195
|
+
assert @tt.all?{ |t| not t.assignment_action? }
|
196
|
+
# not considered functional
|
197
|
+
assert @tt.all?{ |t| t.functionless? }
|
198
|
+
assert @tt.all?{ |t| not t.functional? }
|
199
|
+
# and having nullary action closure
|
200
|
+
assert @tt.all?{ |t| t.action_closure.arity == 0 }
|
201
|
+
# the transitions should be able to #fire!
|
202
|
+
@ftS1.fire!
|
203
|
+
# the difference is apparent: marking of place @p1 jumped to 2:
|
204
|
+
assert_equal 2, @p1.marking
|
205
|
+
# but should not #fire (no exclamation mark) unless cocked
|
206
|
+
assert !@ftS1.cocked?
|
207
|
+
@ftS1.fire
|
208
|
+
assert_equal 2, @p1.marking
|
209
|
+
# cock it
|
210
|
+
@ftS1.cock
|
211
|
+
assert @ftS1.cocked?
|
212
|
+
# uncock again, just to test cocking
|
213
|
+
@ftS1.uncock
|
214
|
+
assert @ftS1.uncocked?
|
215
|
+
@ftS1.cock
|
216
|
+
assert !@ftS1.uncocked?
|
217
|
+
@ftS1.fire
|
218
|
+
assert_equal 3, @p1.marking
|
219
|
+
# enough playing, we'll reset @p1 marking
|
220
|
+
@p1.reset_marking
|
221
|
+
assert_equal 1, @p1.marking
|
222
|
+
# #action
|
223
|
+
assert @tt.all?{ |t| t.action == [ 1 ] }
|
224
|
+
# #zero_action
|
225
|
+
assert @tt.all?{ |t| t.zero_action }
|
226
|
+
# #action_after_feasibility_check
|
227
|
+
assert @tt.all?{ |t| t.action_after_feasibility_check == [ 1 ] }
|
228
|
+
# #domain_marking
|
229
|
+
assert @tt.all?{ |t| t.domain_marking == [] }
|
230
|
+
# #codomain_marking
|
231
|
+
assert @tt.all?{ |t| t.codomain_marking == [ @p1.marking ] }
|
232
|
+
# #enabled?
|
233
|
+
assert @tt.all?{ |t| t.enabled? == true }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "functional tS transitions" do
|
238
|
+
|
239
|
+
# If function block is supplied to tS transitions, it governs
|
240
|
+
# their action based on marking of the domain places.
|
241
|
+
|
242
|
+
before do
|
243
|
+
# stoichiometric vector given as hash
|
244
|
+
@FtS1 = @ç.new action_closure: λ { 1 }, s: { @p1 => 1 }
|
245
|
+
# instead of :action_closure, just saying :action is enough
|
246
|
+
@FtS2 = @ç.new action: λ { 1 }, s: { @p1 => 1 }
|
247
|
+
# stoichiometric vector given as coeff. array + codomain
|
248
|
+
@FtS3 = @ç.new s: 1, codomain: @p1, action: λ { 1 }
|
249
|
+
# while saying timed: false and timeless: true should be ok
|
250
|
+
@FtS4 = @ç.new s: { @p1 => 1 }, action: λ { 1 }, timed: false
|
251
|
+
@FtS5 = @ç.new s: { @p1 => 1 }, action: λ { 1 }, timeless: true
|
252
|
+
# even both are ok
|
253
|
+
@FtS6 = @ç.new s: { @p1 => 1 }, action: λ { 1 }, timed: false, timeless: true
|
254
|
+
@tt = @FtS1, @FtS2, @FtS3, @FtS4, @FtS5, @FtS6
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should raise errors for bad parameters" do
|
258
|
+
# saying timed: true should raise a complaint:
|
259
|
+
assert_raises AErr do @ç.new sv: { @p1 => 1 }, action: λ{ 1 }, timed: true end
|
260
|
+
# same for saying timeless: false
|
261
|
+
assert_raises AErr do
|
262
|
+
@ç.new sv: { @p1 => 1 }, action: λ{ 1 }, timeless: false end
|
263
|
+
# while conflicting values will raise error
|
264
|
+
assert_raises AErr do
|
265
|
+
@ç.new sv: { @p1 => 1 }, action: λ { 1 }, timeless: true, timed: true
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should init and perform" do
|
270
|
+
assert @tt.all?{ |t| t.action_arcs == [ @p1 ] }
|
271
|
+
assert @tt.all?{ |t| t.timeless? }
|
272
|
+
assert @tt.all?{ |t| not t.has_rate? }
|
273
|
+
assert @tt.all?{ |t| t.rateless? }
|
274
|
+
assert @tt.all?{ |t| not t.assignment_action? }
|
275
|
+
assert @tt.all?{ |t| not t.functionless? }
|
276
|
+
assert @tt.all?{ |t| t.functional? }
|
277
|
+
# and having nullary action closure
|
278
|
+
assert @tt.all?{ |t| t.action_closure.arity == 0 }
|
279
|
+
# the transitions should be able to #fire!
|
280
|
+
@FtS1.fire!
|
281
|
+
# no need for more testing here
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "4. timed rateless stoichiometric (TSr) transitions" do
|
287
|
+
|
288
|
+
# Rateless stoichiometric transitions have action closure, and they
|
289
|
+
# require a function block, and thus are always functional. Their
|
290
|
+
# function block must take Δt as its first argument.
|
291
|
+
|
292
|
+
#LATER: To save time, I omit the tests of TSr transitions for now.
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "5. nonstoichiometric transitions with rate (sR transitions)" do
|
296
|
+
|
297
|
+
# They require a function block with arity equal to their domain, whose
|
298
|
+
# output is an array of rates of the size equal to that of codomain.
|
299
|
+
|
300
|
+
#LATER: To save time, I omit the full test suite.
|
301
|
+
end
|
302
|
+
|
303
|
+
describe "6. stoichiometric transitions with rate (SR transitions)" do
|
304
|
+
before do
|
305
|
+
# now this should give standard mass action by magic:
|
306
|
+
@SR1 = @ç.new s: { @p1 => -1, @p2 => -1, @p4 => 1 }, flux_closure: 0.1
|
307
|
+
# while this has custom flux closure
|
308
|
+
@SR2 = @ç.new s: { @p1 => -1, @p3 => 1 }, flux_closure: λ { |a| a * 0.5 }
|
309
|
+
# while this one even has domain specified:
|
310
|
+
@SR3 = @ç.new s: { @p1 => -1, @p2 => -1, @p4 => 1 }, upstream_arcs: @p3, flux: λ { |a| a * 0.5 }
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should init and work" do
|
314
|
+
assert_equal true, @SR1.has_rate?
|
315
|
+
assert_equal [ @p1, @p2 ], @SR1.upstream_arcs
|
316
|
+
assert_equal [ @p1, @p2, @p4 ], @SR1.action_arcs
|
317
|
+
assert_equal [ @p1 ], @SR2.domain
|
318
|
+
assert_equal [ @p1, @p3 ], @SR2.action_arcs
|
319
|
+
assert_equal [ @p3 ], @SR3.domain
|
320
|
+
assert_equal [ @p1, @p2, @p4 ], @SR3.action_arcs
|
321
|
+
# and flex them
|
322
|
+
@SR1.fire! 1.0
|
323
|
+
assert_equal [ 0.8, 1.8, 4.2 ], [ @p1, @p2, @p4 ].map( &:marking )
|
324
|
+
@SR2.fire! 1.0
|
325
|
+
assert_equal [ 0.4, 3.4 ], [ @p1, @p3 ].map( &:marking )
|
326
|
+
# the action t3 cannot fire with delta time 1.0
|
327
|
+
assert_raises RuntimeError do @SR3.fire! 1.0 end
|
328
|
+
assert_equal [ 0.4, 1.8, 3.4, 4.2 ], [ @p1, @p2, @p3, @p4 ].map( &:marking )
|
329
|
+
# but it can fire with eg. delta time 0.1
|
330
|
+
@SR3.fire! 0.1
|
331
|
+
assert_in_epsilon 0.23, @p1.marking, 1e-15
|
332
|
+
assert_in_epsilon 1.63, @p2.marking, 1e-15
|
333
|
+
assert_in_epsilon 3.4, @p3.marking, 1e-15
|
334
|
+
assert_in_epsilon 4.37, @p4.marking, 1e-15
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
# **************************************************************************
|
341
|
+
# Test of mutual knowedge of upstream/downstream arcs of places/transitions.
|
342
|
+
# **************************************************************************
|
343
|
+
#
|
344
|
+
describe "upstream and downstream reference mτs of places and transitions" do
|
345
|
+
before do
|
346
|
+
# skip "to speed up testing"
|
347
|
+
@tç = tç = Class.new ::YPetri::Transition
|
348
|
+
@pç = pç = Class.new ::YPetri::Place
|
349
|
+
[ tç, pç ].each { |ç|
|
350
|
+
ç.class_exec {
|
351
|
+
define_method :Place do pç end
|
352
|
+
define_method :Transition do tç end
|
353
|
+
private :Place, :Transition
|
354
|
+
}
|
355
|
+
}
|
356
|
+
@a = @pç.new( dflt_m: 1.0 )
|
357
|
+
@b = @pç.new( dflt_m: 2.0 )
|
358
|
+
@c = @pç.new( dflt_m: 3.0 )
|
359
|
+
end
|
360
|
+
|
361
|
+
describe "Place" do
|
362
|
+
it "should have #register_ustream/downstream_transition methods" do
|
363
|
+
@t1 = @tç.new s: {}
|
364
|
+
@a.instance_variable_get( :@upstream_arcs ).must_equal []
|
365
|
+
@a.instance_variable_get( :@downstream_arcs ).must_equal []
|
366
|
+
@a.send :register_upstream_transition, @t1
|
367
|
+
@a.instance_variable_get( :@upstream_arcs ).must_equal [ @t1 ]
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "upstream and downstream reference methods" do
|
372
|
+
before do
|
373
|
+
@t1 = @tç.new s: { @a => -1, @b => 1 }, rate: 1
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should show on the referencers" do
|
377
|
+
@a.upstream_arcs.must_equal [ @t1 ]
|
378
|
+
@b.downstream_arcs.must_equal [ ]
|
379
|
+
@b.ϝ.must_equal [ @t1 ]
|
380
|
+
@t1.upstream_arcs.must_equal [ @a ]
|
381
|
+
@t1.action_arcs.must_equal [ @a, @b ]
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
describe "assignment action transitions" do
|
386
|
+
before do
|
387
|
+
@p = @pç.new default_marking: 1.0
|
388
|
+
@t = @tç.new codomain: @p, action: λ { 1 }, assignment_action: true
|
389
|
+
end
|
390
|
+
|
391
|
+
it "should work" do
|
392
|
+
@p.marking = 3
|
393
|
+
assert_equal 3, @p.marking
|
394
|
+
assert @t.assignment_action?
|
395
|
+
assert_equal @t.domain, []
|
396
|
+
assert_equal 0, @t.action_closure.arity
|
397
|
+
@t.fire!
|
398
|
+
assert_equal 1, @p.marking
|
399
|
+
end
|
400
|
+
end # context assignment action transiotions
|
401
|
+
end
|
402
|
+
|
403
|
+
|
404
|
+
# **************************************************************************
|
405
|
+
# Test of Net class.
|
406
|
+
# **************************************************************************
|
407
|
+
#
|
408
|
+
describe ::YPetri::Net do
|
409
|
+
before do
|
410
|
+
# skip "to speed up testing"
|
411
|
+
@tç = tç = Class.new ::YPetri::Transition
|
412
|
+
@pç = pç = Class.new ::YPetri::Place
|
413
|
+
@nç = nç = Class.new ::YPetri::Net
|
414
|
+
[ tç, pç, nç ].each { |ç|
|
415
|
+
ç.class_exec {
|
416
|
+
define_method :Place do pç end
|
417
|
+
define_method :Transition do tç end
|
418
|
+
define_method :Net do nç end
|
419
|
+
private :Place, :Transition, :Net
|
420
|
+
}
|
421
|
+
}
|
422
|
+
@p1 = pç.new ɴ: "A", quantum: 0.1, marking: 1.1
|
423
|
+
@p2 = pç.new ɴ: "B", quantum: 0.1, marking: 2.2
|
424
|
+
@p3 = pç.new ɴ: "C", quantum: 0.1, marking: 3.3
|
425
|
+
@net = nç.new
|
426
|
+
[ @p1, @p2, @p3 ].each { |p| @net.include_place! p }
|
427
|
+
@p_not_included = pç.new ɴ: "X", m: 0
|
428
|
+
end
|
429
|
+
|
430
|
+
describe "net of 3 places and no transitions" do
|
431
|
+
before do
|
432
|
+
@p1.m = 1.1
|
433
|
+
@p2.m = 2.2
|
434
|
+
@p3.m = 3.3
|
435
|
+
end
|
436
|
+
|
437
|
+
it "should expose its elements" do
|
438
|
+
assert_equal [@p1, @p2, @p3], @net.places
|
439
|
+
assert_equal [:A, :B, :C], @net.pp
|
440
|
+
assert_equal [], @net.transitions
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should expose transition groups" do
|
444
|
+
assert_equal [], @net.transitions_with_rate
|
445
|
+
assert_equal [], @net.rateless_transitions
|
446
|
+
assert_equal [], @net.transitions_without_rate
|
447
|
+
assert_equal [], @net.stoichiometric_transitions
|
448
|
+
assert_equal [], @net.nonstoichiometric_transitions
|
449
|
+
end
|
450
|
+
|
451
|
+
it "should tell its qualities" do
|
452
|
+
assert_equal true, @net.functional?
|
453
|
+
assert_equal true, @net.timed?
|
454
|
+
assert @net.include?( @p1 ) && !@net.include?( nil )
|
455
|
+
end
|
456
|
+
|
457
|
+
it "should have 'standard equipment' methods" do
|
458
|
+
assert @net == @net.dup
|
459
|
+
assert @net.inspect.start_with? "#<Net:"
|
460
|
+
assert @net.include?( @p1 )
|
461
|
+
assert ! @net.include?( @p_not_included )
|
462
|
+
begin
|
463
|
+
@net.exclude_place! @p_not_included
|
464
|
+
@net.include_transition! YPetri::Transition.new( s: { @p_not_included => -1 } )
|
465
|
+
flunk "Attempt to include illegal transition fails to raise"
|
466
|
+
rescue; end
|
467
|
+
end
|
468
|
+
|
469
|
+
describe "plus 1 stoichio. transition with rate" do
|
470
|
+
before do
|
471
|
+
@t1 = @tç.new!( ɴ: "T1",
|
472
|
+
s: { @p1 => 1, @p2 => -1, @p3 => -1 },
|
473
|
+
rate: 0.01 )
|
474
|
+
@net.include_transition! @t1
|
475
|
+
end
|
476
|
+
|
477
|
+
it "should expose its elements" do
|
478
|
+
assert_equal [@t1], @net.transitions
|
479
|
+
assert_equal [:T1], @net.tt
|
480
|
+
end
|
481
|
+
|
482
|
+
it "should expose transition groups" do
|
483
|
+
assert_equal true, @t1.has_rate?
|
484
|
+
assert_equal [@t1], @net.transitions_with_rate
|
485
|
+
assert_equal [], @net.rateless_transitions
|
486
|
+
assert_equal [@t1], @net.stoichiometric_transitions
|
487
|
+
assert_equal [], @net.nonstoichiometric_transitions
|
488
|
+
end
|
489
|
+
|
490
|
+
it "should tell its qualities" do
|
491
|
+
assert_equal true, @net.functional?
|
492
|
+
assert_equal true, @net.timed?
|
493
|
+
assert @net.include?( @t1 )
|
494
|
+
end
|
495
|
+
|
496
|
+
it "should have #place & #transition for safe access to the said elements" do
|
497
|
+
@net.send( :place, @p1 ).must_equal @p1
|
498
|
+
@net.send( :transition, @t1 ).must_equal @t1
|
499
|
+
end
|
500
|
+
|
501
|
+
it "has #new_simulation & #new_timed_simulation constructors" do
|
502
|
+
@net.must_respond_to :new_simulation
|
503
|
+
@net.must_respond_to :new_timed_simulation
|
504
|
+
end
|
505
|
+
|
506
|
+
it "should have other methods" do
|
507
|
+
assert_equal [1.1, 2.2, 3.3], [@p1, @p2, @p3].map( &:marking ).map{ |n| n.round 6 }
|
508
|
+
assert_equal 2.2 * 3.3 * 0.01, @t1.rate_closure.call( @p2.marking, @p3.marking )
|
509
|
+
assert_equal [ @p2, @p3 ], @t1.domain
|
510
|
+
@t1.fire! 1
|
511
|
+
assert_equal [1.1726, 2.1274, 3.2274], [@p1, @p2, @p3].map( &:marking ).map{ |n| n.round 6 }
|
512
|
+
end
|
513
|
+
|
514
|
+
describe "plus 1 more nameless timeless functionless transition" do
|
515
|
+
before do
|
516
|
+
@t2 = @tç.new s: { @p2 => -1, @p3 => 1 }
|
517
|
+
@net.include_transition! @t2
|
518
|
+
end
|
519
|
+
|
520
|
+
it "should expose its elements" do
|
521
|
+
assert_equal [@t1, @t2], @net.transitions
|
522
|
+
assert_equal [:T1, nil], @net.tt
|
523
|
+
@net.tap{ |n| n.exclude_transition! @t1 }.exclude_transition! @t2
|
524
|
+
@net.tap{ |n| n.exclude_place! @p3 }.pp.must_equal [:A, :B]
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should expose transition groups" do
|
528
|
+
assert_equal [], @net.timeless_nonstoichiometric_transitions
|
529
|
+
assert_equal [], @net.timeless_nonstoichiometric_tt
|
530
|
+
assert_equal [@t2], @net.timeless_stoichiometric_transitions
|
531
|
+
assert_equal [nil], @net.timeless_stoichiometric_tt
|
532
|
+
assert_equal [], @net.timed_nonstoichiometric_transitions_without_rate
|
533
|
+
assert_equal [], @net.timed_rateless_nonstoichiometric_transitions
|
534
|
+
assert_equal [], @net.timed_nonstoichiometric_tt_without_rate
|
535
|
+
assert_equal [], @net.timed_rateless_nonstoichiometric_tt
|
536
|
+
assert_equal [], @net.timed_nonstoichiometric_transitions_without_rate
|
537
|
+
assert_equal [], @net.timed_rateless_nonstoichiometric_transitions
|
538
|
+
assert_equal [], @net.timed_nonstoichiometric_tt_without_rate
|
539
|
+
assert_equal [], @net.timed_rateless_nonstoichiometric_tt
|
540
|
+
assert_equal [], @net.nonstoichiometric_transitions_with_rate
|
541
|
+
assert_equal [], @net.nonstoichiometric_tt_with_rate
|
542
|
+
assert_equal [@t1], @net.stoichiometric_transitions_with_rate
|
543
|
+
assert_equal [:T1], @net.stoichiometric_tt_with_rate
|
544
|
+
assert_equal [], @net.transitions_with_explicit_assignment_action
|
545
|
+
assert_equal [], @net.transitions_with_assignment_action
|
546
|
+
assert_equal [], @net.assignment_transitions
|
547
|
+
assert_equal [], @net.tt_with_explicit_assignment_action
|
548
|
+
assert_equal [], @net.tt_with_assignment_action
|
549
|
+
assert_equal [], @net.assignment_tt
|
550
|
+
assert_equal [@t1, @t2], @net.stoichiometric_transitions
|
551
|
+
assert_equal [:T1, nil], @net.stoichiometric_tt
|
552
|
+
assert_equal [], @net.nonstoichiometric_transitions
|
553
|
+
assert_equal [], @net.nonstoichiometric_tt
|
554
|
+
assert_equal [@t1], @net.timed_transitions
|
555
|
+
assert_equal [:T1], @net.timed_tt
|
556
|
+
assert_equal [@t2], @net.timeless_transitions
|
557
|
+
assert_equal [nil], @net.timeless_tt
|
558
|
+
assert_equal [@t1], @net.transitions_with_rate
|
559
|
+
assert_equal [:T1], @net.tt_with_rate
|
560
|
+
assert_equal [@t2], @net.rateless_transitions
|
561
|
+
assert_equal [nil], @net.rateless_tt
|
562
|
+
end
|
563
|
+
|
564
|
+
it "should tell its qualities" do
|
565
|
+
assert_equal false, @net.functional?
|
566
|
+
assert_equal false, @net.timed?
|
567
|
+
@net.exclude_transition! @t2
|
568
|
+
assert_equal true, @net.functional?
|
569
|
+
assert_equal true, @net.timed?
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
|
577
|
+
# **************************************************************************
|
578
|
+
# Test of Simulation class.
|
579
|
+
# **************************************************************************
|
580
|
+
#
|
581
|
+
describe ::YPetri::Simulation do
|
582
|
+
before do
|
583
|
+
# skip "to make the testing faster"
|
584
|
+
@pç = pç = Class.new( ::YPetri::Place )
|
585
|
+
@tç = tç = Class.new( ::YPetri::Transition )
|
586
|
+
@nç = nç = Class.new( ::YPetri::Net )
|
587
|
+
[ @pç, @tç, @nç ].each { |klass|
|
588
|
+
klass.class_exec {
|
589
|
+
private
|
590
|
+
define_method :Place do pç end
|
591
|
+
define_method :Transition do tç end
|
592
|
+
define_method :Net do nç end
|
593
|
+
}
|
594
|
+
}
|
595
|
+
@p1 = @pç.new name: "P1", default_marking: 1
|
596
|
+
@p2 = @pç.new name: "P2", default_marking: 2
|
597
|
+
@p3 = @pç.new name: "P3", default_marking: 3
|
598
|
+
@p4 = @pç.new name: "P4", default_marking: 4
|
599
|
+
@p5 = @pç.new name: "P5", default_marking: 5
|
600
|
+
@t1 = @tç.new name: "T1",
|
601
|
+
s: { @p1 => -1, @p2 => -1, @p4 => 1 },
|
602
|
+
flux_closure: 0.1
|
603
|
+
@t2 = @tç.new name: "T2",
|
604
|
+
s: { @p1 => -1, @p3 => 1 },
|
605
|
+
flux_closure: λ { |a| a * 0.5 }
|
606
|
+
@t3 = @tç.new name: "T3",
|
607
|
+
s: { @p1 => -1, @p2 => -1, @p4 => 1 },
|
608
|
+
domain: @p3, flux: λ { |a| a * 0.5 }
|
609
|
+
@net = @nç.new << @p1 << @p2 << @p3 << @p4 << @p5
|
610
|
+
@net.include_transition! @t1
|
611
|
+
@net.include_transition! @t2
|
612
|
+
@net << @t3
|
613
|
+
@s = YPetri::Simulation.new net: @net,
|
614
|
+
place_clamps: { @p1 => 2.0, @p5 => 2.0 },
|
615
|
+
initial_marking: { @p2 => @p2.default_marking,
|
616
|
+
@p3 => @p3.default_marking,
|
617
|
+
@p4 => @p4.default_marking }
|
618
|
+
end
|
619
|
+
|
620
|
+
it "exposes the net" do
|
621
|
+
@s.net.must_equal @net
|
622
|
+
@s.net.places.size.must_equal 5
|
623
|
+
@s.net.transitions.size.must_equal 3
|
624
|
+
assert @net.include? @t1
|
625
|
+
assert @s.net.include? @t1
|
626
|
+
assert @net.include? @t2
|
627
|
+
assert @s.net.include? @t2
|
628
|
+
assert @net.include? @t3
|
629
|
+
assert @s.net.include? @t3
|
630
|
+
@s.net.transitions.size.must_equal 3
|
631
|
+
end
|
632
|
+
|
633
|
+
it "exposes Petri net places" do
|
634
|
+
@s.places.must_equal [ @p1, @p2, @p3, @p4, @p5 ]
|
635
|
+
@s.pp.must_equal [ :P1, :P2, :P3, :P4, :P5 ]
|
636
|
+
@s.places( :pp ).must_equal( { @p1 => :P1, @p2 => :P2, @p3 => :P3,
|
637
|
+
@p4 => :P4, @p5 => :P5 } )
|
638
|
+
@s.pp( :pp ).must_equal( { P1: :P1, P2: :P2, P3: :P3, P4: :P4, P5: :P5 } )
|
639
|
+
end
|
640
|
+
|
641
|
+
it "exposes Petri net transitions" do
|
642
|
+
@s.transitions.must_equal [ @t1, @t2, @t3 ]
|
643
|
+
@s.tt.must_equal [ :T1, :T2, :T3 ]
|
644
|
+
@s.transitions( :tt ).must_equal( { @t1 => :T1, @t2 => :T2, @t3 => :T3 } )
|
645
|
+
@s.tt( :tt ).must_equal( { T1: :T1, T2: :T2, T3: :T3 } )
|
646
|
+
end
|
647
|
+
|
648
|
+
it "exposes place clamps" do
|
649
|
+
@s.clamped_places( :place_clamps ).must_equal( { @p1 => 2, @p5 => 2 } )
|
650
|
+
@s.clamped_pp( :place_clamps ).must_equal( { P1: 2, P5: 2 } )
|
651
|
+
end
|
652
|
+
|
653
|
+
it "presents free places" do
|
654
|
+
@s.free_places.must_equal [ @p2, @p3, @p4 ]
|
655
|
+
@s.free_pp.must_equal [ :P2, :P3, :P4 ]
|
656
|
+
@s.free_places( :free_pp )
|
657
|
+
.must_equal( { @p2 => :P2, @p3 => :P3, @p4 => :P4 } )
|
658
|
+
@s.free_pp( :free_pp )
|
659
|
+
.must_equal( { P2: :P2, P3: :P3, P4: :P4 } )
|
660
|
+
end
|
661
|
+
|
662
|
+
it "presents clamped places" do
|
663
|
+
@s.clamped_places.must_equal [ @p1, @p5 ]
|
664
|
+
@s.clamped_pp.must_equal [ :P1, :P5 ]
|
665
|
+
@s.clamped_places( :clamped_pp ).must_equal( { @p1 => :P1, @p5 => :P5 } )
|
666
|
+
@s.clamped_pp( :clamped_pp ).must_equal( { P1: :P1, P5: :P5 } )
|
667
|
+
end
|
668
|
+
|
669
|
+
it "exposes initial marking" do
|
670
|
+
@s.free_places( :im ).must_equal( { @p2 => 2, @p3 => 3, @p4 => 4 } )
|
671
|
+
@s.free_pp( :im ).must_equal( { P2: 2, P3: 3, P4: 4 } )
|
672
|
+
@s.im.must_equal [ 2, 3, 4 ]
|
673
|
+
@s.im_vector.must_equal Matrix[[2], [3], [4]]
|
674
|
+
@s.im_vector.must_equal @s.iᴍ
|
675
|
+
end
|
676
|
+
|
677
|
+
it "exposes marking (simulation state)" do
|
678
|
+
@s.m.must_equal [2, 3, 4] # (we're after reset)
|
679
|
+
@s.free_places( :m ).must_equal( { @p2 => 2, @p3 => 3, @p4 => 4 } )
|
680
|
+
@s.free_pp( :m ).must_equal( { P2: 2, P3: 3, P4: 4 } )
|
681
|
+
@s.ᴍ.must_equal Matrix[[2], [3], [4]]
|
682
|
+
end
|
683
|
+
|
684
|
+
it "separately exposes marking of clamped places" do
|
685
|
+
@s.m_clamped.must_equal [ 2, 2 ]
|
686
|
+
@s.clamped_places( :m_clamped ).must_equal( { @p1 => 2, @p5 => 2 } )
|
687
|
+
@s.clamped_pp( :m_clamped ).must_equal( { P1: 2, P5: 2 } )
|
688
|
+
@s.ᴍ_clamped.must_equal Matrix[[2], [2]]
|
689
|
+
end
|
690
|
+
|
691
|
+
it "exposes marking of all places (with capitalized M)" do
|
692
|
+
@s.marking.must_equal [ 2, 2, 3, 4, 2 ]
|
693
|
+
@s.places( :marking )
|
694
|
+
.must_equal( { @p1 => 2, @p2 => 2, @p3 => 3, @p4 => 4, @p5 => 2 } )
|
695
|
+
@s.pp( :marking ).must_equal( { P1: 2, P2: 2, P3: 3, P4: 4, P5: 2 } )
|
696
|
+
@s.marking_vector.must_equal Matrix[[2], [2], [3], [4], [2]]
|
697
|
+
end
|
698
|
+
|
699
|
+
it "has #S_for / #stoichiometry_matrix_for" do
|
700
|
+
assert_equal Matrix.empty(3, 0), @s.S_for( [] )
|
701
|
+
assert_equal Matrix[[-1], [0], [1]], @s.S_for( [@t1] )
|
702
|
+
x = Matrix[[-1, -1], [0, 0], [1, 1]]
|
703
|
+
x.must_equal @s.S_for( [@t1, @t3] )
|
704
|
+
x.must_equal( @s.S_for( [@t1, @t3] ) )
|
705
|
+
@s.stoichiometry_matrix_for( [] ).must_equal Matrix.empty( 5, 0 )
|
706
|
+
end
|
707
|
+
|
708
|
+
it "has stoichiometry matrix for 3. tS transitions" do
|
709
|
+
@s.S_for_tS.must_equal Matrix.empty( 3, 0 )
|
710
|
+
end
|
711
|
+
|
712
|
+
it "has stoichiometry matrix for 4. Sr transitions" do
|
713
|
+
@s.S_for_TSr.must_equal Matrix.empty( 3, 0 )
|
714
|
+
end
|
715
|
+
|
716
|
+
it "has stoichiometry matrix for 6. SR transitions" do
|
717
|
+
@s.S_for_SR.must_equal Matrix[[-1, 0, -1], [0, 1, 0], [1, 0, 1]]
|
718
|
+
@s.S.must_equal @s.S_for_SR
|
719
|
+
end
|
720
|
+
|
721
|
+
it "presents 1. ts" do
|
722
|
+
assert_equal [], @s.ts_transitions
|
723
|
+
assert_equal( {}, @s.ts_transitions( :ts_transitions ) )
|
724
|
+
assert_equal [], @s.ts_tt
|
725
|
+
assert_equal( {}, @s.ts_tt( :ts_tt ) )
|
726
|
+
end
|
727
|
+
|
728
|
+
it "presents 2. tS transitions" do
|
729
|
+
assert_equal [], @s.tS_transitions
|
730
|
+
assert_equal( {}, @s.tS_transitions( :tS_transitions ) )
|
731
|
+
assert_equal [], @s.tS_tt
|
732
|
+
assert_equal( {}, @s.tS_tt( :tS_tt ) )
|
733
|
+
end
|
734
|
+
|
735
|
+
it "presents 3. Tsr transitions" do
|
736
|
+
assert_equal [], @s.Tsr_transitions
|
737
|
+
assert_equal( {}, @s.Tsr_transitions( :Tsr_transitions ) )
|
738
|
+
assert_equal [], @s.Tsr_tt
|
739
|
+
assert_equal( {}, @s.Tsr_tt( :Tsr_tt ) )
|
740
|
+
end
|
741
|
+
|
742
|
+
it "presents 4. TSr transitions" do
|
743
|
+
assert_equal [], @s.TSr_transitions
|
744
|
+
assert_equal( {}, @s.TSr_transitions( :TSr_tt ) )
|
745
|
+
assert_equal [], @s.TSr_tt
|
746
|
+
assert_equal( {}, @s.TSr_tt( :TSr_tt ) )
|
747
|
+
end
|
748
|
+
|
749
|
+
it "presents 5. sR transitions" do
|
750
|
+
assert_equal [], @s.sR_transitions
|
751
|
+
assert_equal( {}, @s.sR_transitions( :sR_transitions ) )
|
752
|
+
assert_equal [], @s.sR_tt
|
753
|
+
assert_equal( {}, @s.sR_tt( :sR_tt ) )
|
754
|
+
end
|
755
|
+
|
756
|
+
it "presents SR transitions" do
|
757
|
+
assert_equal [@t1, @t2, @t3], @s.SR_transitions
|
758
|
+
assert_equal( { @t1 => :T1, @t2 => :T2, @t3 => :T3 },
|
759
|
+
@s.SR_transitions( :SR_tt ) )
|
760
|
+
assert_equal [:T1, :T2, :T3], @s.SR_tt
|
761
|
+
assert_equal( { T1: :T1, T2: :T2, T3: :T3 }, @s.SR_tt( :SR_tt ) )
|
762
|
+
end
|
763
|
+
|
764
|
+
it "presents A transitions" do
|
765
|
+
assert_equal [], @s.A_transitions
|
766
|
+
assert_equal( {}, @s.A_transitions( :A_tt ) )
|
767
|
+
assert_equal [], @s.A_tt
|
768
|
+
assert_equal( {}, @s.A_tt( :A_tt ) )
|
769
|
+
end
|
770
|
+
|
771
|
+
it "presents S transitions" do
|
772
|
+
assert_equal [@t1, @t2, @t3], @s.S_transitions
|
773
|
+
assert_equal [:T1, :T2, :T3], @s.S_tt
|
774
|
+
assert_equal( { T1: :T1, T2: :T2, T3: :T3 }, @s.S_tt( :S_tt ) )
|
775
|
+
end
|
776
|
+
|
777
|
+
it "presents s transitions" do
|
778
|
+
assert_equal [], @s.s_transitions
|
779
|
+
assert_equal [], @s.s_tt
|
780
|
+
assert_equal( {}, @s.s_tt( :s_tt ) )
|
781
|
+
end
|
782
|
+
|
783
|
+
it "presents R transitions" do
|
784
|
+
assert_equal [@t1, @t2, @t3], @s.R_transitions
|
785
|
+
assert_equal [:T1, :T2, :T3], @s.R_tt
|
786
|
+
assert_equal( { T1: :T1, T2: :T2, T3: :T3 }, @s.R_tt( :R_tt ) )
|
787
|
+
end
|
788
|
+
|
789
|
+
it "presents r transitions" do
|
790
|
+
assert_equal [], @s.r_transitions
|
791
|
+
assert_equal [], @s.r_tt
|
792
|
+
end
|
793
|
+
|
794
|
+
it "1. handles ts transitions" do
|
795
|
+
@s.Δ_closures_for_ts.must_equal []
|
796
|
+
@s.Δ_if_ts_fire_once.must_equal Matrix.zero( @s.free_pp.size, 1 )
|
797
|
+
end
|
798
|
+
|
799
|
+
it "2. handles Tsr transitions" do
|
800
|
+
@s.Δ_closures_for_Tsr.must_equal []
|
801
|
+
@s.Δ_for_Tsr( 1.0 ).must_equal Matrix.zero( @s.free_pp.size, 1 )
|
802
|
+
end
|
803
|
+
|
804
|
+
it "3. handles tS transitions" do
|
805
|
+
@s.action_closures_for_tS.must_equal []
|
806
|
+
@s.action_vector_for_tS.must_equal Matrix.column_vector( [] )
|
807
|
+
@s.α_for_t.must_equal Matrix.column_vector( [] )
|
808
|
+
@s.Δ_if_tS_fire_once.must_equal Matrix.zero( @s.free_pp.size, 1 )
|
809
|
+
end
|
810
|
+
|
811
|
+
it "4. handles TSr transitions" do
|
812
|
+
@s.action_closures_for_TSr.must_equal []
|
813
|
+
@s.action_closures_for_Tr.must_equal []
|
814
|
+
@s.action_vector_for_TSr( 1.0 ).must_equal Matrix.column_vector( [] )
|
815
|
+
@s.action_vector_for_Tr( 1.0 ).must_equal Matrix.column_vector( [] )
|
816
|
+
@s.Δ_for_TSr( 1.0 ).must_equal Matrix.zero( @s.free_pp.size, 1 )
|
817
|
+
end
|
818
|
+
|
819
|
+
it "5. handles sR transitions" do
|
820
|
+
assert_equal [], @s.rate_closures_for_sR
|
821
|
+
assert_equal [], @s.rate_closures_for_s
|
822
|
+
@s.gradient_for_sR.must_equal Matrix.zero( @s.free_pp.size, 1 )
|
823
|
+
@s.Δ_Euler_for_sR( 1.0 ).must_equal Matrix.zero( @s.free_pp.size, 1 )
|
824
|
+
end
|
825
|
+
|
826
|
+
it "6. handles stoichiometric transitions with rate" do
|
827
|
+
@s.rate_closures_for_SR.size.must_equal 3
|
828
|
+
@s.rate_closures_for_S.size.must_equal 3
|
829
|
+
@s.rate_closures.size.must_equal 3
|
830
|
+
@s.flux_vector_for_SR.must_equal Matrix.column_vector( [ 0.4, 1.0, 1.5 ] )
|
831
|
+
@s.φ_for_SR.must_equal @s.flux_vector
|
832
|
+
@s.SR_tt( :φ_for_SR ).must_equal( { T1: 0.4, T2: 1.0, T3: 1.5 } )
|
833
|
+
@s.Euler_action_vector_for_SR( 1 )
|
834
|
+
.must_equal Matrix.column_vector [ 0.4, 1.0, 1.5 ]
|
835
|
+
@s.SR_tt( :Euler_action_for_SR, 1 ).must_equal( T1: 0.4, T2: 1.0, T3: 1.5 )
|
836
|
+
@s.Δ_Euler_for_SR( 1 ).must_equal Matrix[[-1.9], [1.0], [1.9]]
|
837
|
+
@s.free_pp( :Δ_Euler_for_SR, 1 ).must_equal( { P2: -1.9, P3: 1.0, P4: 1.9 } )
|
838
|
+
end
|
839
|
+
|
840
|
+
it "presents sparse stoichiometry vectors for its transitions" do
|
841
|
+
@s.sparse_σ( @t1 ).must_equal Matrix.cv( [-1, 0, 1] )
|
842
|
+
@s.sparse_stoichiometry_vector( @t1 )
|
843
|
+
.must_equal Matrix.cv( [-1, -1, 0, 1, 0] )
|
844
|
+
end
|
845
|
+
|
846
|
+
it "presents correspondence matrices free, clamped => all places" do
|
847
|
+
@s.F2A.must_equal Matrix[[0, 0, 0], [1, 0, 0], [0, 1, 0],
|
848
|
+
[0, 0, 1], [0, 0, 0]]
|
849
|
+
@s.C2A.must_equal Matrix[[1, 0], [0, 0], [0, 0], [0, 0], [0, 1]]
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
|
854
|
+
# **************************************************************************
|
855
|
+
# Test of TimedSimulation class.
|
856
|
+
# **************************************************************************
|
857
|
+
#
|
858
|
+
describe ::YPetri::TimedSimulation do
|
859
|
+
before do
|
860
|
+
# skip "to speed up testing"
|
861
|
+
@a = ::YPetri::Place.new default_marking: 1.0
|
862
|
+
@b = ::YPetri::Place.new default_marking: 2.0
|
863
|
+
@c = ::YPetri::Place.new default_marking: 3.0
|
864
|
+
end
|
865
|
+
|
866
|
+
describe "timed assembly a + b >> c" do
|
867
|
+
before do
|
868
|
+
@t1 = ::YPetri::Transition.new s: { @a => -1, @b => -1, @c => 1 }, rate: 0.1
|
869
|
+
@net = ::YPetri::Net.new << @a << @b << @c << @t1
|
870
|
+
@im_collection = [@a, @b, @c].τBmχHτ &:default_marking
|
871
|
+
end
|
872
|
+
|
873
|
+
describe "simulation with step size 1" do
|
874
|
+
before do
|
875
|
+
@sim = ::YPetri::TimedSimulation.new net: @net,
|
876
|
+
initial_marking: @im_collection,
|
877
|
+
step: 1,
|
878
|
+
sampling: 10,
|
879
|
+
target_time: 100
|
880
|
+
end
|
881
|
+
|
882
|
+
it "should #step! with expected results" do
|
883
|
+
m = @sim.step!.marking
|
884
|
+
assert_in_delta 0.8, m[ 0 ], 1e-9
|
885
|
+
assert_in_delta 1.8, m[ 1 ], 1e-9
|
886
|
+
assert_in_delta 3.2, m[ 2 ], 1e-9
|
887
|
+
end
|
888
|
+
|
889
|
+
it "should behave" do
|
890
|
+
assert_in_delta 0, ( Matrix.column_vector( [-0.02, -0.02, 0.02] ) -
|
891
|
+
@sim.ΔE( 0.1 ) ).column( 0 ).norm, 1e-9
|
892
|
+
@sim.step! 0.1
|
893
|
+
assert_in_delta 0, ( Matrix.column_vector( [0.98, 1.98, 3.02] ) -
|
894
|
+
@sim.marking_vector ).column( 0 ).norm, 1e-9
|
895
|
+
|
896
|
+
end
|
897
|
+
end
|
898
|
+
|
899
|
+
describe "simulation with step size 0.1" do
|
900
|
+
before do
|
901
|
+
@sim = ::YPetri::TimedSimulation.new net: @net,
|
902
|
+
initial_marking: @im_collection,
|
903
|
+
step: 0.1,
|
904
|
+
sampling: 10,
|
905
|
+
target_time: 100
|
906
|
+
end
|
907
|
+
|
908
|
+
it "should behave" do
|
909
|
+
m = @sim.step!.marking
|
910
|
+
assert_equal 10, @sim.sampling_period
|
911
|
+
assert_in_delta 0.98, m[ 0 ], 1e-9
|
912
|
+
assert_in_delta 1.98, m[ 1 ], 1e-9
|
913
|
+
assert_in_delta 3.02, m[ 2 ], 1e-9
|
914
|
+
end
|
915
|
+
|
916
|
+
it "should behave" do
|
917
|
+
@sim.run_until_target_time! 31
|
918
|
+
expected_recording = {
|
919
|
+
0 => [ 1, 2, 3 ],
|
920
|
+
10 => [ 0.22265, 1.22265, 3.77735 ],
|
921
|
+
20 => [ 0.07131, 1.07131, 3.92869 ],
|
922
|
+
30 => [ 0.02496, 1.02496, 3.97503 ]
|
923
|
+
}
|
924
|
+
assert_equal expected_recording.keys, @sim.recording.keys
|
925
|
+
assert_in_delta 0, expected_recording.values.zip( @sim.recording.values )
|
926
|
+
.map{ |expected, actual| ( Vector[ *expected ] -
|
927
|
+
Vector[ *actual ] ).norm }.reduce( :+ ), 1e-4
|
928
|
+
expected_recording_string =
|
929
|
+
"0.0,1.0,2.0,3.0\n" +
|
930
|
+
"10.0,0.22265,1.22265,3.77735\n" +
|
931
|
+
"20.0,0.07131,1.07131,3.92869\n" +
|
932
|
+
"30.0,0.02496,1.02496,3.97504\n"
|
933
|
+
assert_equal expected_recording_string, @sim.recording_csv_string
|
934
|
+
end
|
935
|
+
end
|
936
|
+
end
|
937
|
+
|
938
|
+
describe "timed 'isomerization' with flux given as λ" do
|
939
|
+
before do
|
940
|
+
@t2 = ::YPetri::Transition.new s: { @a => -1, @c => 1 },
|
941
|
+
rate_closure: λ { |a| a * 0.5 }
|
942
|
+
@net = ::YPetri::Net.new << @a << @b << @c << @t2
|
943
|
+
end
|
944
|
+
|
945
|
+
describe "behavior of #step" do
|
946
|
+
before do
|
947
|
+
@sim = ::YPetri::TimedSimulation.new net: @net,
|
948
|
+
initial_marking: [ @a, @b, @c ].τBᴍHτ( &:default_marking ),
|
949
|
+
step: 1,
|
950
|
+
sampling: 10
|
951
|
+
end
|
952
|
+
|
953
|
+
it "should have expected stoichiometry matrix" do
|
954
|
+
@sim.S.must_equal Matrix[ [-1, 0, 1] ].t
|
955
|
+
m = @sim.step!.marking
|
956
|
+
m[ 0 ].must_be_within_epsilon( 0.5, 1e-6 )
|
957
|
+
m[ 1 ].must_equal 2
|
958
|
+
m[ 2 ].must_be_within_delta( 3.5, 1e-9 )
|
959
|
+
end
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
describe "timed controlled isomerization" do
|
964
|
+
before do
|
965
|
+
@t3 = ::YPetri::Transition.new s: { @a => -1, @c => 1 },
|
966
|
+
domain: @b,
|
967
|
+
rate: λ { |a| a * 0.5 }
|
968
|
+
@net = ::YPetri::Net.new << @a << @b << @c << @t3
|
969
|
+
@sim = ::YPetri::TimedSimulation.new net: @net,
|
970
|
+
initial_marking: { @a => 1, @b => 0.6, @c => 3 },
|
971
|
+
step: 1,
|
972
|
+
sampling: 10,
|
973
|
+
target_time: 2
|
974
|
+
end
|
975
|
+
|
976
|
+
it "should exhibit correct behavior of #step" do
|
977
|
+
@sim.marking.must_equal [1.0, 0.6, 3.0]
|
978
|
+
@t3.stoichiometric?.must_equal true
|
979
|
+
@t3.timed?.must_equal true
|
980
|
+
@t3.has_rate?.must_equal true
|
981
|
+
@sim.gradient.must_equal Matrix.cv [-0.3, 0.0, 0.3]
|
982
|
+
@sim.Δ_Euler.must_equal Matrix.cv [-0.3, 0.0, 0.3]
|
983
|
+
@sim.step!
|
984
|
+
@sim.marking_vector.must_equal Matrix.cv [0.7, 0.6, 3.3]
|
985
|
+
@sim.euler_step!
|
986
|
+
@sim.run!
|
987
|
+
@sim.marking_vector.map( &[:round, 5] )
|
988
|
+
.must_equal Matrix.cv [0.4, 0.6, 3.6]
|
989
|
+
end
|
990
|
+
end
|
991
|
+
end
|
992
|
+
|
993
|
+
|
994
|
+
# **************************************************************************
|
995
|
+
# Test of Workspace class.
|
996
|
+
# **************************************************************************
|
997
|
+
#
|
998
|
+
describe ::YPetri::Workspace do
|
999
|
+
before do
|
1000
|
+
# skip "to speed up testing"
|
1001
|
+
@w = ::YPetri::Workspace.new
|
1002
|
+
a = @w.Place.new!( default_marking: 1.0, name: "AA" )
|
1003
|
+
b = @w.Place.new!( default_marking: 2.0, name: "BB" )
|
1004
|
+
c = @w.Place.new!( ɴ: "CC", default_marking: 3.0 )
|
1005
|
+
t1 = @w.Transition.new! s: { a => -1, b => -1, c => 1 },
|
1006
|
+
rate: 0.1,
|
1007
|
+
ɴ: "AA_BB_assembly"
|
1008
|
+
t2 = @w.Transition.new! ɴ: "AA_appearing",
|
1009
|
+
codomain: a,
|
1010
|
+
rate: λ{ 0.1 },
|
1011
|
+
stoichiometry: 1
|
1012
|
+
@pp, @tt = [a, b, c], [t1, t2]
|
1013
|
+
@f_name = "test_output.csv"
|
1014
|
+
@w.set_imc @pp.τBᴍHτ( &:default_marking )
|
1015
|
+
@w.set_ssc step: 0.1, sampling: 10, target_time: 50
|
1016
|
+
@w.set_cc( {} )
|
1017
|
+
@sim = @w.new_timed_simulation
|
1018
|
+
File.delete @f_name rescue nil
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
it "should present places, transitions, nets, simulations" do
|
1022
|
+
assert_kind_of ::YPetri::Net, @w.Net::Top
|
1023
|
+
assert_equal @pp[0], @w.place( "AA" )
|
1024
|
+
assert_equal :AA, @w.p( @pp[0] )
|
1025
|
+
assert_equal @tt[0], @w.transition( "AA_BB_assembly" )
|
1026
|
+
assert_equal :AA_appearing, @w.t( @tt[1] )
|
1027
|
+
assert_equal @pp, @w.places
|
1028
|
+
assert_equal @tt, @w.transitions
|
1029
|
+
assert_equal 1, @w.nets.size
|
1030
|
+
assert_equal 1, @w.simulations.size
|
1031
|
+
assert_equal 0, @w.cc.size
|
1032
|
+
assert_equal 3, @w.imc.size
|
1033
|
+
assert [0.1, 10, 50].each { |e| @w.ssc.include? e }
|
1034
|
+
assert_equal @sim, @w.simulation
|
1035
|
+
assert_equal [:Base], @w.clamp_collections.keys
|
1036
|
+
assert_equal [:Base], @w.initial_marking_collections.keys
|
1037
|
+
assert_equal [:Base], @w.simulation_settings_collections.keys
|
1038
|
+
assert_equal [:AA, :BB, :CC], @w.pp
|
1039
|
+
assert_equal [:AA_BB_assembly, :AA_appearing], @w.tt
|
1040
|
+
assert_equal [:Top], @w.nn
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
it "should simulate" do
|
1044
|
+
assert_equal 1, @w.simulations.size
|
1045
|
+
assert_kind_of( ::YPetri::Simulation, @w.simulation )
|
1046
|
+
assert_equal 2, @w.simulation.SR_transitions.size
|
1047
|
+
@tt[0].domain.must_equal [ @pp[0], @pp[1] ]
|
1048
|
+
@tt[1].domain.must_equal []
|
1049
|
+
assert_equal [0.2, 0.1], @w.simulation.φ.column_to_a
|
1050
|
+
@w.simulation.step!
|
1051
|
+
@w.simulation.run!
|
1052
|
+
rec_string = @w.simulation.recording_csv_string
|
1053
|
+
expected_recording_string =
|
1054
|
+
"0.0,1.0,2.0,3.0\n" +
|
1055
|
+
"10.0,0.86102,0.86102,4.13898\n" +
|
1056
|
+
"20.0,1.29984,0.29984,4.70016\n"
|
1057
|
+
assert rec_string.start_with?( expected_recording_string )
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
# **************************************************************************
|
1062
|
+
# Test of Manipulator class.
|
1063
|
+
# **************************************************************************
|
1064
|
+
#
|
1065
|
+
describe ::YPetri::Manipulator do
|
1066
|
+
before do
|
1067
|
+
# skip "for now"
|
1068
|
+
@m = ::YPetri::Manipulator.new
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
it "has net basic points" do
|
1072
|
+
# --- net point related assets ---
|
1073
|
+
@m.net_point_reset
|
1074
|
+
@m.net_point_to @m.workspace.net( :Top )
|
1075
|
+
@m.net.must_equal @m.workspace.Net::Top
|
1076
|
+
# --- simulation point related assets ---
|
1077
|
+
@m.simulation_point_reset
|
1078
|
+
@m.simulation_point_to nil
|
1079
|
+
@m.simulation.must_equal nil
|
1080
|
+
@m.simulation_point_position.must_equal nil
|
1081
|
+
# --- cc point related assets ---
|
1082
|
+
@m.cc_point_reset
|
1083
|
+
@m.cc_point_to :Base
|
1084
|
+
@m.cc.must_equal @m.workspace.clamp_collection
|
1085
|
+
@m.cc.wont_equal :Base
|
1086
|
+
@m.cc_point_position.must_equal :Base
|
1087
|
+
# --- imc point related assets ---
|
1088
|
+
@m.imc_point_reset
|
1089
|
+
@m.imc_point_to :Base
|
1090
|
+
@m.imc.must_equal @m.workspace.initial_marking_collection
|
1091
|
+
@m.imc.wont_equal :Base
|
1092
|
+
@m.imc_point_position.must_equal :Base
|
1093
|
+
# --- ssc point related assets ---
|
1094
|
+
@m.ssc_point_reset
|
1095
|
+
@m.ssc_point_to :Base
|
1096
|
+
@m.ssc.must_equal @m.workspace.simulation_settings_collection
|
1097
|
+
@m.ssc.wont_equal :Base
|
1098
|
+
@m.ssc_point_position.must_equal :Base
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
it "has basic selections" do
|
1102
|
+
@m.net_selection_clear
|
1103
|
+
@m.simulation_selection_clear
|
1104
|
+
@m.cc_selection_clear
|
1105
|
+
@m.imc_selection_clear
|
1106
|
+
@m.ssc_selection_clear
|
1107
|
+
@m.net_selection.must_equal []
|
1108
|
+
@m.simulation_selection.must_equal []
|
1109
|
+
@m.ssc_selection.must_equal []
|
1110
|
+
@m.cc_selection.must_equal []
|
1111
|
+
@m.imc_selection.must_equal []
|
1112
|
+
[ :net, :simulation, :cc, :imc, :ssc ].each { |sym1|
|
1113
|
+
[ :select!, :select, :unselect ].each { |sym2|
|
1114
|
+
@m.must_respond_to "#{sym1}_#{sym2}"
|
1115
|
+
}
|
1116
|
+
}
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
it "presents some methods from workspace" do
|
1120
|
+
[ @m.places, @m.transitions, @m.nets, @m.simulations ].map( &:size )
|
1121
|
+
.must_equal [ 0, 0, 1, 0 ]
|
1122
|
+
[ @m.clamp_collections,
|
1123
|
+
@m.initial_marking_collections,
|
1124
|
+
@m.simulation_settings_collections ].map( &:size ).must_equal [ 1, 1, 1 ]
|
1125
|
+
[ @m.clamp_collections,
|
1126
|
+
@m.initial_marking_collections,
|
1127
|
+
@m.simulation_settings_collections ]
|
1128
|
+
.map( &:keys ).must_equal [[:Base]] * 3
|
1129
|
+
@m.pp.must_equal []
|
1130
|
+
@m.tt.must_equal []
|
1131
|
+
@m.nn.must_equal [ :Top ] # ie. :Top net spanning whole workspace
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
describe "slightly more complicated case" do
|
1135
|
+
before do
|
1136
|
+
@p = @m.Place ɴ: "P", default_marking: 1
|
1137
|
+
@q = @m.Place ɴ: "Q", default_marking: 1
|
1138
|
+
@decay_t = @m.Transition ɴ: "Tp", s: { P: -1 }, rate: 0.1
|
1139
|
+
@constant_flux_t = @m.Transition ɴ: "Tq", s: { Q: 1 }, rate: λ{ 0.02 }
|
1140
|
+
@m.initial_marking @p => 1.2
|
1141
|
+
@m.initial_marking @q => 2
|
1142
|
+
@m.set_step 0.01
|
1143
|
+
@m.set_sampling 1
|
1144
|
+
@m.set_time 30
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
it "works" do
|
1148
|
+
@m.run!
|
1149
|
+
@m.simulation.places.must_equal [ @p, @q ]
|
1150
|
+
@m.simulation.transitions.must_equal [ @decay_t, @constant_flux_t ]
|
1151
|
+
@m.simulation.SR_tt.must_equal [ :Tp, :Tq ]
|
1152
|
+
@m.simulation.sparse_stoichiometry_vector( :Tp )
|
1153
|
+
.must_equal Matrix.column_vector( [-1, 0] )
|
1154
|
+
@m.simulation.stoichiometry_matrix_for( @m.transitions ).column_size
|
1155
|
+
.must_equal 2
|
1156
|
+
@m.simulation.stoichiometry_matrix_for( @m.transitions ).row_size
|
1157
|
+
.must_equal 2
|
1158
|
+
@m.simulation.flux_vector.row_size.must_equal 2
|
1159
|
+
# @m.plot_recording
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
|
1165
|
+
# **************************************************************************
|
1166
|
+
# Test of YPetri class itself.
|
1167
|
+
# **************************************************************************
|
1168
|
+
#
|
1169
|
+
describe ::YPetri do
|
1170
|
+
before do
|
1171
|
+
# skip "to speed up testing"
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
it "should have basic classes" do
|
1175
|
+
[ :Place, :Transition, :Net,
|
1176
|
+
:Simulation, :TimedSimulation,
|
1177
|
+
:Workspace, :Manipulator ].each { |ß|
|
1178
|
+
assert_kind_of Module, ::YPetri.const_get( ß ) }
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
|
1183
|
+
# **************************************************************************
|
1184
|
+
# ACCEPTANCE TESTS
|
1185
|
+
# **************************************************************************
|
1186
|
+
|
1187
|
+
# describe "Token game" do
|
1188
|
+
# before do
|
1189
|
+
# @m = YPetri::Manipulator.new
|
1190
|
+
# @m.Place name: "A"
|
1191
|
+
# @m.Place name: "B"
|
1192
|
+
# @m.Place name: "C", marking: 7.77
|
1193
|
+
# @m.Transition name: "A2B", stoichiometry: { A: -1, B: 1 }
|
1194
|
+
# @m.Transition name: "C_decay", stoichiometry: { C: -1 }, rate: 0.05
|
1195
|
+
# end
|
1196
|
+
|
1197
|
+
# it "should work" do
|
1198
|
+
# @m.place( :A ).marking = 2
|
1199
|
+
# @m.place( :B ).marking = 5
|
1200
|
+
# @m.places.map( &:name ).must_equal [:A, :B, :C]
|
1201
|
+
# @m.places.map( &:marking ).must_equal [2, 5, 7.77]
|
1202
|
+
# @m.transition( :A2B ).connectivity.must_equal [ @m.place( :A ), @m.place( :B ) ]
|
1203
|
+
# @m.transition( :A2B ).fire!
|
1204
|
+
# @m.places.map( &:marking ).must_equal [1, 6, 7.77]
|
1205
|
+
# @m.transition( :A2B ).fire!
|
1206
|
+
# @m.place( :A ).marking.must_equal 0
|
1207
|
+
# @m.place( :B ).marking.must_equal 7
|
1208
|
+
# 2.times do @m.transition( :C_decay ).fire! 1 end
|
1209
|
+
# @m.transition( :C_decay ).fire! 0.1
|
1210
|
+
# 200.times do @m.transition( :C_decay ).fire! 1 end
|
1211
|
+
# assert_in_delta @m.place( :C ).marking, 0.00024, 0.00001
|
1212
|
+
# end
|
1213
|
+
# end
|
1214
|
+
|
1215
|
+
# describe "Basic use of TimedSimulation" do
|
1216
|
+
# before do
|
1217
|
+
# @m = YPetri::Manipulator.new
|
1218
|
+
# @m.Place( name: "A", default_marking: 0.5 )
|
1219
|
+
# @m.Place( name: "B", default_marking: 0.5 )
|
1220
|
+
# @m.Transition( name: "A_pump",
|
1221
|
+
# stoichiometry: { A: -1 },
|
1222
|
+
# rate: proc { 0.005 } )
|
1223
|
+
# @m.Transition( name: "B_decay",
|
1224
|
+
# stoichiometry: { B: -1 },
|
1225
|
+
# rate: 0.05 )
|
1226
|
+
# end
|
1227
|
+
|
1228
|
+
# it "should work" do
|
1229
|
+
# @m.net.must_be_kind_of ::YPetri::Net
|
1230
|
+
# @m.run!
|
1231
|
+
# @m.simulation.must_be_kind_of ::YPetri::TimedSimulation
|
1232
|
+
# @m.plot_recording
|
1233
|
+
# sleep 3
|
1234
|
+
# end
|
1235
|
+
# end
|
1236
|
+
|
1237
|
+
# describe "Graphviz visualization" do
|
1238
|
+
# before do
|
1239
|
+
# @m = YPetri::Manipulator.new
|
1240
|
+
# @m.Place name: :A, m!: 1
|
1241
|
+
# @m.Place name: :B, m!: 1.5
|
1242
|
+
# @m.Place name: :C, m!: 2
|
1243
|
+
# @m.Place name: :D, m!: 2.5
|
1244
|
+
# @m.Transition name: :A_pump, s: { A: -1 }, rate: proc { 0.005 }
|
1245
|
+
# @m.Transition name: :B_decay, s: { B: -1 }, rate: 0.05
|
1246
|
+
# @m.Transition name: :C_guard, assignment: true, codomain: :C, action: λ { 2 }
|
1247
|
+
# end
|
1248
|
+
|
1249
|
+
# it "should work" do
|
1250
|
+
# @m.net.visualize
|
1251
|
+
# end
|
1252
|
+
# end
|
1253
|
+
|
1254
|
+
# describe "Simplified dTTP pathway used for demo with Dr. Chang" do
|
1255
|
+
# before do
|
1256
|
+
# @m = YPetri::Manipulator.new
|
1257
|
+
# Cytoplasm_volume_in_litres = 5.0e-11
|
1258
|
+
# NA = 6.022e23
|
1259
|
+
# Pieces_per_micromolar = NA / 1_000_000 * Cytoplasm_volume_in_litres
|
1260
|
+
# @m.set_step 60
|
1261
|
+
# @m.set_sampling 300
|
1262
|
+
# @m.set_target_time 60 * 60 * 2
|
1263
|
+
# AMP = @m.Place( name: :AMP, m!: 8695.0 )
|
1264
|
+
# ADP = @m.Place( name: :ADP, m!: 6521.0 )
|
1265
|
+
# ATP = @m.Place( name: :ATP, m!: 3152.0 )
|
1266
|
+
# Deoxycytidine = @m.Place( name: :Deoxycytidine, m!: 0.5 )
|
1267
|
+
# DeoxyCTP = @m.Place( name: :DeoxyCTP, m!: 1.0 )
|
1268
|
+
# DeoxyGMP = @m.Place( name: :DeoxyGMP, m!: 1.0 )
|
1269
|
+
# UMP_UDP_pool = @m.Place( name: :UMP_UDP_pool, m!: 2737.0 )
|
1270
|
+
# DeoxyUMP_DeoxyUDP_pool = @m.Place( name: :DeoxyUMP_DeoxyUDP_pool, m!: 0.0 )
|
1271
|
+
# DeoxyTMP = @m.Place( name: :DeoxyTMP, m!: 3.3 )
|
1272
|
+
# DeoxyTDP_DeoxyTTP_pool = @m.Place( name: :DeoxyTDP_DeoxyTTP_pool, m!: 5.0 )
|
1273
|
+
# Thymidine = @m.Place( name: :Thymidine, m!: 0.5 )
|
1274
|
+
# TK1 = @m.Place( name: :TK1, m!: 100_000 )
|
1275
|
+
# TYMS = @m.Place( name: :TYMS, m!: 100_000 )
|
1276
|
+
# RNR = @m.Place( name: :RNR, m!: 100_000 )
|
1277
|
+
# TMPK = @m.Place( name: :TMPK, m!: 100_000 )
|
1278
|
+
# TK1_kDa = 24.8
|
1279
|
+
# TYMS_kDa = 66.0
|
1280
|
+
# RNR_kDa = 140.0
|
1281
|
+
# TMPK_kDa = 50.0
|
1282
|
+
# TK1_a = 5.40
|
1283
|
+
# TYMS_a = 3.80
|
1284
|
+
# RNR_a = 1.00
|
1285
|
+
# TMPK_a = 0.83
|
1286
|
+
# @m.clamp AMP: 8695.0, ADP: 6521.0, ATP: 3152.0
|
1287
|
+
# @m.clamp Deoxycytidine: 0.5, DeoxyCTP: 1.0, DeoxyGMP: 1.0
|
1288
|
+
# @m.clamp Thymidine: 0.5
|
1289
|
+
# @m.clamp UMP_UDP_pool: 2737.0
|
1290
|
+
# # Functions
|
1291
|
+
# Vmax_per_minute_per_enzyme_molecule =
|
1292
|
+
# lambda { |enzyme_specific_activity_in_micromol_per_minute_per_mg,
|
1293
|
+
# enzyme_molecular_mass_in_kDa|
|
1294
|
+
# enzyme_specific_activity_in_micromol_per_minute_per_mg *
|
1295
|
+
# enzyme_molecular_mass_in_kDa }
|
1296
|
+
# Vmax_per_minute =
|
1297
|
+
# lambda { |specific_activity, kDa, enzyme_molecules_per_cell|
|
1298
|
+
# Vmax_per_minute_per_enzyme_molecule.( specific_activity, kDa ) *
|
1299
|
+
# enzyme_molecules_per_cell }
|
1300
|
+
# Vmax_per_second =
|
1301
|
+
# lambda { |specific_activity, kDa, enzyme_molecules_per_cell|
|
1302
|
+
# Vmax_per_minute.( specific_activity,
|
1303
|
+
# kDa,
|
1304
|
+
# enzyme_molecules_per_cell ) / 60 }
|
1305
|
+
# Km_reduced =
|
1306
|
+
# lambda { |km, ki_hash={}|
|
1307
|
+
# ki_hash.map { |concentration, ci_Ki|
|
1308
|
+
# concentration / ci_Ki
|
1309
|
+
# }.reduce( 1, :+ ) * km }
|
1310
|
+
# Occupancy =
|
1311
|
+
# lambda { |concentration, reactant_Km, compet_inh_w_Ki_hash={}|
|
1312
|
+
# concentration / ( concentration +
|
1313
|
+
# Km_reduced.( reactant_Km,
|
1314
|
+
# compet_inh_w_Ki_hash ) ) }
|
1315
|
+
# MM_with_inh_micromolars_per_second =
|
1316
|
+
# lambda { |reactant_concentration,
|
1317
|
+
# enzyme_specific_activity,
|
1318
|
+
# enzyme_mass_in_kDa,
|
1319
|
+
# enzyme_molecules_per_cell,
|
1320
|
+
# reactant_Km,
|
1321
|
+
# competitive_inh_w_Ki_hash={}|
|
1322
|
+
# Vmax_per_second.( enzyme_specific_activity,
|
1323
|
+
# enzyme_mass_in_kDa,
|
1324
|
+
# enzyme_molecules_per_cell ) *
|
1325
|
+
# Occupancy.( reactant_concentration,
|
1326
|
+
# reactant_Km,
|
1327
|
+
# competitive_inh_w_Ki_hash ) }
|
1328
|
+
# MMi = MM_with_inh_micromolars_per_second
|
1329
|
+
# TK1_Thymidine_Km = 5.0
|
1330
|
+
# TYMS_DeoxyUMP_Km = 2.0
|
1331
|
+
# RNR_UDP_Km = 1.0
|
1332
|
+
# DNA_creation_speed = 3_000_000_000 / ( 12 * 3600 )
|
1333
|
+
# TMPK_DeoxyTMP_Km = 12.0
|
1334
|
+
|
1335
|
+
# # transitions
|
1336
|
+
# @m.Transition name: :TK1_Thymidine_DeoxyTMP,
|
1337
|
+
# domain: [ Thymidine, TK1, DeoxyTDP_DeoxyTTP_pool, DeoxyCTP, Deoxycytidine, AMP, ADP, ATP ],
|
1338
|
+
# stoichiometry: { Thymidine: -1, DeoxyTMP: 1 },
|
1339
|
+
# rate: proc { |rc, e, pool1, ci2, ci3, master1, master2, master3|
|
1340
|
+
# ci1 = pool1 * master3 / ( master2 + master3 )
|
1341
|
+
# MMi.( rc, TK1_a, TK1_kDa, e, TK1_Thymidine_Km,
|
1342
|
+
# ci1 => 13.5, ci2 => 0.8, ci3 => 40.0 ) }
|
1343
|
+
# @m.Transition name: :TYMS_DeoxyUMP_DeoxyTMP,
|
1344
|
+
# domain: [ DeoxyUMP_DeoxyUDP_pool, TYMS, AMP, ADP, ATP ],
|
1345
|
+
# stoichiometry: { DeoxyUMP_DeoxyUDP_pool: -1, DeoxyTMP: 1 },
|
1346
|
+
# rate: proc { |pool, e, master1, master2, master3|
|
1347
|
+
# rc = pool * master2 / ( master1 + master2 )
|
1348
|
+
# MMi.( rc, TYMS_a, TYMS_kDa, e, TYMS_DeoxyUMP_Km ) }
|
1349
|
+
# @m.Transition name: :RNR_UDP_DeoxyUDP,
|
1350
|
+
# domain: [ UMP_UDP_pool, RNR, DeoxyUMP_DeoxyUDP_pool, AMP, ADP, ATP ],
|
1351
|
+
# stoichiometry: { UMP_UDP_pool: -1, DeoxyUMP_DeoxyUDP_pool: 1 },
|
1352
|
+
# rate: proc { |pool, e, master1, master2, master3|
|
1353
|
+
# rc = pool * master2 / ( master1 + master2 )
|
1354
|
+
# MMi.( rc, RNR_a, RNR_kDa, e, RNR_UDP_Km ) }
|
1355
|
+
# @m.Transition name: :DNA_polymerase_consumption_of_DeoxyTTP,
|
1356
|
+
# stoichiometry: { DeoxyTDP_DeoxyTTP_pool: -1 },
|
1357
|
+
# rate: proc { DNA_creation_speed / 4 }
|
1358
|
+
# @m.Transition name: :TMPK_DeoxyTMP_DeoxyTDP,
|
1359
|
+
# domain: [ DeoxyTMP, TMPK, ADP,
|
1360
|
+
# DeoxyTDP_DeoxyTTP_pool,
|
1361
|
+
# DeoxyGMP, AMP, ATP ],
|
1362
|
+
# stoichiometry: { DeoxyTMP: -1, TMPK: 0, DeoxyTDP_DeoxyTTP_pool: 1 },
|
1363
|
+
# rate: proc { |rc, e, ci1, pool, ci4, master1, master3|
|
1364
|
+
# master2 = ci1
|
1365
|
+
# ci2 = pool * master2 / ( master2 + master3 )
|
1366
|
+
# ci3 = pool * master3 / ( master2 + master3 )
|
1367
|
+
# MMi.( rc, TMPK_a, TMPK_kDa, e, TMPK_DeoxyTMP_Km,
|
1368
|
+
# ci1 => 250.0, ci2 => 30.0, ci3 => 750, ci4 => 117 ) }
|
1369
|
+
# end
|
1370
|
+
|
1371
|
+
# it "should work" do
|
1372
|
+
# @m.run!
|
1373
|
+
# @m.plot_recording
|
1374
|
+
# sleep 3
|
1375
|
+
# end
|
1376
|
+
# end
|
1377
|
+
|
1378
|
+
# describe "Use of TimedSimulation with units" do
|
1379
|
+
# before do
|
1380
|
+
# require 'sy'
|
1381
|
+
|
1382
|
+
# @m = YPetri::Manipulator.new
|
1383
|
+
|
1384
|
+
# # === General assumptions
|
1385
|
+
# Cytoplasm_volume = 5.0e-11.l
|
1386
|
+
# Pieces_per_concentration = SY::Nᴀ * Cytoplasm_volume
|
1387
|
+
|
1388
|
+
# # === Simulation settings
|
1389
|
+
# @m.set_step 60.s
|
1390
|
+
# @m.set_target_time 10.min
|
1391
|
+
# @m.set_sampling 120.s
|
1392
|
+
|
1393
|
+
# # === Places
|
1394
|
+
# AMP = @m.Place m!: 8695.0.µM
|
1395
|
+
# ADP = @m.Place m!: 6521.0.µM
|
1396
|
+
# ATP = @m.Place m!: 3152.0.µM
|
1397
|
+
# Deoxycytidine = @m.Place m!: 0.5.µM
|
1398
|
+
# DeoxyCTP = @m.Place m!: 1.0.µM
|
1399
|
+
# DeoxyGMP = @m.Place m!: 1.0.µM
|
1400
|
+
# U12P = @m.Place m!: 2737.0.µM
|
1401
|
+
# DeoxyU12P = @m.Place m!: 0.0.µM
|
1402
|
+
# DeoxyTMP = @m.Place m!: 3.3.µM
|
1403
|
+
# DeoxyT23P = @m.Place m!: 5.0.µM
|
1404
|
+
# Thymidine = @m.Place m!: 0.5.µM
|
1405
|
+
# TK1 = @m.Place m!: 100_000.unit.( SY::MoleAmount ) / Cytoplasm_volume
|
1406
|
+
# TYMS = @m.Place m!: 100_000.unit.( SY::MoleAmount ) / Cytoplasm_volume
|
1407
|
+
# RNR = @m.Place m!: 100_000.unit.( SY::MoleAmount ) / Cytoplasm_volume
|
1408
|
+
# TMPK = @m.Place m!: 100_000.unit.( SY::MoleAmount ) / Cytoplasm_volume
|
1409
|
+
|
1410
|
+
# # === Enzyme molecular masses
|
1411
|
+
# TK1_m = 24.8.kDa
|
1412
|
+
# TYMS_m = 66.0.kDa
|
1413
|
+
# RNR_m = 140.0.kDa
|
1414
|
+
# TMPK_m = 50.0.kDa
|
1415
|
+
|
1416
|
+
# # === Specific activities of the enzymes
|
1417
|
+
# TK1_a = 5.40.µmol.min⁻¹.mg⁻¹
|
1418
|
+
# TYMS_a = 3.80.µmol.min⁻¹.mg⁻¹
|
1419
|
+
# RNR_a = 1.00.µmol.min⁻¹.mg⁻¹
|
1420
|
+
# TMPK_a = 0.83.µmol.min⁻¹.mg⁻¹
|
1421
|
+
|
1422
|
+
# # === Clamps
|
1423
|
+
# @m.clamp AMP: 8695.0.µM, ADP: 6521.0.µM, ATP: 3152.0.µM
|
1424
|
+
# @m.clamp Deoxycytidine: 0.5.µM, DeoxyCTP: 1.0.µM, DeoxyGMP: 1.0.µM
|
1425
|
+
# @m.clamp Thymidine: 0.5.µM
|
1426
|
+
# @m.clamp U12P: 2737.0.µM
|
1427
|
+
|
1428
|
+
# # === Function closures
|
1429
|
+
|
1430
|
+
# # Vmax of an enzyme.
|
1431
|
+
# #
|
1432
|
+
# Vmax_enzyme = lambda { |specific_activity, mass, enzyme_conc|
|
1433
|
+
# specific_activity * mass * enzyme_conc.( SY::Molecularity )
|
1434
|
+
# }
|
1435
|
+
|
1436
|
+
# # Michaelis constant reduced for competitive inhibitors.
|
1437
|
+
# #
|
1438
|
+
# Km_reduced = lambda { |km, ki_hash={}|
|
1439
|
+
# ki_hash.map { |concentration, ci_Ki|
|
1440
|
+
# concentration / ci_Ki }
|
1441
|
+
# .reduce( 1, :+ ) * km
|
1442
|
+
# }
|
1443
|
+
|
1444
|
+
# # Occupancy of enzyme active sites at given concentration of reactants
|
1445
|
+
# # and competitive inhibitors.
|
1446
|
+
# #
|
1447
|
+
# Occupancy = lambda { |ʀ_conc, ʀ_Km, cɪ_Kɪ={}|
|
1448
|
+
# ʀ_conc / ( ʀ_conc + Km_reduced.( ʀ_Km, cɪ_Kɪ ) )
|
1449
|
+
# }
|
1450
|
+
|
1451
|
+
# # Michaelis and Menten equation with competitive inhibitors.
|
1452
|
+
# #
|
1453
|
+
# MMi = MM_equation_with_inhibitors = lambda {
|
1454
|
+
# |ʀ_conc, ᴇ_specific_activity, ᴇ_mass, ᴇ_conc, ʀ_Km, cɪ_Kɪ={}|
|
1455
|
+
# Vmax_enzyme.( ᴇ_specific_activity, ᴇ_mass, ᴇ_conc ) *
|
1456
|
+
# Occupancy.( ʀ_conc, ʀ_Km, cɪ_Kɪ )
|
1457
|
+
# }
|
1458
|
+
|
1459
|
+
# # === Michaelis constants of the enzymes involved.
|
1460
|
+
|
1461
|
+
# TK1_Thymidine_Km = 5.0.µM
|
1462
|
+
# TYMS_DeoxyUMP_Km = 2.0.µM
|
1463
|
+
# RNR_UDP_Km = 1.0.µM
|
1464
|
+
# TMPK_DeoxyTMP_Km = 12.0.µM
|
1465
|
+
|
1466
|
+
# # === DNA synthesis speed.
|
1467
|
+
|
1468
|
+
# DNA_creation_speed = 3_000_000_000.unit.( SY::MoleAmount ) / 12.h / Cytoplasm_volume
|
1469
|
+
|
1470
|
+
# # === Transitions
|
1471
|
+
|
1472
|
+
# # Synthesis of TMP by TK1.
|
1473
|
+
# #
|
1474
|
+
# TK1_Thymidine_DeoxyTMP = @m.Transition s: { Thymidine: -1, DeoxyTMP: 1 },
|
1475
|
+
# domain: [ Thymidine, TK1, DeoxyT23P, DeoxyCTP, Deoxycytidine, AMP, ADP, ATP ],
|
1476
|
+
# rate: proc { |rc, e, pool1, ci2, ci3, master1, master2, master3|
|
1477
|
+
# ci1 = pool1 * master3 / ( master2 + master3 )
|
1478
|
+
# MMi.( rc, TK1_a, TK1_m, e, TK1_Thymidine_Km,
|
1479
|
+
# ci1 => 13.5.µM, ci2 => 0.8.µM, ci3 => 40.0.µM )
|
1480
|
+
# }
|
1481
|
+
|
1482
|
+
# # Methylation of DeoxyUMP into TMP by TYMS.
|
1483
|
+
# TYMS_DeoxyUMP_DeoxyTMP = @m.Transition s: { DeoxyU12P: -1, DeoxyTMP: 1 },
|
1484
|
+
# domain: [ DeoxyU12P, TYMS, AMP, ADP, ATP ],
|
1485
|
+
# rate: proc { |pool, e, master1, master2, master3|
|
1486
|
+
# rc = pool * master2 / ( master1 + master2 )
|
1487
|
+
# MMi.( rc, TYMS_a, TYMS_m, e, TYMS_DeoxyUMP_Km )
|
1488
|
+
# }
|
1489
|
+
|
1490
|
+
# # Reduction of UDP into DeoxyUDP by RNR.
|
1491
|
+
# RNR_UDP_DeoxyUDP = @m.Transition s: { U12P: -1, DeoxyU12P: 1 },
|
1492
|
+
# domain: [ U12P, RNR, DeoxyU12P, AMP, ADP, ATP ],
|
1493
|
+
# rate: proc { |pool, e, master1, master2, master3|
|
1494
|
+
# rc = pool * master2 / ( master1 + master2 )
|
1495
|
+
# MMi.( rc, RNR_a, RNR_m, e, RNR_UDP_Km )
|
1496
|
+
# }
|
1497
|
+
|
1498
|
+
# # Consumption of TTP by DNA synthesis.
|
1499
|
+
# DeoxyTTP_to_DNA = @m.Transition s: { DeoxyT23P: -1 },
|
1500
|
+
# rate: proc { DNA_creation_speed / 4 }
|
1501
|
+
|
1502
|
+
# # Phosphorylation of TMP into TDP-TTP pool.
|
1503
|
+
# TMPK_DeoxyTMP_DeoxyTDP = @m.Transition s: { DeoxyTMP: -1, TMPK: 0, DeoxyT23P: 1 },
|
1504
|
+
# domain: [ DeoxyTMP, TMPK, ADP, DeoxyT23P, DeoxyGMP, AMP, ATP ],
|
1505
|
+
# rate: proc { |rc, e, ci1, pool, ci4, master1, master3|
|
1506
|
+
# master2 = ci1
|
1507
|
+
# ci2 = pool * master2 / ( master2 + master3 )
|
1508
|
+
# ci3 = pool * master3 / ( master2 + master3 )
|
1509
|
+
# MMi.( rc, TMPK_a, TMPK_m, e, TMPK_DeoxyTMP_Km,
|
1510
|
+
# ci1 => 250.0.µM, ci2 => 30.0.µM, ci3 => 750.µM, ci4 => 117.µM )
|
1511
|
+
# }
|
1512
|
+
# end
|
1513
|
+
|
1514
|
+
# it "should work" do
|
1515
|
+
# # === Simulation execution
|
1516
|
+
# @m.run!
|
1517
|
+
# # === Plotting of the results
|
1518
|
+
# @m.plot_recording
|
1519
|
+
# sleep 20
|
1520
|
+
# end
|
1521
|
+
# end
|