y_petri 2.2.4 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +675 -0
- data/README.md +6 -3
- data/Rakefile +1 -1
- data/lib/y_petri/agent/{petri_net_related.rb → petri_net_aspect.rb} +34 -10
- data/lib/y_petri/agent/{simulation_related.rb → simulation_aspect.rb} +49 -34
- data/lib/y_petri/agent.rb +5 -5
- data/lib/y_petri/core/guarded.rb +24 -0
- data/lib/y_petri/core/timed/euler.rb +4 -8
- data/lib/y_petri/core/timed/gillespie.rb +11 -17
- data/lib/y_petri/core/timed/methods.rb +23 -0
- data/lib/y_petri/core/timed/pseudo_euler.rb +10 -13
- data/lib/y_petri/core/timed/quasi_euler.rb +9 -8
- data/lib/y_petri/core/timed/runge_kutta.rb +10 -18
- data/lib/y_petri/core/timed.rb +6 -14
- data/lib/y_petri/core/timeless/methods.rb +15 -0
- data/lib/y_petri/core/timeless/pseudo_euler.rb +4 -8
- data/lib/y_petri/core/timeless.rb +9 -4
- data/lib/y_petri/core.rb +44 -42
- data/lib/y_petri/net/data_set.rb +246 -142
- data/lib/y_petri/net/node_access.rb +282 -0
- data/lib/y_petri/net/own_state.rb +14 -4
- data/lib/y_petri/net/state/feature/assignment.rb +123 -0
- data/lib/y_petri/net/state/feature/delta.rb +55 -35
- data/lib/y_petri/net/state/feature/firing.rb +68 -25
- data/lib/y_petri/net/state/feature/flux.rb +9 -2
- data/lib/y_petri/net/state/feature/gradient.rb +36 -19
- data/lib/y_petri/net/state/feature/marking.rb +10 -5
- data/lib/y_petri/net/state/feature.rb +105 -11
- data/lib/y_petri/net/state/features/record.rb +144 -99
- data/lib/y_petri/net/state/features.rb +327 -200
- data/lib/y_petri/net/state.rb +48 -82
- data/lib/y_petri/net/visualization.rb +1 -1
- data/lib/y_petri/net.rb +62 -47
- data/lib/y_petri/place/arcs.rb +44 -0
- data/lib/y_petri/place/features.rb +115 -0
- data/lib/y_petri/place.rb +62 -29
- data/lib/y_petri/simulation/dependency.rb +31 -67
- data/lib/y_petri/simulation/feature_set.rb +1 -1
- data/lib/y_petri/simulation/initial_marking/access.rb +42 -26
- data/lib/y_petri/simulation/marking_clamps/access.rb +22 -17
- data/lib/y_petri/simulation/marking_clamps.rb +0 -2
- data/lib/y_petri/simulation/marking_vector/access.rb +102 -40
- data/lib/y_petri/simulation/marking_vector.rb +35 -37
- data/lib/y_petri/simulation/matrix.rb +1 -1
- data/lib/y_petri/simulation/node_representation.rb +25 -0
- data/lib/y_petri/simulation/nodes/access.rb +78 -0
- data/lib/y_petri/simulation/{elements.rb → nodes.rb} +14 -13
- data/lib/y_petri/simulation/place_mapping.rb +2 -2
- data/lib/y_petri/simulation/place_representation.rb +8 -7
- data/lib/y_petri/simulation/places/access.rb +89 -70
- data/lib/y_petri/simulation/places/free.rb +1 -1
- data/lib/y_petri/simulation/places/types.rb +20 -22
- data/lib/y_petri/simulation/places.rb +23 -18
- data/lib/y_petri/simulation/recorder.rb +23 -18
- data/lib/y_petri/simulation/timed/recorder.rb +19 -11
- data/lib/y_petri/simulation/timed.rb +93 -29
- data/lib/y_petri/simulation/timeless/recorder.rb +11 -6
- data/lib/y_petri/simulation/timeless.rb +13 -3
- data/lib/y_petri/simulation/transition_representation/A.rb +24 -4
- data/lib/y_petri/simulation/transition_representation/S.rb +11 -1
- data/lib/y_petri/simulation/transition_representation/T.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/Ts.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/a.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/s.rb +12 -1
- data/lib/y_petri/simulation/transition_representation/t.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/tS.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/ts.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/types.rb +1 -1
- data/lib/y_petri/simulation/transition_representation.rb +4 -11
- data/lib/y_petri/simulation/transitions/A.rb +17 -2
- data/lib/y_petri/simulation/transitions/S.rb +1 -1
- data/lib/y_petri/simulation/transitions/T.rb +1 -1
- data/lib/y_petri/simulation/transitions/Ts.rb +6 -5
- data/lib/y_petri/simulation/transitions/a.rb +1 -1
- data/lib/y_petri/simulation/transitions/access.rb +195 -168
- data/lib/y_petri/simulation/transitions/s.rb +1 -1
- data/lib/y_petri/simulation/transitions/t.rb +1 -1
- data/lib/y_petri/simulation/transitions/tS.rb +1 -1
- data/lib/y_petri/simulation/transitions/ts.rb +1 -1
- data/lib/y_petri/simulation/transitions/types.rb +1 -1
- data/lib/y_petri/simulation/transitions.rb +5 -7
- data/lib/y_petri/simulation.rb +84 -90
- data/lib/y_petri/transition/A.rb +8 -2
- data/lib/y_petri/transition/T.rb +25 -2
- data/lib/y_petri/transition/arcs.rb +19 -3
- data/lib/y_petri/transition/construction_convenience.rb +11 -10
- data/lib/y_petri/transition/t.rb +14 -1
- data/lib/y_petri/transition/types.rb +6 -1
- data/lib/y_petri/transition.rb +9 -12
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri/world/dependency.rb +3 -3
- data/lib/y_petri/world/{petri_net_related.rb → petri_net_aspect.rb} +4 -4
- data/lib/y_petri/world/simulation_aspect.rb +352 -0
- data/lib/y_petri/world.rb +4 -4
- data/lib/y_petri.rb +1 -1
- data/test/agent_test.rb +2 -1
- data/test/examples/demonstrator.rb +4 -1
- data/test/examples/demonstrator_2.rb +5 -0
- data/test/examples/demonstrator_4.rb +6 -5
- data/test/examples/example_2.rb +2 -0
- data/test/examples/manual_examples.rb +4 -4
- data/test/net_test.rb +457 -54
- data/test/place_test.rb +11 -7
- data/test/simulation_test.rb +358 -331
- data/test/transition_test.rb +11 -10
- data/test/world_test.rb +2 -0
- data/test/y_petri_test.rb +2 -1
- data/y_petri.gemspec +24 -18
- metadata +71 -17
- data/LICENSE +0 -22
- data/lib/y_petri/net/element_access.rb +0 -239
- data/lib/y_petri/simulation/element_representation.rb +0 -20
- data/lib/y_petri/simulation/elements/access.rb +0 -57
- data/lib/y_petri/transition/type.rb +0 -103
- data/lib/y_petri/transition/type_information.rb +0 -103
- data/lib/y_petri/world/simulation_related.rb +0 -176
@@ -0,0 +1,282 @@
|
|
1
|
+
# Access to nodes (places and transitions) of a Petri net.
|
2
|
+
#
|
3
|
+
module YPetri::Net::NodeAccess
|
4
|
+
# Does the net include a place?
|
5
|
+
#
|
6
|
+
def include_place? id
|
7
|
+
begin
|
8
|
+
place( id ) and true
|
9
|
+
rescue NameError, TypeError; false end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Does the net include a transition?
|
13
|
+
#
|
14
|
+
def include_transition? id
|
15
|
+
begin; transition( id ) and true; rescue NameError, TypeError; false end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Inquirer whether the net includes a node.
|
19
|
+
#
|
20
|
+
def include? id
|
21
|
+
include_place?( id ) || include_transition?( id )
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the net's place identified by the argument.
|
25
|
+
#
|
26
|
+
def place id
|
27
|
+
( super rescue Place().instance( id ) ).tap do |p|
|
28
|
+
fail TypeError, "No place #{id} in the net!" unless places.include? p
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the net's transition identified by the argument.
|
33
|
+
#
|
34
|
+
def transition id
|
35
|
+
( super rescue Transition().instance( id ) ).tap do |t|
|
36
|
+
transitions.include? t or fail TypeError, "No transition #{id} in the net!"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the net's node identified by the argument
|
41
|
+
#
|
42
|
+
def node id
|
43
|
+
begin; place( id ); rescue NameError, TypeError
|
44
|
+
begin; transition( id ); rescue NameError, TypeError
|
45
|
+
puts "Hello from failed #node, id is:"
|
46
|
+
puts id
|
47
|
+
p id
|
48
|
+
raise TypeError, "The net does not include place/transition #{id}!"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Expects an array of nodes (places/transitions) or node ids, and returns an
|
54
|
+
# array of corresponding node instances.
|
55
|
+
#
|
56
|
+
def Nodes array
|
57
|
+
array.map &method( :node )
|
58
|
+
end
|
59
|
+
|
60
|
+
# Expects an arbitrary number of nodes (places/transitions) or node ids and
|
61
|
+
# returns an array of corresponding node instances. If no arguments are
|
62
|
+
# supplied, returns all the nodes.
|
63
|
+
#
|
64
|
+
def nodes *nodes
|
65
|
+
return @places + @transitions if nodes.empty?
|
66
|
+
Nodes( nodes )
|
67
|
+
end
|
68
|
+
alias nn nodes
|
69
|
+
|
70
|
+
# Expects an array of places or place ids, and returns an array of
|
71
|
+
# corresponding place instances.
|
72
|
+
#
|
73
|
+
def Places array
|
74
|
+
array.map &method( :place )
|
75
|
+
end
|
76
|
+
|
77
|
+
# Expects an arbitrary number of places or place ids and returns an array of
|
78
|
+
# corresponding place instances. If no arguments are supplied, returns all
|
79
|
+
# net's places.
|
80
|
+
#
|
81
|
+
def places *places
|
82
|
+
return @places.dup if places.empty?
|
83
|
+
Places( places )
|
84
|
+
end
|
85
|
+
alias pp places
|
86
|
+
|
87
|
+
# Expects an array of transitions or transition ids, and returns an array of
|
88
|
+
# corresponding transition instances.
|
89
|
+
#
|
90
|
+
def Transitions array
|
91
|
+
array.map &method( :transition )
|
92
|
+
end
|
93
|
+
|
94
|
+
# Expects an arbitrary number of transitions or transition ids and returns
|
95
|
+
# an array of corresponding transition instances. If no arguments are supplied,
|
96
|
+
# returns all net's transitions.
|
97
|
+
#
|
98
|
+
def transitions *transitions
|
99
|
+
return @transitions.dup if transitions.empty?
|
100
|
+
Transitions( transitions )
|
101
|
+
end
|
102
|
+
alias tt transitions
|
103
|
+
|
104
|
+
# Expects an array of *ts* transitions or transition ids, and returns an array
|
105
|
+
# of corresponding transition instances.
|
106
|
+
#
|
107
|
+
def ts_Transitions array
|
108
|
+
Transitions( array ).aT_all "transition identifiers", "be ts", &:ts?
|
109
|
+
end
|
110
|
+
|
111
|
+
# Expects an arbitrary number of *ts* transitions or transition ids as
|
112
|
+
# arguments, and returns an array of corresponding transition instances.
|
113
|
+
#
|
114
|
+
def ts_transitions *transitions
|
115
|
+
return transitions().select &:ts? if transitions.empty?
|
116
|
+
ts_Transitions( transitions )
|
117
|
+
end
|
118
|
+
alias ts_tt ts_transitions
|
119
|
+
|
120
|
+
# Expects an array of *tS* transitions or transition ids, and returns an array
|
121
|
+
# of corresponding transition instances.
|
122
|
+
#
|
123
|
+
def tS_Transitions array
|
124
|
+
Transitions( array ).aT_all "transition identifiers", "be tS", &:tS?
|
125
|
+
end
|
126
|
+
|
127
|
+
# Expects an arbitrary number of *tS* transitions or transition ids as
|
128
|
+
# arguments, and returns an array of corresponding transition instances.
|
129
|
+
#
|
130
|
+
def tS_transitions *transitions
|
131
|
+
return transitions().select &:tS? if transitions.empty?
|
132
|
+
tS_Transitions( transitions )
|
133
|
+
end
|
134
|
+
alias tS_tt tS_transitions
|
135
|
+
|
136
|
+
# Expects an array of *Ts* transitions or transition ids, and returns an array
|
137
|
+
# of corresponding transition instances.
|
138
|
+
#
|
139
|
+
def Ts_Transitions array
|
140
|
+
Transitions( array ).aT_all "transition identifiers", "be Ts", &:Ts?
|
141
|
+
end
|
142
|
+
|
143
|
+
# Expects an arbitrary number of *Ts* transitions or transition ids as
|
144
|
+
# arguments, and returns an array of corresponding transition instances.
|
145
|
+
#
|
146
|
+
def Ts_transitions *transitions
|
147
|
+
return transitions().select &:Ts? if transitions.empty?
|
148
|
+
Ts_Transitions( transitions )
|
149
|
+
end
|
150
|
+
alias Ts_tt Ts_transitions
|
151
|
+
|
152
|
+
# Expects an array of *TS* transitions or transition ids, and returns an array
|
153
|
+
# of corresponding transition instances.
|
154
|
+
#
|
155
|
+
def TS_Transitions array
|
156
|
+
Transitions( array ).aT_all "transition identifiers", "be TS", &:TS?
|
157
|
+
end
|
158
|
+
|
159
|
+
# Expects an arbitrary number of *TS* transitions or transition ids as
|
160
|
+
# arguments, and returns an array of corresponding transition instances.
|
161
|
+
#
|
162
|
+
def TS_transitions *transitions
|
163
|
+
return transitions().select &:TS? if transitions.empty?
|
164
|
+
TS_Transitions( transitions )
|
165
|
+
end
|
166
|
+
alias TS_tt TS_transitions
|
167
|
+
|
168
|
+
# Expects an array of *A* transitions or transition ids, and returns an array
|
169
|
+
# of corresponding transition instances.
|
170
|
+
#
|
171
|
+
def A_Transitions array
|
172
|
+
Transitions( array ).aT_all "transition identifiers", "be A", &:A?
|
173
|
+
end
|
174
|
+
|
175
|
+
# Expects an arbitrary number of *A* transitions or transition ids as
|
176
|
+
# arguments, and returns an array of corresponding transition instances.
|
177
|
+
#
|
178
|
+
def A_transitions *transitions
|
179
|
+
return transitions().select &:A? if transitions.empty?
|
180
|
+
A_Transitions( transitions )
|
181
|
+
end
|
182
|
+
alias A_tt A_transitions
|
183
|
+
|
184
|
+
# Expects an array of *a* transitions or transition ids, and returns an array
|
185
|
+
# of corresponding transition instances.
|
186
|
+
#
|
187
|
+
def a_Transitions array
|
188
|
+
Transitions( array ).aT_all "transition identifiers", "be a", &:a?
|
189
|
+
end
|
190
|
+
|
191
|
+
# Expects an arbitrary number of *a* transitions or transition ids as
|
192
|
+
# arguments, and returns an array of corresponding transition instances.
|
193
|
+
#
|
194
|
+
def a_transitions *transitions
|
195
|
+
return transitions().select &:a? if transitions.empty?
|
196
|
+
a_Transitions( transitions )
|
197
|
+
end
|
198
|
+
alias a_tt a_transitions
|
199
|
+
|
200
|
+
# Expects an array of *S* transitions or transition ids, and returns an array
|
201
|
+
# of corresponding transition instances.
|
202
|
+
#
|
203
|
+
def S_Transitions array
|
204
|
+
Transitions( array ).aT_all "transition identifiers", "be S", &:S?
|
205
|
+
end
|
206
|
+
|
207
|
+
# Expects an arbitrary number of *S* transitions or transition ids as
|
208
|
+
# arguments, and returns an array of corresponding transition instances.
|
209
|
+
#
|
210
|
+
def S_transitions *transitions
|
211
|
+
return transitions().select &:S? if transitions.empty?
|
212
|
+
S_Transitions( transitions )
|
213
|
+
end
|
214
|
+
alias S_tt S_transitions
|
215
|
+
|
216
|
+
# Expects an array of *s* transitions or transition ids, and returns an array
|
217
|
+
# of corresponding transition instances.
|
218
|
+
#
|
219
|
+
def s_Transitions array
|
220
|
+
Transitions( array ).aT_all "transition identifiers", "be s", &:s?
|
221
|
+
end
|
222
|
+
|
223
|
+
# Expects an arbitrary number of *s* transitions or transition ids as
|
224
|
+
# arguments, and returns an array of corresponding transition instances.
|
225
|
+
#
|
226
|
+
def s_transitions *transitions
|
227
|
+
return transitions().select &:s? if transitions.empty?
|
228
|
+
s_Transitions( transitions )
|
229
|
+
end
|
230
|
+
alias s_tt s_transitions
|
231
|
+
|
232
|
+
# Expects an array of *T* transitions or transition ids, and returns an array
|
233
|
+
# of corresponding transition instances.
|
234
|
+
#
|
235
|
+
def T_Transitions array
|
236
|
+
Transitions( array ).aT_all "transition identifiers", "be T", &:T?
|
237
|
+
end
|
238
|
+
|
239
|
+
# Expects an arbitrary number of *T* transitions or transition ids as
|
240
|
+
# arguments, and returns an array of corresponding transition instances.
|
241
|
+
#
|
242
|
+
def T_transitions *transitions
|
243
|
+
return transitions().select &:T? if transitions.empty?
|
244
|
+
T_Transitions( transitions )
|
245
|
+
end
|
246
|
+
alias T_tt T_transitions
|
247
|
+
|
248
|
+
# Expects an array of *t* transitions or transition ids, and returns an array
|
249
|
+
# of corresponding transition instances.
|
250
|
+
#
|
251
|
+
def t_Transitions array
|
252
|
+
Transitions( array ).aT_all "transition identifiers", "be t", &:t?
|
253
|
+
end
|
254
|
+
|
255
|
+
# Expects an arbitrary number of *t* transitions or transition ids as
|
256
|
+
# arguments, and returns an array of corresponding transition instances.
|
257
|
+
#
|
258
|
+
def t_transitions *transitions
|
259
|
+
return transitions().select &:t? if transitions.empty?
|
260
|
+
t_Transitions( transitions )
|
261
|
+
end
|
262
|
+
alias t_tt t_transitions
|
263
|
+
|
264
|
+
# Name-returning versions of the node access methods.
|
265
|
+
#
|
266
|
+
chain En: :Elements,
|
267
|
+
en: :elements,
|
268
|
+
Pn: :Places,
|
269
|
+
pn: :places,
|
270
|
+
Tn: :Transitions,
|
271
|
+
tn: :transitions,
|
272
|
+
nts: :ts_transitions,
|
273
|
+
ntS: :tS_transitions,
|
274
|
+
nTs: :Ts_transitions,
|
275
|
+
nTS: :TS_transitions,
|
276
|
+
nA: :A_transitions,
|
277
|
+
na: :a_transitions,
|
278
|
+
nS: :S_transitions,
|
279
|
+
ns: :s_transitions,
|
280
|
+
nT: :T_transitions,
|
281
|
+
nt: :t_transitions do |nodes| nodes.names end
|
282
|
+
end # class YPetri::Net::NodeAccess
|
@@ -1,10 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
# A mixin catering to the net's own state (ie. marking owned by the place
|
2
4
|
# instances themselves) and its features.
|
3
5
|
#
|
4
6
|
module YPetri::Net::OwnState
|
5
|
-
# State owned by the net.
|
6
|
-
#
|
7
|
-
# places as its elements.
|
7
|
+
# State owned by the net. This method returns an instance of +Net::State+
|
8
|
+
# class (a subclass of Array), containing marking owned by the net's places.
|
8
9
|
#
|
9
10
|
def state
|
10
11
|
State().new( marking )
|
@@ -28,7 +29,7 @@ module YPetri::Net::OwnState
|
|
28
29
|
if transition_ids.nil? then
|
29
30
|
fail TypeError, "Method #firing with no arguments is ambiguous for " +
|
30
31
|
"nets with TS transitions!" if timed?
|
31
|
-
firing
|
32
|
+
firing tS_tt
|
32
33
|
else
|
33
34
|
transition_ids.map { |id| tS_transition( id ).firing }
|
34
35
|
end
|
@@ -60,4 +61,13 @@ module YPetri::Net::OwnState
|
|
60
61
|
def delta place_ids=nil, transitions: tt
|
61
62
|
fail NotImplementedError
|
62
63
|
end
|
64
|
+
|
65
|
+
# Takes an array of A transition identifiers as an optional argument, and
|
66
|
+
# returns the array of their actions under current net state. If no argument
|
67
|
+
# is supplied, the array of assignments of all net's A transitions is returned.
|
68
|
+
#
|
69
|
+
def assignment transition_ids=nil
|
70
|
+
return assigment A_tt() if transition_ids.nil?
|
71
|
+
transition_ids.map { |id| A_transition( id ).action }
|
72
|
+
end
|
63
73
|
end # module YPetri::Net::OwnState
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Firing of a Petri net A transition.
|
4
|
+
#
|
5
|
+
class YPetri::Net::State::Feature::Assignment < YPetri::Net::State::Feature
|
6
|
+
attr_reader :place, :transition
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Customization of the Class#parametrize method.
|
10
|
+
#
|
11
|
+
def parametrize *args
|
12
|
+
Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
|
13
|
+
# Prepare the instance registry.
|
14
|
+
hsh = Hash.new do |ꜧ, id|
|
15
|
+
if id.is_a? self then # missing key "id" is an Assignment PS instance
|
16
|
+
ꜧ[ [ id.place, transition: id.transition ] ]
|
17
|
+
elsif id.is_a? ç.net.Place then # a single place
|
18
|
+
ç.construct_from_a_place_with_single_upstream_A_transition( id )
|
19
|
+
elsif id.is_a? Array and id.size == 1 then # single place again
|
20
|
+
ç.construct_from_a_place_with_single_upstream_A_transition( id.first )
|
21
|
+
elsif id.is_a? Array then
|
22
|
+
p = id.fetch( 0 )
|
23
|
+
t = id.fetch( 1 ).fetch( :transition )
|
24
|
+
if p.is_a? ç.net.Place and t.is_a? ç.net.Transition then
|
25
|
+
ꜧ[ id ] = ç.__new__( p, transition: t )
|
26
|
+
else
|
27
|
+
ꜧ[ [ ç.net.place( p ), transition: ç.net.transition( t ) ] ]
|
28
|
+
end
|
29
|
+
else
|
30
|
+
ç.construct_from_a_place_with_single_upstream_A_transition( id )
|
31
|
+
end
|
32
|
+
end # Hash.new do
|
33
|
+
# And assign it to @instances:
|
34
|
+
ç.instance_variable_set :@instances, hsh
|
35
|
+
end # tap
|
36
|
+
end # def parametrize
|
37
|
+
|
38
|
+
attr_reader :instances
|
39
|
+
|
40
|
+
alias __new__ new
|
41
|
+
|
42
|
+
# Constructor that enables special syntax of constructing
|
43
|
+
# Feature::Assignment instance from a single place, as long
|
44
|
+
# as this place has exactly 1 upstream A transition.
|
45
|
+
#
|
46
|
+
def construct_from_a_place_with_single_upstream_A_transition( place )
|
47
|
+
pl = net.place( place )
|
48
|
+
aa = pl.upstream_arcs.select( &:A? )
|
49
|
+
n = aa.size
|
50
|
+
fail TypeError, "When constructing Feature::Assignment from a single" +
|
51
|
+
"place, its upstream arcs must contain exactly one A transition! " +
|
52
|
+
"(place #{pl} has #{n} upstream A transitions)" unless n == 1
|
53
|
+
__new__( pl, transition: aa.first )
|
54
|
+
end
|
55
|
+
|
56
|
+
# Constructor #new is redefined to use instance cache.
|
57
|
+
#
|
58
|
+
def new *args
|
59
|
+
return instances[ *args ] if args.size == 1
|
60
|
+
instances[ args ]
|
61
|
+
end
|
62
|
+
alias to new
|
63
|
+
end
|
64
|
+
|
65
|
+
# The constructor of an assignment feature takes 1 ordered and 1 named
|
66
|
+
# (+:transition+) argument, which must identify the place and the transitions.
|
67
|
+
#
|
68
|
+
def initialize place, transition: transition
|
69
|
+
@place = net.place( place )
|
70
|
+
@transition = net.transition( transition )
|
71
|
+
@place_index_in_codomain = @transition.codomain.index( @place ) or
|
72
|
+
fail TypeError, "The place (#@place) must belong to the codomain of " +
|
73
|
+
"the supplied A transition (#@transition)!"
|
74
|
+
end
|
75
|
+
|
76
|
+
# Extracts the receiver marking feature from the argument. This can be
|
77
|
+
# typically a simulation instance.
|
78
|
+
#
|
79
|
+
def extract_from arg, **nn
|
80
|
+
case arg
|
81
|
+
when YPetri::Simulation then
|
82
|
+
# First, let's identify the relevant transition representation
|
83
|
+
t = arg.send( :A_transitions, transition ).first
|
84
|
+
# Then, let's get its assignment closure
|
85
|
+
closure = t.assignment_closure
|
86
|
+
# And finally, the feature extraction
|
87
|
+
Array( closure.call )[ @place_index_in_codomain ]
|
88
|
+
else
|
89
|
+
fail TypeError, "Argument type not supported!"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Type of this feature.
|
94
|
+
#
|
95
|
+
def type
|
96
|
+
:assignment
|
97
|
+
end
|
98
|
+
|
99
|
+
# A string briefly describing the assignment feature.
|
100
|
+
#
|
101
|
+
def to_s
|
102
|
+
label
|
103
|
+
end
|
104
|
+
|
105
|
+
# Label for the firing feature (to use in the graphics etc.)
|
106
|
+
#
|
107
|
+
def label
|
108
|
+
"A:#{place.name}:#{transition.name}"
|
109
|
+
end
|
110
|
+
|
111
|
+
# Inspect string of the firing feature.
|
112
|
+
#
|
113
|
+
def inspect
|
114
|
+
"<Feature::Assignment to #{place.name or place} by #{transition.name or transition}>"
|
115
|
+
end
|
116
|
+
|
117
|
+
# Two assignment features are equal if their place and transition is equal.
|
118
|
+
#
|
119
|
+
def == other
|
120
|
+
other.is_a? net.State.Feature.Assignment and
|
121
|
+
place == other.place && transition == other.transition
|
122
|
+
end
|
123
|
+
end # YPetri::Net::State::Feature::Assignment
|
@@ -3,44 +3,52 @@
|
|
3
3
|
# Change of a Petri net place caused by a certain set of transitions.
|
4
4
|
#
|
5
5
|
class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
6
|
-
attr_reader :place, :transitions
|
6
|
+
attr_reader :place, :transitions
|
7
|
+
alias tt transitions
|
7
8
|
|
8
9
|
class << self
|
9
10
|
# Customization of the Class#parametrize method.
|
10
11
|
#
|
11
12
|
def parametrize *args
|
12
13
|
Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
|
13
|
-
# First, prepare the
|
14
|
+
# First, prepare the instance registry.
|
14
15
|
hsh = Hash.new do |ꜧ, id|
|
15
16
|
if id.is_a? self then # missing key "id" is a Delta instance
|
16
17
|
ꜧ[ [ id.place, transitions: id.transitions.sort_by( &:object_id ) ] ]
|
17
18
|
else
|
18
19
|
p = id.fetch( 0 )
|
19
20
|
tt = id.fetch( 1 ).fetch( :transitions ) # value of :transitions key
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
21
|
+
tt_array = Array( tt )
|
22
|
+
if tt == tt_array then
|
23
|
+
if p.is_a? ç.net.Place and tt.all? { |t| t.is_a? ç.net.Transition }
|
24
|
+
if tt == tt.sort_by( &:object_id ) then
|
25
|
+
# Cache the instance.
|
26
|
+
ꜧ[ id ] = if tt.all? &:timed? then
|
27
|
+
ç.timed( *id )
|
28
|
+
elsif tt.all? &:timeless? then
|
29
|
+
fail TypeError, "Net::State::Feature::Delta does " +
|
30
|
+
"not admit A transitions!" if tt.any? &:A?
|
31
|
+
ç.timeless( *id )
|
32
|
+
else
|
33
|
+
fail TypeError, "Net::State::Feature::Delta only " +
|
34
|
+
"admits the transition sets that are either " +
|
35
|
+
"all timed, or all timeless!"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
ꜧ[ [ p, transitions: tt.sort_by( &:object_id ) ] ]
|
39
|
+
end
|
40
|
+
else # convert place and transition ids to places and transitions
|
41
|
+
ꜧ[ [ ç.net.place( p ), transitions: ç.net.Transitions( tt ) ] ]
|
34
42
|
end
|
35
|
-
else
|
36
|
-
ꜧ[ [
|
43
|
+
else
|
44
|
+
ꜧ[ [ p, transitions: tt_array ] ]
|
37
45
|
end
|
38
46
|
end
|
39
47
|
end
|
40
|
-
#
|
48
|
+
# Then, assign it to the :@instances variable.
|
41
49
|
ç.instance_variable_set :@instances, hsh
|
42
|
-
end
|
43
|
-
end
|
50
|
+
end # tap
|
51
|
+
end # def parametrize
|
44
52
|
|
45
53
|
attr_reader :instances
|
46
54
|
|
@@ -51,7 +59,7 @@ class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
|
51
59
|
#
|
52
60
|
def timed place, transitions: net.T_tt
|
53
61
|
tt = begin
|
54
|
-
net.
|
62
|
+
net.T_Transitions( transitions )
|
55
63
|
rescue TypeError => err
|
56
64
|
msg = "Transitions #{transitions} not recognized as timed " +
|
57
65
|
"transitions in #{net}! (%s)"
|
@@ -66,13 +74,13 @@ class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
|
66
74
|
#
|
67
75
|
def timeless place, transitions: net.t_tt
|
68
76
|
tt = begin
|
69
|
-
net.
|
77
|
+
net.t_Transitions( transitions )
|
70
78
|
rescue TypeError => err
|
71
79
|
msg = "Transitions #{transitions} not recognized as timed " +
|
72
80
|
"transitions in #{net}! (%s)"
|
73
81
|
raise TypeError, msg % err
|
74
82
|
end
|
75
|
-
__new__( place, transitions: net.
|
83
|
+
__new__( place, transitions: net.t_Transitions( transitions ) )
|
76
84
|
.tap { |inst| inst.instance_variable_set :@timed, false }
|
77
85
|
end
|
78
86
|
|
@@ -92,22 +100,21 @@ class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
|
92
100
|
#
|
93
101
|
def initialize place, transitions: net.tt
|
94
102
|
@place = net.place( place )
|
95
|
-
@transitions = net.
|
103
|
+
@transitions = net.Transitions( transitions )
|
96
104
|
end
|
97
105
|
|
98
|
-
# Extracts the value of this feature from the
|
99
|
-
#
|
106
|
+
# Extracts the value of this feature from the target (eg. a simulation).
|
107
|
+
# If the receiver delta feature is timed, this method requires an additional
|
108
|
+
# named argument +:delta_time+, alias +:Δt+.
|
100
109
|
#
|
101
|
-
def extract_from arg, **
|
102
|
-
# **nn is here because of timed / timeless possibility, where
|
103
|
-
# **nn would contain :step named argument.
|
110
|
+
def extract_from arg, **named_args
|
104
111
|
case arg
|
105
112
|
when YPetri::Simulation then
|
106
113
|
if timed? then
|
107
|
-
|
108
|
-
|
114
|
+
arg.send( :T_Transitions, transitions )
|
115
|
+
.delta( named_args.must_have :delta_time, syn!: :Δt ).fetch( place )
|
109
116
|
else
|
110
|
-
arg.send( :
|
117
|
+
arg.send( :t_Transitions, transitions ).delta.fetch( place )
|
111
118
|
end
|
112
119
|
else
|
113
120
|
fail TypeError, "Argument type not supported!"
|
@@ -135,13 +142,18 @@ class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
|
135
142
|
# A string briefly describing this delta feature.
|
136
143
|
#
|
137
144
|
def to_s
|
138
|
-
|
145
|
+
label
|
139
146
|
end
|
140
147
|
|
141
148
|
# Label for the delta feature (to use in graphics etc.)
|
142
149
|
#
|
143
150
|
def label
|
144
|
-
"Δ:#{place.name}
|
151
|
+
"Δ:#{place.name}:%s" %
|
152
|
+
if transitions.size == 1 then
|
153
|
+
transitions.first.name || transitions.first
|
154
|
+
else
|
155
|
+
"#{transitions.size}tt"
|
156
|
+
end
|
145
157
|
end
|
146
158
|
|
147
159
|
# Inspect string of the delta feature.
|
@@ -150,4 +162,12 @@ class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
|
150
162
|
"<Feature::Delta Δ:#{place.name || place}:[%s]>" %
|
151
163
|
transitions.names( true ).join( ', ' )
|
152
164
|
end
|
165
|
+
|
166
|
+
# Delta features are equal if they are of equal PS and refer to
|
167
|
+
# the same place and transition set.
|
168
|
+
#
|
169
|
+
def == other
|
170
|
+
other.is_a? net.State.Feature.Delta and
|
171
|
+
place == other.place && transitions == other.transitions
|
172
|
+
end
|
153
173
|
end # class YPetri::Net::State::Feature::Delta
|