y_petri 1.0.0

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.
@@ -0,0 +1,458 @@
1
+ #encoding: utf-8
2
+
3
+ # Represents a <em>Petri net</em>: A collection of places and
4
+ # transitions. The connector arrows – called <em>arcs</em> in
5
+ # classical Petri net terminology – are considered a property
6
+ # of transitions. In <tt>YPetri</tt>, 'arcs' is a synonym for
7
+ # places / transitions connected to a given transition / place.
8
+ #
9
+ class YPetri::Net
10
+ include NameMagic
11
+
12
+ def initialize *args; oo = args.extract_options!
13
+ @places, @transitions = [], [] # empty arrays
14
+ # LATER: let the places/transitions be specified upon init
15
+ end
16
+
17
+ attr_reader :places, :transitions
18
+
19
+ # Names of places in the net.
20
+ #
21
+ def pp; places.map &:name end
22
+
23
+ # Names of transitions in the net.
24
+ #
25
+ def tt; transitions.map &:name end
26
+
27
+ # Includes a place in the net. Returns <em>true</em> if successful,
28
+ # <em>false</em> if the place is already included in the net.
29
+ #
30
+ def include_place! place
31
+ p = place( place )
32
+ return false if @places.include? p
33
+ @places << p
34
+ return true
35
+ end
36
+
37
+ # Includes a transition in the net. Returns <em>true</em> if successful,
38
+ # <em>false</em> if the transition is already included in the net. The
39
+ # arcs of the transition being included may only connect to the places
40
+ # already in the net.
41
+ #
42
+ def include_transition! transition;
43
+ t = transition( transition )
44
+ return false if @transitions.include? t
45
+ raise TypeError, "Unable to include the transition #{t} in #{self}: " +
46
+ "It connects to one or more places outside the net." unless
47
+ t.arcs.all? { |p| include? p }
48
+ @transitions << t
49
+ return true
50
+ end
51
+
52
+ # Excludes a place from the net. Returns <em>true<em> if successful,
53
+ # <em>false</em> if the place was not found in the net. A place may
54
+ # not be excluded from the net so long as any transitions in the
55
+ # net connect to it.
56
+ #
57
+ def exclude_place! place
58
+ p = place( place )
59
+ raise "Unable to exclude #{p} from #{self}: One or more transitions" +
60
+ "depend on it" if transitions.any? { |t| t.arcs.include? p }
61
+ return true if @places.delete p
62
+ return false
63
+ end
64
+
65
+ # Excludes a transition from the net. Returns <em>true</em> if successful,
66
+ # <em>false</em> if the transition was not found in the net.
67
+ #
68
+ def exclude_transition! transition
69
+ t = transition( transition )
70
+ return true if @transitions.delete t
71
+ return false
72
+ end
73
+
74
+ # Includes an object (either place or transition) in the net. Acts by
75
+ # calling #include_place! or #include_transition!, as needed, the
76
+ # difference being, that errors from bad arguments are swallowed.
77
+ #
78
+ def << place_or_transition
79
+ begin
80
+ include_place! place_or_transition
81
+ rescue NameError
82
+ begin
83
+ include_transition! place_or_transition
84
+ rescue NameError
85
+ raise NameError,
86
+ "Unrecognized place or transition: #{place_or_transition}"
87
+ end
88
+ end
89
+ return self
90
+ end
91
+
92
+ # Inquirer whether the net includes a place / transition.
93
+ #
94
+ def include? place_or_transition
95
+ p = begin
96
+ place( place_or_transition )
97
+ rescue NameError
98
+ nil
99
+ end
100
+ return places.include? p if p
101
+ t = begin
102
+ transition( place_or_transition )
103
+ rescue NameError
104
+ nil
105
+ end
106
+ return transitions.include? t if t
107
+ return false
108
+ end
109
+
110
+ # ----------------------------------------------------------------------
111
+ # Methods exposing transition collections acc. to their properties:
112
+
113
+ # Array of <em>ts</em> transitions in the net.
114
+ #
115
+ def timeless_nonstoichiometric_transitions
116
+ transitions.select{ |t| t.timeless? and t.nonstoichiometric? }
117
+ end
118
+ alias ts_transitions timeless_nonstoichiometric_transitions
119
+
120
+ # Names of <em>ts</em> transitions in the net.
121
+ #
122
+ def timeless_nonstoichiometric_tt
123
+ timeless_nonstoichiometric_transitions.map &:name
124
+ end
125
+ alias ts_tt timeless_nonstoichiometric_tt
126
+
127
+ # Array of <em>tS</em> transitions in the net.
128
+ #
129
+ def timeless_stoichiometric_transitions
130
+ transitions.select{ |t| t.timeless? and t.stoichiometric? }
131
+ end
132
+ alias tS_transitions timeless_stoichiometric_transitions
133
+
134
+ # Names of <em>tS</em> transitions in the net.
135
+ #
136
+ def timeless_stoichiometric_tt
137
+ timeless_stoichiometric_transitions.map &:name
138
+ end
139
+ alias tS_tt timeless_stoichiometric_tt
140
+
141
+ # Array of <em>Tsr</em> transitions in the net.
142
+ #
143
+ def timed_nonstoichiometric_transitions_without_rate
144
+ transitions.select{ |t| t.timed? and t.nonstoichiometric? and t.rateless? }
145
+ end
146
+ alias timed_rateless_nonstoichiometric_transitions \
147
+ timed_nonstoichiometric_transitions_without_rate
148
+ alias Tsr_transitions timed_nonstoichiometric_transitions_without_rate
149
+
150
+ # Names of <em>Tsr</em> transitions in the net.
151
+ #
152
+ def timed_nonstoichiometric_tt_without_rate
153
+ timed_nonstoichiometric_transitions_without_rate.map &:name
154
+ end
155
+ alias timed_rateless_nonstoichiometric_tt \
156
+ timed_nonstoichiometric_tt_without_rate
157
+ alias Tsr_tt timed_nonstoichiometric_tt_without_rate
158
+
159
+ # Array of <em>TSr</em> transitions in the net.
160
+ #
161
+ def timed_stoichiometric_transitions_without_rate
162
+ transitions.select { |t| t.timed? and t.stoichiometric? and t.rateless? }
163
+ end
164
+ alias timed_rateless_stoichiometric_transitions \
165
+ timed_stoichiometric_transitions_without_rate
166
+ alias TSr_transitions timed_stoichiometric_transitions_without_rate
167
+
168
+ # Names of <em>TSr</em> transitions in the net.
169
+ #
170
+ def timed_stoichiometric_tt_without_rate
171
+ timed_stoichiometric_transitions_without_rate.map &:name
172
+ end
173
+ alias timed_rateless_stoichiometric_tt timed_stoichiometric_tt_without_rate
174
+ alias Tsr_tt timed_stoichiometric_tt_without_rate
175
+
176
+ # Array of <em>sR</em> transitions in the net.
177
+ #
178
+ def nonstoichiometric_transitions_with_rate
179
+ transitions.select { |t| t.has_rate? and t.nonstoichiometric? }
180
+ end
181
+ alias sR_transitions nonstoichiometric_transitions_with_rate
182
+
183
+ # Names of <em>sR</em> transitions in the net.
184
+ #
185
+ def nonstoichiometric_tt_with_rate
186
+ nonstoichiometric_transitions_with_rate.map &:name
187
+ end
188
+ alias sR_tt nonstoichiometric_tt_with_rate
189
+
190
+ # Array of <em>SR</em> transitions in the net.
191
+ #
192
+ def stoichiometric_transitions_with_rate
193
+ transitions.select { |t| t.has_rate? and t.stoichiometric? }
194
+ end
195
+ alias SR_transitions stoichiometric_transitions_with_rate
196
+
197
+ # Names of <em>SR</em> transitions in the net.
198
+ #
199
+ def stoichiometric_tt_with_rate
200
+ stoichiometric_transitions_with_rate.map &:name
201
+ end
202
+ alias SR_tt stoichiometric_tt_with_rate
203
+
204
+ # Array of transitions with <em>explicit assignment action</em>
205
+ # (<em>A</em> transitions) in the net.
206
+ #
207
+ def transitions_with_explicit_assignment_action
208
+ transitions.select { |t| t.assignment_action? }
209
+ end
210
+ alias transitions_with_assignment_action \
211
+ transitions_with_explicit_assignment_action
212
+ alias assignment_transitions transitions_with_explicit_assignment_action
213
+ alias A_transitions transitions_with_explicit_assignment_action
214
+
215
+ # Names of transitions with <em>explicit assignment action</em>
216
+ # (<em>A</em> transitions) in the net.
217
+ #
218
+ def tt_with_explicit_assignment_action
219
+ transitions_with_explicit_assignment_action.map &:name
220
+ end
221
+ alias tt_with_assignment_action tt_with_explicit_assignment_action
222
+ alias assignment_tt tt_with_assignment_action
223
+ alias A_tt tt_with_assignment_action
224
+
225
+ # Array of <em>stoichiometric</em> transitions in the net.
226
+ #
227
+ def stoichiometric_transitions
228
+ transitions.select &:stoichiometric?
229
+ end
230
+ alias S_transitions stoichiometric_transitions
231
+
232
+ # Names of <em>stoichiometric</em> transitions in the net.
233
+ #
234
+ def stoichiometric_tt
235
+ stoichiometric_transitions.map &:name
236
+ end
237
+ alias S_tt stoichiometric_tt
238
+
239
+ # Array of <em>nonstoichiometric</em> transitions in the net.
240
+ #
241
+ def nonstoichiometric_transitions
242
+ transitions.select &:nonstoichiometric?
243
+ end
244
+ alias s_transitions nonstoichiometric_transitions
245
+
246
+ # Names of <em>nonstoichimetric</em> transitions in the net.
247
+ #
248
+ def nonstoichiometric_tt
249
+ nonstoichiometric_transitions.map &:name
250
+ end
251
+ alias s_tt nonstoichiometric_tt
252
+
253
+ # Array of <em>timed</em> transitions in the net.
254
+ #
255
+ def timed_transitions; transitions.select &:timed? end
256
+ alias T_transitions timed_transitions
257
+
258
+ # Names of <em>timed</em> transitions in the net.
259
+ #
260
+ def timed_tt; timed_transitions.map &:name end
261
+ alias T_tt timed_tt
262
+
263
+ # Array of <em>timeless</em> transitions in the net.
264
+ #
265
+ def timeless_transitions; transitions.select &:timeless? end
266
+ alias t_transitions timeless_transitions
267
+
268
+ # Names of <em>timeless</em> transitions in the net.
269
+ #
270
+ def timeless_tt; timeless_transitions.map &:name end
271
+ alias t_tt timeless_tt
272
+
273
+ # Array of <em>transitions with rate</em> in the net.
274
+ #
275
+ def transitions_with_rate; transitions.select &:has_rate? end
276
+ alias R_transitions transitions_with_rate
277
+
278
+ # Names of <em>transitions with rate</em> in the net.
279
+ #
280
+ def tt_with_rate; transitions_with_rate.map &:name end
281
+ alias R_tt tt_with_rate
282
+
283
+ # Array of <em>rateless</em> transitions in the net.
284
+ #
285
+ def rateless_transitions; transitions.select &:rateless? end
286
+ alias transitions_without_rate rateless_transitions
287
+ alias r_transitions rateless_transitions
288
+
289
+ # Names of <em>rateless</em> transitions in the net.
290
+ #
291
+ def rateless_tt; rateless_transitions.map &:name end
292
+ alias tt_without_rate rateless_tt
293
+ alias r_tt rateless_tt
294
+
295
+ # ==== Inquirer methods about net qualities
296
+
297
+ # Is the net <em>functional</em>?
298
+ #
299
+ def functional?; transitions.all? { |t| t.functional? } end
300
+
301
+ # Is the net <em>timed</em>?
302
+ #
303
+ def timed?; transitions.all? { |t| t.timed? } end
304
+
305
+ # ==== Simulation constructors
306
+
307
+ # Creates a new simulation from the net.
308
+ #
309
+ def new_simulation *args
310
+ oo = args.extract_options!
311
+ YPetri::Simulation.new *args, oo.merge( net: self )
312
+ end
313
+
314
+ # Creates a new timed simulation from the net.
315
+ #
316
+ def new_timed_simulation *args
317
+ oo = args.extract_options!
318
+ YPetri::TimedSimulation.new oo.merge( net: self )
319
+ end
320
+
321
+ # ==== Sundry methods
322
+
323
+ # Networks are equal when their places and transitions are equal.
324
+ #
325
+ def == other
326
+ return false unless other.class_complies?( ç )
327
+ places == other.places && transitions == other.transitions
328
+ end
329
+
330
+ # Returns a string briefly describing the net.
331
+ #
332
+ def to_s
333
+ "#<Net: " + ( name.nil? ? "%s" : "name: #{name}, %s" ) %
334
+ "#{places.size} places, #{transitions.size} transitions" + " >"
335
+ end
336
+
337
+ def visualize
338
+ require 'graphviz'
339
+ γ = GraphViz.new :G # creating a new graph
340
+
341
+ # main = γ.add_nodes( "main", shape: "box" )
342
+ # parse = γ.add_nodes( "parse", fillcolor: "yellow", style: "rounded,filled", shape: "diamond" )
343
+ # execute = γ.add_nodes( "execute", shape: "record", label: "{ a | b | c }", style: "rounded" )
344
+ # init = γ.add_nodes( "init", fillcolor: "yellow", style: "filled" )
345
+
346
+ # # set global node options
347
+ # g.node[:color] = "#ddaa66"
348
+ # g.node[:style] = "filled"
349
+ # g.node[:shape] = "box"
350
+ # g.node[:penwidth] = "1"
351
+ # g.node[:fontname] = "Trebuchet MS"
352
+ # g.node[:fontsize] = "8"
353
+ # g.node[:fillcolor] = "#ffeecc"
354
+ # g.node[:fontcolor] = "#775500"
355
+ # g.node[:margin] = "0.0"
356
+
357
+ # # set global edge options
358
+ # g.edge[:color] = "#999999"
359
+ # g.edge[:weight] = "1"
360
+ # g.edge[:fontsize] = "6"
361
+ # g.edge[:fontcolor] = "#444444"
362
+ # g.edge[:fontname] = "Verdana"
363
+ # g.edge[:dir] = "forward"
364
+ # g.edge[:arrowsize] = "0.5"
365
+
366
+ # add place nodes
367
+ place_nodes =
368
+ Hash[ places.zip places.map { |p|
369
+ γ.add_nodes p.name.to_s, fillcolor: 'lightgrey', color: 'grey', style: 'filled'
370
+ } ]
371
+
372
+ # add transition nodes
373
+ transition_nodes =
374
+ Hash[ transitions.zip transitions.map { |t|
375
+ γ.add_nodes( t.name.to_s,
376
+ shape: 'box',
377
+ fillcolor: if t.assignment? then 'yellow'
378
+ elsif t.basic_type == :SR then 'lightcyan'
379
+ else 'ghostwhite' end,
380
+ color: if t.assignment? then 'goldenrod'
381
+ elsif t.basic_type == :SR then 'cyan'
382
+ else 'grey' end,
383
+ style: 'filled'
384
+ )
385
+
386
+ } ]
387
+
388
+ # add edges
389
+ transition_nodes.each { |t, t_node|
390
+ if t.assignment? then
391
+ t.codomain.each { |p|
392
+ γ.add_edges t_node, place_nodes[p], color: 'goldenrod'
393
+ }
394
+ ( t.domain - t.codomain ).each { |p|
395
+ γ.add_edges t_node, place_nodes[p], color: 'grey', arrowhead: 'none'
396
+ }
397
+ elsif t.basic_type == :SR then
398
+ t.codomain.each { |p|
399
+ if t.stoichio[p] > 0 then # producing arc
400
+ γ.add_edges t_node, place_nodes[p], color: 'cyan'
401
+ elsif t.stoichio[p] < 0 then # consuming arc
402
+ γ.add_edges place_nodes[p], t_node, color: 'cyan'
403
+ else
404
+ γ.add_edges place_nodes[p], t_node, color: 'grey', arrowhead: 'none'
405
+ end
406
+ }
407
+ ( t.domain - t.codomain ).each { |p|
408
+ γ.add_edges t_node, place_nodes[p], color: 'grey', arrowhead: 'none'
409
+ }
410
+ end
411
+ }
412
+
413
+ # place_collection.each { |place_name, place_label|
414
+ # place_instance = place( place_name )
415
+ # place_instance.upstream_places.each { |upstream_place|
416
+ # node = nodes[ place_name ]
417
+ # next unless set_of_places.map { |ɴ, _| ɴ }.include?( upstream_place.name )
418
+ # next if upstream_place == place_instance
419
+ # upstream_node = nodes[ upstream_place.name ]
420
+ # node << upstream_node
421
+ # }
422
+ # }
423
+
424
+ # Generate output image
425
+ γ.output png: "y_petri_graph.png"
426
+ show_file_with_kioclient "y_petri_graph.png"
427
+ end
428
+
429
+ # display it with kioclient
430
+ def show_file_with_kioclient( fɴ )
431
+ system "sleep 0.2; kioclient exec 'file:%s'" % File.expand_path( '.', fɴ )
432
+ end
433
+
434
+ # Inspect string of the instance.
435
+ #
436
+ def inspect; to_s end
437
+
438
+ private
439
+
440
+ # Display a file with kioclient (KDE).
441
+ #
442
+ def show_file_with_kioclient( file_name )
443
+ system "sleep 0.2; kioclient exec 'file:%s'" %
444
+ File.expand_path( '.', file_name )
445
+ end
446
+
447
+ # Place, Transition, Net classes.
448
+ #
449
+ def Place; ::YPetri::Place end
450
+ def Transition; ::YPetri::Transition end
451
+ def Net; ::YPetri::Net end
452
+
453
+ # Instance identification methods.
454
+ #
455
+ def place( which ); Place().instance( which ) end
456
+ def transition( which ); Transition().instance( which ) end
457
+ def net( which ); Net().instance( which ) end
458
+ end # class YPetri::Net
@@ -0,0 +1,189 @@
1
+ #encoding: utf-8
2
+
3
+ # This class represents Petri net places.
4
+ #
5
+ class YPetri::Place
6
+ USE_QUANTUM = false
7
+ include NameMagic
8
+
9
+ attr_reader :quantum
10
+ attr_accessor :default_marking
11
+ attr_accessor :marking # instance-attached marking
12
+ alias :value :marking
13
+ alias :m :marking
14
+
15
+ # Alias for #marking=
16
+ #
17
+ def value=( marking ); self.marking = marking end
18
+
19
+ # Alias for #marking=
20
+ #
21
+ def m=( marking ); self.marking = marking end
22
+
23
+ # Transitions that can directly add/remove tokens from this place.
24
+ # It is aliased as #upstream_transitions and #ϝ. (ϝ (Greek digamma) looks
25
+ # like "function", which we know from spreadsheet software: A collection
26
+ # of transitions directly affecting marking of this place.)
27
+ #
28
+ attr_reader :upstream_arcs
29
+ alias :upstream_transitions :upstream_arcs
30
+ alias :ϝ :upstream_arcs
31
+
32
+ # Transitions whose action directly depends on this place. Aliased
33
+ # as #downstream_transitions.
34
+ #
35
+ attr_reader :downstream_arcs
36
+ alias :downstream_transitions :downstream_arcs
37
+
38
+ # Named parameters supplied upon place initialization may include:
39
+ #
40
+ # * :marking (alias :m)
41
+ # * :default_marking (alias :dflt_m or :m!)
42
+ # * :quantum (alias :q)
43
+ #
44
+ # While 'marking' is a standard Petri net concept, and default marking
45
+ # is self-explanatory, place quantum is the concept by which YPetri
46
+ # reconciles with letter H in the abbreviation HFPN. YPetri places are
47
+ # always considered discrete, and it is true insomuch, as their marking
48
+ # is represented by a finite-digit number. The place quantum feature is
49
+ # not supported yet, but in future, it should enable smooth transition
50
+ # between continuous and stochastic modes of simulation.
51
+ #
52
+ def initialize *aa; oo = aa.extract_options!
53
+ # set domain and codomain of the place empty
54
+ @upstream_arcs = []
55
+ @downstream_arcs = []
56
+ @quantum = oo.may_have( :quantum, syn!: :q ) || 1
57
+ @default_marking = oo.may_have( :default_marking, syn!: [ :dflt_m, :m! ] )
58
+ @marking = oo.may_have( :marking, syn!: :m ) || @default_marking
59
+ end
60
+
61
+ # Returns an array of all the transitions connected to the place.
62
+ #
63
+ def arcs
64
+ upstream_arcs | downstream_arcs
65
+ end
66
+ alias :connectivity :arcs
67
+
68
+ # Returns the union of domains of the transitions associated
69
+ # with the upstream arcs of this place.
70
+ #
71
+ def precedents
72
+ upstream_transitions
73
+ .map( &:upstream_places )
74
+ .reduce( [], :| )
75
+ end
76
+ alias :upstream_places :precedents
77
+
78
+ # Returns the union of codomains of the transitions associated
79
+ # with the downstream arcs originating from this place.
80
+ #
81
+ def dependents
82
+ downstream_transitions
83
+ .map( &:downstream_places )
84
+ .reduce( [], :| )
85
+ end
86
+ alias :downstream_places :dependents
87
+
88
+ # Adds tokens to the place.
89
+ #
90
+ def add( amount_of_tokens )
91
+ @marking += amount_of_tokens
92
+ end
93
+
94
+ # Subtracts tokens from the place.
95
+ #
96
+ def subtract( amount_of_tokens)
97
+ @marking -= amount_of_tokens
98
+ end
99
+
100
+ # Resets place marking back to its default marking.
101
+ #
102
+ def reset_marking
103
+ @marking = @default_marking
104
+ end
105
+
106
+ # Firing of upstream transitions regardless of cocking. (To #fire
107
+ # transitions, they have to be cocked with #cock method; the firing
108
+ # methods with exclamation marks disregard cocking.)
109
+ #
110
+ def fire_upstream!
111
+ @upstream_arcs.each &:fire!
112
+ end
113
+ alias :fire! :fire_upstream!
114
+
115
+ # Fires whole upstream portion of the net.
116
+ #
117
+ def fire_upstream_recursively
118
+ # LATER: so far, implemented without concerns about infinite loops
119
+ # LATER: This as a global hash { place => fire_list }
120
+ @upstream_arcs.each &:fire_upstream_recursively
121
+ end
122
+ alias :fire_upstream! :fire_upstream_recursively
123
+
124
+ # Firing of downstream transitions regardless of cocking. (To #fire
125
+ # transitions, they have to be cocked with #cock method; the firing
126
+ # methods with exclamation marks disregard cocking.)
127
+ #
128
+ def fire_downstream!
129
+ @downstream_arcs.each &:fire!
130
+ end
131
+
132
+ # Fires whole downstream portion of the net.
133
+ #
134
+ def fire_downstream_recursively
135
+ # LATER: so far, implemented withoud concerns about infinite loops
136
+ # LATER: This as a global hash { place => fire_list }
137
+ @downstream_arcs.each &:fire_downstream_recursively
138
+ end
139
+ alias :fire_downstream! :fire_downstream_recursively
140
+
141
+ # Produces the inspect string of the place.
142
+ #
143
+ def inspect
144
+ n, m, d, q = instance_description_strings
145
+ "#<Place: #{ ( USE_QUANTUM ? [n, m, d, q] : [n, m, d] ).join ', ' } >"
146
+ end
147
+
148
+ # Returns a string briefly describing the place.
149
+ #
150
+ def to_s
151
+ n, m = name, marking
152
+ "#{n.nil? ? 'Place' : n}[ #{m.nil? ? 'nil' : m} ]"
153
+ end
154
+
155
+ private
156
+
157
+ # Makes the place notice an upstream transition;
158
+ # to be called from the connecting transitions.
159
+ def register_upstream_transition( transition )
160
+ @upstream_arcs << transition
161
+ end
162
+
163
+ # Makes the place notice a downstream transition;
164
+ # to be called from the connecting transitions.
165
+ def register_downstream_transition( transition )
166
+ @downstream_arcs << transition
167
+ end
168
+
169
+ def instance_description_strings
170
+ m, n, d, q = marking, name, default_marking, quantum
171
+ nς = "name: #{n.nil? ? '∅' : n}"
172
+ mς = "marking: #{m.nil? ? 'nil' : m}"
173
+ dς = "default_marking: #{d.nil? ? '∅' : d}"
174
+ qς = "quantum: #{q.nil? ? '∅' : q}"
175
+ return nς, mς, dς, qς
176
+ end
177
+
178
+ # Place, Transition, Net class
179
+ #
180
+ def Place; ::YPetri::Place end
181
+ def Transition; ::YPetri::Transition end
182
+ def Net; ::YPetri::Net end
183
+
184
+ # Instance identification methods.
185
+ #
186
+ def place( which ); Place().instance( which ) end
187
+ def transition( which ); Transition().instance( which ) end
188
+ def net( which ); Net().instance( which ) end
189
+ end # class YPetri::Place