y_petri 2.2.4 → 2.3.2

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.
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
@@ -1,129 +1,95 @@
1
1
  # encoding: utf-8
2
2
 
3
- # An array whose elements correspond to the full marking of the net's places.
4
- #
3
+ # An array whose elements represent marking of places of a +YPetri::Net+.
4
+ #
5
5
  class YPetri::Net::State < Array
6
6
  require_relative 'state/feature'
7
7
  require_relative 'state/features'
8
8
 
9
9
  class << self
10
- # Customization of the parametrize method for the State class: Its
11
- # dependents Feature and Features (feature set class) are also parametrized.
10
+ # Customization of the parametrize method for the State class: Its dependents
11
+ # Feature and Features (feature set class) are also parametrized.
12
12
  #
13
13
  def parametrize net: ( fail ArgumentError, "No owning net!" )
14
14
  Class.new( self ).tap do |ç|
15
15
  ç.define_singleton_method :net do net end
16
- ç.param_class( { Feature: Feature,
17
- Features: Features },
18
- with: { State: ç } )
16
+ ç.param_class!( { Feature: Feature,
17
+ Features: Features },
18
+ with: { State: ç } )
19
19
  end
20
20
  end
21
21
 
22
- delegate :Marking,
23
- :Firing,
24
- :Gradient,
25
- :Flux,
26
- :Delta,
27
- to: "Feature()"
28
-
29
22
  # Returns the feature identified by the argument.
30
- #
31
- def feature *id
32
- fail ArgumentError, "No feature identifier!" if id.empty?
33
- case id.first
34
- when Feature() then id.first
35
- when Feature then id.first.class.new( id.first )
36
- else
37
- msg = "Malformed feature identifier!"
38
- fail ArgumentError, msg unless id.size == 1 and id.first.is_a? Hash
39
- ꜧ = id.first
40
- fail ArgumentError, msg unless ꜧ.size == 1
41
- key, val = ꜧ.keys.first, ꜧ.values.first
42
- recognized = :marking, :firing, :gradient, :flux, :delta
43
- msg = "Unrecognized feature: #{key}"
44
- fail ArgumentError, msg unless recognized.include? key
45
- # And now, with everything clean...
23
+ #
24
+ def Feature arg=nil, **named_args
25
+ case arg
26
+ when Feature() then arg
27
+ when Feature then arg.class.new( arg )
28
+ when nil then
29
+ key, val = named_args.first
46
30
  case key
47
- when :marking then Marking( val )
48
- when :firing then Firing( val )
49
- when :flux then Flux( val )
50
- when :gradient then Gradient( *val )
51
- when :delta then Delta( *val )
31
+ when :marking then Feature().Marking( val )
32
+ when :firing then Feature().Firing( val )
33
+ when :flux then Feature().Flux( val )
34
+ when :gradient then Feature().Gradient( *val )
35
+ when :delta then Feature().Delta( *val )
36
+ when :assignment then Feature().Assignment( val )
37
+ else fail ArgumentError, "Unrecognized feature: #{key}!"
52
38
  end
39
+ else
40
+ Feature().infer_from_node( arg )
53
41
  end
54
42
  end
55
43
 
56
- # If the argument is an array of features, or another Features instance,
57
- # a feature set based on this array is returned. But the real purpose of
58
- # this method is to allow hash-type argument, with keys +:marking+,
59
- # +:firing+, +:gradient+, +:flux+ and +:delta+, specifying the respective
60
- # features. For +:marking+, an array of places (or Marking features) is
61
- # expected. For +:firing+ and +:flux+, an array of transitions (or Firing
62
- # / Flux features) is expected. For +:gradient+ and +:delta+, a hash value
63
- # is expected, containing keys +:places+ and +:transitions+, specifying
64
- # for which place set / transition set should gradient / delta features
65
- # be constructed. More in detail, values supplied under keys +:marking+,
66
- # +:firing+, +:gradient+, +:flux+ and +:delta+ are delegated to
67
- # +Features.marking+, +Features.firing+, +Features.gradient+ and
68
- # +Features.flux+ methods, and their results are joined into a single
69
- # feature set.
44
+ # A constructor of a +Features+ instance. Note that the message +:Features+
45
+ # called without arguments is intercepted by a singleton method and returns
46
+ # the parametrized subclass of +State::Features+ owned by this class.
70
47
  #
