Class: YPetri::Net::State::Features

Inherits:
Array
  • Object
show all
Defined in:
lib/y_petri/net/state/features.rb

Overview

A feature set. In other words, a set of state features, such as marking, flux etc. The supported features are:

marking

Applicable to all places, all places have marking.

firing

Applicable to all stoichiometric transitions, but delta time has to be known for timed transitions.

flux

Applicable to timed stochiometric transitions only.

delta

Expresses change to a chosen set of places caused by firing of a chosen set of transitions. Requires delta time to be provided if there are timed transitions in the set.

gradient

Expresses gradient of change of a chosen set of places caused by firing of a chosen set of transitions. Only applicable to timed transitions.

Defined Under Namespace

Classes: Record

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.[](*ordered_args, **named_args) ⇒ Object

Takes an arbitrary number of ordered arguments identifying features, or named arguments :marking, :firing, :gradient, :flux, :delta, :assignment containing arrays identifying the corresponding type of features.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/y_petri/net/state/features.rb', line 57

def [] *ordered_args, **named_args
  unless ordered_args.empty?
    fail ArgumentError, "Named arguments must not be given if ordered " +
      "arguments are given!" unless named_args.empty?
    return infer_from_nodes( ordered_args )
  end
  a = []
  a << Marking( Array named_args[ :marking ] ) if named_args[ :marking ]
  a << Firing( Array named_args[ :firing ] ) if named_args[ :firing ]
  a << Flux( Array named_args[ :flux ] ) if named_args[ :flux ]
  if named_args[ :gradient ] then
    ordered = Array( named_args[ :gradient ] )
    named = ordered.extract_options!
    a << Gradient( ordered, **named )
  end
  if named_args[ :delta ] then
    ordered = Array( named_args[ :delta ] )
    named = ordered.extract_options!
    a << Delta( ordered, **named )
  end
  if named_args[ :assignment ] then
    ordered = Array( named_args[ :assignment ] )
    named = ordered.extract_options!
    a << Assignment( ordered, **named )
  end
  a.size == 1 ? a.first : a.reduce( new( [] ), :+ )
end

.__new__Object



38
# File 'lib/y_petri/net/state/features.rb', line 38

alias __new__ new

.aaObject

Convenience method that returns the full set of assignment features for those places, which have exactly one A transition in their upstream arcs.



248
249
250
251
252
253
# File 'lib/y_petri/net/state/features.rb', line 248

def aa
  Assignment net.places.select { |p|
    upstream = p.upstream_arcs
    upstream.size == 1 && upstream.first.A?
  }
end

.assignment(*ids, transition: L! ) ⇒ Object

Expects an arbitrary number of assignment feature identifiers and constructs a feature set out of them.



230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/y_petri/net/state/features.rb', line 230

def assignment *ids, transition: L!
  if transition.local_object? then
    fail ArgumentError, "Sorry, but Features.assignment method cannot " +
      "be called without arguments. There is a convenience method " +
      "Features.aa available, returning all the assignment features " +
      "for the places with exactly one A transition upstream, if that." +
      "is what you mean." if ids.empty?
    Assignment( ids )
  else
    return Assignment( ids, transition: transition ) unless ids.empty?
    Assignment net.transition( transition ).codomain, transition: transition
  end
end

.Assignment(array, transition: L! ) ⇒ Object

Constructs a set of assignment features from an array of assignment feature identifiers.



217
218
219
220
221
222
223
224
225
# File 'lib/y_petri/net/state/features.rb', line 217

def Assignment array, transition: L!
  if transition.local_object? then
    new array.map &net.State.Feature.method( :Assignment )
  else
    new array.map { |id|
      net.State.Feature.Assignment id, transition: transition
    }
  end
end

.Delta(array, transitions: nil) ⇒ Object

Constructs a set of delta features from an array of delta feature identifiers, optionally qualified by an array of transitions supplied via the named argument :transitions.



162
163
164
165
166
167
168
# File 'lib/y_petri/net/state/features.rb', line 162

def Delta array, transitions: nil
  return new array.map &net.State.Feature.method( :Delta ) if
    transitions.nil?
  new array.map { |id|
    net.State.Feature.Delta id, transitions: transitions
  }
end

.delta(*args, transitions: L! ) ⇒ Object

Expects an arbitrary number of delta feature identifiers and constructs a feature set out of them, optionally qualified by an array of transitions supplied via the named argument :transitions. Returns the corresponding feature set. Without ordered arguments, full delta feature set for the underlying net is returned.



176
177
178
179
180
181
182
183
184
185
186
# File 'lib/y_petri/net/state/features.rb', line 176

