y_petri 2.0.15 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/lib/y_petri/{manipulator → agent}/hash_key_pointer.rb +2 -2
  3. data/lib/y_petri/agent/petri_net_related.rb +115 -0
  4. data/lib/y_petri/{manipulator → agent}/selection.rb +2 -1
  5. data/lib/y_petri/{manipulator/simulation_related_methods.rb → agent/simulation_related.rb} +93 -110
  6. data/lib/y_petri/agent.rb +22 -0
  7. data/lib/y_petri/core/timed/euler.rb +20 -0
  8. data/lib/y_petri/core/timed/pseudo_euler.rb +31 -0
  9. data/lib/y_petri/core/timed/quasi_euler.rb +23 -0
  10. data/lib/y_petri/core/timed.rb +70 -0
  11. data/lib/y_petri/core/timeless/pseudo_euler.rb +20 -0
  12. data/lib/y_petri/core/timeless.rb +12 -0
  13. data/lib/y_petri/core.rb +100 -0
  14. data/lib/y_petri/dsl.rb +66 -0
  15. data/lib/y_petri/fixed_assets.rb +7 -0
  16. data/lib/y_petri/net/element_access.rb +239 -0
  17. data/lib/y_petri/net/state/feature/delta.rb +88 -0
  18. data/lib/y_petri/net/state/feature/firing.rb +57 -0
  19. data/lib/y_petri/net/state/feature/flux.rb +58 -0
  20. data/lib/y_petri/net/state/feature/gradient.rb +75 -0
  21. data/lib/y_petri/net/state/feature/marking.rb +62 -0
  22. data/lib/y_petri/net/state/feature.rb +79 -0
  23. data/lib/y_petri/net/state/features/dataset.rb +135 -0
  24. data/lib/y_petri/net/state/features/record.rb +50 -0
  25. data/lib/y_petri/net/state/features.rb +126 -0
  26. data/lib/y_petri/net/state.rb +121 -0
  27. data/lib/y_petri/net/timed.rb +8 -0
  28. data/lib/y_petri/net/visualization.rb +3 -3
  29. data/lib/y_petri/net.rb +73 -77
  30. data/lib/y_petri/place.rb +8 -3
  31. data/lib/y_petri/simulation/dependency.rb +107 -0
  32. data/lib/y_petri/simulation/element_representation.rb +20 -0
  33. data/lib/y_petri/simulation/elements/access.rb +57 -0
  34. data/lib/y_petri/simulation/elements.rb +45 -0
  35. data/lib/y_petri/simulation/feature_set.rb +21 -0
  36. data/lib/y_petri/simulation/initial_marking/access.rb +55 -0
  37. data/lib/y_petri/simulation/initial_marking.rb +15 -0
  38. data/lib/y_petri/simulation/marking_clamps/access.rb +34 -0
  39. data/lib/y_petri/simulation/marking_clamps.rb +18 -0
  40. data/lib/y_petri/simulation/marking_vector/access.rb +106 -0
  41. data/lib/y_petri/simulation/marking_vector.rb +156 -0
  42. data/lib/y_petri/simulation/matrix.rb +64 -0
  43. data/lib/y_petri/simulation/place_mapping.rb +62 -0
  44. data/lib/y_petri/simulation/place_representation.rb +74 -0
  45. data/lib/y_petri/simulation/places/access.rb +121 -0
  46. data/lib/y_petri/simulation/places/clamped.rb +8 -0
  47. data/lib/y_petri/simulation/places/free.rb +8 -0
  48. data/lib/y_petri/simulation/places/types.rb +25 -0
  49. data/lib/y_petri/simulation/places.rb +41 -0
  50. data/lib/y_petri/simulation/recorder.rb +54 -0
  51. data/lib/y_petri/simulation/timed/recorder.rb +53 -0
  52. data/lib/y_petri/simulation/timed.rb +161 -261
  53. data/lib/y_petri/simulation/timeless/recorder.rb +25 -0
  54. data/lib/y_petri/simulation/timeless.rb +35 -0
  55. data/lib/y_petri/simulation/transition_representation/A.rb +58 -0
  56. data/lib/y_petri/simulation/transition_representation/S.rb +45 -0
  57. data/lib/y_petri/simulation/transition_representation/T.rb +80 -0
  58. data/lib/y_petri/simulation/transition_representation/TS.rb +46 -0
  59. data/lib/y_petri/simulation/transition_representation/Ts.rb +32 -0
  60. data/lib/y_petri/simulation/transition_representation/a.rb +30 -0
  61. data/lib/y_petri/simulation/transition_representation/s.rb +29 -0
  62. data/lib/y_petri/simulation/transition_representation/t.rb +37 -0
  63. data/lib/y_petri/simulation/transition_representation/tS.rb +38 -0
  64. data/lib/y_petri/simulation/transition_representation/ts.rb +32 -0
  65. data/lib/y_petri/simulation/transition_representation/types.rb +62 -0
  66. data/lib/y_petri/simulation/transition_representation.rb +79 -0
  67. data/lib/y_petri/simulation/transitions/A.rb +40 -0
  68. data/lib/y_petri/simulation/transitions/S.rb +24 -0
  69. data/lib/y_petri/simulation/transitions/T.rb +34 -0
  70. data/lib/y_petri/simulation/transitions/TS.rb +57 -0
  71. data/lib/y_petri/simulation/transitions/Ts.rb +60 -0
  72. data/lib/y_petri/simulation/transitions/a.rb +8 -0
  73. data/lib/y_petri/simulation/transitions/access.rb +186 -0
  74. data/lib/y_petri/simulation/transitions/s.rb +9 -0
  75. data/lib/y_petri/simulation/transitions/t.rb +22 -0
  76. data/lib/y_petri/simulation/transitions/tS.rb +55 -0
  77. data/lib/y_petri/simulation/transitions/ts.rb +58 -0
  78. data/lib/y_petri/simulation/transitions/types.rb +98 -0
  79. data/lib/y_petri/simulation/transitions.rb +21 -0
  80. data/lib/y_petri/simulation.rb +176 -781
  81. data/lib/y_petri/transition/assignment.rb +7 -5
  82. data/lib/y_petri/transition/construction.rb +119 -187
  83. data/lib/y_petri/transition/init.rb +311 -0
  84. data/lib/y_petri/transition/ordinary_timeless.rb +8 -6
  85. data/lib/y_petri/transition/timed.rb +11 -18
  86. data/lib/y_petri/transition.rb +104 -132
  87. data/lib/y_petri/version.rb +1 -1
  88. data/lib/y_petri/world/dependency.rb +40 -0
  89. data/lib/y_petri/world/petri_net_related.rb +61 -0
  90. data/lib/y_petri/{workspace/simulation_related_methods.rb → world/simulation_related.rb} +42 -49
  91. data/lib/y_petri/world.rb +27 -0
  92. data/lib/y_petri.rb +47 -99
  93. data/test/{manipulator_test.rb → agent_test.rb} +19 -17
  94. data/{lib/y_petri → test/examples}/demonstrator.rb +0 -0
  95. data/{lib/y_petri → test/examples}/demonstrator_2.rb +1 -0
  96. data/{lib/y_petri → test/examples}/demonstrator_3.rb +0 -0
  97. data/{lib/y_petri → test/examples}/demonstrator_4.rb +0 -0
  98. data/test/examples/example_2.rb +16 -0
  99. data/test/{manual_examples.rb → examples/manual_examples.rb} +0 -0
  100. data/test/net_test.rb +126 -121
  101. data/test/place_test.rb +1 -1
  102. data/test/sim_test +565 -0
  103. data/test/simulation_test.rb +338 -264
  104. data/test/transition_test.rb +77 -174
  105. data/test/world_mock.rb +12 -0
  106. data/test/{workspace_test.rb → world_test.rb} +19 -20
  107. data/test/y_petri_test.rb +4 -5
  108. metadata +101 -26
  109. data/lib/y_petri/dependency_injection.rb +0 -45
  110. data/lib/y_petri/manipulator/petri_net_related_methods.rb +0 -74
  111. data/lib/y_petri/manipulator.rb +0 -20
  112. data/lib/y_petri/net/selections.rb +0 -209
  113. data/lib/y_petri/simulation/collections.rb +0 -460
  114. data/lib/y_petri/workspace/parametrized_subclassing.rb +0 -22
  115. data/lib/y_petri/workspace/petri_net_related_methods.rb +0 -88
  116. data/lib/y_petri/workspace.rb +0 -16
  117. data/test/timed_simulation_test.rb +0 -153