71
- def features arg
72
- case arg
73
- when Features(), Array then Features().new( arg )
74
- else # the real job of the method
75
- marking = arg[:marking] || []
76
- firing = arg[:firing] || [] # array of tS transitions
77
- gradient = arg[:gradient] || [ [], transitions: [] ]
78
- flux = arg[:flux] || [] # array of TS transitions
79
- delta = arg[:delta] || [ [], transitions: [] ]
80
- [ Features().marking( marking ),
81
- Features().firing( firing ),
82
- Features().gradient( *gradient ),
83
- Features().flux( flux ),
84
- Features().delta( *delta ) ].reduce :+
85
- end
48
+ # This method may accept a single array-type argument, constructing a feature
49
+ # set out of it. Alternatively, the method may accept named arguments:
50
+ # +:marking+, +:firing+, +:gradient+, +:flux+, +:delta+, and +:assignment+,
51
+ # specifying the a single (possibly mixed) feature set.
52
+ #
53
+ def Features array=nil, **named_args
54
+ Features()[ *array, **named_args ]
86
55
  end
56
+ end # class << self
87
57
 
88
- delegate :marking, :firing, :gradient, :flux, :delta, to: "Features()"
89
- end
90
-
91
- # For non-parametrized vesion of the class, the class instance variables
92
- # hold the non-parametrized dependent classes.
58
+ # For non-parametrized vesion of the class, should it ever be used in such way,
59
+ # the class instance variables hold the non-parametrized dependent classes.
93
60
  #
94
61
  @Feature, @Features = Feature, Features
95
62
 
96
63
  delegate :net,
97
- :Feature,
98
- :Features,
99
- :features,
100
- :marking, :firing, :gradient, :flux, :delta,
64
+ :Feature, # Note that as syntactic salt, specific methods
65
+ :Features, # #marking, #firing, #gradient, #flux etc. are
66
+ :features, # not delegated to self.class.
101
67
  to: "self.class"
102
68
 
103
- # Given a set of clamped places, this method outputs a Record instance
69
+ # Given a set of clamped places, this method outputs a +Record+ instance
104
70
  # containing the marking of the free places (complementary to the supplied
105
71
  # set of clamped places). I no set of clamped places is supplied, it is
106
72
  # considered empty.
107
73
  #
108
- def to_record clamped_places=[]
74
+ def to_record clamped_places
109
75
  free_places = case clamped_places
110
76
  when Hash then to_record( clamped_places.keys )
111
77
  else
112
- free_places = places - places( clamped_places )
78
+ places - places( clamped_places )
113
79
  end
114
80
  features( marking: free_places ).Record.load markings( free_places )
115
81
  end
116
82
 
117
83
  # Marking of a single given place in this state.
118
84
  #
119
- def marking place_id
120
- self[ places.index place( place_id ) ]
85
+ def marking place
86
+ self[ net.places.index net.place( place ) ]
121
87
  end
122
88
 
123
- # Returns an array of markings of particular places in this state..
89
+ # Expects an arbitrary number of places or place ids, and returns an array
90
+ # of their markings as per the receiver +State+ instance.
124
91
  #
125
- def markings place_ids=nil
126
- return markings( places ) if place_ids.nil?
127
- place_ids.map &:marking
92
+ def markings *places
93
+ places.map &method( :marking )
128
94
  end
129
95
  end # YPetri::Net::State
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # Own visualization capabilities of a Petri net.
4
4
  #
data/lib/y_petri/net.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require_relative 'net/element_access'
3
+ require_relative 'net/node_access'
4
4
  require_relative 'net/visualization'
5
5
  require_relative 'net/own_state'
6
6
  require_relative 'net/data_set'
