y_petri 2.2.4 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
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