def delta *args, transitions: L!
  return Delta args, transitions: transitions unless args.empty?
  fail ArgumentError, "Sorry, but feature set constructor Features.delta " +
    "cannot be used without :transitions named argument, because it is " +
    "ambiguous whether the transition set should default to the timed or " +
    "timeless transitions (they cannot be mixed together when " +
    "constructing a delta feature). Please specify the transitions, or " + 
    "disambiguate timedness by using either .delta_timed or " +
    ".delta_timeless method " if transitions.local_object?
  Delta net.pp, transitions: transitions
end

.delta_timed(*args, transitions: L! ) ⇒ Object

Expects an arbitrary number of place idetifiers and constructs a feature set out of them, optionally qualified by an array of T transitions supplied via the named argument :transitions. Returns the corresponding feature set. Without ordered arguments, full delta feature set for the underlying net is returned. If no transitions are supplied, full set of T transitions is assumed.



195
196
197
198
199
# File 'lib/y_petri/net/state/features.rb', line 195

def delta_timed *args, transitions: L!
  return delta *args, transitions: net.T_transitions if
    transitions.local_object?
  delta *args, transitions: net.T_Transitions( Array( transitions ) )
end

.delta_timeless(*args, transitions: L! ) ⇒ Object

Expects an arbitrary number of place idetifiers and constructs a feature set out of them, optionally qualified by an array of t (timeless) transitions supplied via the named argument :transitions. Returns the corresponding feature set. Without ordered arguments, full delta feature set for the underlying net is returned. If no transitions are supplied, full set of t (timeless) transitions is assumed.



208
209
210
211
212
# File 'lib/y_petri/net/state/features.rb', line 208

def delta_timeless *args, transitions: L!
  return delta *args, transitions: net.t_transitions if
    transitions.local_object?
  delta *args, transitions: net.t_Transitions( Array( transitions ) )
end

.Firing(array, **named_args) ⇒ Object

Constructs a set of firing features from an array of firing feature identifiers.



104
105
106
# File 'lib/y_petri/net/state/features.rb', line 104

def Firing array, **named_args
  new array.map &net.State.Feature.method( :Firing )
end

.firing(*firing_feature_identifiers) ⇒ Object

Expects an arbitrary number of firing feature identifiers and constructs a feature set out of them. Without arguments, full firing feature set (all S transitions) for the underlying net is returned.



112
113
114
115
# File 'lib/y_petri/net/state/features.rb', line 112

def firing *firing_feature_identifiers
  return Firing net.S_tt if firing_feature_identifiers.empty?
  Firing firing_feature_identifiers
end

.Flux(array) ⇒ Object

Constructs a set of flux features from an array of flux feature identifiers.



145
146
147
# File 'lib/y_petri/net/state/features.rb', line 145

def Flux array
  new array.map &net.State.Feature.method( :Flux )
end

.flux(*flux_feature_identifiers) ⇒ Object

Expects an arbitrary number of flux feature identifiers and constructs a feature set out of them. Without arguments, full flux feature set for the underlying net is returned.



153
154
155
156
# File 'lib/y_petri/net/state/features.rb', line 153

def flux *flux_feature_identifiers
  return Flux net.TS_tt if flux_feature_identifiers.empty?
  Flux flux_feature_identifiers
end

.gradient(*args, transitions: nil) ⇒ Object

Expects an arbitrary number of gradient feature identifiers and constructs a feature set out of them, optionally qualified by an array of transitions supplied via the named argument :transitions. Returns the corresponding feature set. Without ordered arguments, full gradient feature set for the underlying net is returned.



136
137
138
139
140
# File 'lib/y_petri/net/state/features.rb', line 136

def gradient *args, transitions: nil
  return Gradient args, transitions: transitions unless args.empty?
  return Gradient net.pp, transitions: net.T_tt if transitions.nil?
  Gradient net.pp, transitions: transitions
end

.Gradient(array, transitions: nil) ⇒ Object

Constructs a set of gradient features from an array of gradient feature identifiers, optionally qualified by an array of transitions supplied via the named argument :transitions.



121
122
123
124
125
126
127
128
# File 'lib/y_petri/net/state/features.rb', line 121

def Gradient array, transitions: nil
  return new array.map &net.State.Feature.method( :Gradient ) if
    transitions.nil?
  ary = array.map { |id|
    net.State.Feature.Gradient id, transitions: transitions
  }
  new ary
end

.infer_from_nodes(nodes) ⇒ Object

Takes an array of the net’s nodes, and infers a feature set from them as follows: Places or place ids are converted to marking features. Remaining array elements are treated as transition ids, and are converted to either flux features (if the transition is timed), or firing features (if the transition is timeless).



261
262
263
# File 'lib/y_petri/net/state/features.rb', line 261

def infer_from_nodes( nodes )
  new nodes.map &net.State.Feature.method( :infer_from_node )