@@ -10,21 +10,33 @@ require_relative 'net/state'
10
10
  # connector arrows – called _arcs_ in classical Petri net terminology – can be
11
11
  # considered a property of transitions. Therefore in +YPetri::Net+, you won't
12
12
  # find arcs as first-class citizens, but only as a synonym denoting nearest
13
- # neighbors of elements (places or transitions).
13
+ # neighbors of nodes (places or transitions).
14
14
  #
15
15
  class YPetri::Net
16
+ # ===========================================================================
17
+ # !!! TODO !!!
18
+ #
19
+ # Refactoring plans for Net class
20
+ #
21
+ # Make it a subclass of Module class, so places and transitions can simply
22
+ # be defined as its constants.
23
+ #
24
+ # ===========================================================================
25
+
16
26
  ★ NameMagic # ★ means include
17
- ElementAccess # to be below ElementAccess
27
+ NodeAccess
18
28
  ★ Visualization
19
29
  ★ OwnState
20
30
 
21
31
  class << self
22
32
  ★ YPetri::World::Dependency
23
33
 
24
- # Constructs a net containing a particular set of elements.
34
+ private :new
35
+
36
+ # Constructs a net containing a particular set of nodes.
25
37
  #
26
- def of elements
27
- new.tap { |inst| elements.each { |e| inst << e } }
38
+ def of nodes
39
+ new.tap { |inst| nodes.each { |node| inst << node } }
28
40
  end
29
41
  end
30
42
 
@@ -34,93 +46,95 @@ class YPetri::Net
34
46
  # Takes 2 arguments (+:places+ and +:transitions+) and builds a net from them.
35
47
  #
36
48
  def initialize( places: [], transitions: [] )
37
- param_class( { State: State }, with: { net: self } )
49
+ param_class!( { State: State,
50
+ Simulation: YPetri::Simulation },
51
+ with: { net: self } )
38
52
  @places, @transitions = [], []
39
53
  places.each &method( :include_place )
40
54
  transitions.each &method( :include_transition )
41
- param_class( { Simulation: YPetri::Simulation },
42
- with: { net: self } )
43
55
  end
44
56
 
45
57
  # Includes a place in the receiver. Returns _true_ if successful, _false_ if
46
58
  # the place is already included in the receiver net.
47
59
  #
48
- def include_place id
49
- pl = Place().instance( id )
50
- return false if includes_place? pl
51
- true.tap { @places << pl }
60
+ def include_place place
61
+ place = Place().instance( place )
62
+ return false if include_place? place
63
+ true.tap { @places << place }
52
64
  end
53
65
 
54
66
  # Includes a transition in the receiver. Returns _true_ if successful, _false_
55
67
  # if the transition is already included in the net. The arcs of the transition
56
68
  # being included may only connect to the places already in the receiver net.
57
69
  #
58
- def include_transition id
59
- tr = Transition().instance( id )
60
- return false if includes_transition? tr
61
- msg = "Transition #{tr} has arcs to places outside #{self}!"
62
- fail msg unless tr.arcs.all? { |p| includes_place? p }
63
- true.tap { @transitions << tr }
70
+ def include_transition transition
71
+ transition = Transition().instance( transition )
72
+ return false if include_transition? transition
73
+ fail "Transition #{transition} has arcs to places outside #{self}!" unless
74
+ transition.arcs.all? { |place| include_place? place }
75
+ true.tap { @transitions << transition }
64
76
  end
65
77
 
66
78
  # Excludes a place from the receiver. Returns _true_ if successful, _false_
67
79
  # if the place was not found in the receiver net. A place may not be excluded
68
80
  # from the receiver so long as any transitions therein connect to it.
69
81
  #
70
- def exclude_place id
71
- pl = Place().instance( id )
72
- msg = "Unable to exclude #{pl} from #{self}: Transition(s) depend on it!"
73
- fail msg if transitions.any? { |tr| tr.arcs.include? pl }
74
- false.tap { return true if @places.delete( pl ) }
82
+ def exclude_place place
83
+ place = Place().instance( place )
84
+ fail "Unable to exclude #{place} from #{self}: Transitions depend on it!" if
85
+ transitions.any? { |transition| transition.arcs.include? place }
86
+ false.tap { return true if @places.delete( place ) }
75
87
  end