@@ -19,12 +19,14 @@ module YPetri::Transition::Assignment
19
19
  # Assigns the action closure result to the codomain, regardless of cocking.
20
20
  #
21
21
  def fire!
22
- try "to call #fire! method" do
22
+ consciously "to #fire!" do
23
23
  act = note "action", is: Array( action )
24
- codomain.each_with_index do |codomain_place, i|
25
- note "assigning action element no. #{i} to place #{codomain_place}"
26
- codomain_place.marking = note "marking to assign", is: act.fetch( i )
27
- end
24
+ msg = "Wrong output arity of the action closure of #{self}"
25
+ fail TypeError, msg if act.size != codomain.size
26
+ codomain.each_with_index { |p, i|
27
+ note "assigning action element no. #{i} to #{p}"
28
+ p.marking = note "marking to assign", is: act.fetch( i )
29
+ }
28
30
  end
29
31
  return nil
30
32
  end
@@ -14,7 +14,29 @@ class YPetri::Transition
14
14
  # best explained by examples -- let us have 3 places A, B, C, for whe we will
15
15
  # create different kinds of transitions:
16
16
  #
17
+ #
18
+ # ==== TS (timed stoichiometric)
19
+ #
20
+ # Rate closure and stoichiometry has to be supplied. Rate closure arity should
21
+ # correspond to the domain size. Return arity should be 1 (to be multiplied by
22
+ # the stoichiometry vector, as in all other stoichiometric transitions).
23
+ #
24
+ # Transition.new stoichiometry: { A: -1, B: 1 },
25
+ # rate: -> a { a * 0.5 }
26
+ #
27
+ #
28
+ # ==== Ts (timed nonstoichiometric)
29
+ #
30
+ # Rate closure has to be supplied, whose arity should match the domain, and
31
+ # output arity codomain.
32
+ #
33
+ # ==== tS (timeless stoichiometric)
34
+ #
35
+ # Stoichiometry has to be supplied, action closure is optional. If supplied,
36
+ # its return arity should be 1 (to be multiplied by the stoichiometry vector).
37
+ #
17
38
  # ==== ts transitions (timeless nonstoichiometric)
