y_petri 2.2.4 → 2.3.2
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 +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
|