76
88
 
77
89
  # Excludes a transition from the receiver. Returns _true_ if successful,
78
90
  # _false_ if the transition was not found in the receiver net.
79
91
  #
80
- def exclude_transition id
81
- tr = Transition().instance( id )
82
- false.tap { return true if @transitions.delete( tr ) }
92
+ def exclude_transition transition
93
+ transition = Transition().instance( transition )
94
+ false.tap { return true if @transitions.delete( transition ) }
83
95
  end
84
96
 
85
97
  # Includes another net in the receiver net. Returns _true_ if successful
86
98
  # (ie. if there was any change to the receiver net), _false_ if the receiver
87
99
  # net already includes the argument net.
88
100
  #
89
- def include_net id
90
- net = Net().instance( id )
91
- p_rslt = net.pp.map { |p| include_place p }.reduce :|
92
- t_rslt = net.tt.map { |t| include_transition t }.reduce :|
93
- p_rslt || t_rslt
101
+ def include_net net
102
+ net = Net().instance( net ) rescue YPetri::Net.instance( net )
103
+ p_results = net.pp.map &method( :include_place )
104
+ t_results = net.tt.map &method( :include_transition )
105
+ ( p_results + t_results ).reduce :|
94
106
  end
95
107
  alias merge! include_net
96
108
 
97
109
  # Excludes another net from the receiver net. Returns _true_ if successful
98
110
  # (ie. if there was any change to the receiver net), _false_ if the receiver
99
- # net contained no element of the argument net.
111
+ # net contained no node of the argument net.
100
112
  #
101
113
  def exclude_net id
102
- net = Net().instance( id )
114
+ net = Net().instance( id ) rescue YPetri::Net.instance( net )
103
115
  t_rslt = net.tt.map { |t| exclude_transition t }.reduce :|
104
116
  p_rslt = net.pp.map { |p| exclude_place p }.reduce :|
105
117
  p_rslt || t_rslt
106
118
  end
107
119
 
108
- # Includes an element (place or transition) in the net.
120
+ # Includes a node (place or transition) in the receiver net.
109
121
  #
110
- def << element_id
122
+ def << node
111
123
  begin
112
- type, element = :place, self.class.place( element_id )
124
+ type = :place
125
+ place = self.class.place node
113
126
  rescue NameError, TypeError
114
127
  begin
115
- type, element = :transition, self.class.transition( element_id )
128
+ type = :transition
129
+ transition = self.class.transition node
116
130
  rescue NameError, TypeError => err
117
- raise TypeError, "Current world contains no place or transition " +
118
- "identified by #{element_id}! (#{err})"
131
+ raise TypeError, "Current world contains no place or " +
132
+ "transition #{node}! (#{err})"
119
133
  end
120
134
  end
121
135
  case type # Factored out to minimize the code inside the rescue clause.
122
- when :place then include_place( element )
123
- when :transition then include_transition( element )
136
+ when :place then include_place( place )
137
+ when :transition then include_transition( transition )
124
138
  else fail "Implementation error!" end
125
139
  return self # important to enable chaining, eg. foo_net << p1 << p2 << t1
126
140
  end
@@ -135,12 +149,12 @@ class YPetri::Net
135
149
  end
136
150
  end
137
151
 
138
- # Creates a new net that contains the places and transition of the receiver
139
- # after excluding the second operand.
152
+ # Returns a new net that is the result of subtraction of the net given as
153
+ # argument from this net.
140
154
  #
141
155
  def - other
142
156
  self.class.send( :new ).tap do |net|
143
- net.merge! self
157
+ net.include_net self
144
158
  net.exclude_net other
145
159
  end
146
160
  end
@@ -148,13 +162,13 @@ class YPetri::Net
148
162
  # Is the net _functional_?
149
163
  #
150
164
  def functional?