39
+ #
18
40
  # Action closure is expected with return arity equal to the codomain size:
19
41
  #
20
42
  # Transition.new upstream_arcs: [A, C], downstream_arcs: [A, B],
@@ -23,43 +45,8 @@ class YPetri::Transition
23
45
  # else [1, 0] end
24
46
  # }
25
47
  #
26
- # (If C is positive, half of A's marking is moved to B, otherwise A is
27
- # incremented by 1.)
28
- #
29
- # ==== tS transitions (timeless stoichiometric)
30
- # Stochiometry has to be supplied, action closure is optional. If supplied,
31
- # its return arity should be 1 (to be multiplied by the stochiometry vector).
32
- #
33
- # If no action closure is given, a _functionless_ transition will be
34
- # constructed, with action closure == 1 * stoichiometry vector.
35
- #
36
- # ==== Tsr transitions (timed rateless nonstoichiometric)
37
- # Action closure has to be supplied, whose first argument is Δt, and the
38
- # remaining ones correspond to the domain size. Return arity of this closure
39
- # should, in turn, correspond to the codomain size.
40
- #
41
- # ==== TSr transitions (timed rateless stoichiometric)
42
- # Action closure has to be supplied, whose first argument is Δt, and the
43
- # remaining ones correspond to the domain size. Return arity of this closure
44
- # should be 1 (to be multiplied by the stoichiometry vector).
45
- #
46
- # ==== sR transitions (nonstoichiometric transitions with rate)
47
- # Rate closure has to be supplied, whose arity should correspond to the domain
48
- # size (Δt argument is not needed). Return arity of this should, in turn,
49
- # correspond to the codomain size -- it represents this transition's
50
- # contribution to the rate of change of marking of the codomain places.
51
- #
52
- # ==== SR transitions (stoichiometric transitions with rate)
53
- #
54
- # Rate closure and stoichiometry has to be supplied. Rate closure arity should
55
- # correspond to the domain size. Return arity should be 1 (to be multiplied by
56
- # the stoichiometry vector, as in all other stoichiometric transitions).
57
- #
58
- # Transition.new stoichiometry: { A: -1, B: 1 },
59
- # rate: -> a { a * 0.5 }
60
- #
61
- def initialize *args
62
- check_in_arguments *args # the big work of checking in args
48
+ def initialize *args, &block
49
+ check_in_arguments *args, &block # the big job
63
50
  extend timed? ? Timed : assignment? ? Assignment : OrdinaryTimeless