end

.marking(*marking_feature_identifiers) ⇒ Object

Expects an arbitrary number of marking feature identifiers and constructs a feature set out of them. Without arguments, full marking feature set for the underlying net is returned.



96
97
98
99
# File 'lib/y_petri/net/state/features.rb', line 96

def marking *marking_feature_identifiers
  return Marking net.pp if marking_feature_identifiers.empty?
  Marking marking_feature_identifiers
end

.Marking(array) ⇒ Object

Constructs a set of marking features from an array of marking feature identifiers.



88
89
90
# File 'lib/y_petri/net/state/features.rb', line 88

def Marking array
  new array.map &net.State.Feature.method( :Marking )
end

.new(features) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/y_petri/net/state/features.rb', line 40

def new features
  features = features.map &State().method( :Feature )
  __new__( features ).tap do |inst|
    # Parametrize them <em>one more time</em> with Features instance.
    # Banged version of #param_class! ensures that #Record, #Dataset
    # methods are shadowed.
    inst.param_class!( { Record: Record(),
                         DataSet: DataSet() },
                       with: { features: inst } )
  end
end

.parametrize(parameters) ⇒ Object

Customization of the parametrize method for the Features class: Its dependents Record and Dataset are also parametrized.



24
25
26
27
28
29
30
31
32
33
# File 'lib/y_petri/net/state/features.rb', line 24

def parametrize parameters
  Class.new( self ).tap do |ç|
    parameters.each_pair { |symbol, value|
      ç.define_singleton_method symbol do value end
    }
    ç.param_class( { Record: Record,
                     DataSet: YPetri::Net::DataSet },
                   with: { Features: ç } )
  end
end

Instance Method Details

#%(operand) ⇒ Object

Interpolation operator % acts as an alias for the #extract_from feature extraction method.



287
288
289
290
291
292
# File 'lib/y_petri/net/state/features.rb', line 287

def % operand
  args = Array( operand )
  named_args = args.extract_options!
  arg = args.first
  extract_from arg, **named_args
end

#*(other) ⇒ Object

Multiplication (like in arrays).



308
309
310
# File 'lib/y_petri/net/state/features.rb', line 308

def * other
  self.class.new( super )
end

#+(other) ⇒ Object

Summation of feature sets.



296
297
298
# File 'lib/y_petri/net/state/features.rb', line 296

def + other
  self.class.new( super )
end

#-(other) ⇒ Object

Subtraction of feature sets.



302
303
304
# File 'lib/y_petri/net/state/features.rb', line 302

def - other
  self.class.new( super )
end

#Assignment(array) ⇒ Object

Returns a subset of assignment features selected from this feature set. Expects a single array argument.



442
443
444
445
446
447
448
# File 'lib/y_petri/net/state/features.rb', line 442

def Assignment array
  self.class.new array.map { |id|
    net.State.Feature.Assignment( id ).tap do |f|
      include? f or fail KeyError, "No flux feature '#{f}' in this set!"
    end
  }
end

#assignment(*ids) ⇒ Object

Returns a subset of assignment features selected from this feature set. Expects an arbitrary number of arguments. Without arguments, selects all of them.



454
455
456
457
# File 'lib/y_petri/net/state/features.rb', line 454

def assignment *ids
  return Assignment ids unless ids.empty?
  self.class.new select { |f| f.is_a? net.State.Feature.Assignment }
end

#Delta(array, transitions: nil) ⇒ Object

Returns a subset of delta features selected from this feature set. Expects a single array argument, optionally qualified by :transitions named argument, defaulting to all the transitions in the net.



416
417
418
419
420
421
422
423
# File 'lib/y_petri/net/state/features.rb', line 416

def Delta array, transitions: nil
  self.class.new array.map { |id|
    net.State.Feature.Delta( id, transitions: transitions ).tap do |f|
      include? f or
        fail KeyError, "No delta feature '#{f}' in this feature set!"
    end
  }
end

#delta(*ids, transitions: L! ) ⇒ Object

Returns a subset of delta features selected from this feature set. Expects an arbitrary number of arguments, optionally qualified by :transitions named argument, defaulting to all the transitions in the net. Without arguments, selects all the delta features.



430
431
432
433
434
435
436
437
# File 'lib/y_petri/net/state/features.rb', line 430

def delta *ids, transitions: L!
  return Delta ids, transitions: transitions unless ids.empty?
  if transitions.local_object? then
    self.class.new select { |f| f.is_a? net.State.Feature.Delta }
  else
    self.class.new select { |f| f.transitions == net.tt( Array transitions ) }
  end
end

#extract_from(target, **nn) ⇒ Object

Extracts the features from a given target, returning a record.



279
280
281
282
# File 'lib/y_petri/net/state/features.rb', line 279