151
- transitions.any? { |t| t.functional? }
165
+ transitions.any? &:functional?
152
166
  end
153
167
 
154
168
  # Is the net _timed_?
155
169
  #
156
170
  def timed?
157
- transitions.any? { |t| t.timed? }
171
+ transitions.any? &:timed?
158
172
  end
159
173
 
160
174
  # Creates a new simulation from the net.
@@ -162,6 +176,7 @@ class YPetri::Net
162
176
  def simulation( **settings )
163
177
  Simulation().__new__ **settings
164
178
  end
179
+ alias new_simulation simulation
165
180
 
166
181
  # Networks are equal when their places and transitions are equal.
167
182
  #
@@ -23,6 +23,24 @@ module YPetri::Place::Arcs
23
23
  upstream_arcs | downstream_arcs
24
24
  end
25
25
 
26
+ # Names of the transitions connected to the place. The optional argument
27
+ # controls what is returned for unnamed instances, and works just like in
28
+ # <tt>Array#names</tt> method from <tt>y_support/name_magic</tt>:
29
+ # The default value (_nil_) returns _nil_, _true_ returns the instance itself,
30
+ # and _false_ drops the unnamed instances from the list altogether.
31
+ #
32
+ def aa arg=nil
33
+ arcs.names arg
34
+ end
35
+
36
+ # Arc (a transition connected to this place) identifier.
37
+ #
38
+ def arc id
39
+ transition = transition( id )
40
+ arcs.find { |t| t == transition } or
41
+ fail TypeError, "No transition #{id} connected to #{self}!"
42
+ end
43
+
26
44
  # Union of the domains of the upstream transitions.
27
45
  #
28
46
  def precedents
@@ -37,6 +55,32 @@ module YPetri::Place::Arcs
37
55
  end
38
56
  alias :downstream_places :dependents
39
57
 
58
+ # A net containing all the upstream transitions and their connected places.
59
+ #
60
+ def upstream_net
61
+ net_klass = world.Net rescue YPetri::Net # for when not used as PS
62
+ upstream_transitions.each_with_object net_klass.send( :new ) do |t, net|
63
+ t.arcs.each { |place| net << place }
64
+ net << t
65
+ end
66
+ end
67
+
68
+ # A net containing all the upstream transitions and their connected places.
69
+ #
70
+ def downstream_net
71
+ net_klass = world.Net rescue YPetri::Net # for when not used as PS
72
+ downstream_transitions.each_with_object net_klass.send( :new ) do |t, net|
73
+ t.arcs.each { |place| net << place }
74
+ net << t
75
+ end
76
+ end
77
+
78
+ # A union of upstream local net and downstream local net.
79
+ #
80
+ def local_net
81
+ downstream_net + upstream_net
82
+ end
83
+
40
84
  # Fires the upstream transitions.
41
85
  #
