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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/lib/y_petri/demonstrator.rb +164 -0
- data/lib/y_petri/demonstrator_2.rb +176 -0
- data/lib/y_petri/demonstrator_3.rb +150 -0
- data/lib/y_petri/demonstrator_4.rb +217 -0
- data/lib/y_petri/manipulator.rb +598 -0
- data/lib/y_petri/net.rb +458 -0
- data/lib/y_petri/place.rb +189 -0
- data/lib/y_petri/simulation.rb +1313 -0
- data/lib/y_petri/timed_simulation.rb +281 -0
- data/lib/y_petri/transition.rb +921 -0
- data/lib/y_petri/version.rb +3 -0
- data/lib/y_petri/workspace/instance_methods.rb +254 -0
- data/lib/y_petri/workspace/parametrized_subclassing.rb +26 -0
- data/lib/y_petri/workspace.rb +16 -0
- data/lib/y_petri.rb +141 -0
- data/test/simple_manual_examples.rb +28 -0
- data/test/y_petri_graph.png +0 -0
- data/test/y_petri_test.rb +1521 -0
- data/y_petri.gemspec +21 -0
- metadata +112 -0
data/lib/y_petri/net.rb
ADDED
@@ -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
|