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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +675 -0
  3. data/README.md +6 -3
  4. data/Rakefile +1 -1
  5. data/lib/y_petri/agent/{petri_net_related.rb → petri_net_aspect.rb} +34 -10
  6. data/lib/y_petri/agent/{simulation_related.rb → simulation_aspect.rb} +49 -34
  7. data/lib/y_petri/agent.rb +5 -5
  8. data/lib/y_petri/core/guarded.rb +24 -0
  9. data/lib/y_petri/core/timed/euler.rb +4 -8
  10. data/lib/y_petri/core/timed/gillespie.rb +11 -17
  11. data/lib/y_petri/core/timed/methods.rb +23 -0
  12. data/lib/y_petri/core/timed/pseudo_euler.rb +10 -13
  13. data/lib/y_petri/core/timed/quasi_euler.rb +9 -8
  14. data/lib/y_petri/core/timed/runge_kutta.rb +10 -18
  15. data/lib/y_petri/core/timed.rb +6 -14
  16. data/lib/y_petri/core/timeless/methods.rb +15 -0
  17. data/lib/y_petri/core/timeless/pseudo_euler.rb +4 -8
  18. data/lib/y_petri/core/timeless.rb +9 -4
  19. data/lib/y_petri/core.rb +44 -42
  20. data/lib/y_petri/net/data_set.rb +246 -142
  21. data/lib/y_petri/net/node_access.rb +282 -0
  22. data/lib/y_petri/net/own_state.rb +14 -4
  23. data/lib/y_petri/net/state/feature/assignment.rb +123 -0
  24. data/lib/y_petri/net/state/feature/delta.rb +55 -35
  25. data/lib/y_petri/net/state/feature/firing.rb +68 -25
  26. data/lib/y_petri/net/state/feature/flux.rb +9 -2
  27. data/lib/y_petri/net/state/feature/gradient.rb +36 -19
  28. data/lib/y_petri/net/state/feature/marking.rb +10 -5
  29. data/lib/y_petri/net/state/feature.rb +105 -11
  30. data/lib/y_petri/net/state/features/record.rb +144 -99
  31. data/lib/y_petri/net/state/features.rb +327 -200
  32. data/lib/y_petri/net/state.rb +48 -82
  33. data/lib/y_petri/net/visualization.rb +1 -1
  34. data/lib/y_petri/net.rb +62 -47
  35. data/lib/y_petri/place/arcs.rb +44 -0
  36. data/lib/y_petri/place/features.rb +115 -0
  37. data/lib/y_petri/place.rb +62 -29
  38. data/lib/y_petri/simulation/dependency.rb +31 -67
  39. data/lib/y_petri/simulation/feature_set.rb +1 -1
  40. data/lib/y_petri/simulation/initial_marking/access.rb +42 -26
  41. data/lib/y_petri/simulation/marking_clamps/access.rb +22 -17
  42. data/lib/y_petri/simulation/marking_clamps.rb +0 -2
  43. data/lib/y_petri/simulation/marking_vector/access.rb +102 -40
  44. data/lib/y_petri/simulation/marking_vector.rb +35 -37
  45. data/lib/y_petri/simulation/matrix.rb +1 -1
  46. data/lib/y_petri/simulation/node_representation.rb +25 -0
  47. data/lib/y_petri/simulation/nodes/access.rb +78 -0
  48. data/lib/y_petri/simulation/{elements.rb → nodes.rb} +14 -13
  49. data/lib/y_petri/simulation/place_mapping.rb +2 -2
  50. data/lib/y_petri/simulation/place_representation.rb +8 -7
  51. data/lib/y_petri/simulation/places/access.rb +89 -70
  52. data/lib/y_petri/simulation/places/free.rb +1 -1
  53. data/lib/y_petri/simulation/places/types.rb +20 -22
  54. data/lib/y_petri/simulation/places.rb +23 -18
  55. data/lib/y_petri/simulation/recorder.rb +23 -18
  56. data/lib/y_petri/simulation/timed/recorder.rb +19 -11
  57. data/lib/y_petri/simulation/timed.rb +93 -29
  58. data/lib/y_petri/simulation/timeless/recorder.rb +11 -6
  59. data/lib/y_petri/simulation/timeless.rb +13 -3
  60. data/lib/y_petri/simulation/transition_representation/A.rb +24 -4
  61. data/lib/y_petri/simulation/transition_representation/S.rb +11 -1
  62. data/lib/y_petri/simulation/transition_representation/T.rb +1 -1
  63. data/lib/y_petri/simulation/transition_representation/Ts.rb +1 -1
  64. data/lib/y_petri/simulation/transition_representation/a.rb +1 -1
  65. data/lib/y_petri/simulation/transition_representation/s.rb +12 -1
  66. data/lib/y_petri/simulation/transition_representation/t.rb +1 -1
  67. data/lib/y_petri/simulation/transition_representation/tS.rb +1 -1
  68. data/lib/y_petri/simulation/transition_representation/ts.rb +1 -1
  69. data/lib/y_petri/simulation/transition_representation/types.rb +1 -1
  70. data/lib/y_petri/simulation/transition_representation.rb +4 -11
  71. data/lib/y_petri/simulation/transitions/A.rb +17 -2
  72. data/lib/y_petri/simulation/transitions/S.rb +1 -1
  73. data/lib/y_petri/simulation/transitions/T.rb +1 -1
  74. data/lib/y_petri/simulation/transitions/Ts.rb +6 -5
  75. data/lib/y_petri/simulation/transitions/a.rb +1 -1
  76. data/lib/y_petri/simulation/transitions/access.rb +195 -168
  77. data/lib/y_petri/simulation/transitions/s.rb +1 -1
  78. data/lib/y_petri/simulation/transitions/t.rb +1 -1
  79. data/lib/y_petri/simulation/transitions/tS.rb +1 -1
  80. data/lib/y_petri/simulation/transitions/ts.rb +1 -1
  81. data/lib/y_petri/simulation/transitions/types.rb +1 -1
  82. data/lib/y_petri/simulation/transitions.rb +5 -7
  83. data/lib/y_petri/simulation.rb +84 -90
  84. data/lib/y_petri/transition/A.rb +8 -2
  85. data/lib/y_petri/transition/T.rb +25 -2
  86. data/lib/y_petri/transition/arcs.rb +19 -3
  87. data/lib/y_petri/transition/construction_convenience.rb +11 -10
  88. data/lib/y_petri/transition/t.rb +14 -1
  89. data/lib/y_petri/transition/types.rb +6 -1
  90. data/lib/y_petri/transition.rb +9 -12
  91. data/lib/y_petri/version.rb +1 -1
  92. data/lib/y_petri/world/dependency.rb +3 -3
  93. data/lib/y_petri/world/{petri_net_related.rb → petri_net_aspect.rb} +4 -4
  94. data/lib/y_petri/world/simulation_aspect.rb +352 -0
  95. data/lib/y_petri/world.rb +4 -4
  96. data/lib/y_petri.rb +1 -1
  97. data/test/agent_test.rb +2 -1
  98. data/test/examples/demonstrator.rb +4 -1
  99. data/test/examples/demonstrator_2.rb +5 -0
  100. data/test/examples/demonstrator_4.rb +6 -5
  101. data/test/examples/example_2.rb +2 -0
  102. data/test/examples/manual_examples.rb +4 -4
  103. data/test/net_test.rb +457 -54
  104. data/test/place_test.rb +11 -7
  105. data/test/simulation_test.rb +358 -331
  106. data/test/transition_test.rb +11 -10
  107. data/test/world_test.rb +2 -0
  108. data/test/y_petri_test.rb +2 -1
  109. data/y_petri.gemspec +24 -18
  110. metadata +71 -17
  111. data/LICENSE +0 -22
  112. data/lib/y_petri/net/element_access.rb +0 -239
  113. data/lib/y_petri/simulation/element_representation.rb +0 -20
  114. data/lib/y_petri/simulation/elements/access.rb +0 -57
  115. data/lib/y_petri/transition/type.rb +0 -103
  116. data/lib/y_petri/transition/type_information.rb +0 -103
  117. 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. More precisely, an instance of the Net::State class,
