Class: YPetri::Net::DataSet
- Inherits:
-
Hash
- Object
- Hash
- YPetri::Net::DataSet
- Defined in:
- lib/y_petri/net/data_set.rb
Overview
YPetri::Net::DataSet is a collection of labeled state records. It is a subclass of Hash. DataSet keys are known as events, and values are data points. Each of these data points is an array that can be used to reconstruct a record, (an object of YPetri::Net::State::Features::Record class). Each record records a specific feature set (of YPetri::Net::State::Features class). DataSet class is intended to be parametrized with such specific feature set, which indicates the meaning of its data points.
Apart from methods inherited from Hash, DataSet can load a record at a given event (#record method), reconstruct a simulation at a given event (#reconstruct method), return columns corresponding to features (#series method) and perform feature selection (#marking, #firing, #flux, #gradient, #delta, #assignment, and #reduced_features for mixed feature sets). Apart from standard inspection methods, DataSet has methods #print and #plot for visual presentation. Also, DataSet has methods specially geared towards records of timed simulations, whose events are points in time. Method #interpolate uses linear interpolation to find the approximate state of the system at some exact time using linear interpolation between the nearest earlier and later data points (which can be accessed respectively by #floor and #ceiling methods). Interpolation is available to the user, and is also used by DataSet#resample method for resampling the dataset.
Finally, it is possible that especially professional statisticians have written, or are planning to write, a DataSet class better than this one. If I discover a good DataSet class in the future, I would like to inherit from it or otherwise integrate with it for the purposes of DataSet.
Instance Attribute Summary collapse
-
#settings ⇒ Object
readonly
TODO: More like event_type, idea not matured yet.
-
#type ⇒ Object
readonly
TODO: More like event_type, idea not matured yet.
Class Method Summary collapse
Instance Method Summary collapse
-
#Assignment(array) ⇒ Object
Expects an array of assignment feature identifiers.
-
#assignment(*ids) ⇒ Object
Expects an arbitrary number of assignment feature identifiers as arguments, and returns a subset of this dataset with only the specified assignment features retained.
-
#ceiling(event, equal_ok = true) ⇒ Object
Returns the nearest event greater or equal to the supplied event-type argument.
-
#Delta(array, transitions: nil, **named_args) ⇒ Object
Expects an array of delta feature identifiers, optionally qualified by the
:transitionsnamed argument, defaulting to all the transitions in the net. -
#delta(*ordered_args, transitions: nil, **named_args) ⇒ Object
Expects an arbitrary number of ordered arguments identifying delta features, optionally qualified by the
:transitionsnamed argument, defaulting to all the transitions in the net. - #delta_timed(*ordered_args, **named_args) ⇒ Object
- #delta_timeless(*ordered_args, **named_args) ⇒ Object
-
#distance(other) ⇒ Object
Computes the distance to another dataset.
-
#firing(*ids, **named_args) ⇒ Object
Expects an arbitrary number of firing feature identifiers and returns a subset of this dataset with only the specified firing features retained.
-
#Firing(array, **named_args) ⇒ Object
Expects an array of firing feature identifiers, and returns a subset of this dataset with only the specified firing features retained.
-
#floor(event, equal_ok = true) ⇒ Object
Returns the nearest event smaller or equal to the supplied event-type argument.
-
#Flux(array) ⇒ Object
Expects an array of flux feature identifiers, and returns a subset of this dataset with only the specified flux features retained.
-
#flux(*ids) ⇒ Object
Expects an arbitrary number of flux feature identifiers, and returns a subset of this dataset, with only the specified flux features retained.
-
#Gradient(array, transitions: nil) ⇒ Object
Expects an array of gradient feature identifiers, optionally qualified by the
:transitionsnamed argument, defaulting to all T transitions in the net. -
#gradient(*ids, transitions: nil) ⇒ Object
Returns a subset of this dataset with only the specified gradient features identified by the arguments retained.
-
#inspect ⇒ Object
Inspect string of the instance.
-
#interpolate(event) ⇒ Object
(also: #at)
Interpolates the recording at the given point (event).
-
#Marking(array) ⇒ Object
Expects an array of marking feature identifiers, and returns a subset of this dataset with only the specified marking features retained.
-
#marking(*ids) ⇒ Object
Expects an arbitrary number of marking feature identifiers, and returns a subset of this dataset with only the specified marking features retained.
-
#plot(nodes = nil, except: [], **named_args) ⇒ Object
Plots the dataset.
-
#print(precision: 4, distance: precision + 4) ⇒ Object
Pretty print the dataset.
-
#reconstruct(at: (fail "No event given!"), **settings) ⇒ Object
Recreates the simulation at a given event label.
-
#record(event) ⇒ Object
Returns the Record instance corresponding to the given recorded event.
-
#records ⇒ Object
Revives records from values.
-
#reduce_features(array = nil, **named_args) ⇒ Object
Expects a hash of features (:marking (alias :state) of places, :firing of tS transitions, :delta of places and/or transitions, :assignment of A transitions) and returns the corresponding mapping of the recording.
-
#resample(**settings) ⇒ Object
Resamples the recording.
-
#series(array = nil) ⇒ Object
Returns the data series for the specified features.
-
#timed? ⇒ Boolean
Type of the dataset.
-
#to_csv ⇒ Object
Outputs the current recording in CSV format.
-
#to_s ⇒ Object
Returns a string briefly discribing the dataset.
Instance Attribute Details
#settings ⇒ Object (readonly)
TODO: More like event_type, idea not matured yet.
57 58 59 |
# File 'lib/y_petri/net/data_set.rb', line 57 def settings @settings end |
#type ⇒ Object (readonly)
TODO: More like event_type, idea not matured yet.
57 58 59 |
# File 'lib/y_petri/net/data_set.rb', line 57 def type @type end |
Class Method Details
.__new__ ⇒ Object
34 |
# File 'lib/y_petri/net/data_set.rb', line 34 alias __new__ new |
.new(type: nil) ⇒ Object
36 37 38 39 40 41 42 43 44 |
# File 'lib/y_petri/net/data_set.rb', line 36 def new type: nil __new__ do |hsh, missing| case missing when Float then nil else hsh[ missing.to_f ] end end.tap { |inst| inst.instance_variable_set :@type, type } end |
Instance Method Details
#Assignment(array) ⇒ Object
Expects an array of assignment feature identifiers. Returns a subset of this dataset with only the specified assignment features retained.
326 327 328 |
# File 'lib/y_petri/net/data_set.rb', line 326 def Assignment array reduce_features assignment: array end |
#assignment(*ids) ⇒ Object
Expects an arbitrary number of assignment feature identifiers as arguments, and returns a subset of this dataset with only the specified assignment features retained. If no arguments are given, all the assignment features are assumed.
335 336 337 338 |
# File 'lib/y_petri/net/data_set.rb', line 335 def assignment *ids return reduce_features net.State.Features.assignment if args.empty? reduce_features assignment: ids end |
#ceiling(event, equal_ok = true) ⇒ Object
Returns the nearest event greater or equal to the supplied event-type argument. The second optional ordered argument, true by default, controls whether equality is accepted. If set to false, then the nearest greater event is sought.
87 88 89 90 |
# File 'lib/y_petri/net/data_set.rb', line 87 def ceiling( event, equal_ok=true ) e = events.ascending_ceiling( event, equal_ok ) e.nil? ? nil : e end |
#Delta(array, transitions: nil, **named_args) ⇒ Object
Expects an array of delta feature identifiers, optionally qualified by the :transitions named argument, defaulting to all the transitions in the net.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/y_petri/net/data_set.rb', line 286 def Delta array, transitions: nil, **named_args if named_args.has? :delta_time, syn!: : |
#delta(*ordered_args, transitions: nil, **named_args) ⇒ Object
Expects an arbitrary number of ordered arguments identifying delta features, optionally qualified by the :transitions named argument, defaulting to all the transitions in the net.
307 308 309 310 311 312 |
# File 'lib/y_petri/net/data_set.rb', line 307 def delta *ordered_args, transitions: nil, **named_args return Delta( ordered_args, transitions: transitions, **named_args ) unless ordered_args.empty? return Delta( net.places, **named_args ) if transitions.nil? Delta( net.places, transitions: transitions, **named_args ) end |
#delta_timed(*ordered_args, **named_args) ⇒ Object
315 316 317 |
# File 'lib/y_petri/net/data_set.rb', line 315 def delta_timed *ordered_args, **named_args delta *ordered_args, transitions: net.T_transitions, **named_args end |
#delta_timeless(*ordered_args, **named_args) ⇒ Object
319 320 321 |
# File 'lib/y_petri/net/data_set.rb', line 319 def delta_timeless *ordered_args, **named_args delta *ordered_args, transitions: net.t_transitions, **named_args end |
#distance(other) ⇒ Object
Computes the distance to another dataset.
151 152 153 154 155 156 157 158 |
# File 'lib/y_petri/net/data_set.rb', line 151 def distance( other ) sum_of_sq = events .map { |e| [ e, other.interpolate( e ) ] } .map { |rec1, rec2| rec1.euclidean_distance rec2 } .map { |dist| dist * dist } .reduce( :+ ) sum_of_sq ** 0.5 end |
#firing(*ids, **named_args) ⇒ Object
Expects an arbitrary number of firing feature identifiers and returns a subset of this dataset with only the specified firing features retained. Named arguments may include :delta_time, alias :Δt (for firing of timed transitions).
239 240 241 242 |
# File 'lib/y_petri/net/data_set.rb', line 239 def firing *ids, **named_args return Firing net.State.Features.firing, **named_args if ids.empty? Firing ids, **named_args end |
#Firing(array, **named_args) ⇒ Object
Expects an array of firing feature identifiers, and returns a subset of this dataset with only the specified firing features retained. Named arguments may include :delta_time, alias :Δt (for firing of timed transitions).
230 231 232 |
# File 'lib/y_petri/net/data_set.rb', line 230 def Firing array, **named_args reduce_features firing: array, **named_args end |
#floor(event, equal_ok = true) ⇒ Object
Returns the nearest event smaller or equal to the supplied event-type argument. The second optional ordered argument, true by default, controls whether equality is accepted. If set to false, then the nearest smaller event is sought.
77 78 79 80 |
# File 'lib/y_petri/net/data_set.rb', line 77 def floor( event, equal_ok=true ) e = events.ascending_floor( event, equal_ok ) e.nil? ? nil : e end |
#Flux(array) ⇒ Object
Expects an array of flux feature identifiers, and returns a subset of this dataset with only the specified flux features retained.
247 248 249 |
# File 'lib/y_petri/net/data_set.rb', line 247 def Flux array reduce_features flux: array end |
#flux(*ids) ⇒ Object
Expects an arbitrary number of flux feature identifiers, and returns a subset of this dataset, with only the specified flux features retained. If no aruments are given, full set of flux features is assumed.
255 256 257 258 |
# File 'lib/y_petri/net/data_set.rb', line 255 def flux *ids return Flux net.State.Features.flux if ids.empty? Flux ids end |
#Gradient(array, transitions: nil) ⇒ Object
Expects an array of gradient feature identifiers, optionally qualified by the :transitions named argument, defaulting to all T transitions in the net.
264 265 266 267 268 269 270 |
# File 'lib/y_petri/net/data_set.rb', line 264 def Gradient array, transitions: nil if transitions.nil? then reduce_features gradient: array else reduce_features gradient: [ *array, transitions: transitions ] end end |
#gradient(*ids, transitions: nil) ⇒ Object
Returns a subset of this dataset with only the specified gradient features identified by the arguments retained. If no arguments are given, all the gradient features from the receiver dataset are selected.
276 277 278 279 280 |
# File 'lib/y_petri/net/data_set.rb', line 276 def gradient *ids, transitions: nil return Gradient net.State.Features.gradient, transitions: transitions if ids.empty? Gradient ids, transitions: transitions end |
#inspect ⇒ Object
Inspect string of the instance.
439 440 441 |
# File 'lib/y_petri/net/data_set.rb', line 439 def inspect to_s end |
#interpolate(event) ⇒ Object Also known as: at
Interpolates the recording at the given point (event). Return value is the Record class instance.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/y_petri/net/data_set.rb', line 114 def interpolate( event ) begin record( event ) rescue KeyError => msg timed? or raise TypeError, "Event #{event} not recorded! (%s)" % "simulation type: #{type.nil? ? 'nil' : type}" # (Remark: #floor, #ceiling supported by timed datasets only) floor = floor( event ) fail "Event #{event} has no floor!" if floor.nil? fl = Matrix.column_vector record( floor ) ceiling = ceiling( event ) fail "Event #{event} has no ceiling!" if ceiling.nil? ce = Matrix.column_vector record( ceiling ) rslt = fl + ( ce - fl ) / ( ceiling - floor ) * ( event - floor ) features.load( rslt.column_to_a ) end end |
#Marking(array) ⇒ Object
Expects an array of marking feature identifiers, and returns a subset of this dataset with only the specified marking features retained.
212 213 214 |
# File 'lib/y_petri/net/data_set.rb', line 212 def Marking array reduce_features marking: array end |
#marking(*ids) ⇒ Object
Expects an arbitrary number of marking feature identifiers, and returns a subset of this dataset with only the specified marking features retained. If no arguments are given, all the marking features are assumed.
220 221 222 223 |
# File 'lib/y_petri/net/data_set.rb', line 220 def marking *ids return Marking net.State.Features.marking if ids.empty? Marking ids end |
#plot(nodes = nil, except: [], **named_args) ⇒ Object
Plots the dataset. Takes several optional arguments: The list of nodes can be supplied as optional first ordered argument, which are then converted into features using Net::State::Features.infer_from_nodes method. Similarly, the features to exclude can be specifies as a list of nodes (or a feature-specifying hash) supplied under except: keyword. Otherwise, feature specification can be passed to the method as named arguments. If no feature specification is explicitly provided, it is assumed that all the features of this dataset are meant to be plotted.
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
# File 'lib/y_petri/net/data_set.rb', line 357 def plot( nodes=nil, except: [], **named_args ) nn = named_args time = nn.may_have :time, syn!: :time_range events = events() # Figure out features. ff = if nodes.nil? then nn_ff = nn.slice [ :marking, :flux, :firing, :gradient, :delta, :assignment ] nn_ff.empty? ? features : net.State.Features( nn_ff ) else net.State.Features.infer_from_nodes( nodes ) end # Figure out the features not to plot ("except" features). xff = case except when Array then net.State.Features.infer_from_nodes( except ) when Hash then net.State.Features( except ) else fail TypeError, "Wrong type of :except argument: #{except.class}" end # Subtract the "except" features from features to plot. ff -= xff # Convert the feature set into a set of data arrays. data_arrays = series( ff ) # Figure out the x axis range for plotting. x_range = if nn.has? :time then if time.is_a? Range then "[#{time.begin}:#{time.end}]" else "[-0:#{SY::Time.magnitude( time ).amount rescue time}]" end else from = events.first || 0 to = if events.last and events.last > from then events.last else events.first + 1 end "[#{from}:#{to}]" end # Invoke Gnuplot. Gnuplot.open do |gp| Gnuplot::Plot.new gp do |plot| plot.xrange x_range if nn.has? :yrange, syn!: :y_range then if nn[:yrange].is_a? Range then plot.yrange "[#{nn[:yrange].begin}:#{nn[:yrange].end}]" else fail TypeError, "Argument :yrange is not a range!" end end plot.title nn[:title] || "#{net} plot" plot.ylabel nn[:ylabel] || "Values" plot.xlabel nn[:xlabel] || "Time [s]" ff.labels.zip( data_arrays ).each do |label, array| # Replace NaN and Infinity with 0.0 and warn about it. nan, inf = 0, 0 array = array.map { |v| if v.to_f.infinite? then inf += 1; 0.0 elsif v.to_f.nan? then nan += 1; 0.0 else v end } # Warn. nan = nan > 0 ? "#{nan} NaN values" : nil inf = inf > 0 ? "#{inf} infinite values" : nil msg = "Warning: column #{label} contains %s plotted as 0!" warn msg % [ nan, inf ].compact.join( ' and ' ) if nan or inf # Finally, plot. plot.data << Gnuplot::DataSet.new( [ events, array ] ) { |set| set.with = "linespoints" set.title = label } end end end end |
#print(precision: 4, distance: precision + 4) ⇒ Object
Pretty print the dataset. Takes :precision and :distance named arguments, that control the shape of the printed table.
446 447 448 449 450 451 452 453 |
# File 'lib/y_petri/net/data_set.rb', line 446 def print precision: 4, distance: precision + 4 features.labels.print_as_line precision: precision, distance: distance puts '-' * features.size * distance records.each { |record| record.print_as_line precision: precision, distance: distance } return nil end |
#reconstruct(at: (fail "No event given!"), **settings) ⇒ Object
Recreates the simulation at a given event label.
100 101 102 103 104 105 106 107 108 109 |
# File 'lib/y_petri/net/data_set.rb', line 100 def reconstruct at: (fail "No event given!"), **settings # settings may include marking clamps, marking, inital marking... record = interpolate( at ) settings = settings().merge settings if settings() if timed? then record.reconstruct time: at, **settings else record.reconstruct **settings end end |
#record(event) ⇒ Object
Returns the Record instance corresponding to the given recorded event.
68 69 70 |
# File 'lib/y_petri/net/data_set.rb', line 68 def record( event ) features.load( fetch event ) end |
#records ⇒ Object
Revives records from values.
94 95 96 |
# File 'lib/y_petri/net/data_set.rb', line 94 def records values.map { |value| features.Record.new( value ) } end |
#reduce_features(array = nil, **named_args) ⇒ Object
Expects a hash of features (:marking (alias :state) of places, :firing of tS transitions, :delta of places and/or transitions, :assignment of A transitions) and returns the corresponding mapping of the recording.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/y_petri/net/data_set.rb', line 171 def reduce_features array=nil, **named_args delta_time_given = named_args.has? :delta_time, syn!: : |
#resample(**settings) ⇒ Object
Resamples the recording.
135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/y_petri/net/data_set.rb', line 135 def resample **settings time_range = settings.may_have( :time_range, syn!: :time ) || events.first .. events.last sampling = settings.must_have :sampling t0, target_time = time_range.begin, time_range.end t = t0 o = self.class.new type: type loop do o.update t => interpolate( t ) t += sampling return o if t > target_time end end |
#series(array = nil) ⇒ Object
Returns the data series for the specified features.
162 163 164 165 |
# File 'lib/y_petri/net/data_set.rb', line 162 def series array=nil return records.transpose if array.nil? reduce_features( net.State.Features array ).series end |
#timed? ⇒ Boolean
Type of the dataset.
62 63 64 |
# File 'lib/y_petri/net/data_set.rb', line 62 def timed? type == :timed end |
#to_csv ⇒ Object
Outputs the current recording in CSV format.
342 343 344 345 346 |
# File 'lib/y_petri/net/data_set.rb', line 342 def to_csv require 'csv' [ ":event", *features.labels.map( &:to_s ) ].join( ',' ) + "\n" + map { |lbl, rec| [ lbl, *rec ].join ',' }.join( "\n" ) end |
#to_s ⇒ Object
Returns a string briefly discribing the dataset.
430 431 432 433 434 435 |
# File 'lib/y_petri/net/data_set.rb', line 430 def to_s "#<DataSet: " + "#{keys.size} records, " + "features: #{features}" + ">" end |