y_petri 2.0.2 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/y_petri/manipulator/hash_key_pointer.rb +38 -0
- data/lib/y_petri/manipulator/petri_net_related_methods.rb +55 -0
- data/lib/y_petri/manipulator/selection.rb +11 -0
- data/lib/y_petri/manipulator/simulation_related_methods.rb +361 -0
- data/lib/y_petri/manipulator.rb +9 -587
- data/lib/y_petri/net.rb +65 -106
- data/lib/y_petri/simulation.rb +28 -9
- data/lib/y_petri/timed_simulation.rb +10 -3
- data/lib/y_petri/transition.rb +13 -28
- data/lib/y_petri/version.rb +2 -1
- data/lib/y_petri/workspace/petri_net_related_methods.rb +88 -0
- data/lib/y_petri/workspace/{instance_methods.rb → simulation_related_methods.rb} +7 -80
- data/lib/y_petri/workspace.rb +8 -8
- data/lib/y_petri.rb +29 -58
- data/test/y_petri_test.rb +38 -43
- metadata +9 -6
- data/test/y_petri_graph.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7785c5d949ae026d98f538426713dbf8ba5c087b
|
4
|
+
data.tar.gz: ae69a454df83b31f1314dd2935282ab97e12653f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a6cb9bc4a188d7de73fd3dd01067772be90ecfbd6f9673fb1adcfee464d590b9d470faeb154d07b89a95e930525ce3c090682817440a23b79829027e5cdf6d8
|
7
|
+
data.tar.gz: fdaed6c9020950aa17a2345567d8fdece08b2987f237aa3448ace6dc75ef14d8f417951ce39690f7de3fab7b24722f0bfcbfe888d151863771ca5f1328f36127
|
data/.gitignore
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Represents a pointer to a key of a specific hash associated with the pointer
|
2
|
+
# instance. Used to implement pointers of the Manipulator class.
|
3
|
+
#
|
4
|
+
class YPetri::Manipulator::HashKeyPointer
|
5
|
+
# Key at which the pointer points.
|
6
|
+
#
|
7
|
+
attr_reader :key
|
8
|
+
|
9
|
+
# Short text explaining what does a value of the associated hash represent.
|
10
|
+
#
|
11
|
+
attr_reader :what_is_hash_value
|
12
|
+
|
13
|
+
# Upon initalization, hash key pointer requires a hash, with which the
|
14
|
+
# instance will be associated, a textual description explaining what does
|
15
|
+
# a value of the associated hash represent, and the default hash key.
|
16
|
+
#
|
17
|
+
def initialize( hash: nil, hash_value_is: '', default_key: nil )
|
18
|
+
@hash = hash
|
19
|
+
@what_is_hash_value = hash_value_is
|
20
|
+
@default_key = default_key
|
21
|
+
end
|
22
|
+
|
23
|
+
# Resets the key to the default key.
|
24
|
+
#
|
25
|
+
def reset; @key = @default_key end
|
26
|
+
|
27
|
+
# Sets the pointer key to the one given in the argument.
|
28
|
+
#
|
29
|
+
def set arg; @key = arg end
|
30
|
+
|
31
|
+
# Gets the <em>value</em> paired in the hash associated with the current
|
32
|
+
# key to which this pointer points.
|
33
|
+
#
|
34
|
+
def get
|
35
|
+
return @hash[@default_key] if @key.nil?
|
36
|
+
@hash[@key] or raise "No #{what_is_hash_value} identified by #{arg}!"
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Public command interface of YPetri.
|
3
|
+
#
|
4
|
+
module YPetri::Manipulator::PetriNetRelatedMethods
|
5
|
+
# Net selection class.
|
6
|
+
#
|
7
|
+
NetSelection = Class.new YPetri::Manipulator::Selection
|
8
|
+
|
9
|
+
# Net point
|
10
|
+
#
|
11
|
+
attr_reader :net_point
|
12
|
+
|
13
|
+
# Net selection.
|
14
|
+
#
|
15
|
+
attr_reader :net_selection
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
net_point_reset
|
19
|
+
@net_selection = NetSelection.new
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
delegate :place, :transition, :pl, :tr,
|
24
|
+
:places, :transitions, :nets,
|
25
|
+
:pp, :tt, :nn, to: :workspace
|
26
|
+
|
27
|
+
# Place constructor: Creates a new place in the current workspace.
|
28
|
+
#
|
29
|
+
def Place *args, &b; workspace.Place.new *args, &b end
|
30
|
+
|
31
|
+
# Transiton constructor: Creates a new transition in the current workspace.
|
32
|
+
#
|
33
|
+
def Transition *args, &b; workspace.Transition.new *args, &b end
|
34
|
+
|
35
|
+
# Net constructor: Creates a new Net instance in the current workspace.
|
36
|
+
#
|
37
|
+
def Net *args, &b; workspace.Net.new *args, &b end
|
38
|
+
|
39
|
+
# Returns the net identified, or the net at point (if no argument given).
|
40
|
+
#
|
41
|
+
def net id=nil; id.nil? ? @net_point : workspace.net( id ) end
|
42
|
+
|
43
|
+
# Returns the name of the identified net, or of the net at point (if no
|
44
|
+
# argument given).
|
45
|
+
#
|
46
|
+
def ne id=nil; net( id ).name end
|
47
|
+
|
48
|
+
# Sets net point to workspace.Net::Top
|
49
|
+
#
|
50
|
+
def net_point_reset; net_point_set( workspace.Net::Top ) end
|
51
|
+
|
52
|
+
# Sets net point to the net identified by the argument (by name or instance).
|
53
|
+
#
|
54
|
+
def net_point_set id; @net_point = workspace.net( id ) end
|
55
|
+
end # module YPetri::Manipulator::PetriNetRelatedMethods
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class YPetri::Manipulator::Selection
|
2
|
+
def initialize
|
3
|
+
clear
|
4
|
+
end
|
5
|
+
def clear; @selection = [] end
|
6
|
+
def set *aa; @selection = aa end
|
7
|
+
def get; @selection end
|
8
|
+
def add arg; @selection << arg end
|
9
|
+
alias :<< :add
|
10
|
+
def subtract arg; @selection -= arg end
|
11
|
+
end
|
@@ -0,0 +1,361 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Manipulator instance methods related to simulation (initial marking
|
3
|
+
# collections, clamp collections, initial marking collections, management
|
4
|
+
# of simulations...)
|
5
|
+
#
|
6
|
+
module YPetri::Manipulator::SimulationRelatedMethods
|
7
|
+
require_relative 'hash_key_pointer'
|
8
|
+
require_relative 'selection'
|
9
|
+
|
10
|
+
# Simulation selection class.
|
11
|
+
#
|
12
|
+
SimulationSelection = Class.new YPetri::Manipulator::Selection
|
13
|
+
|
14
|
+
# Simulation settings collection selection class.
|
15
|
+
#
|
16
|
+
SscSelection = Class.new YPetri::Manipulator::Selection
|
17
|
+
|
18
|
+
# Clamp collection selection class.
|
19
|
+
#
|
20
|
+
CcSelection = Class.new YPetri::Manipulator::Selection
|
21
|
+
|
22
|
+
# Initial marking collection selection class.
|
23
|
+
#
|
24
|
+
ImcSelection = Class.new YPetri::Manipulator::Selection
|
25
|
+
|
26
|
+
class SimulationPoint < YPetri::Manipulator::HashKeyPointer
|
27
|
+
# Reset to the first simulation, or nil if that is absent.
|
28
|
+
#
|
29
|
+
def reset; @key = @hash.empty? ? nil : set( @hash.first[0] ) end
|
30
|
+
|
31
|
+
# A simulation is identified either by its name (if named), or by its
|
32
|
+
# parameters and settings (:net, :cc, :imc, :ssc).
|
33
|
+
#
|
34
|
+
def set *args
|
35
|
+
key = identify *args
|
36
|
+
@key = if key.nil? then key
|
37
|
+
elsif @hash.has_key? key then key
|
38
|
+
else raise "No simulation identified by #{key}!" end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Helper method specifying how a simulation is identified by arguments.
|
42
|
+
#
|
43
|
+
def identify( simulation_name=nil, net: nil, cc: nil, imc: nil, ssc: nil )
|
44
|
+
simulation_name || { net: net, cc: cc, imc: imc, ssc: ssc }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Pointer to a collection of simulation settings.
|
49
|
+
#
|
50
|
+
SscPoint = Class.new YPetri::Manipulator::HashKeyPointer
|
51
|
+
|
52
|
+
# Pointer to a clamp collection.
|
53
|
+
#
|
54
|
+
CcPoint = Class.new YPetri::Manipulator::HashKeyPointer
|
55
|
+
|
56
|
+
# Pointer to a collection of initial markings.
|
57
|
+
#
|
58
|
+
ImcPoint = Class.new YPetri::Manipulator::HashKeyPointer
|
59
|
+
|
60
|
+
attr_reader :simulation_point, :ssc_point, :cc_point, :imc_point,
|
61
|
+
:simulation_selection, :ssc_selection,
|
62
|
+
:cc_selection, :imc_selection
|
63
|
+
|
64
|
+
def initialize
|
65
|
+
# set up this manipulator's pointers
|
66
|
+
@simulation_point = SimulationPoint.new( hash: simulations,
|
67
|
+
hash_value_is: "simulation" )
|
68
|
+
@ssc_point = SscPoint.new( hash: simulation_settings_collections,
|
69
|
+
hash_value_is: "simulation settings collection",
|
70
|
+
default_key: :Base )
|
71
|
+
@cc_point = CcPoint.new( hash: clamp_collections,
|
72
|
+
hash_value_is: "clamp collection",
|
73
|
+
default_key: :Base )
|
74
|
+
@imc_point = ImcPoint.new( hash: initial_marking_collections,
|
75
|
+
hash_value_is: "initial marking collection",
|
76
|
+
default_key: :Base )
|
77
|
+
# set up this manipulator's selections
|
78
|
+
@simulation_selection = SimulationSelection.new
|
79
|
+
@ssc_selection = SscSelection.new
|
80
|
+
@cc_selection = CcSelection.new
|
81
|
+
@imc_selection = ImcSelection.new
|
82
|
+
# do anything else prescribed
|
83
|
+
super
|
84
|
+
end
|
85
|
+
|
86
|
+
# Simulation-related methods delegated to the workspace.
|
87
|
+
delegate :simulations,
|
88
|
+
:clamp_collections,
|
89
|
+
:initial_marking_collections,
|
90
|
+
:simulation_settings_collections,
|
91
|
+
:clamp_collection_names, :cc_names,
|
92
|
+
:initial_marking_collection_names, :imc_names,
|
93
|
+
:simulation_settings_collection_names, :ssc_names,
|
94
|
+
:set_clamp_collection, :set_cc,
|
95
|
+
:set_initial_marking_collection, :set_imc,
|
96
|
+
:set_simulation_settings_collection, :set_ssc,
|
97
|
+
:new_timed_simulation,
|
98
|
+
:clamp_cc, :initial_marking_cc, :simulation_settings_cc,
|
99
|
+
to: :workspace
|
100
|
+
|
101
|
+
# Returns the simulation identified by the argument, or one at simulation
|
102
|
+
# point, if no argument given. The simulation is identified in the same way
|
103
|
+
# as for #simulation_point_to method.
|
104
|
+
#
|
105
|
+
def simulation *args
|
106
|
+
return simulation_point.get if args.empty?
|
107
|
+
SimulationPoint.new( hash: simulations, hash_value_is: "simulation" ).get
|
108
|
+
end
|
109
|
+
|
110
|
+
# # TEMPORARY KLUGE - FIXME
|
111
|
+
# #
|
112
|
+
# def simulation; @workspace.simulations.values[-1] end
|
113
|
+
|
114
|
+
# Returns identified clamp collection, or (if no argument given) one
|
115
|
+
# corresponding to cc_point.
|
116
|
+
#
|
117
|
+
def clamp_collection id=nil
|
118
|
+
if id.nil? then cc_point.get else clamp_collections[ id ] end
|
119
|
+
end
|
120
|
+
alias cc clamp_collection
|
121
|
+
|
122
|
+
# Returns identified initial marking collection, or (if no argument given)
|
123
|
+
# one corresponding to imc_point.
|
124
|
+
#
|
125
|
+
def initial_marking_collection id=nil
|
126
|
+
if id.nil? then imc_point.get else
|
127
|
+
initial_marking_collections[ id ]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
alias imc initial_marking_collection
|
131
|
+
|
132
|
+
# Returns identified simulation settings collection, or (if no argument given)
|
133
|
+
# one corresponding to ssc_point.
|
134
|
+
#
|
135
|
+
def simulation_settings_collection id=nil
|
136
|
+
if id.nil? then ssc_point.get else
|
137
|
+
simulation_settings_collections[ id ]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
alias ssc simulation_settings_collection
|
141
|
+
|
142
|
+
# FIXME: This is going to be tested
|
143
|
+
|
144
|
+
def clamp clamp_hash
|
145
|
+
clamp_hash.each_pair do |place, clamp|
|
146
|
+
clamp_collection.merge! workspace.place( place ) => clamp
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns or modifies current initial marking(s) as indicated by the argument
|
151
|
+
# field:
|
152
|
+
# * No arguments: returns current imc
|
153
|
+
# * Exactly one ordered argument: it is assumed to identify a place whose
|
154
|
+
# im in teh current imc will be returned.
|
155
|
+
# * A hash: Assumed to be { place_id => im }, current imc is updated with it.
|
156
|
+
# * One ordered argument, and a hash: The imc identified by the ordered
|
157
|
+
# ordered arg is updated with the hash.
|
158
|
+
# * 2 ordered arguments: First is assumed to identify an imc, second place
|
159
|
+
# whose im acc. to that imc to return.
|
160
|
+
#
|
161
|
+
def initial_marking *args;
|
162
|
+
oo = args.extract_options!
|
163
|
+
case args.size
|
164
|
+
when 0 then
|
165
|
+
if oo.empty? then # no ordered arguments were given,
|
166
|
+
initial_marking_collection # current imc will be returned
|
167
|
+
else # hash was supplied, assumed of pairs { place_id => marking },
|
168
|
+
initial_marking_collection # it will be merged to imc
|
169
|
+
.update( oo.with_keys do |key| place( key ) end )
|
170
|
+
end
|
171
|
+
when 1 then # exactly one ordered argument was given,
|
172
|
+
if oo.empty? then # without any named arguments, it is
|
173
|
+
place = place( args[0] ) # assumed that it identifies a place,
|
174
|
+
initial_marking_collection[ place ] # return its init. marking in imc
|
175
|
+
else # One ordered argument (imc), and one hash (update values) given.
|
176
|
+
im_coll = initial_marking_collection( args[0] )
|
177
|
+
im_coll.update( oo.with_keys do |key| place( key ) end )
|
178
|
+
end
|
179
|
+
when 2 then # 2 ordered arguments (imc, place whose marking to return)
|
180
|
+
im_coll = initial_marking_collection( args[0] )
|
181
|
+
place = place( args[1] )
|
182
|
+
im_coll[ place ]
|
183
|
+
else raise ArgumentError, "Too many ordered parameters" end
|
184
|
+
end
|
185
|
+
alias im initial_marking
|
186
|
+
|
187
|
+
# Changes the time step of the current ssc (ssc = simulation settings
|
188
|
+
# collection).
|
189
|
+
#
|
190
|
+
def set_step Δt
|
191
|
+
ssc.update step_size: Δt
|
192
|
+
end
|
193
|
+
alias set_step_size set_step
|
194
|
+
|
195
|
+
# Changes the simulation time of the current ssc (ssc = simulation
|
196
|
+
# settings collection).
|
197
|
+
#
|
198
|
+
def set_time t
|
199
|
+
ssc.update target_time: t
|
200
|
+
end
|
201
|
+
alias set_target_time set_time
|
202
|
+
|
203
|
+
# Changes the sampling period of the current ssc (ssc = simulation
|
204
|
+
# settings collection).
|
205
|
+
#
|
206
|
+
def set_sampling Δt
|
207
|
+
ssc.update sampling_period: Δt
|
208
|
+
end
|
209
|
+
|
210
|
+
# Changes the simulation method of the current ssc (ssc = simulation
|
211
|
+
# settings collection).
|
212
|
+
#
|
213
|
+
def set_simulation_method m
|
214
|
+
ssc.update method: m
|
215
|
+
end
|
216
|
+
|
217
|
+
# Create a new timed simulation and make it available in the simulations
|
218
|
+
# table.
|
219
|
+
#
|
220
|
+
def new_timed_simulation *args, &block
|
221
|
+
instance = workspace.new_timed_simulation( *args, &block )
|
222
|
+
# Set the point to it
|
223
|
+
simulation_point.set( simulations.rassoc( instance )[0] )
|
224
|
+
return instance
|
225
|
+
end
|
226
|
+
|
227
|
+
# Create a new timed simulation and run it.
|
228
|
+
#
|
229
|
+
def run!
|
230
|
+
new_timed_simulation.run!
|
231
|
+
end
|
232
|
+
|
233
|
+
# Write the recorded samples in a file (csv).
|
234
|
+
#
|
235
|
+
def print_recording( filename = nil )
|
236
|
+
if filename.nil? then
|
237
|
+
puts simulation.recording_csv_string
|
238
|
+
else
|
239
|
+
File.open( filename, "w" ) do |f|
|
240
|
+
f << simulation.recording_csv_string
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Plot the recorded samples.
|
246
|
+
#
|
247
|
+
def plot *args
|
248
|
+
oo = args.extract_options!
|
249
|
+
case args.size
|
250
|
+
when 0 then plot_recording oo
|
251
|
+
when 1 then
|
252
|
+
plot_what = args[0]
|
253
|
+
case plot_what
|
254
|
+
when :state then plot_recording oo
|
255
|
+
when :flux then plot_flux oo
|
256
|
+
when :all then plot_all oo
|
257
|
+
else plot_selected *args end
|
258
|
+
else raise "Too many ordered arguments!" end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Plot the selected features.
|
262
|
+
#
|
263
|
+
def plot_selected *args
|
264
|
+
oo = args.extract_options!
|
265
|
+
collection = Array args[0]
|
266
|
+
return nil unless sim = @workspace.simulations.values[-1] # sim@point
|
267
|
+
# Decide abnout the features
|
268
|
+
features = sim.places.dup.map { |p|
|
269
|
+
collection.include?( p ) ? p : nil
|
270
|
+
}
|
271
|
+
# Get recording
|
272
|
+
rec = sim.recording
|
273
|
+
# Select a time series for each feature.
|
274
|
+
time_series = features.map.with_index do |feature, i|
|
275
|
+
feature and rec.map { |key, val| [ key, val[i] ] }.transpose
|
276
|
+
end
|
277
|
+
# Time axis
|
278
|
+
ᴛ = sim.target_time
|
279
|
+
# Gnuplot call
|
280
|
+
gnuplot( ᴛ, features.compact.map( &:name ), time_series.compact,
|
281
|
+
title: "Selected features plot", ylabel: "Marking" )
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
# Plot the recorded samples (system state history).
|
286
|
+
#
|
287
|
+
def plot_state( *args )
|
288
|
+
oo = args.extract_options!
|
289
|
+
excluded = Array oo[:except]
|
290
|
+
return nil unless sim = @workspace.simulations.values[-1] # sim@point
|
291
|
+
# Decide about the features to plot.
|
292
|
+
features = excluded.each_with_object sim.places.dup do |x, α|
|
293
|
+
i = α.index x
|
294
|
+
α[i] = nil if i
|
295
|
+
end
|
296
|
+
# Get recording
|
297
|
+
rec = sim.recording
|
298
|
+
# Select a time series for each feature.
|
299
|
+
time_series = features.map.with_index do |feature, i|
|
300
|
+
feature and rec.map { |key, val| [ key, val[i] ] }.transpose
|
301
|
+
end
|
302
|
+
# Time axis
|
303
|
+
ᴛ = sim.target_time
|
304
|
+
# Gnuplot call
|
305
|
+
gnuplot( ᴛ, features.compact.map( &:name ), time_series.compact,
|
306
|
+
title: "State plot", ylabel: "Marking" )
|
307
|
+
end
|
308
|
+
|
309
|
+
# Plot the recorded flux (computed flux history at the sampling points).
|
310
|
+
#
|
311
|
+
def plot_flux( *args )
|
312
|
+
oo = args.extract_options!
|
313
|
+
excluded = Array oo[:except]
|
314
|
+
return nil unless sim = @workspace.simulations.values[-1] # sim@point
|
315
|
+
# Decide about the features to plot.
|
316
|
+
all = sim.SR_transitions
|
317
|
+
features = excluded.each_with_object all.dup do |x, α|
|
318
|
+
i = α.index x
|
319
|
+
if i then α[i] = nil end
|
320
|
+
end
|
321
|
+
# Get recording.
|
322
|
+
rec = sim.recording
|
323
|
+
# Get flux recording.
|
324
|
+
flux = rec.modify { |ᴛ, ᴍ| [ ᴛ, sim.at( t: ᴛ, m: ᴍ ).flux_for( *all ) ] }
|
325
|
+
# Select a time series for each feature.
|
326
|
+
time_series = features.map.with_index do |feature, i|
|
327
|
+
feature and flux.map { |ᴛ, flux| [ ᴛ, flux[i] ] }.transpose
|
328
|
+
end
|
329
|
+
# Time axis
|
330
|
+
ᴛ = sim.target_time
|
331
|
+
# Gnuplot call
|
332
|
+
gnuplot( ᴛ, features.compact.map( &:name ), time_series.compact,
|
333
|
+
title: "Flux plot", ylabel: "Flux [µMⁿ.s⁻¹]" )
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
# Gnuplots things.
|
339
|
+
#
|
340
|
+
def gnuplot( time, labels, time_series, *args )
|
341
|
+
labels = labels.dup
|
342
|
+
time_series = time_series.dup
|
343
|
+
oo = args.extract_options!
|
344
|
+
|
345
|
+
Gnuplot.open do |gp|
|
346
|
+
Gnuplot::Plot.new( gp ) do |plot|
|
347
|
+
plot.xrange "[-0:#{SY::Time.magnitude( time ).amount rescue time}]"
|
348
|
+
plot.title oo[:title] || "Simulation plot"
|
349
|
+
plot.ylabel oo[:ylabel] || "Values"
|
350
|
+
plot.xlabel oo[:xlabel] || "Time [s]"
|
351
|
+
|
352
|
+
labels.zip( time_series ).each { |label, series|
|
353
|
+
plot.data << Gnuplot::DataSet.new( series ) do |data_series|
|
354
|
+
data_series.with = "linespoints"
|
355
|
+
data_series.title = label
|
356
|
+
end
|
357
|
+
}
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end # module YPetri::Manipulator
|