y_petri 2.1.3 → 2.1.6
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/lib/y_petri/agent/petri_net_related.rb +25 -5
- data/lib/y_petri/agent/selection.rb +12 -10
- data/lib/y_petri/agent/simulation_related.rb +14 -58
- data/lib/y_petri/agent.rb +15 -17
- data/lib/y_petri/core/timed/euler.rb +13 -15
- data/lib/y_petri/core/timed/pseudo_euler.rb +22 -24
- data/lib/y_petri/core/timed/quasi_euler.rb +15 -17
- data/lib/y_petri/core/timed.rb +42 -44
- data/lib/y_petri/core/timeless/pseudo_euler.rb +12 -14
- data/lib/y_petri/core/timeless.rb +10 -7
- data/lib/y_petri/core.rb +3 -3
- data/lib/y_petri/dsl.rb +46 -46
- data/lib/y_petri/fixed_assets.rb +8 -0
- data/lib/y_petri/net/data_set.rb +238 -0
- data/lib/y_petri/net/own_state.rb +63 -0
- data/lib/y_petri/net/state/feature/delta.rb +98 -71
- data/lib/y_petri/net/state/feature/firing.rb +51 -54
- data/lib/y_petri/net/state/feature/flux.rb +51 -55
- data/lib/y_petri/net/state/feature/gradient.rb +55 -59
- data/lib/y_petri/net/state/feature/marking.rb +55 -59
- data/lib/y_petri/net/state/feature.rb +65 -67
- data/lib/y_petri/net/state/features/record.rb +150 -43
- data/lib/y_petri/net/state/features.rb +252 -96
- data/lib/y_petri/net/state.rb +114 -106
- data/lib/y_petri/net/visualization.rb +3 -2
- data/lib/y_petri/net.rb +29 -24
- data/lib/y_petri/place/arcs.rb +3 -3
- data/lib/y_petri/place/guard.rb +35 -117
- data/lib/y_petri/place/guarded.rb +86 -0
- data/lib/y_petri/place.rb +6 -3
- data/lib/y_petri/simulation/element_representation.rb +2 -2
- data/lib/y_petri/simulation/elements.rb +3 -1
- data/lib/y_petri/simulation/feature_set.rb +3 -1
- data/lib/y_petri/simulation/marking_vector.rb +3 -1
- data/lib/y_petri/simulation/place_mapping.rb +3 -1
- data/lib/y_petri/simulation/places.rb +1 -1
- data/lib/y_petri/simulation/recorder.rb +60 -54
- data/lib/y_petri/simulation/timed/recorder.rb +12 -1
- data/lib/y_petri/simulation/timed.rb +173 -172
- data/lib/y_petri/simulation/transitions/access.rb +97 -29
- data/lib/y_petri/simulation.rb +11 -9
- data/lib/y_petri/transition/{assignment.rb → A.rb} +2 -2
- data/lib/y_petri/transition/{timed.rb → T.rb} +2 -2
- data/lib/y_petri/transition/arcs.rb +3 -3
- data/lib/y_petri/transition/cocking.rb +3 -3
- data/lib/y_petri/transition/{init.rb → construction_convenience.rb} +6 -53
- data/lib/y_petri/transition/{ordinary_timeless.rb → t.rb} +2 -2
- data/lib/y_petri/transition/type.rb +103 -0
- data/lib/y_petri/transition/type_information.rb +103 -0
- data/lib/y_petri/transition/types.rb +107 -0
- data/lib/y_petri/transition/usable_without_world.rb +14 -0
- data/lib/y_petri/transition.rb +87 -101
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri/world/dependency.rb +30 -28
- data/lib/y_petri/world.rb +10 -8
- data/test/acceptance/basic_usage_test.rb +3 -3
- data/test/acceptance/simulation_test.rb +3 -3
- data/test/acceptance/simulation_with_physical_units_test.rb +2 -2
- data/test/acceptance/token_game_test.rb +2 -2
- data/test/acceptance/visualization_test.rb +3 -3
- data/test/acceptance_tests.rb +2 -2
- data/test/agent_test.rb +1 -1
- data/test/net_test.rb +41 -17
- data/test/place_test.rb +1 -1
- data/test/simulation_test.rb +39 -39
- data/test/transition_test.rb +1 -1
- data/test/world_test.rb +1 -1
- data/test/y_petri_test.rb +1 -1
- metadata +13 -8
- data/lib/y_petri/net/state/features/dataset.rb +0 -135
- data/lib/y_petri/transition/construction.rb +0 -311
@@ -0,0 +1,238 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Dataset is a collection of labeled state records.
|
4
|
+
#
|
5
|
+
class YPetri::Net::DataSet < Hash
|
6
|
+
class << self
|
7
|
+
alias __new__ new
|
8
|
+
|
9
|
+
def new type: nil
|
10
|
+
__new__ do |hsh, missing|
|
11
|
+
case missing
|
12
|
+
when Float then nil
|
13
|
+
else hsh[ missing.to_f ] end
|
14
|
+
end.tap { |inst|
|
15
|
+
inst.instance_variable_set :@type, type
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
private :__new__
|
20
|
+
|
21
|
+
delegate :net, to: :features
|
22
|
+
delegate :State, to: :net
|
23
|
+
delegate :Marking, :Firing, :Flux, :Gradient, :Delta,
|
24
|
+
to: "State()"
|
25
|
+
end
|
26
|
+
|
27
|
+
alias events keys
|
28
|
+
alias records values
|
29
|
+
|
30
|
+
delegate :features,
|
31
|
+
:net,
|
32
|
+
:State,
|
33
|
+
:Marking, :Firing, :Flux, :Gradient, :Delta,
|
34
|
+
to: "self.class"
|
35
|
+
|
36
|
+
attr_reader :type # more like event_type, idea not matured yet
|
37
|
+
|
38
|
+
# Type of the dataset.
|
39
|
+
#
|
40
|
+
def timed?
|
41
|
+
type == :timed
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a Record instance corresponding to the given recorded event.
|
45
|
+
#
|
46
|
+
def record( event )
|
47
|
+
features.load( fetch event )
|
48
|
+
end
|
49
|
+
|
50
|
+
# Revives records from values.
|
51
|
+
#
|
52
|
+
def records
|
53
|
+
values.map { |value| features.Record.new( value ) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Recreates the simulation at a given event label.
|
57
|
+
#
|
58
|
+
def reconstruct event: (fail "No event given!"),
|
59
|
+
**settings # settings include marking clamps
|
60
|
+
rec = interpolate( event )
|
61
|
+
if timed? then
|
62
|
+
rec.reconstruct time: event, **settings
|
63
|
+
else
|
64
|
+
rec.reconstruct **settings
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Interpolates the recording an the given point (event). Return value is the
|
69
|
+
# Record class instance.
|
70
|
+
#
|
71
|
+
def interpolate( event )
|
72
|
+
# TODO: This whole interpolation thing is unfinished.
|
73
|
+
begin
|
74
|
+
record( event )
|
75
|
+
rescue KeyError => msg
|
76
|
+
timed? or raise TypeError, "Event #{event} does not have a record! (%s)" %
|
77
|
+
"simulation type: #{type.nil? ? 'nil' : type}"
|
78
|
+
f_time, floor = floor( event ) # timed datasets support floor, ceiling
|
79
|
+
c_time, ceiling = ceiling( time )
|
80
|
+
floor + ( ceiling - floor ) / ( c_time - f_time ) * ( time - f_time )
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the data series for the specified features.
|
85
|
+
#
|
86
|
+
def series arg=nil
|
87
|
+
return records.transpose if arg.nil?
|
88
|
+
reduce_features( State().features( arg ) ).series
|
89
|
+
end
|
90
|
+
|
91
|
+
# Expects a hash of features (:marking (alias :state) of places, :firing
|
92
|
+
# of tS transitions, :delta of places and/or transitions) and returns the
|
93
|
+
# corresponding mapping of the recording.
|
94
|
+
#
|
95
|
+
def reduce_features *args
|
96
|
+
Δt = if args.last.is_a? Hash then
|
97
|
+
args.last.may_have( :delta_time, syn!: :Δt )
|
98
|
+
args.last.delete( :delta_time )
|
99
|
+
.tap { args.delete_at( -1 ) if args.last.empty? }
|
100
|
+
end
|
101
|
+
reduced_features = net.State.features *args
|
102
|
+
rf_Record = reduced_features.Record
|
103
|
+
reduced_features.new_dataset( type: type ).tap do |dataset|
|
104
|
+
( events >> records ).each_pair do |event, record|
|
105
|
+
absent_features = reduced_features - features()
|
106
|
+
if absent_features.empty? then # it is a subset
|
107
|
+
line = reduced_features.map { |feature| record.fetch feature }
|
108
|
+
else # it will require simulation reconstruction
|
109
|
+
sim = reconstruct event: event
|
110
|
+
if absent_features.any? { |f| f.timed? rescue false } then
|
111
|
+
fail ArgumentError, "Reconstruction of timed features requires " +
|
112
|
+
"the named arg :delta_time to be given!" unless Δt
|
113
|
+
line = reduced_features.map do |feature|
|
114
|
+
if absent_features.include? feature then
|
115
|
+
if ( feature.timed? rescue false ) then
|
116
|
+
feature.extract_from( sim ).( Δt )
|
117
|
+
else
|
118
|
+
feature.extract_from( sim )
|
119
|
+
end
|
120
|
+
else
|
121
|
+
record.fetch feature
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
line = reduced_features.map do |feature|
|
126
|
+
if absent_features.include? feature then
|
127
|
+
feature.extract_from( sim )
|
128
|
+
else
|
129
|
+
record.fetch feature
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
dataset.update event => rf_Record.load( line )
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns a subset of this dataset with only the specified marking features
|
140
|
+
# identified by the arguments retained. If no arguments are given, all the
|
141
|
+
# marking features from the receiver dataset are selected.
|
142
|
+
#
|
143
|
+
def marking ids=nil
|
144
|
+
return reduce_features net.State.marking if ids.nil?
|
145
|
+
reduce_features marking: ids
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns a subset of this dataset with only the specified firing features
|
149
|
+
# identified by the arguments retained. If no arguments are given, all the
|
150
|
+
# firing features from the receiver dataset are selected.
|
151
|
+
#
|
152
|
+
def firing *args
|
153
|
+
Δt = if args.last.is_a? Hash then
|
154
|
+
args.last.may_have( :delta_time, syn!: :Δt )
|
155
|
+
args.last.delete( :delta_time )
|
156
|
+
.tap { args.delete_at( -1 ) if args.last.empty? }
|
157
|
+
end
|
158
|
+
if Δt then
|
159
|
+
return reduce_features net.State.firing, delta_time: Δt if args.empty?
|
160
|
+
reduce_features firing: args.first, delta_time: Δt
|
161
|
+
else
|
162
|
+
return reduce_features net.State.firing if args.empty?
|
163
|
+
reduce_features firing: args.first
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns a subset of this dataset with only the specified flux features
|
168
|
+
# identified by the arguments retained. If no arguments are given, all the
|
169
|
+
# flux features from the receiver dataset are selected.
|
170
|
+
#
|
171
|
+
def flux ids=nil
|
172
|
+
return reduce_features net.State.flux if ids.nil?
|
173
|
+
reduce_features flux: ids
|
174
|
+
end
|
175
|
+
|
176
|
+
# Returns a subset of this dataset with only the specified gradient features
|
177
|
+
# identified by the arguments retained. If no arguments are given, all the
|
178
|
+
# gradient features from the receiver dataset are selected.
|
179
|
+
#
|
180
|
+
def gradient *args
|
181
|
+
return reduce_features net.State.gradient if args.empty?
|
182
|
+
reduce_features gradient: args
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns a subset of this dataset with only the specified delta features
|
186
|
+
# identified by the arguments retained. If no arguments are given, all the
|
187
|
+
# delta features from the receiver dataset are selected.
|
188
|
+
#
|
189
|
+
def delta *args
|
190
|
+
Δt = if args.last.is_a? Hash then
|
191
|
+
args.last.may_have( :delta_time, syn!: :Δt )
|
192
|
+
args.last.delete( :delta_time )
|
193
|
+
.tap { args.delete_at( -1 ) if args.last.empty? }
|
194
|
+
end
|
195
|
+
if Δt then
|
196
|
+
return reduce_features net.State.delta, delta_time: Δt if args.empty?
|
197
|
+
reduce_features delta: args, delta_time: Δt
|
198
|
+
else
|
199
|
+
return reduce_features net.State.delta if args.empty?
|
200
|
+
reduce_features delta: args
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Outputs the current recording in CSV format.
|
205
|
+
#
|
206
|
+
def to_csv
|
207
|
+
map { |lbl, rec| [ lbl, *rec ].join ',' }.join "\n"
|
208
|
+
end
|
209
|
+
|
210
|
+
# Plots the dataset.
|
211
|
+
#
|
212
|
+
def plot( time: nil, **nn )
|
213
|
+
events = events()
|
214
|
+
data_ss = series
|
215
|
+
x_range = if time.is_a? Range then
|
216
|
+
"[#{time.begin}:#{time.end}]"
|
217
|
+
else
|
218
|
+
"[-0:#{SY::Time.magnitude( time ).amount rescue time}]"
|
219
|
+
end
|
220
|
+
|
221
|
+
Gnuplot.open do |gp|
|
222
|
+
Gnuplot::Plot.new gp do |plot|
|
223
|
+
plot.xrange x_range
|
224
|
+
plot.title nn[:title] || "#{net} plot"
|
225
|
+
plot.ylabel nn[:ylabel] || "Values"
|
226
|
+
plot.xlabel nn[:xlabel] || "Time [s]"
|
227
|
+
|
228
|
+
features.labels.zip( data_ss )
|
229
|
+
.each { |label, data_array|
|
230
|
+
plot.data << Gnuplot::DataSet.new( [ events, data_array ] ) { |ds|
|
231
|
+
ds.with = "linespoints"
|
232
|
+
ds.title = label
|
233
|
+
}
|
234
|
+
}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end # YPetri::Net::Dataset
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# A mixin catering to the net's own state (ie. marking owned by the place
|
2
|
+
# instances themselves) and its features.
|
3
|
+
#
|
4
|
+
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.
|
8
|
+
#
|
9
|
+
def state
|
10
|
+
State().new( marking )
|
11
|
+
end
|
12
|
+
|
13
|
+
# If no argument is supplied, the method returns the array of the markings
|
14
|
+
# owned by the net's places. If an array of place identifiers is supplied,
|
15
|
+
# the return value is the array of the markings owned by those places.
|
16
|
+
#
|
17
|
+
def marking place_ids=nil
|
18
|
+
return marking( pp ) if place_ids.nil?
|
19
|
+
place_ids.map { |id| place( id ).marking }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Takes an array of tS transition identifiers as an optional argument, and
|
23
|
+
# returns the array of their firing under current net state. If no argument
|
24
|
+
# is supplied, the net is required to contain no TS transtions, and the
|
25
|
+
# method returns the array of firing of all net's tS transitions.
|
26
|
+
#
|
27
|
+
def firing transition_ids=nil
|
28
|
+
if transition_ids.nil? then
|
29
|
+
fail TypeError, "Method #firing with no arguments is ambiguous for " +
|
30
|
+
"nets with TS transitions!" if timed?
|
31
|
+
firing( tS_tt )
|
32
|
+
else
|
33
|
+
transition_ids.map { |id| tS_transition( id ).firing }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Takes an array of TS transition identifiers as an optional argument, and
|
38
|
+
# returns the array of their fluxes under current net state. If no argument
|
39
|
+
# is supplied, the array of fluxes of all net's TS transitions is returned.
|
40
|
+
#
|
41
|
+
def flux transition_ids=nil
|
42
|
+
return flux TS_tt() if transition_ids.nil?
|
43
|
+
transition_ids.map { |id| TS_transition( id ).flux }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Takes an array of place identifiers, and a named argument +:transitions+,
|
47
|
+
# and returns the array of the place gradient contribution by the indicated
|
48
|
+
# transitions. The +:transitions+ argument defaults to all the transitions,
|
49
|
+
# place identifiers default to all the places. The net must be timed.
|
50
|
+
#
|
51
|
+
#
|
52
|
+
def gradient place_ids=pp, transitions: tt
|
53
|
+
fail NotImplementedError
|
54
|
+
end
|
55
|
+
|
56
|
+
# Takes an array of place identifier, and a named argument +:transitions+,
|
57
|
+
# and returns the array of the place delta contribution by the indicated
|
58
|
+
# transitions.
|
59
|
+
#
|
60
|
+
def delta place_ids=nil, transitions: tt
|
61
|
+
fail NotImplementedError
|
62
|
+
end
|
63
|
+
end # module YPetri::Net::OwnState
|
@@ -1,88 +1,115 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
class Delta < Feature
|
8
|
-
attr_reader :place, :transitions, :step
|
3
|
+
# Change of a Petri net place caused by a certain set of transitions.
|
4
|
+
#
|
5
|
+
class YPetri::Net::State::Feature::Delta < YPetri::Net::State::Feature
|
6
|
+
attr_reader :place, :transitions, :step
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
class << self
|
9
|
+
def parametrize *args
|
10
|
+
Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
|
11
|
+
# First, prepare the hash of instances.
|
12
|
+
hsh = Hash.new do |ꜧ, id|
|
13
|
+
if id.is_a? self then # missing key "id" is a Delta instance
|
14
|
+
ꜧ[ [ id.place, transitions: id.transitions.sort( &:object_id ) ] ]
|
15
|
+
else
|
16
|
+
p = id.fetch( 0 )
|
17
|
+
tt = id.fetch( 1 ).fetch( :transitions ) # value of :transitions key
|
18
|
+
if p.is_a? ç.net.Place and tt.all? { |t| t.is_a? ç.net.Transition }
|
19
|
+
if tt == tt.sort then
|
20
|
+
# Cache the instance.
|
21
|
+
ꜧ[ id ] = if tt.all? &:timed? then
|
22
|
+
ç.timed( *id )
|
23
|
+
elsif tt.all? &:timeless? then
|
24
|
+
ç.timeless( *id )
|
25
|
+
else
|
26
|
+
fail TypeError, "Net::State::Feature::Delta only " +
|
27
|
+
"admits the transition sets that are either " +
|
28
|
+
"all timed, or all timeless!"
|
29
|
+
end
|
21
30
|
else
|
22
|
-
|
23
|
-
p id
|
24
|
-
puts "id size is #{id.size}"
|
25
|
-
p = id.fetch( 0 )
|
26
|
-
tt = id
|
27
|
-
.fetch( 1 )
|
28
|
-
.fetch( :transitions )
|
29
|
-
if p.is_a? ç.net.Place and tt.all? { |t| t.is_a? ç.net.Transition }
|
30
|
-
if tt == tt.sort then
|
31
|
-
ꜧ[ id ] = ç.__new__( *id )
|
32
|
-
else
|
33
|
-
ꜧ[ [ p, transitions: tt.sort ] ]
|
34
|
-
end
|
35
|
-
else
|
36
|
-
ꜧ[ [ ç.net.place( p ), transitions: ç.net.transitions( tt ) ] ]
|
37
|
-
end
|
31
|
+
ꜧ[ [ p, transitions: tt.sort ] ]
|
38
32
|
end
|
33
|
+
else # convert place and transition ids to places and transitions
|
34
|
+
ꜧ[ [ ç.net.place( p ), transitions: ç.net.transitions( tt ) ] ]
|
39
35
|
end
|
40
|
-
# And then, assign it to the :@instances variable.
|
41
|
-
ç.instance_variable_set :@instances, hsh
|
42
36
|
end
|
43
37
|
end
|
38
|
+
# And then, assign it to the :@instances variable.
|
39
|
+
ç.instance_variable_set :@instances, hsh
|
40
|
+
end
|
41
|
+
end
|
44
42
|
|
45
|
-
|
43
|
+
attr_reader :instances
|
46
44
|
|
47
|
-
|
45
|
+
alias __new__ new
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
# Timed delta feature constructor. Takes a place, and an array of timed
|
48
|
+
# transition identifiers supplied as +:transitions: parameter.
|
49
|
+
#
|
50
|
+
def timed place, transitions: net.T_tt
|
51
|
+
__new__( place, transitions: net.T_tt( transitions ) )
|
52
|
+
.tap { |inst| inst.instance_variable_set :@timed, true }
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
# Timeless delta feature constructor. Takes a place, and an array of
|
56
|
+
# timeless transition identifiers as +:transitions: parameter.
|
57
|
+
#
|
58
|
+
def timeless place, transitions: net.t_tt
|
59
|
+
__new__( place, transitions: net.t_tt( transitions ) )
|
60
|
+
.tap { |inst| inst.instance_variable_set :@timed, false }
|
61
|
+
end
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
# Constructor #new is redefined to use instance cache.
|
64
|
+
#
|
65
|
+
def new *args
|
66
|
+
return instances[ *args ] if args.size == 1
|
67
|
+
instances[ args ]
|
68
|
+
end
|
69
|
+
alias of new
|
70
|
+
end
|
63
71
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
when YPetri::Simulation then
|
69
|
-
_T = arg.send( :T_transitions, transitions )
|
70
|
-
_t = arg.send( :t_transitions, transitions )
|
71
|
-
if _T.empty? then _t.delta.fetch( place ) else # time step is required
|
72
|
-
_t.delta.fetch( place ) + _T.delta( nn[:step] ).fetch( place )
|
73
|
-
end
|
74
|
-
else
|
75
|
-
fail TypeError, "Argument type not supported!"
|
76
|
-
end
|
77
|
-
end
|
72
|
+
def initialize place, transitions: net.tt
|
73
|
+
@place = net.place( place )
|
74
|
+
@transitions = net.transitions( transitions )
|
75
|
+
end
|
78
76
|
|
79
|
-
|
80
|
-
|
77
|
+
# Extracts the value of this feature from the supplied target
|
78
|
+
# (eg. a simulation).
|
79
|
+
#
|
80
|
+
def extract_from arg, **nn
|
81
|
+
# **nn is here because of timed / timeless possibility, where
|
82
|
+
# **nn would contain :step named argument.
|
83
|
+
case arg
|
84
|
+
when YPetri::Simulation then
|
85
|
+
if timed? then
|
86
|
+
tt = arg.send( :T_transitions, transitions )
|
87
|
+
-> Δt { tt.delta( Δt ).fetch( place ) }
|
88
|
+
else
|
89
|
+
arg.send( :t_transitions, transitions ).delta.fetch( place )
|
81
90
|
end
|
91
|
+
else
|
92
|
+
fail TypeError, "Argument type not supported!"
|
93
|
+
end
|
94
|
+
end
|
82
95
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
|
96
|
+
# Is the delta feature timed?
|
97
|
+
#
|
98
|
+
def timed?
|
99
|
+
@timed
|
100
|
+
end
|
101
|
+
|
102
|
+
# Opposite of +#timed?+.
|
103
|
+
#
|
104
|
+
def timeless?
|
105
|
+
! timed?
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_s
|
109
|
+
place.name
|
110
|
+
end
|
111
|
+
|
112
|
+
def label
|
113
|
+
"∂:#{place.name}:#{transitions.size}tt"
|
114
|
+
end
|
115
|
+
end # class YPetri::Net::State::Feature::Delta
|
@@ -1,57 +1,54 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
class YPetri::Net::State
|
3
|
-
class Feature
|
4
|
-
# Firing of a Petri net tS transition.
|
5
|
-
#
|
6
|
-
class Firing < Feature
|
7
|
-
attr_reader :transition
|
8
|
-
|
9
|
-
class << self
|
10
|
-
def parametrize *args
|
11
|
-
Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
|
12
|
-
ç.instance_variable_set( :@instances,
|
13
|
-
Hash.new do |hsh, id|
|
14
|
-
case id
|
15
|
-
when Firing then
|
16
|
-
hsh[ id.transition ]
|
17
|
-
when ç.net.Transition then
|
18
|
-
hsh[ id ] = ç.__new__( id )
|
19
|
-
else
|
20
|
-
hsh[ ç.net.transition( id ) ]
|
21
|
-
end
|
22
|
-
end )
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_reader :instances
|
27
|
-
|
28
|
-
alias __new__ new
|
29
|
-
|
30
|
-
def new id
|
31
|
-
instances[ id ]
|
32
|
-
end
|
33
|
-
|
34
|
-
def of id
|
35
|
-
new id
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def initialize transition
|
40
|
-
@transition = net.transition( transition )
|
41
|
-
end
|
42
|
-
|
43
|
-
def extract_from arg, **nn
|
44
|
-
case arg
|
45
|
-
when YPetri::Simulation then
|
46
|
-
arg.send( :tS_transitions, [ transition ] ).firing.first
|
47
|
-
else
|
48
|
-
fail TypeError, "Argument type not supported!"
|
49
|
-
end
|
50
|
-
end
|
51
2
|
|
52
|
-
|
53
|
-
|
3
|
+
# Firing of a Petri net tS transition.
|
4
|
+
#
|
5
|
+
class YPetri::Net::State::Feature::Firing < YPetri::Net::State::Feature
|
6
|
+
attr_reader :transition
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def parametrize *args
|
10
|
+
Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
|
11
|
+
ç.instance_variable_set( :@instances,
|
12
|
+
Hash.new do |hsh, id|
|
13
|
+
case id
|
14
|
+
when self then
|
15
|
+
hsh[ id.transition ]
|
16
|
+
when ç.net.Transition then
|
17
|
+
hsh[ id ] = ç.__new__( id )
|
18
|
+
else
|
19
|
+
hsh[ ç.net.transition( id ) ]
|
20
|
+
end
|
21
|
+
end )
|
54
22
|
end
|
55
|
-
end
|
56
|
-
|
57
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :instances
|
26
|
+
|
27
|
+
alias __new__ new
|
28
|
+
|
29
|
+
def new id
|
30
|
+
instances[ id ]
|
31
|
+
end
|
32
|
+
|
33
|
+
def of id
|
34
|
+
new id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize transition
|
39
|
+
@transition = net.transition( transition )
|
40
|
+
end
|
41
|
+
|
42
|
+
def extract_from arg, **nn
|
43
|
+
case arg
|
44
|
+
when YPetri::Simulation then
|
45
|
+
arg.send( :tS_transitions, [ transition ] ).firing.first
|
46
|
+
else
|
47
|
+
fail TypeError, "Argument type not supported!"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def label
|
52
|
+
"f:#{transition.name}"
|
53
|
+
end
|
54
|
+
end # YPetri::Net::State::Feature::Firing
|