42
86
  def fire_upstream
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ # Place instance methods concerned with state and/or simulation features.
4
+ #
5
+ module YPetri::Place::Features
6
+ # Expects an array of transitions, and +:net+ named argument. Returns a single
7
+ # gradient feature belonging to the net for this place, and those upstream T
8
+ # transitions, that are also in the included in the array. If no ordered
9
+ # arguments are given, complete set of upstream T transitions is assumed. If
10
+ # no +:net+ is given, +Top+ is assumed.
11
+ #
12
+ def Gradient array, net: world.net( :Top )
13
+ fail TypeError, "#{self} must be included in the net!" unless
14
+ net.include? self
15
+ transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
16
+ net.State.Feature.Gradient( self, transitions: transitions )
17
+ end
18
+
19
+ # Expects an arbitrary number of transitions, and +:net+ named argument.
20
+ # Returns a single gradient feature belonging to the net for this place,
21
+ # and those upstream T transitions, that are also in the included among
22
+ # the arguments. If no ordered arguments are given, complete set of upstream
23
+ # T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
24
+ #
25
+ def gradient *transitions, net: world.net( :Top )
26
+ return Gradient upstream_arcs, net: net if transitions.empty?
27
+ Gradient transitions, net: net
28
+ end
29
+
30
+ # Expects an array of transitions, and +:net+ named argument. Returns a
31
+ # feature set belonging to the net, consisting of the features for this
32
+ # place, and those upstream T transitions, that are also included in the
33
+ # array. If no +:net+ is given, +Top+ is assumed.
34
+ #
35
+ def Gradients array, net: world.net( :Top )
36
+ fail TypeError, "#{self} must be included in the net!" unless
37
+ net.include? self
38
+ transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
39
+ net.State.Features( transitions.map { |t| gradient t, net: net } )
40
+ end
41
+
42
+ # Expects an arbitrary number of transitions, and +:net+ named argument.
43
+ # Returns a feature set belonging to the net, constisting of the features
44
+ # for this place, and those upstream T transitions, that are also included
45
+ # in the array. If no ordered arguments are given, complete set of upstream
46
+ # T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
47
+ #
48
+ def gradients *transitions, net: world.net( :Top )
49
+ return Gradients upstream_arcs, net: net if transitions.empty?
50
+ Gradients transitions, net: net
51
+ end
52
+
53
+ # Expects an array of transitions, and +:net+ named argument. Returns a single
54
+ # delta feature belonging to the net for this place, and those upstream T
55
+ # transitions, that are also in the included in the array. If no ordered
56
+ # arguments are given, complete set of upstream T transitions is assumed. If
57
+ # no +:net+ is given, +Top+ is assumed.
58
+ #
59
+ def Delta array, net: world.net( :Top )
60
+ fail TypeError, "#{self} must be included in the net!" unless
61
+ net.include? self
62
+ transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
63
+ net.State.Feature.Delta( self, transitions: transitions )
64
+ end
65
+
66
+ # Expects an arbitrary number of transitions, and +:net+ named argument.
67
+ # Returns a single delta feature belonging to the net for this place,
68
+ # and those upstream T transitions, that are also in the included among
69
+ # the arguments. If no ordered arguments are given, complete set of upstream
70
+ # T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
71
+ #
72
+ def delta *transitions, net: world.net( :Top )
73
+ return Delta upstream_arcs, net: net if transitions.empty?
74
+ Delta transitions, net: net
75
+ end
76
+
77
+ # Expects an array of transitions, and +:net+ named argument. Returns a
78
+ # feature set belonging to the net, consisting of the features for this
79
+ # place, and those upstream T transitions, that are also included in the
80
+ # array. If no +:net+ is given, +Top+ is assumed.
81
+ #
82
+ def Deltas array, net: world.net( :Top )
83
+ fail TypeError, "#{self} must be included in the net!" unless
84
+ net.include? self
85
+ transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
86
+ net.State.Features( transitions.map { |t| delta t, net: net } )
87
+ end
88
+
89
+ # Expects an arbitrary number of transitions, and +:net+ named argument.
90
+ # Returns a feature set belonging to the net, constisting of the features
91
+ # for this place, and those upstream T transitions, that are also included
92
+ # in the array. If no ordered arguments are given, complete set of upstream
93
+ # T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
94
+ #
95
+ def deltas *transitions, net: world.net( :Top )
96
+ return Deltas upstream_arcs, net: net if transitions.empty?
97
+ Deltas transitions, net: net
98
+ end
99
+
100
+ # Convenience method. Prints gradients under curent simulation.
101
+ #
102
+ def pg simulation=world.simulation, precision: 8, **nn
103
+ ( gradients >> gradients % simulation )
104
+ .pretty_print_numeric_values precision: precision, **nn
105
+ end
106
+
107
+ # Convenience method. Prints deltas under current simulation.
108
+ #
109
+ def pd simulation=world.simulation, precision: 8, **nn
110
+ nn.may_have :delta_time, syn!: :Δt
111
+ delta_time = nn.delete( :delta_time ) || world.simulation.step
112
+ ( deltas >> deltas % [ simulation, delta_time: delta_time ] )
113
+ .pretty_print_numeric_values precision: precision, **nn
114
+ end
115
+ end # class YPetri::Place::Features