def extract_from target, **nn
  values = map { |feature| feature.extract_from( target, **nn ) }
  Record( values )
end

#Firing(array) ⇒ Object

Returns a subset of firing features selected from this feature set. Expects a single array argument.



351
352
353
354
355
356
357
# File 'lib/y_petri/net/state/features.rb', line 351

def Firing array
  self.class.new array.map { |id|
    net.State.Feature.Firing( id ).tap do |f|
      include? f or fail KeyError, "No firing feature '#{f}' in this set!"
    end
  }
end

#firing(*ids) ⇒ Object

Returns a subset of firing features selected from this feature set. Expects an arbitrary number of arguments. Without arguments, selects all of them.



362
363
364
365
# File 'lib/y_petri/net/state/features.rb', line 362

def firing *ids
  return Firing ids unless ids.empty?
  self.class.new select { |f| f.is_a? net.State.Feature.Firing }
end

#Flux(array) ⇒ Object

Returns a subset of flux features selected from this feature set. Expects a single array argument.



370
371
372
373
374
375
376
# File 'lib/y_petri/net/state/features.rb', line 370

def Flux array
  self.class.new array.map { |id|
    net.State.Feature.Flux( id ).tap do |f|
      include? f or fail KeyError, "No flux feature '#{f}' in this set!"
    end
  }
end

#flux(*ids) ⇒ Object

Returns a subset of flux features selected from this feature set. Expects an arbitrary number of arguments. Without arguments, selects all of them.



381
382
383
384
# File 'lib/y_petri/net/state/features.rb', line 381

def flux *ids
  return Flux ids unless ids.empty?
  self.class.new select { |f| f.is_a? net.State.Feature.Flux }
end

#Gradient(array, transitions: nil) ⇒ Object

Returns a subset of gradient features selected from this feature set. Expects a single array argument, optionally qualified by :transitions named argument, defaulting to all T transitions in the net.



390
391
392
393
394
395
396
# File 'lib/y_petri/net/state/features.rb', line 390

def Gradient array, transitions: nil
  self.class.new array.map { |id|
    net.State.Feature.Gradient( id, transitions: transitions ).tap do |f|
      include? f or fail KeyError, "No flux feature '#{f}' in this set!"
    end
  }
end

#gradient(*ids, transitions: L! ) ⇒ Object

Returns a subset of gradient features selected from this feature set. Expects an arbitrary number of arguments, optionally qualified by :transitions named argument, defaulting to all T transitions in the net. Without arguments, selects all of them.



403
404
405
406
407
408
409
410
# File 'lib/y_petri/net/state/features.rb', line 403

def gradient *ids, transitions: L!
  return Gradient ids, transitions: transitions unless ids.empty?
  if transitions.local_object? then
    self.class.new select { |f| f.is_a? net.State.Feature.Gradient }
  else
    self.class.new select { |f| f.transitions == net.tt( Array transitions ) }
  end
end

#inspectObject

Inspect string of the instance.



469
470
471
# File 'lib/y_petri/net/state/features.rb', line 469

def inspect
  "#<Features: #{to_s}>"
end

#labelsObject

Labels of the features of the receiver feature set.



314
315
316
# File 'lib/y_petri/net/state/features.rb', line 314

def labels
  map &:label
end

#marking(*ids) ⇒ Object

Returns a subset of marking features selected from this feature set. Expects an arbitrary number of arguments. Without arguments, selects all of them.



343
344
345
346
# File 'lib/y_petri/net/state/features.rb', line 343

def marking *ids
  return Marking ids unless ids.empty?
  self.class.new select { |f| f.is_a? net.State.Feature.Marking }
end

#Marking(array) ⇒ Object

Returns a subset of marking features selected from this feature set. Expects a single array argument.



331
332
333
334
335
336
337
338
# File 'lib/y_petri/net/state/features.rb', line 331

def Marking array
  array = array.map do |id|
    net.State.Feature.Marking( id ).tap do |f|
      include? f or fail KeyError, "No marking feature '#{f}' in this set!"
    end
  end
  self.class.new array
end

#reduce_features(features) ⇒ Object

Expects a hash identifying a set of features, that is a subset of the current set of features.



321
322
323
324
325
326
# File 'lib/y_petri/net/state/features.rb', line 321

def reduce_features features
  net.State.features( features ).tap do |ff|
    msg = "The argument must identify a subset of the current feature set!"
    fail TypeError, msg unless ( ff - self ).empty?
  end
end

#to_sObject

Returns a string briefly describing the feature set.



461
462
463
464
465
# File 'lib/y_petri/net/state/features.rb', line 461

def to_s
  group_by( &:type )
    .map { |feature_type, ff| "#{feature_type}: #{ff.size}" }
    .join ', '
end