y_petri 2.0.14 → 2.0.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04fefe57afd5fa9850489c3d5dcfe27ffd520e05
4
- data.tar.gz: f544785cc23baa8b9d26d0afb15984d8c85c59a4
3
+ metadata.gz: 3c819010da78d8924cb320612edc32744c5d745a
4
+ data.tar.gz: f3320f25920735b13fa67be3793fa3dd768915fc
5
5
  SHA512:
6
- metadata.gz: 705160694568b66998cbeff7a273113e5a84f80d97f14fe161c427bf95d06894e4eee6d0cc8a7b9e4f60aec4c1483b8685826df339de92c3a7856eda4a3c8f3b
7
- data.tar.gz: 98e978bf1c89bcef1bac79c5b1f3a90dbfc48fc98842cd18569f46a672a2484853fc0a7d1d1f1e70c883db6a13c849e85e888b98ac1d7702733d34c4dbe95969
6
+ metadata.gz: e65d106f512773919f4fcf810927ac7f61c8c0e50c0faeea4b23c7671b2ae175a770ef8ce4da9d08366eb14b55e021b7949965b9c55de7f86f501d8f25128561
7
+ data.tar.gz: 834d55aeb5103d792a2ff8370352802278815fea76c6286bb465e59973a9e9166c24bce73309d20da1ca85303581cf0ac5cfc015c763f26a3287024dcbc37cdc
@@ -192,14 +192,19 @@ module YPetri::Manipulator::SimulationRelatedMethods
192
192
  end
193
193
  alias set_step_size set_step
194
194
 
195
- # Changes the simulation time of the current ssc (ssc = simulation
196
- # settings collection).
195
+ # Sets the time frame of the current ssc (sim. settings collection).
197
196
  #
198
- def set_time t
199
- ssc.update target_time: t
197
+ def set_time time_range
198
+ ssc.update time: time_range.aT_kind_of( Range )
200
199
  end
201
- alias set_target_time set_time
202
200
 
201
+ # Sets the time frame of the current ssc to run from zero to the time supplied
202
+ # as the argument.
203
+ #
204
+ def set_target_time time
205
+ set_time time * 0 .. time
206
+ end
207
+
203
208
  # Changes the sampling period of the current ssc (ssc = simulation
204
209
  # settings collection).
205
210
  #
data/lib/y_petri/net.rb CHANGED
@@ -113,14 +113,14 @@ class YPetri::Net
113
113
 
114
114
  # Creates a new simulation from the net.
115
115
  #
116
- def new_simulation( **named_args )
117
- YPetri::Simulation.new **named_args.merge( net: self )
116
+ def new_simulation( **nn )
117
+ YPetri::Simulation.new **nn.merge( net: self )
118
118
  end
119
119
 
120
120
  # Creates a new timed simulation from the net.
121
121
  #
122
- def new_timed_simulation( **named_args )
123
- YPetri::TimedSimulation.new **named_args.merge( net: self )
122
+ def new_timed_simulation( **nn )
123
+ new_simulation( **nn ).aT &:timed?
124
124
  end
125
125
 
126
126
  # Networks are equal when their places and transitions are equal.
@@ -6,9 +6,13 @@ class YPetri::Place
6
6
  # Marking guard.
7
7
  #
8
8
  class Guard
9
- ERRMSG = -> m, assert { "Marking #{m}:#{m.class} #{assert}!" }
9
+ ERRMSG = -> m, of, assert do
10
+ "Marking #{m}:#{m.class}" +
11
+ if of then " of #{of.name || of rescue of}" else '' end +
12
+ " #{assert}!"
13
+ end
10
14
 
11
- attr_reader :assertion, :block
15
+ attr_reader :place, :assertion, :block
12
16
 
13
17
  # Requires a NL guard assertion (used in GuardError messages), and a guard
14
18
  # block expressing the same assertion formally, in code. Attention: *Only
@@ -21,8 +25,8 @@ class YPetri::Place
21
25
  # automatically raise appropriately worded +GuardError+. See also:
22
26
  # {+YPetri#guard+ method}[rdoc-ref:YPetri::guard].
23
27
  #