6
- # which is an Array subclass, containing the markings owned by the net's
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( tS_tt )
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, :step
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 hash of instances.
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
- if p.is_a? ç.net.Place and tt.all? { |t| t.is_a? ç.net.Transition }
21
- if tt == tt.sort_by( &:object_id ) then
22
- # Cache the instance.
23
- ꜧ[ id ] = if tt.all? &:timed? then
24
- ç.timed( *id )
25
- elsif tt.all? &:timeless? then
26
- ç.timeless( *id )
27
- else
28
- fail TypeError, "Net::State::Feature::Delta only " +
29
- "admits the transition sets that are either " +
30
- "all timed, or all timeless!"
31
- end
32
- else
33
- ꜧ[ [ p, transitions: tt.sort_by( &:object_id ) ] ]
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 # convert place and transition ids to places and transitions
36
- ꜧ[ [ ç.net.place( p ), transitions: ç.net.transitions( tt ) ] ]
43
+ else
44
+ ꜧ[ [ p, transitions: tt_array ] ]
37
45
  end
38
46
  end
39
47
  end
40
- # And then, assign it to the :@instances variable.
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.T_tt( transitions )
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.t_tt( transitions )
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.t_tt( transitions ) )
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.transitions( transitions )
103
+ @transitions = net.Transitions( transitions )
96
104
  end
97
105
 
98
- # Extracts the value of this feature from the supplied target
99
- # (eg. a simulation).
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, **nn
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
- tt = arg.send( :T_transitions, transitions )
108
- -> Δt { tt.delta( Δt ).fetch( place ) }
114
+ arg.send( :T_Transitions, transitions )
115
+ .delta( named_args.must_have :delta_time, syn!: :Δt ).fetch( place )
109
116
  else
110
- arg.send( :t_transitions, transitions ).delta.fetch( place )
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
- place.name
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}:#{transitions.size}tt"
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