y_petri 2.0.7 → 2.0.14.p1
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.
- 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
|