24
- def initialize assertion_NL_string, &block
25
- @assertion, @block = assertion_NL_string, block
28
+ def initialize( assertion_NL_string, place: nil, &block )
29
+ @place, @assertion, @block = place, assertion_NL_string, block
26
30
  @Lab = Class.new BasicObject do
27
31
  def initialize λ; @λ = λ end
28
32
  def fail; @λ.call end
@@ -32,9 +36,9 @@ class YPetri::Place
32
36
  # Validates a supplied marking value against the guard block. Raises
33
37
  # +YPetri::GuardError+ if the guard fails, otherwise returns _true_.
34
38
  #
35
- def validate( marking_value )
36
- λ = __fail__( marking_value, assertion )
37
- λ.call if @Lab.new( λ ).instance_exec( marking_value, &block ) == false
39
+ def validate( marking )
40
+ λ = __fail__( marking, assertion )
41
+ λ.call if @Lab.new( λ ).instance_exec( marking, &block ) == false
38
42
  return true
39
43
  end
40
44
 
@@ -42,8 +46,9 @@ class YPetri::Place
42
46
 
43
47
  # Constructs the fail closure.
44
48
  #
45
- def __fail__ marking_value, assertion
46
- -> { fail YPetri::GuardError, ERRMSG.( marking_value, assertion ) }
49
+ def __fail__ marking, assertion
50
+ pl = place
51
+ -> { fail YPetri::GuardError, ERRMSG.( marking, pl, assertion ) }
47
52
  end
48
53
  end
49
54
 
@@ -80,7 +85,7 @@ class YPetri::Place
80
85
  # were given (behaving as +#federated_guard_closure+ alias in this case).
81
86
  #
82
87
  def guard *args, &block
83
- if block then @guards << Guard.new( *args, &block )
88
+ if block then @guards << Guard.new( *args, place: name || self, &block )
84
89
  elsif args.size == 1 then federated_guard_closure.( args[0] )
85
90
  elsif args.empty? then federated_guard_closure
86
91
  end
@@ -91,8 +96,8 @@ class YPetri::Place
91
96
  # blocks pass for the given marking value.
92
97
  #
93
98
  def federated_guard_closure
94
- lineup = guards.dup
95
- -> m { lineup.each { |g| g.validate m }; return m }
99
+ place_name, lineup = name.to_s, guards.dup
100
+ -> m { lineup.each { |g| g.validate( m ) }; return m }
96
101
  end
97
102
 
98
103
  # Applies guards on the marking currently owned by the place.