64
51
  inform_upstream_places # that they have been connected
65
52
  inform_downstream_places # that they have been connected
@@ -73,52 +60,55 @@ class YPetri::Transition
73
60
  # else then defining the duck type of the input argument collection.
74
61
  # TypeError is therefore raised if invalid collection has been supplied.
75
62
  #
76
- def check_in_arguments *aa, **oo, &block
77
- oo.may_have :stoichiometry, syn!: [ :stoichio, :s ]
78
- oo.may_have :codomain, syn!: [ :codomain_arcs, :codomain_places,
63
+ def check_in_arguments **nn, &block
64
+ nn.update( action: block ) if block_given?
65
+ nn.may_have :domain, syn!: [ :domain_arcs, :domain_places,
66
+ :upstream, :upstream_arcs, :upstream_places ]
67
+ nn.may_have :codomain, syn!: [ :codomain_arcs, :codomain_places,
79
68
  :downstream,
80
69
  :downstream_arcs, :downstream_places,
81
70
  :action_arcs ]
82
- oo.may_have :domain, syn!: [ :domain_arcs, :domain_places,
83
- :upstream, :upstream_arcs, :upstream_places ]
84
- oo.may_have :rate, syn!: [ :rate_closure, :propensity,
71
+ nn.may_have :rate, syn!: [ :rate_closure, :propensity,
85
72
  :propensity_closure ]
86
- oo.may_have :action, syn!: :action_closure
87
- oo.may_have :timed
88
- oo.may_have :domain_guard
89
- oo.may_have :codomain_guard
73
+ nn.may_have :action, syn!: :action_closure
74
+ nn.may_have :stoichiometry, syn!: [ :stoichio, :s ]
75
+ nn.may_have :domain_guard
76
+ nn.may_have :codomain_guard
90
77
 
91
- @has_rate = oo.has? :rate # was the rate was given?
78
+ # If the rate was given, the transition is timed:
79
+ @timed = nn.has? :rate
92
80
 
93
- # is the transition stoichiometric (S) or nonstoichiometric (s)?
94
- @stoichiometric = oo.has? :stoichiometry
81
+ # If stoichiometry was given, the transition is stoichiometric:
82
+ @stoichiometric = nn.has? :stoichiometry
95
83
 
96
- # downstream description arguments: codomain, stoichiometry (if S)
84
+ # Downstream description involves the codomain, and the stochiometry
85
+ # (for stoichiometric transitions only):
97
86
  if stoichiometric? then
98
- @codomain, @stoichiometry = check_in_downstream_description_for_S( oo )
99
- else # s transitions have no stoichiometry
100
- @codomain = check_in_downstream_description_for_s( oo )
87
+ @codomain, @stoichiometry = __downstream_for_S__( **nn )
88
+ else
89
+ @codomain = __downstream_for_s__( **nn )
101
90
  end
102
91
 
103
- # check in domain first, :missing symbol may appear
104
- @domain = check_in_domain( oo )
92
+ # Check in the domain first, :missing symbol may be returned if the user
93
+ # has not supplied the domaing (the constructor will attempt to guessf it
94
+ # automatically).
95
+ @domain = __domain__( **nn )
105
96
 
106
- # upstream description arguments; also takes care of :missing domain
107
- if has_rate? then
108
- @domain, @rate_closure, @timed, @functional =
109
- check_in_upstream_description_for_R( oo, &block )
97
+ # Upstream description involves the domain and the rate/action closure.
98
+ # Also, :missing domain is taken care of here.
99
+ if timed? then
100
+ @domain, @rate_closure, @functional = __upstream_for_T__( **nn )
110
101
  else
111
- @domain, @action_closure, @timed, @functional =
112
- check_in_upstream_description_for_r( oo, &block )
102
+ @domain, @action_closure, @functional = __upstream_for_t__( **nn )
113
103
  end
114
104
 
115
- # optional assignment action:
116
- @assignment_action = check_in_assignment_action( oo )
105
+ # Optional assignment action:
106
+ @assignment_action = __assignment_action__( **nn )
107
+
108
+ # Optional type guards for domain / codomain:
109
+ @domain_guard, @codomain_guard = __guards__( **nn )
110
+ end
117
111
 
118
- # optional type guards for domain / codomain:
119
- @domain_guard, @codomain_guard = check_in_guards( oo )
120
- end # def check_in_arguments
121
-
122
112
  # Validates that the supplied collection consists only of places of
123
113
  # correct type. Second optional argument customizes the error message.
124
114
  #
@@ -134,10 +124,10 @@ class YPetri::Transition
134
124
  coll == coll.uniq
135
125
  end
136
126
  end
137
-
127
+
138
128
  # Private method, part of #initialize argument checking-in.
139
129
  #
140
- def check_in_domain( oo )
130
+ def __domain__( **oo )
141
131
  if oo.has? :domain then
142
132
  sanitize_place_collection( oo[:domain], "supplied domain" )
143
133
  else
@@ -150,131 +140,73 @@ class YPetri::Transition
150
140
  # Barring the caller's error, missing domain can mean:
151
141
  # 1. empty domain
152
142
  # 2. domain == codomain
153
- # This will be figured later by rate/action closure arity
143
+ # This will be figured later by the rate/action closure arity.
154
144
  end
155
145
  end
156
146
  end
157
147
 
158
- # Private method, part of the init process when :rate is given. Also takes
159
- # care for missing domain (@domain == :missing).
148
+ # Private method, part of the init process for timed transitions. Also takes
149
+ # care for :missing domain, if :missing.
160
150
  #
161
- def check_in_upstream_description_for_R( oo, &block )
151
+ def __upstream_for_T__( **oo )
162
152
  _domain = domain # this method may modify domain
163
- fail ArgumentError, "Rate/propensity and action may not be both given!" if
164
- oo.has? :action # check against colliding :action named argument
165
- fail ArgumentError, "If block is given, rate must not be given!" if block
166
- # Let's figure the rate closure now. (Block is never used.)
167
- rate_λ = case ra = oo[:rate]
168
- when Proc then # We received the closure directly,
169
- ra.tap do |λ| # but we've to be concerned about missing domain.
170
- if domain == :missing then # we've to figure user's intent
171
- _domain = if λ.arity == 0 then [] # user meant empty domain
172
- else codomain end # user meant domain == codomain
173
- else # domain not missing
174
- fail TypeError, "Rate closure arity (#{λ.arity}) > " +
175
- "domain (#{domain.size})!" if λ.arity.abs > domain.size
176
- end
177
- end
178
- else # We received something else, must guess user's intent.
179
- if stoichiometric? then # user's intent was mass action
180
- fail TypeError, "When a number is supplied as rate, " +
181
- "domain must not be given!" if oo.has? :domain
182
- construct_standard_mass_action( ra )
183
- else # user's intent was constant closure
184
- fail TypeError, "When rate is a number and stoichiometry " +
185
- "is not given, codomain size must be 1!" unless
186
- codomain.size == 1
187
- # Missing domain is OK here,
188
- _domain = [] if domain == :missing
189
- # but if it was supplied explicitly, it must be empty.
190
- fail TypeError, "Rate is a number, but non-empty domain " +
191
- "was supplied!" unless domain.empty? if oo.has?( :domain )
192
- -> { ra }
193
- end
194
- end
195
- # R transitions are implicitly timed
196
- _timed = true
197
- # check against colliding :timed argument
198
- oo[:timed].tE :timed, "not be false if rate given" if oo.has? :timed
199
- # R transitions are implicitly functional
200
- _functional = true
201
- return _domain, rate_λ, _timed, _functional
153
+ _functional = true # T transitions are implicitly functional
154
+ fail ArgumentError, "Rate and action collision!" if oo.has? :action
155
+ # Let's figure the rate closure now.
156
+ λ = oo[:rate]
157
+ if λ.is_a? Proc then
158
+ # Solve :missing domain:
159
+ _domain = λ.arity == 0 ? [] : codomain if domain == :missing
160
+ # Validate arity:
161
+ msg = "Rate closure arity (#{λ.arity}) > domain (#{domain.size})!"
162
+ fail TypeError, msg if λ.arity.abs > domain.size
163
+ else # not a Proc, must guess user's intent
164
+ λ = if stoichiometric? then # standard mass action
165
+ msg = "With numeric rate, domain must not be given!"
166
+ fail TypeError, msg if oo.has? :domain
167
+ __standard_mass_action__( λ )
168
+ else # constant closure
169
+ msg = "With numeric rate and no stoichio., codomain size must be 1!"
170
+ fail TypeError, msg unless codomain.size == 1
171
+ _domain = [] if domain == :missing # Missing domain is OK here,
172
+ # But in case it was supplied explicitly, it must be empty.
173
+ msg = "Rate is a number, but domain is non-empty!"
174
+ fail TypeError, msg unless domain.empty? if oo.has? :domain
175
+ -> { λ } # the closure itself
176
+ end
177
+ end
178
+ return _domain, λ, _functional
202
179
  end
203
180
 
204
181
  # Private method, part of the init process when :rate is not given. Also
205
182
  # takes care for missing domain (@domain == :missing).
206
183
  #
207
- def check_in_upstream_description_for_r( oo, &block )
208
- _domain = domain # this method may modify domain
184
+ def __upstream_for_t__( **oo )
185
+ _domain = domain # this method may modify domain
209
186
  _functional = true
210
- # Was action closure was given explicitly?
187
+ # Was action given explicitly?
211
188
  if oo.has? :action then
212
- fail ArgumentError, "If block is given, rate must not be given!" if block
213
- action_λ = oo[:action].aT_is_a Proc, "supplied action named argument"
214
- if oo.has? :timed then
215
- _timed = oo[:timed]
216
- # Time to worry about the domain_missing
217
- if domain == :missing then # figure user's intent from closure arity
218
- _domain = if action_λ.arity == ( _timed ? 1 : 0 ) then
219
- [] # user meant empty domain
220
- else
221
- codomain # user meant domain same as codomain
222
- end
223
- else # domain not missing
224
- fail TypeError, "Rate closure arity (#{rate_arg.arity}) > domain " +
225
- "size (#{domain.size})!" if action_λ.arity.abs > domain.size
226
- end
227
- else # :timed argument not supplied
228
- if domain == :missing then
229
- # If no domain was supplied, there is no way to reasonably figure
230
- # out the user's intent, except when arity is 0:
231
- _domain = case action_λ.arity
232
- when 0 then
233
- _timed = false
234
- [] # empty domain is implied
235
- else # no deduction of user intent possible
236
- fail ArgumentError, "Too much ambiguity: Rateless " +
237
- "transition with neither domain nor timedness given."
238
- end
239
- else # domain not missing
240
- # Even if the user did not bother to inform us explicitly about
241
- # timedness, we can use closure arity as a clue. If it equals the
242
- # domain size, leaving no room for Δtime argument, the user intent
243
- # was to create timeless transition. If it equals domain size + 1,
244
- # theu user intended to create a timed transition.
245
- _timed = case action_λ.arity
246
- when domain.size then false
247
- when domain.size + 1 then true
248
- else # no deduction of user intent possible
249
- fail ArgumentError, "Timedness was not specified, and " +
250
- "action closure arity (#{action_λ.arity}) does not " +
251
- "give a clear hint on it!"
252
- end
253
- end
189
+ λ = oo[:action].aT_is_a Proc, "supplied action named argument"
190
+ # Time to worry about the domain_missing, guess the user's intention:
191
+ if domain == :missing then
192
+ _domain = ( λ.arity == 0 ? [] : codomain )
193
+ else
194
+ msg = "Action closure arity (#{λ.arity}) > domain size (#{domain.size})!"
195
+ fail TypeError, msg if λ.arity.abs > domain.size
254
196
  end
255
- else # rateless cases with no action closure specified
256
- # Consume block, if given:
257
- check_in_upstream_for_r oo.update( action: block ) if block
258
- # If there is really really no closure, an assumption must be made taken
259
- # as for the transition's action, in particular, -> { 1 } closure:
260
- action_λ = -> { 1 }
261
- # The transition is then required to be stoichiometric and timeless.
262
- # Domain will be required empty.
263
- fail ArgumentError, "Stoichiometry is compulsory, if no rate/action " +
264
- "was supplied." unless stoichiometric?
265
- # With this, we can drop worries about missing domain.
266
- fail ArgumentError, "When no rate/propensity or action is supplied, " +
267
- "the transition cannot be timed." if oo[:timed] if oo.has? :timed
268
- _timed = false
269
- _domain = []
270
- _functional = false # the transition is considered functionless
197
+ else # functionless transition
198
+ _functional = false
199
+ λ = -> { 1 }
200
+ msg = "Stoichiometry is compulsory, if no rate/action was supplied."
201
+ fail ArgumentError, msg unless S?
202
+ _domain = [] # in any case, the domain is empty
271
203
  end
272
- return _domain, action_λ, _timed, _functional
204
+ return _domain, λ, _functional
273
205
  end
274
206
 
275
207
  # Default rate closure for SR transitions whose rate is hinted as a number.
276
208
  #
277
- def construct_standard_mass_action( num )
209
+ def __standard_mass_action__( num )
278
210
  # assume standard mass-action law
279
211
  nonpositive_coeffs = stoichiometry.select { |coeff| coeff <= 0 }
280
212
  # the closure takes markings of the domain as its arguments
@@ -294,21 +226,21 @@ class YPetri::Transition
294
226
  # Private method, checking in downstream specification from the argument
295
227
  # field for stoichiometric transition.
296
228
  #
297
- def check_in_downstream_description_for_S( oo )
229
+ def __downstream_for_S__( **oo )
298
230
  codomain, stoichio =
299
231
  case oo[:stoichiometry]
300
232
  when Hash then
301
233
  # contains pairs { codomain place => stoichiometry coefficient }
302
- fail ArgumentError, "With hash-type stoichiometry, :codomain " +
303
- "argument must not be given!" if oo.has? :codomain
234
+ msg = "With hash-type stoichiometry, :codomain must not be given!"
235
+ fail ArgumentError, msg if oo.has? :codomain
304
236
  oo[:stoichiometry].each_with_object [[], []] do |(cd_pl, coeff), memo|
305
- memo[0] << cd_pl
306
- memo[1] << coeff
307
- end
237
+ memo[0] << cd_pl
238
+ memo[1] << coeff
239
+ end
308
240
  else
309
241
  # array of stoichiometry coefficients
310
- fail ArgumentError, "With array-type stoichiometry, :codomain " +
311
- "argument must be given!" unless oo.has? :codomain
242
+ msg = "With array-type stoichiometry, :codomain must be given!"
243
+ fail ArgumentError unless oo.has? :codomain
312
244
  [ oo[:codomain], Array( oo[:stoichiometry] ) ]
313
245
  end
314
246
  # enforce that stoichiometry is a collection of numbers
@@ -319,7 +251,7 @@ class YPetri::Transition
319
251
  # Private method, checking in downstream specification from the argument
320
252
  # field for nonstoichiometric transition.
321
253
  #
322
- def check_in_downstream_description_for_s( oo )
254
+ def __downstream_for_s__( **oo )
323
255
  # codomain must be explicitly given - no way around it:
324
256
  fail ArgumentError, "For non-stoichiometric transitions, :codomain " +
325
257
  "argument is compulsory." unless oo.has? :codomain
@@ -328,7 +260,7 @@ class YPetri::Transition
328
260
 
329
261
  # Private method, part of #initialize argument checking-in.
330
262
  #
331
- def check_in_assignment_action( oo )
263
+ def __assignment_action__( **oo )
332
264
  if oo.has? :assignment_action, syn!: [ :assignment, :assign, :A ] then
333
265
  if timed? then
334
266
  false.tap do
@@ -341,7 +273,7 @@ class YPetri::Transition
341
273
 
342
274
  # Private method, part of #initialize argument checking-in
343
275
  #
344
- def check_in_guards( oo )
276
+ def __guards__( **oo )
345
277
  if oo.has? :domain_guard then
346
278
  oo[:domain_guard].aT_is_a Proc, "supplied domain guard"
347
279
  else