y_petri 2.0.7 → 2.0.14.p1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/y_petri/net/selections.rb +209 -0
- data/lib/y_petri/net/visualization.rb +67 -0
- data/lib/y_petri/net.rb +33 -311
- data/lib/y_petri/place/guard.rb +20 -13
- data/lib/y_petri/place.rb +12 -7
- data/lib/y_petri/simulation.rb +8 -9
- data/lib/y_petri/transition/assignment.rb +37 -0
- data/lib/y_petri/transition/{constructor_syntax.rb → construction.rb} +1 -0
- data/lib/y_petri/transition/ordinary_timeless.rb +46 -0
- data/lib/y_petri/transition/timed.rb +57 -0
- data/lib/y_petri/transition.rb +103 -220
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri.rb +1 -1
- data/test/acceptance/basic_usage_test.rb +30 -0
- data/test/acceptance/simulation_test.rb +132 -0
- data/test/acceptance/simulation_with_physical_units_test.rb +153 -0
- data/test/acceptance/token_game_test.rb +36 -0
- data/test/acceptance/visualization_test.rb +25 -0
- data/test/acceptance_tests.rb +14 -0
- data/test/manipulator_test.rb +100 -0
- data/test/{simple_manual_examples.rb → manual_examples.rb} +0 -0
- data/test/net_test.rb +171 -0
- data/test/place_test.rb +7 -6
- data/test/simulation_test.rb +280 -0
- data/test/timed_simulation_test.rb +149 -0
- data/test/transition_test.rb +2 -4
- data/test/workspace_test.rb +72 -0
- data/test/y_petri_test.rb +16 -1107
- metadata +34 -7
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# Mixin for timed Petri net transitions.
|
4
|
+
#
|
5
|
+
module YPetri::Transition::Timed
|
6
|
+
# Transition's action (before validation). Requires Δt as an argument.
|
7
|
+
#
|
8
|
+
def action Δt
|
9
|
+
if has_rate? then
|
10
|
+
if stoichiometric? then
|
11
|
+
rate = rate_closure.( *domain_marking )
|
12
|
+
stoichiometry.map { |coeff| rate * coeff * Δt }
|
13
|
+
else # assuming that rate closure return value has correct arity
|
14
|
+
rate_closure.( *domain_marking ).map { |e| component * Δt }
|
15
|
+
end
|
16
|
+
else # timed rateless
|
17
|
+
if stoichiometric? then
|
18
|
+
rslt = action_closure.( Δt, *domain_marking )
|
19
|
+
stoichiometry.map { |coeff| rslt * coeff }
|
20
|
+
else
|
21
|
+
action_closure.( Δt, *domain_marking ) # caveat result arity!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fires the transition, honoring cocking. Returns true if the transition
|
27
|
+
# fired, false if it wasn't cocked.
|
28
|
+
#
|
29
|
+
def fire Δt
|
30
|
+
cocked?.tap { |x| ( uncock; fire! Δt ) if x }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Fires the transition regardless of cocking. For timed transitions, takes
|
34
|
+
# Δt as an argument.
|
35
|
+
#
|
36
|
+
def fire! Δt
|
37
|
+
try "to call #fire method" do
|
38
|
+
act = note "action", is: Array( action Δt )
|
39
|
+
codomain.each_with_index do |codomain_place, i|
|
40
|
+
note "adding action element no. #{i} to place #{codomain_place}"
|
41
|
+
codomain_place.add( note "marking change", is: act.fetch( i ) )
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# YPetri transitions are _enabled_ if and only if the intended action would
|
48
|
+
# lead to a legal codomain marking. For timed transitions, +#enabled?+ method
|
49
|
+
# takes Δt as an argument.
|
50
|
+
#
|
51
|
+
def enabled? Δt
|
52
|
+
codomain.zip( action Δt ).all? do |place, change|
|
53
|
+
begin; place.guard.( place.marking + change )
|
54
|
+
rescue YPetri::GuardError; false end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end # class YPetri::Transition::Timed
|
data/lib/y_petri/transition.rb
CHANGED
@@ -3,124 +3,124 @@
|
|
3
3
|
require_relative 'dependency_injection'
|
4
4
|
require_relative 'transition/arcs'
|
5
5
|
require_relative 'transition/cocking'
|
6
|
-
require_relative 'transition/
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# * <b>sR</b> – nonstoichiometric with rate
|
15
|
-
# * <b>SR</b> – stoichiometric with rate
|
16
|
-
#
|
17
|
-
# These 6 kinds of YPetri transitions correspond to the vertices of a cube,
|
18
|
-
# whose 3 dimensions are:
|
19
|
-
#
|
20
|
-
# - stoichiometric (S) / nonstoichiometric (s)
|
21
|
-
# - timed (T) / timeless (t)
|
22
|
-
# - having rate (R) / not having rate (r)
|
23
|
-
#
|
24
|
-
# I. For stoichiometric transitions:
|
25
|
-
# 1. Rate vector is computed as rate * stoichiometry vector, or
|
26
|
-
# 2. Δ vector is computed a action * stoichiometry vector.
|
27
|
-
# II. For non-stoichiometric transitions:
|
28
|
-
# 1. Rate vector is obtained as the rate closure result, or
|
29
|
-
# 2. action vector is obtained as the action closure result.
|
30
|
-
#
|
31
|
-
# Conclusion: stoichiometricity distinguishes *need to multiply the
|
32
|
-
# rate/action closure result by stoichiometry*.
|
33
|
-
#
|
34
|
-
# I. For transitions with rate, the closure result has to be
|
35
|
-
# multiplied by the time step duration (delta_t) to get action.
|
36
|
-
# II. For rateless transitions, the closure result is used as is.
|
37
|
-
#
|
38
|
-
# Conclusion: has_rate? distinguishes *need to multiply the closure
|
39
|
-
# result by delta time* -- differentiability of action by time.
|
6
|
+
require_relative 'transition/construction'
|
7
|
+
require_relative 'transition/timed'
|
8
|
+
require_relative 'transition/ordinary_timeless'
|
9
|
+
require_relative 'transition/assignment'
|
10
|
+
|
11
|
+
# A Petri net transition. Usually depicted as square boxes, transitions
|
12
|
+
# represent operations over the net's marking vector -- how the marking changes
|
13
|
+
# when the transition activates (_fires_).
|
40
14
|
#
|
41
|
-
# I. For timed transitions, action is time-dependent. Transitions with
|
42
|
-
# rate are thus always timed. In rateless transitions, timedness means
|
43
|
-
# that the action closure expects time step length (delta_t) as its first
|
44
|
-
# argument - its arity is thus codomain size + 1.
|
45
|
-
# II. For timeless transitions, action is time-independent. Timeless
|
46
|
-
# transitions are necessarily also rateless. Arity of the action closure
|
47
|
-
# is expected to match the domain size.
|
48
|
-
#
|
49
|
-
# Conclusion: Transitions with rate are always timed. In rateless
|
50
|
-
# transitions, timedness distinguishes the need to supply time step
|
51
|
-
# duration as the first argument to the action closure.
|
52
|
-
#
|
53
|
-
# Since transitions with rate are always timed, and vice-versa, timeless
|
54
|
-
# transitions cannot have rate, there are not 8, but only 6 permissible
|
55
|
-
# combinations -- 6 basic transition types listed above.
|
56
|
-
#
|
57
15
|
# === Domain and codomin
|
58
16
|
#
|
59
|
-
# Each transition has a
|
17
|
+
# Each transition has a _domain_ -- upstream places. Upstream places are those,
|
60
18
|
# whose marking directly affects the transition's operation. Also, each
|
61
|
-
# transition has a
|
19
|
+
# transition has a _codomain_ -- downstream places. Downstream places are those,
|
62
20
|
# whose marking is directly affected by the transition's operation.
|
63
21
|
#
|
64
22
|
# === Action and action vector
|
65
23
|
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
24
|
+
# Every transition has an _action_ -- the operation it represents, the of what
|
25
|
+
# happens to the marking of its codomain when it fires. With respect to the
|
26
|
+
# transition's codomain, we can talk about the _action vector_ -- Δ state of the
|
27
|
+
# codomain. For _non-stoichiometric_ transitions, this action vector is given
|
28
|
+
# as the output of the _action closure_, or (for transitions with rate) of _rate
|
29
|
+
# vector_ * Δ_time. For _stoichiometric_ transitions, this output needs to be
|
30
|
+
# additionally multiplied by the transition's _stoichiometry vector_.
|
31
|
+
#
|
32
|
+
# === Basic types of transitions
|
33
|
+
#
|
34
|
+
# We have already mentioned different types of transitions _stoichiometric_ and
|
35
|
+
# _non-stoichometric_, with or without rate... In total, there are 6 basic types
|
36
|
+
# of transitions in *YPetri*:
|
75
37
|
#
|
76
|
-
#
|
38
|
+
# * *ts* – _timeless nonstoichiometric_
|
39
|
+
# * *tS* – _timeless stoichiometric_
|
40
|
+
# * *Tsr* – _timed rateless nonstoichiometric_
|
41
|
+
# * *TSr* – _timed rateless stoichiometric_
|
42
|
+
# * *sR* – _nonstoichiometric with rate_
|
43
|
+
# * *SR* – _stoichiometric with rate_
|
77
44
|
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
# *
|
83
|
-
#
|
84
|
-
#
|
45
|
+
# These 6 kinds of YPetri transitions correspond to the vertices of a cube, with
|
46
|
+
# the following 3 dimensions:
|
47
|
+
#
|
48
|
+
# - *Stoichiometricity*: _stoichiometric_ (S) / _nonstoichiometric_ (s)
|
49
|
+
# - *Timedness*: _timed_ (T) / _timeless_ (t)
|
50
|
+
# - *Having rate*: _having rate_ (R) / _not having rate_, _rateless_ (r)
|
51
|
+
#
|
52
|
+
# ==== Stoichiometricity
|
53
|
+
#
|
54
|
+
# I. For stoichiometric transitions:
|
55
|
+
# 1. Either *rate vector* is computed as *rate * stoichiometry vector*,
|
56
|
+
# 2. or *action vector* is computed a *action * stoichiometry vector*.
|
57
|
+
# II. For non-stoichiometric transitions:
|
58
|
+
# 1. Either *Rate vector* is obtained as the *rate closure result*,
|
59
|
+
# 2. or *action vector* is obtained as the *action closure result*.
|
85
60
|
#
|
86
|
-
#
|
87
|
-
#
|
61
|
+
# Summary: stoichiometricity distinguishes the *need to multiply the rate/action
|
62
|
+
# closure result by stoichiometry*.
|
88
63
|
#
|
89
|
-
# ==== Having
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
64
|
+
# ==== Having rate
|
65
|
+
#
|
66
|
+
# I. For transitions with rate, the closure *returns the rate*. The rate has to
|
67
|
+
# be multiplied by the time step (Δt) to get the action value.
|
68
|
+
# II. For transitions without rate (_rateless transitions_), the closure result
|
69
|
+
# directly specifies the action.
|
93
70
|
#
|
94
|
-
#
|
95
|
-
# result by
|
71
|
+
# Summary: Having vs. not having rate distinguishes the *need to multiply the
|
72
|
+
# closure result by Δ time* -- differentiability of the action by time.
|
96
73
|
#
|
97
|
-
# ====
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
# transitions are
|
104
|
-
#
|
74
|
+
# ==== Timedness
|
75
|
+
#
|
76
|
+
# I. Timed transitions are defined as those, whose action has time as a
|
77
|
+
# parameter. Transitions with rate are thus always timed. For rateless
|
78
|
+
# transitions, being timed means that the action closure expects time step
|
79
|
+
# (Δt) as its first argument -- its arity is thus its codomain size + 1.
|
80
|
+
# II. Timeless transitions, in turn, are those, whose action is does not have
|
81
|
+
# time a parameter. Timeless transitions are necessarily also rateless.
|
82
|
+
# Arity of their action closure can be expected to match the domain size.
|
105
83
|
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
84
|
+
# Summary: In rateless transitions, timedness distinguishes the *need to supply
|
85
|
+
# time step duration as the first argument to the action closure*. Whereas the
|
86
|
+
# transitions with rate are always timed, and vice-versa, timeless transitions
|
87
|
+
# always rateless, there are only 6 instead of 2 ** 3 == 8 basic types.
|
109
88
|
#
|
110
89
|
# === Other transition types
|
111
90
|
#
|
112
|
-
# ==== Assignment transitions
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
91
|
+
# ==== Assignment transitions (_A transitions_)
|
92
|
+
# If +:assignment_action+ is set to _true_, it indicates that the transition
|
93
|
+
# action entirely replaces the marking of its codomain with the result of its
|
94
|
+
# action closure -- like we are used to from spreadsheets. This behavior does
|
95
|
+
# not represent a truly novel type of a transition -- assignment transition is
|
96
|
+
# merely a *ts transition that cares to clear the codomain before adding the
|
97
|
+
# new value to it*. In other words, this behavior is (at least for numeric
|
98
|
+
# types) already achievable with ordinary ts transitions, and existence of
|
99
|
+
# specialized A transitions is just a convenience.
|
118
100
|
#
|
119
101
|
# ==== Functional / Functionless transitions
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
102
|
+
# YPetri is a domain model of _functional Petri nets_. Original Petri's
|
103
|
+
# definition does not speak about transition "functions". The transitions are
|
104
|
+
# defined as timeless and more or less assumed to be stoichiometric. Therefore,
|
105
|
+
# in +YPetri::Transition+ constructor, stoichiometric transitions with no
|
106
|
+
# function specified become functionless vanilla Petri net transitions.
|
107
|
+
#
|
108
|
+
# === "Discrete" vs. "continuous" in YPetri
|
109
|
+
#
|
110
|
+
# YPetri uses terminology of both "discrete" and "continuous" Petri nets. But
|
111
|
+
# in fact, in YPetri domain model, place marking is always considered discrete
|
112
|
+
# -- a discrete number of _tokens_, as defined by Carl Adam Petri. The meaning
|
113
|
+
# of _continuous_ in YPetri is different: A pragmatic measure of approximating
|
114
|
+
# this integer by a floating point number when the integer is so large, that the
|
115
|
+
# impact of this approximation is acceptable. The responsibility for the
|
116
|
+
# decision of how to represent the number of tokens is not a concern of the
|
117
|
+
# domain model, but only of the simulation method. Therefore, in YPetri, there
|
118
|
+
# are no _a priori_ "discrete" and "continuous" places or transitions.
|
119
|
+
#
|
120
|
+
# As for the transitions, terms _flux_ (flow), associated with continuous
|
121
|
+
# transitions, and _propensity_, associated with discrete stochastic
|
122
|
+
# transitions, are unified as _rate_. Again, the decision between "discrete"
|
123
|
+
# and "stochastic" is a concern of the simulation method, not the domain model.
|
124
124
|
#
|
125
125
|
class YPetri::Transition
|
126
126
|
include NameMagic
|
@@ -197,14 +197,10 @@ class YPetri::Transition
|
|
197
197
|
not has_rate?
|
198
198
|
end
|
199
199
|
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
# current marking of the transition's connectivity and quanta of its
|
205
|
-
# codomain. To emphasize unity of 'flux' and 'propensity', term 'rate' is
|
206
|
-
# used to represent both of them. Rate closure input arguments must
|
207
|
-
# correspond to the domain places.
|
200
|
+
# In YPetri, _rate_ is a unifying term for both _flux_ and _propensity_,
|
201
|
+
# both of which are treated as aliases of _rate_. The decision between
|
202
|
+
# discrete and continuous computation is a concern of the simulation.
|
203
|
+
# Rate closure arity should correspond to the transition's domain.
|
208
204
|
#
|
209
205
|
attr_reader :rate_closure
|
210
206
|
alias :rate :rate_closure
|
@@ -285,125 +281,12 @@ class YPetri::Transition
|
|
285
281
|
def assignment_action?; @assignment_action end
|
286
282
|
alias :assignment? :assignment_action?
|
287
283
|
|
288
|
-
# Result of the transition's "function", regardless of the #enabled? status.
|
289
|
-
#
|
290
|
-
def action Δt=nil
|
291
|
-
raise ArgumentError, "Δtime argument required for timed transitions!" if
|
292
|
-
timed? and Δt.nil?
|
293
|
-
# the code here looks awkward, because I was trying to speed it up
|
294
|
-
if has_rate? then
|
295
|
-
if stoichiometric? then
|
296
|
-
rate = rate_closure.( *domain_marking )
|
297
|
-
stoichiometry.map { |coeff| rate * coeff * Δt }
|
298
|
-
else # assuming correct return value arity from the rate closure:
|
299
|
-
rate_closure.( *domain_marking ).map { |e| component * Δt }
|
300
|
-
end
|
301
|
-
else # rateless
|
302
|
-
if timed? then
|
303
|
-
if stoichiometric? then
|
304
|
-
rslt = action_closure.( Δt, *domain_marking )
|
305
|
-
stoichiometry.map { |coeff| rslt * coeff }
|
306
|
-
else
|
307
|
-
action_closure.( Δt, *domain_marking ) # caveat result arity!
|
308
|
-
end
|
309
|
-
else # timeless
|
310
|
-
if stoichiometric? then
|
311
|
-
rslt = action_closure.( *domain_marking )
|
312
|
-
stoichiometry.map { |coeff| rslt * coeff }
|
313
|
-
else
|
314
|
-
action_closure.( *domain_marking ) # caveat result arity!
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
end # action
|
319
|
-
|
320
284
|
# Zero action
|
321
285
|
#
|
322
286
|
def zero_action
|
323
287
|
codomain.map { 0 }
|
324
288
|
end
|
325
289
|
|
326
|
-
# Changes to the marking of codomain, as they would happen if #fire! was
|
327
|
-
# called right now (ie. honoring #enabled?, but not #cocked? status.
|
328
|
-
#
|
329
|
-
def action_after_feasibility_check( Δt=nil )
|
330
|
-
raise AErr, "Δtime argument required for timed transitions!" if
|
331
|
-
timed? and Δt.nil?
|
332
|
-
act = Array( action Δt )
|
333
|
-
# Assignment actions are always feasible - no need to check:
|
334
|
-
return act if assignment?
|
335
|
-
# check if the marking after the action would still be positive
|
336
|
-
enabled = codomain
|
337
|
-
.zip( act )
|
338
|
-
.all? { |place, change| place.marking.to_f >= -change.to_f }
|
339
|
-
if enabled then act else
|
340
|
-
raise "firing of #{self}#{ Δt ? ' with Δtime %s' % Δt : '' } " +
|
341
|
-
"would result in negative marking"
|
342
|
-
zero_action
|
343
|
-
end
|
344
|
-
# LATER: This use of #zip here should be avoided for speed
|
345
|
-
end
|
346
|
-
|
347
|
-
# Applies transition's action (adding/taking tokens) on its downstream
|
348
|
-
# places (aka. domain places). If the transition is timed, delta time has
|
349
|
-
# to be supplied as argument. In order for this method to work, the
|
350
|
-
# transition has to be cocked (#cock method), and firing uncocks the
|
351
|
-
# transition, so it has to be cocked again before it can be fired for
|
352
|
-
# the second time. If the transition is not cocked, this method has no
|
353
|
-
# effect.
|
354
|
-
#
|
355
|
-
def fire( Δt=nil )
|
356
|
-
raise ArgumentError, "Δtime argument required for timed transitions!" if
|
357
|
-
timed? and Δt.nil?
|
358
|
-
return false unless cocked?
|
359
|
-
uncock
|
360
|
-
fire! Δt
|
361
|
-
return true
|
362
|
-
end
|
363
|
-
|
364
|
-
# Fires the transition just like #fire method, but disregards the cocked /
|
365
|
-
# uncocked state of the transition.
|
366
|
-
#
|
367
|
-
def fire!( Δt=nil )
|
368
|
-
raise ArgumentError, "Δt required for timed transitions!" if
|
369
|
-
Δt.nil? if timed?
|
370
|
-
try "to fire" do
|
371
|
-
if assignment_action? then
|
372
|
-
note has: "assignment action"
|
373
|
-
act = note "action", is: Array( action( Δt ) )
|
374
|
-
codomain.each_with_index do |place, i|
|
375
|
-
"place #{place}".try "to assign marking #{i}" do
|
376
|
-
place.marking = act[i]
|
377
|
-
end
|
378
|
-
end
|
379
|
-
else
|
380
|
-
act = note "action", is: action_after_feasibility_check( Δt )
|
381
|
-
codomain.each_with_index do |place, i|
|
382
|
-
"place #{place}".try "to assign marking #{i}" do
|
383
|
-
place.add act[i]
|
384
|
-
end
|
385
|
-
end
|
386
|
-
end
|
387
|
-
end
|
388
|
-
return nil
|
389
|
-
end
|
390
|
-
|
391
|
-
# Sanity of execution is ensured by Petri's notion of transitions being
|
392
|
-
# "enabled" if and only if the intended action can immediately take
|
393
|
-
# place without getting places into forbidden state (negative marking).
|
394
|
-
#
|
395
|
-
def enabled?( Δt=nil )
|
396
|
-
fail ArgumentError, "Δtime argument compulsory for timed transitions!" if
|
397
|
-
timed? && Δt.nil?
|
398
|
-
codomain.zip( action Δt ).all? do |place, change|
|
399
|
-
begin
|
400
|
-
place.guard.( place.marking + change )
|
401
|
-
rescue YPetri::GuardError
|
402
|
-
false
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
290
|
# def lock
|
408
291
|
# # LATER
|
409
292
|
# end
|
@@ -445,7 +328,7 @@ class YPetri::Transition
|
|
445
328
|
# Conversion to a string.
|
446
329
|
#
|
447
330
|
def to_s
|
448
|
-
"#<Transition: %s
|
331
|
+
"#<Transition: %s>" %
|
449
332
|
"#{name.nil? ? '' : '%s ' % name }(#{basic_type}%s)%s" %
|
450
333
|
[ "#{assignment_action? ? ' Assign.' : ''}",
|
451
334
|
"#{name.nil? ? ' id:%s' % object_id : ''}" ]
|
data/lib/y_petri/version.rb
CHANGED
data/lib/y_petri.rb
CHANGED
@@ -7,7 +7,7 @@ require 'y_support/respond_to'
|
|
7
7
|
require 'y_support/name_magic'
|
8
8
|
require 'y_support/unicode'
|
9
9
|
require 'y_support/typing'
|
10
|
-
require 'y_support/
|
10
|
+
require 'y_support/try'
|
11
11
|
require 'y_support/core_ext/hash'
|
12
12
|
require 'y_support/core_ext/array'
|
13
13
|
require 'y_support/stdlib_ext/matrix'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
# -*- coding: 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
|
+
# require 'sy'
|
9
|
+
|
10
|
+
describe "Basic use of TimedSimulation" do
|
11
|
+
before do
|
12
|
+
@m = YPetri::Manipulator.new
|
13
|
+
@m.Place( name: "A", default_marking: 0.5 )
|
14
|
+
@m.Place( name: "B", default_marking: 0.5 )
|
15
|
+
@m.Transition( name: "A_pump",
|
16
|
+
stoichiometry: { A: -1 },
|
17
|
+
rate: proc { 0.005 } )
|
18
|
+
@m.Transition( name: "B_decay",
|
19
|
+
stoichiometry: { B: -1 },
|
20
|
+
rate: 0.05 )
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should work" do
|
24
|
+
@m.net.must_be_kind_of ::YPetri::Net
|
25
|
+
@m.run!
|
26
|
+
@m.simulation.must_be_kind_of ::YPetri::TimedSimulation
|
27
|
+
@m.plot_state
|
28
|
+
sleep 3
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
# -*- coding: 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
|
+
# require 'sy'
|
9
|
+
|
10
|
+
describe "Simplified dTTP pathway used for demo with Dr. Chang" do
|
11
|
+
before do
|
12
|
+
@m = YPetri::Manipulator.new
|
13
|
+
Cytoplasm_volume_in_litres = 5.0e-11
|
14
|
+
NA = 6.022e23
|
15
|
+
Pieces_per_micromolar = NA / 1_000_000 * Cytoplasm_volume_in_litres
|
16
|
+
@m.set_step 60
|
17
|
+
@m.set_sampling 300
|
18
|
+
@m.set_target_time 60 * 60 * 2
|
19
|
+
AMP = @m.Place( name: :AMP, m!: 8695.0 )
|
20
|
+
ADP = @m.Place( name: :ADP, m!: 6521.0 )
|
21
|
+
ATP = @m.Place( name: :ATP, m!: 3152.0 )
|
22
|
+
Deoxycytidine = @m.Place( name: :Deoxycytidine, m!: 0.5 )
|
23
|
+
DeoxyCTP = @m.Place( name: :DeoxyCTP, m!: 1.0 )
|
24
|
+
DeoxyGMP = @m.Place( name: :DeoxyGMP, m!: 1.0 )
|
25
|
+
UMP_UDP_pool = @m.Place( name: :UMP_UDP_pool, m!: 2737.0 )
|
26
|
+
DeoxyUMP_DeoxyUDP_pool = @m.Place( name: :DeoxyUMP_DeoxyUDP_pool, m!: 0.0 )
|
27
|
+
DeoxyTMP = @m.Place( name: :DeoxyTMP, m!: 3.3 )
|
28
|
+
DeoxyTDP_DeoxyTTP_pool = @m.Place( name: :DeoxyTDP_DeoxyTTP_pool, m!: 5.0 )
|
29
|
+
Thymidine = @m.Place( name: :Thymidine, m!: 0.5 )
|
30
|
+
TK1 = @m.Place( name: :TK1, m!: 100_000 )
|
31
|
+
TYMS = @m.Place( name: :TYMS, m!: 100_000 )
|
32
|
+
RNR = @m.Place( name: :RNR, m!: 100_000 )
|
33
|
+
TMPK = @m.Place( name: :TMPK, m!: 100_000 )
|
34
|
+
TK1_kDa = 24.8
|
35
|
+
TYMS_kDa = 66.0
|
36
|
+
RNR_kDa = 140.0
|
37
|
+
TMPK_kDa = 50.0
|
38
|
+
TK1_a = 5.40
|
39
|
+
TYMS_a = 3.80
|
40
|
+
RNR_a = 1.00
|
41
|
+
TMPK_a = 0.83
|
42
|
+
@m.clamp AMP: 8695.0, ADP: 6521.0, ATP: 3152.0
|
43
|
+
@m.clamp Deoxycytidine: 0.5, DeoxyCTP: 1.0, DeoxyGMP: 1.0
|
44
|
+
@m.clamp Thymidine: 0.5
|
45
|
+
@m.clamp UMP_UDP_pool: 2737.0
|
46
|
+
# Functions
|
47
|
+
Vmax_per_minute_per_enzyme_molecule =
|
48
|
+
lambda { |enzyme_specific_activity_in_micromol_per_minute_per_mg,
|
49
|
+
enzyme_molecular_mass_in_kDa|
|
50
|
+
enzyme_specific_activity_in_micromol_per_minute_per_mg *
|
51
|
+
enzyme_molecular_mass_in_kDa }
|
52
|
+
Vmax_per_minute =
|
53
|
+
lambda { |specific_activity, kDa, enzyme_molecules_per_cell|
|
54
|
+
Vmax_per_minute_per_enzyme_molecule.( specific_activity, kDa ) *
|
55
|
+
enzyme_molecules_per_cell }
|
56
|
+
Vmax_per_second =
|
57
|
+
lambda { |specific_activity, kDa, enzyme_molecules_per_cell|
|
58
|
+
Vmax_per_minute.( specific_activity,
|
59
|
+
kDa,
|
60
|
+
enzyme_molecules_per_cell ) / 60 }
|
61
|
+
Km_reduced =
|
62
|
+
lambda { |km, ki_hash={}|
|
63
|
+
ki_hash.map { |concentration, ci_Ki|
|
64
|
+
concentration / ci_Ki
|
65
|
+
}.reduce( 1, :+ ) * km }
|
66
|
+
Occupancy =
|
67
|
+
lambda { |concentration, reactant_Km, compet_inh_w_Ki_hash={}|
|
68
|
+
concentration / ( concentration +
|
69
|
+
Km_reduced.( reactant_Km,
|
70
|
+
compet_inh_w_Ki_hash ) ) }
|
71
|
+
MM_with_inh_micromolars_per_second =
|
72
|
+
lambda { |reactant_concentration,
|
73
|
+
enzyme_specific_activity,
|
74
|
+
enzyme_mass_in_kDa,
|
75
|
+
enzyme_molecules_per_cell,
|
76
|
+
reactant_Km,
|
77
|
+
competitive_inh_w_Ki_hash={}|
|
78
|
+
Vmax_per_second.( enzyme_specific_activity,
|
79
|
+
enzyme_mass_in_kDa,
|
80
|
+
enzyme_molecules_per_cell ) *
|
81
|
+
Occupancy.( reactant_concentration,
|
82
|
+
reactant_Km,
|
83
|
+
competitive_inh_w_Ki_hash ) }
|
84
|
+
MMi = MM_with_inh_micromolars_per_second
|
85
|
+
TK1_Thymidine_Km = 5.0
|
86
|
+
TYMS_DeoxyUMP_Km = 2.0
|
87
|
+
RNR_UDP_Km = 1.0
|
88
|
+
DNA_creation_speed = 3_000_000_000 / ( 12 * 3600 )
|
89
|
+
TMPK_DeoxyTMP_Km = 12.0
|
90
|
+
|
91
|
+
# transitions
|
92
|
+
@m.Transition name: :TK1_Thymidine_DeoxyTMP,
|
93
|
+
domain: [ Thymidine, TK1, DeoxyTDP_DeoxyTTP_pool, DeoxyCTP, Deoxycytidine, AMP, ADP, ATP ],
|
94
|
+
stoichiometry: { Thymidine: -1, DeoxyTMP: 1 },
|
95
|
+
rate: proc { |rc, e, pool1, ci2, ci3, master1, master2, master3|
|
96
|
+
ci1 = pool1 * master3 / ( master2 + master3 )
|
97
|
+
MMi.( rc, TK1_a, TK1_kDa, e, TK1_Thymidine_Km,
|
98
|
+
ci1 => 13.5, ci2 => 0.8, ci3 => 40.0 ) }
|
99
|
+
@m.Transition name: :TYMS_DeoxyUMP_DeoxyTMP,
|
100
|
+
domain: [ DeoxyUMP_DeoxyUDP_pool, TYMS, AMP, ADP, ATP ],
|
101
|
+
stoichiometry: { DeoxyUMP_DeoxyUDP_pool: -1, DeoxyTMP: 1 },
|
102
|
+
rate: proc { |pool, e, master1, master2, master3|
|
103
|
+
rc = pool * master2 / ( master1 + master2 )
|
104
|
+
MMi.( rc, TYMS_a, TYMS_kDa, e, TYMS_DeoxyUMP_Km ) }
|
105
|
+
@m.Transition name: :RNR_UDP_DeoxyUDP,
|
106
|
+
domain: [ UMP_UDP_pool, RNR, DeoxyUMP_DeoxyUDP_pool, AMP, ADP, ATP ],
|
107
|
+
stoichiometry: { UMP_UDP_pool: -1, DeoxyUMP_DeoxyUDP_pool: 1 },
|
108
|
+
rate: proc { |pool, e, master1, master2, master3|
|
109
|
+
rc = pool * master2 / ( master1 + master2 )
|
110
|
+
MMi.( rc, RNR_a, RNR_kDa, e, RNR_UDP_Km ) }
|
111
|
+
@m.Transition name: :DNA_polymerase_consumption_of_DeoxyTTP,
|
112
|
+
stoichiometry: { DeoxyTDP_DeoxyTTP_pool: -1 },
|
113
|
+
rate: proc { DNA_creation_speed / 4 }
|
114
|
+
@m.Transition name: :TMPK_DeoxyTMP_DeoxyTDP,
|
115
|
+
domain: [ DeoxyTMP, TMPK, ADP,
|
116
|
+
DeoxyTDP_DeoxyTTP_pool,
|
117
|
+
DeoxyGMP, AMP, ATP ],
|
118
|
+
stoichiometry: { DeoxyTMP: -1, TMPK: 0, DeoxyTDP_DeoxyTTP_pool: 1 },
|
119
|
+
rate: proc { |rc, e, ci1, pool, ci4, master1, master3|
|
120
|
+
master2 = ci1
|
121
|
+
ci2 = pool * master2 / ( master2 + master3 )
|
122
|
+
ci3 = pool * master3 / ( master2 + master3 )
|
123
|
+
MMi.( rc, TMPK_a, TMPK_kDa, e, TMPK_DeoxyTMP_Km,
|
124
|
+
ci1 => 250.0, ci2 => 30.0, ci3 => 750, ci4 => 117 ) }
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should work" do
|
128
|
+
@m.run!
|
129
|
+
@m.plot_state
|
130
|
+
sleep 3
|
131
|
+
end
|
132
|
+
end
|