@@ -0,0 +1,460 @@
1
+ #encoding: utf-8
2
+
3
+ # Mixin that provides methods exposing place and transition collections to
4
+ # YPetri::Simulation.
5
+ #
6
+ class YPetri::Simulation
7
+ module Collections
8
+ # Returns the simulation's places. Optional arguments / block make it return
9
+ # a hash <tt>places => values</tt>, such as:
10
+ #
11
+ # places :marking
12
+ # #=> { <Place:Foo> => 42, <Place:Bar> => 43, ... }
13
+ #
14
+ def places *aa, &b
15
+ return @places.dup if aa.empty? && b.nil?
16
+ zip_to_hash places, *aa, &b
17
+ end
18
+
19
+ # Returns the simulation's transitions. Optional arguments / block make it
20
+ # return a hash <tt>places => values</tt>, such as:
21
+ #
22
+ # transitions :flux
23
+ # #=> { <Transition:Baz> => 42, <Transition:Quux => 43, ... }
24
+ #
25
+ def transitions *aa, &b
26
+ return @transitions.dup if aa.empty? && b.nil?
27
+ zip_to_hash transitions, *aa, &b
28
+ end
29
+
30
+ # Like #places method, except that in the output, names are used instead of
31
+ # place instances when possible.
32
+ #
33
+ def pp *aa, &b
34
+ return places.map &:name if aa.empty? && b.nil?
35
+ zip_to_hash( places.map { |p| p.name || p }, *aa, &b )
36
+ end
37
+
38
+ # Like #transitions method, except that in the output, names are used
39
+ # instead of transition instances when possible.
40
+ #
41
+ def tt *aa, &b
42
+ return transitions.map &:name if aa.empty? && b.nil?
43
+ zip_to_hash( transitions.map { |t| t.name || t }, *aa, &b )
44
+ end
45
+
46
+ # Returns the simulation's free places, with same syntax options as #places
47
+ # method.
48
+ #
49
+ def free_places *aa, &b
50
+ return zip_to_hash free_places, *aa, &b unless aa.empty? && b.nil?
51
+ kk = @initial_marking.keys
52
+ places.select { |p| kk.include? p }
53
+ end
54
+
55
+ # Like #free_places, except that in the output, names are used instead of
56
+ # place instances when possible.
57
+ #
58
+ def free_pp *aa, &b
59
+ return free_places.map { |p| p.name || p } if aa.empty? && b.nil?
60
+ zip_to_hash free_pp, *aa, &b
61
+ end
62
+
63
+ # Initial marking definitions for free places (as array).
64
+ #
65
+ def im
66
+ free_places.map { |p| @initial_marking[p] }
67
+ end
68
+
69
+ # Marking array of all places as it appears at the beginning of a simulation.
70
+ #
71
+ def initial_marking
72
+ raise # FIXME: "Initial marking" for all places (ie. incl. clamped ones).
73
+ end
74
+
75
+ # Initial marking of free places (as column vector).
76
+ #
77
+ def im_vector
78
+ Matrix.column_vector im
79
+ end
80
+ alias iᴍ im_vector
81
+
82
+ # Marking of all places at the beginning of a simulation (as column vector).
83
+ #
84
+ def initial_marking_vector
85
+ Matrix.column_vector initial_marking
86
+ end
87
+
88
+ # Returns the simulation's clamped places, with same syntax options as #places
89
+ # method.
90
+ #
91
+ def clamped_places *aa, &b
92
+ return zip_to_hash clamped_places, *aa, &b unless aa.empty? && b.nil?
93
+ kk = @marking_clamps.keys
94
+ places.select { |p| kk.include? p }
95
+ end
96
+
97
+ # Like #clamped_places, except that in the output, names are used instead of
98
+ # place instances whenever possible.
99
+ #
100
+ def clamped_pp *aa, &b
101
+ return clamped_places.map { |p| p.name || p } if aa.empty? && b.nil?
102
+ zip_to_hash clamped_pp, *aa, &b
103
+ end
104
+
105
+ # Place clamp definitions for clamped places (as array)
106
+ #
107
+ def marking_clamps
108
+ clamped_places.map { |p| @marking_clamps[p] }
109
+ end
110
+ alias place_clamps marking_clamps
111
+
112
+ # Marking of free places (as array).
113
+ #
114
+ def m
115
+ m_vector.column_to_a
116
+ end
117
+
118
+ # Marking of free places (as hash of pairs <tt>{ name: marking }</tt>).
119
+ #
120
+ def pm
121
+ free_pp :m
122
+ end
123
+ alias p_m pm
124
+
125
+ # Marking of free places (as hash of pairs <tt>{ place: marking }</tt>.
126
+ #
127
+ def place_m
128
+ free_places :m
129
+ end
130
+
131
+ # Marking of all places (as array).
132
+ #
133
+ def marking
134
+ marking_vector ? marking_vector.column_to_a : nil
135
+ end
136
+
137
+ # Marking of all places (as hash of pairs <tt>{ name: marking }</tt>).
138
+ #
139
+ def p_marking
140
+ pp :marking
141
+ end
142
+ alias pmarking p_marking
143
+
144
+ # Marking of all places (as hash of pairs <tt>{ place: marking }</tt>.
145
+ #
146
+ def place_marking
147
+ places :marking
148
+ end
149
+
150
+ # Marking of a specified place or a collection of places.
151
+ #
152
+ def marking_of places
153
+ m = place_marking
154
+ return places.map { |pl| m[ place( pl ) ] } if places.respond_to? :each
155
+ m[ place( place_or_places ) ]
156
+ end
157
+ alias m_of marking_of
158
+
159
+ # Marking of free places ( as column vector).
160
+ #
161
+ def m_vector
162
+ F2A().t * @marking_vector
163
+ end
164
+ alias ᴍ m_vector
165
+
166
+ # Marking of clamped places (as column vector).
167
+ #
168
+ def marking_vector_of_clamped_places
169
+ C2A().t * @marking_vector
170
+ end
171
+ alias ᴍ_clamped marking_vector_of_clamped_places
172
+
173
+ # Marking of clamped places (as array).
174
+ #
175
+ def marking_of_clamped_places
176
+ marking_vector_of_clamped_places.column( 0 ).to_a
177
+ end
178
+ alias m_clamped marking_of_clamped_places
179
+
180
+ # Returns a stoichiometry matrix for an arbitrary array of stoichiometric
181
+ # transitions. The returned stoichiometry matrix has the number of columns
182
+ # equal to the number of supplied stoichimetric transitions, and the number
183
+ # of rows equal to the number of free places. When multiplied by a vector
184
+ # corresponding to the transitions (such as flux vector), the resulting
185
+ # column vector corresponds to the free places.
186
+ #
187
+ def S_for( stoichiometric_transitions )
188
+ stoichiometric_transitions.map { |t| sparse_σ t }
189
+ .reduce( Matrix.empty( free_places.size, 0 ), :join_right )
190
+ end
191
+
192
+ # Returns a stoichiometry matrix for an arbitrary array of stoichiometric
193
+ # transitions. Behaves like +#S_for+ method, with the difference that the
194
+ # rows correspond to _all_ places, not just free places.
195
+ #
196
+ def stoichiometry_matrix_for( stoichiometric_transitions )
197
+ stoichiometric_transitions.map { |t| sparse_stoichiometry_vector t }
198
+ .reduce( Matrix.empty( places.size, 0 ), :join_right )
199
+ end
200
+
201
+ # Stoichiometry matrix of this simulation. By calling this method, the
202
+ # caller asserts, that all transitions in this simulation are SR transitions
203
+ # (or error).
204
+ #
205
+ def S
206
+ return S_SR() if s_transitions.empty? && r_transitions.empty?
207
+ raise "The simulation contains also non-stoichiometric transitions! " +
208
+ "Consider using #S_for_SR."
209
+ end
210
+
211
+ # ==== ts transitions
212
+
213
+ # Returns the simulation's *ts* transitions, with syntax options like
214
+ # #transitions method.
215
+ #
216
+ def ts_transitions *aa, &b
217
+ return zip_to_hash ts_transitions, *aa, &b unless aa.empty? && b.nil?
218
+ sift_from_net :ts_transitions
219
+ end
220
+
221
+ # Like #ts_transitions, except that in the output, names are used instead
222
+ # of instances when possible.
223
+ #
224
+ def ts_tt *aa, &b
225
+ return zip_to_hash ts_tt, *aa, &b unless aa.empty? && b.nil?
226
+ ts_transitions.map { |t| t.name || t }
227
+ end
228
+
229
+ # Returns the simulation's *non-assignment* *ts* transtitions, with syntax
230
+ # options like #transitions method. While *A* transitions can be regarded
231
+ # as a special kind of *ts* transitions, it may often be useful to separate
232
+ # them out from the collection of "ordinary" *ts* transtitions (*tsa*
233
+ # transitions).
234
+ #
235
+ def tsa_transitions *aa, &b
236
+ return zip_to_hash tsa_transitions, *aa, &b unless aa.empty? && b.nil?
237
+ sift_from_net :tsa_transitions
238
+ end
239
+
240
+ # Like #tsa_transitions, except that in the output, names are used instead
241
+ # of instances when possible.
242
+ #
243
+ def tsa_tt *aa, &b
244
+ return zip_to_hash tsa_tt, *aa, &b unless aa.empty? && b.nil?
245
+ tsa_transitions.map { |t| t.name || t }
246
+ end
247
+
248
+ # ==== tS transitions
249
+
250
+ # Returns the simulation's *tS* transitions, with syntax options like
251
+ # #transitions method.
252
+ #
253
+ def tS_transitions *aa, &b
254
+ return zip_to_hash tS_transitions, *aa, &b unless aa.empty? && b.nil?
255
+ sift_from_net :tS_transitions
256
+ end
257
+
258
+ # Like #tS_transitions, except that in the output, names are used instead
259
+ # of instances when possible.
260
+ #
261
+ def tS_tt *aa, &b
262
+ return zip_to_hash tS_tt, *aa, &b unless aa.empty? && b.nil?
263
+ tS_transitions.map { |t| t.name || t }
264
+ end
265
+
266
+ # ==== Tsr transitions
267
+
268
+ # Returns the simulation's *Tsr* transitions, with syntax options like
269
+ # #transitions method.
270
+ #
271
+ def Tsr_transitions *aa, &b
272
+ return zip_to_hash Tsr_transitions(), *aa, &b unless aa.empty? && b.nil?
273
+ sift_from_net :Tsr_transitions
274
+ end
275
+
276
+ # Like #Tsr_transitions, except that in the output, names are used instead
277
+ # of instances when possible.
278
+ #
279
+ def Tsr_tt *aa, &b
280
+ return zip_to_hash Tsr_tt(), *aa, &b unless aa.empty? && b.nil?
281
+ Tsr_transitions().map { |t| t.name || t }
282
+ end
283
+
284
+ # ==== TSr transitions
285
+
286
+ # Returns the simulation's *TSr* transitions, with syntax options like
287
+ # #transitions method.
288
+ #
289
+ def TSr_transitions *aa, &b
290
+ return zip_to_hash TSr_transitions(), *aa, &b unless aa.empty? && b.nil?
291
+ sift_from_net :TSr_transitions
292
+ end
293
+
294
+ # Like #TSr_transitions, except that in the output, names are used instead
295
+ # of instances when possible.
296
+ #
297
+ def TSr_tt *aa, &b
298
+ return zip_to_hash TSr_tt(), *aa, &b unless aa.empty? && b.nil?
299
+ TSr_transitions().map { |t| t.name || t }
300
+ end
301
+
302
+ # ==== sR transitions
303
+
304
+ # Returns the simulation's *sR* transitions, with syntax options like
305
+ # #transitions method.
306
+ #
307
+ def sR_transitions *aa, &b
308
+ return zip_to_hash sR_transitions(), *aa, &b unless aa.empty? && b.nil?
309
+ sift_from_net :sR_transitions
310
+ end
311
+
312
+ # Like #sR_transitions, except that in the output, names are used instead
313
+ # of instances when possible.
314
+ #
315
+ def sR_tt *aa, &b
316
+ return zip_to_hash sR_tt(), *aa, &b unless aa.empty? && b.nil?
317
+ sR_transitions.map { |t| t.name || t }
318
+ end
319
+
320
+ # ==== SR transitions
321
+
322
+ # Returns the simulation's *SR* transitions, with syntax options like
323
+ # #transitions method.
324
+ #
325
+ def SR_transitions *aa, &b
326
+ return zip_to_hash SR_transitions(), *aa, &b unless aa.empty? && b.nil?
327
+ sift_from_net :SR_transitions
328
+ end
329
+
330
+ # Like #SR_transitions, except that in the output, names are used instead
331
+ # of instances when possible.
332
+ #
333
+ def SR_tt *aa, &b
334
+ return zip_to_hash SR_tt(), *aa, &b unless aa.empty? && b.nil?
335
+ SR_transitions().map { |t| t.name || t }
336
+ end
337
+
338
+ # ==== Assignment (A) transitions
339
+
340
+ # Returns the simulation's *A* transitions, with syntax options like
341
+ # #transitions method.
342
+ #
343
+ def A_transitions *aa, &b
344
+ return zip_to_hash A_transitions(), *aa, &b unless aa.empty? && b.nil?
345
+ sift_from_net :A_transitions
346
+ end
347
+ alias assignment_transitions A_transitions
348
+
349
+ # Like #A_transitions, except that in the output, names are used instead
350
+ # of instances when possible.
351
+ #
352
+ def A_tt *aa, &b
353
+ return zip_to_hash A_tt(), *aa, &b unless aa.empty? && b.nil?
354
+ A_transitions().map { |t| t.name || t }
355
+ end
356
+ alias assignment_tt A_tt
357
+
358
+ # ==== Stoichiometric transitions of arbitrary type (S transitions)
359
+
360
+ # Returns the simulation's *S* transitions, with syntax options like
361
+ # #transitions method.
362
+ #
363
+ def S_transitions *aa, &b
364
+ return zip_to_hash S_transitions(), *aa, &b unless aa.empty? && b.nil?
365
+ sift_from_net :S_transitions
366
+ end
367
+
368
+ # Like #S_transitions, except that in the output, names are used instead
369
+ # of instances when possible.
370
+ #
371
+ def S_tt *aa, &b
372
+ return zip_to_hash S_tt(), *aa, &b unless aa.empty? && b.nil?
373
+ S_transitions().map { |t| t.name || t }
374
+ end
375
+
376
+ # ==== Nonstoichiometric transitions of arbitrary type (s transitions)
377
+
378
+ # Returns the simulation's *s* transitions, with syntax options like
379
+ # #transitions method.
380
+ #
381
+ def s_transitions *aa, &b
382
+ return zip_to_hash s_transitions, *aa, &b unless aa.empty? && b.nil?
383
+ sift_from_net :s_transitions
384
+ end
385
+
386
+ # Like #s_transitions, except that in the output, names are used instead
387
+ # of instances when possible.
388
+ #
389
+ def s_tt *aa, &b
390
+ return zip_to_hash s_tt, *aa, &b unless aa.empty? && b.nil?
391
+ s_transitions.map { |t| t.name || t }
392
+ end
393
+
394
+ # ==== Transitions with rate of arbitrary type (R transitions)
395
+
396
+ # Returns the simulation's *R* transitions, with syntax options like
397
+ # #transitions method.
398
+ #
399
+ def R_transitions *aa, &b
400
+ return zip_to_hash R_transitions(), *aa, &b unless aa.empty? && b.nil?
401
+ sift_from_net :R_transitions
402
+ end
403
+
404
+ # Like #R_transitions, except that in the output, names are used instead
405
+ # of instances when possible.
406
+ #
407
+ def R_tt *aa, &b
408
+ return zip_to_hash R_tt(), *aa, &b unless aa.empty? && b.nil?
409
+ R_transitions().map { |t| t.name || t }
410
+ end
411
+
412
+ # ==== Rateless transitions of arbitrary type (r transitions)
413
+
414
+ # Returns the simulation's *r* transitions, with syntax options like
415
+ # #transitions method.
416
+ #
417
+ def r_transitions *aa, &b
418
+ return zip_to_hash r_transitions, *aa, &b unless aa.empty? && b.nil?
419
+ sift_from_net :r_transitions
420
+ end
421
+
422
+ # Like #r_transitions, except that transition names are used instead of
423
+ # instances, whenever possible.
424
+ #
425
+ def r_tt *aa, &b
426
+ return zip_to_hash r_tt, *aa, &b unless aa.empty? && b.nil?
427
+ r_transitions.map { |t| t.name || t }
428
+ end
429
+
430
+ private
431
+
432
+ # This helper method takes a collection, a variable number of other arguments
433
+ # and an optional block, and returns a hash whose keys are the collection
434
+ # members, and whose values are given by the supplied othe arguments and/or
435
+ # block in the following way: If there is no additional argument, but a block
436
+ # is supplied, this is applied to the collection. If there is exactly one
437
+ # other argument, and it is also a collection, it is used as values.
438
+ # Otherwise, these other arguments are treated as a message to be sent to
439
+ # self (via #send), expecting it to return a collection to be used as hash
440
+ # values. Optional block (which is always assumed to be unary) can be used
441
+ # to additionally modify the second collection.
442
+ #
443
+ def zip_to_hash collection, *args, &block
444
+ sz = args.size
445
+ values = if sz == 0 then collection
446
+ elsif sz == 1 && args[0].respond_to?( :each ) then args[0]
447
+ else send *args end
448
+ Hash[ collection.zip( block ? values.map( &block ) : values ) ]
449
+ end
450
+
451
+ # Chicken approach towards ensuring that transitions in question come in
452
+ # the same order as in @transitions local variable. Takes a symbol as the
453
+ # argument (:SR, :TSr, :sr etc.)
454
+ #
455
+ def sift_from_net type_of_transitions
456
+ from_net = net.send type_of_transitions
457
+ @transitions.select { |t| from_net.include? t }
458
+ end
459
+ end # module Collections
460
+ end # class YPetri::Simulation