y_petri 2.0.14 → 2.0.15

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