y_petri 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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