y_petri 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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