y_petri 2.0.15 → 2.1.3

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/lib/y_petri/{manipulator → agent}/hash_key_pointer.rb +2 -2
  3. data/lib/y_petri/agent/petri_net_related.rb +115 -0
  4. data/lib/y_petri/{manipulator → agent}/selection.rb +2 -1
  5. data/lib/y_petri/{manipulator/simulation_related_methods.rb → agent/simulation_related.rb} +93 -110
  6. data/lib/y_petri/agent.rb +22 -0
  7. data/lib/y_petri/core/timed/euler.rb +20 -0
  8. data/lib/y_petri/core/timed/pseudo_euler.rb +31 -0
  9. data/lib/y_petri/core/timed/quasi_euler.rb +23 -0
  10. data/lib/y_petri/core/timed.rb +70 -0
  11. data/lib/y_petri/core/timeless/pseudo_euler.rb +20 -0
  12. data/lib/y_petri/core/timeless.rb +12 -0
  13. data/lib/y_petri/core.rb +100 -0
  14. data/lib/y_petri/dsl.rb +66 -0
  15. data/lib/y_petri/fixed_assets.rb +7 -0
  16. data/lib/y_petri/net/element_access.rb +239 -0
  17. data/lib/y_petri/net/state/feature/delta.rb +88 -0
  18. data/lib/y_petri/net/state/feature/firing.rb +57 -0
  19. data/lib/y_petri/net/state/feature/flux.rb +58 -0
  20. data/lib/y_petri/net/state/feature/gradient.rb +75 -0
  21. data/lib/y_petri/net/state/feature/marking.rb +62 -0
  22. data/lib/y_petri/net/state/feature.rb +79 -0
  23. data/lib/y_petri/net/state/features/dataset.rb +135 -0
  24. data/lib/y_petri/net/state/features/record.rb +50 -0
  25. data/lib/y_petri/net/state/features.rb +126 -0
  26. data/lib/y_petri/net/state.rb +121 -0
  27. data/lib/y_petri/net/timed.rb +8 -0
  28. data/lib/y_petri/net/visualization.rb +3 -3
  29. data/lib/y_petri/net.rb +73 -77
  30. data/lib/y_petri/place.rb +8 -3
  31. data/lib/y_petri/simulation/dependency.rb +107 -0
  32. data/lib/y_petri/simulation/element_representation.rb +20 -0
  33. data/lib/y_petri/simulation/elements/access.rb +57 -0
  34. data/lib/y_petri/simulation/elements.rb +45 -0
  35. data/lib/y_petri/simulation/feature_set.rb +21 -0
  36. data/lib/y_petri/simulation/initial_marking/access.rb +55 -0
  37. data/lib/y_petri/simulation/initial_marking.rb +15 -0
  38. data/lib/y_petri/simulation/marking_clamps/access.rb +34 -0
  39. data/lib/y_petri/simulation/marking_clamps.rb +18 -0
  40. data/lib/y_petri/simulation/marking_vector/access.rb +106 -0
  41. data/lib/y_petri/simulation/marking_vector.rb +156 -0
  42. data/lib/y_petri/simulation/matrix.rb +64 -0
  43. data/lib/y_petri/simulation/place_mapping.rb +62 -0
  44. data/lib/y_petri/simulation/place_representation.rb +74 -0
  45. data/lib/y_petri/simulation/places/access.rb +121 -0
  46. data/lib/y_petri/simulation/places/clamped.rb +8 -0
  47. data/lib/y_petri/simulation/places/free.rb +8 -0
  48. data/lib/y_petri/simulation/places/types.rb +25 -0
  49. data/lib/y_petri/simulation/places.rb +41 -0
  50. data/lib/y_petri/simulation/recorder.rb +54 -0
  51. data/lib/y_petri/simulation/timed/recorder.rb +53 -0
  52. data/lib/y_petri/simulation/timed.rb +161 -261
  53. data/lib/y_petri/simulation/timeless/recorder.rb +25 -0
  54. data/lib/y_petri/simulation/timeless.rb +35 -0
  55. data/lib/y_petri/simulation/transition_representation/A.rb +58 -0
  56. data/lib/y_petri/simulation/transition_representation/S.rb +45 -0
  57. data/lib/y_petri/simulation/transition_representation/T.rb +80 -0
  58. data/lib/y_petri/simulation/transition_representation/TS.rb +46 -0
  59. data/lib/y_petri/simulation/transition_representation/Ts.rb +32 -0
  60. data/lib/y_petri/simulation/transition_representation/a.rb +30 -0
  61. data/lib/y_petri/simulation/transition_representation/s.rb +29 -0
  62. data/lib/y_petri/simulation/transition_representation/t.rb +37 -0
  63. data/lib/y_petri/simulation/transition_representation/tS.rb +38 -0
  64. data/lib/y_petri/simulation/transition_representation/ts.rb +32 -0
  65. data/lib/y_petri/simulation/transition_representation/types.rb +62 -0
  66. data/lib/y_petri/simulation/transition_representation.rb +79 -0
  67. data/lib/y_petri/simulation/transitions/A.rb +40 -0
  68. data/lib/y_petri/simulation/transitions/S.rb +24 -0
  69. data/lib/y_petri/simulation/transitions/T.rb +34 -0
  70. data/lib/y_petri/simulation/transitions/TS.rb +57 -0
  71. data/lib/y_petri/simulation/transitions/Ts.rb +60 -0
  72. data/lib/y_petri/simulation/transitions/a.rb +8 -0
  73. data/lib/y_petri/simulation/transitions/access.rb +186 -0
  74. data/lib/y_petri/simulation/transitions/s.rb +9 -0
  75. data/lib/y_petri/simulation/transitions/t.rb +22 -0
  76. data/lib/y_petri/simulation/transitions/tS.rb +55 -0
  77. data/lib/y_petri/simulation/transitions/ts.rb +58 -0
  78. data/lib/y_petri/simulation/transitions/types.rb +98 -0
  79. data/lib/y_petri/simulation/transitions.rb +21 -0
  80. data/lib/y_petri/simulation.rb +176 -781
  81. data/lib/y_petri/transition/assignment.rb +7 -5
  82. data/lib/y_petri/transition/construction.rb +119 -187
  83. data/lib/y_petri/transition/init.rb +311 -0
  84. data/lib/y_petri/transition/ordinary_timeless.rb +8 -6
  85. data/lib/y_petri/transition/timed.rb +11 -18
  86. data/lib/y_petri/transition.rb +104 -132
  87. data/lib/y_petri/version.rb +1 -1
  88. data/lib/y_petri/world/dependency.rb +40 -0
  89. data/lib/y_petri/world/petri_net_related.rb +61 -0
  90. data/lib/y_petri/{workspace/simulation_related_methods.rb → world/simulation_related.rb} +42 -49
  91. data/lib/y_petri/world.rb +27 -0
  92. data/lib/y_petri.rb +47 -99
  93. data/test/{manipulator_test.rb → agent_test.rb} +19 -17
  94. data/{lib/y_petri → test/examples}/demonstrator.rb +0 -0
  95. data/{lib/y_petri → test/examples}/demonstrator_2.rb +1 -0
  96. data/{lib/y_petri → test/examples}/demonstrator_3.rb +0 -0
  97. data/{lib/y_petri → test/examples}/demonstrator_4.rb +0 -0
  98. data/test/examples/example_2.rb +16 -0
  99. data/test/{manual_examples.rb → examples/manual_examples.rb} +0 -0
  100. data/test/net_test.rb +126 -121
  101. data/test/place_test.rb +1 -1
  102. data/test/sim_test +565 -0
  103. data/test/simulation_test.rb +338 -264
  104. data/test/transition_test.rb +77 -174
  105. data/test/world_mock.rb +12 -0
  106. data/test/{workspace_test.rb → world_test.rb} +19 -20
  107. data/test/y_petri_test.rb +4 -5
  108. metadata +101 -26
  109. data/lib/y_petri/dependency_injection.rb +0 -45
  110. data/lib/y_petri/manipulator/petri_net_related_methods.rb +0 -74
  111. data/lib/y_petri/manipulator.rb +0 -20
  112. data/lib/y_petri/net/selections.rb +0 -209
  113. data/lib/y_petri/simulation/collections.rb +0 -460
  114. data/lib/y_petri/workspace/parametrized_subclassing.rb +0 -22
  115. data/lib/y_petri/workspace/petri_net_related_methods.rb +0 -88
  116. data/lib/y_petri/workspace.rb +0 -16
  117. data/test/timed_simulation_test.rb +0 -153
@@ -0,0 +1,106 @@
1
+ #encoding: utf-8
2
+
3
+ # A mixin.
4
+ #
5
+ class YPetri::Simulation::MarkingVector
6
+ module Access
7
+ # Marking of all places (as a column vector).
8
+ #
9
+ def m_vector ids=nil
10
+ if ids.nil? then
11
+ msg = "Marking vector not established yet!"
12
+ @m_vector or fail TypeError, msg
13
+ else
14
+ m_vector.select( ids )
15
+ end
16
+ end
17
+
18
+ # Marking of all places (as array).
19
+ #
20
+ def m ids=nil
21
+ m_vector( ids ).to_a
22
+ end
23
+
24
+ # Marking of all places (as hash).
25
+ #
26
+ def place_m ids=nil
27
+ m_vector( ids ).to_hash
28
+ end
29
+
30
+ # Marking of all places (as hash with place names as keys).
31
+ #
32
+ def p_m ids=nil
33
+ places( ids ).names( true ) >> m( ids )
34
+ end
35
+ alias pn_m p_m
36
+ alias pm p_m
37
+
38
+ # Modifies the marking vector. Takes one argument. If the argument is a hash
39
+ # of pairs { place => new value }, only the specified places' markings are
40
+ # updated. If the argument is an array, it must match the number of places
41
+ # in the simulation, and all marking values are updated.
42
+ #
43
+ def update_m new_m
44
+ case new_m
45
+ when Hash then # assume { place => marking } hash
46
+ new_m.each_pair { |id, val| m_vector.set( id, val ) }
47
+ when Array then
48
+ msg = "T be a collection with size == number of net's places!"
49
+ fail TypeError, msg unless new_m.size == places.size
50
+ update_m( places >> new_m )
51
+ else # convert it with #each
52
+ update_m( new_m.each.to_a )
53
+ end
54
+ end
55
+
56
+ # Marking vector of free places.
57
+ #
58
+ def marking_vector ids=nil
59
+ m_vector free_places( ids )
60
+ end
61
+
62
+ # Marking of free places (as array).
63
+ #
64
+ def marking ids=nil
65
+ marking_vector( ids ).to_a
66
+ end
67
+
68
+ # Marking of free places (as hash).
69
+ #
70
+ def place_marking ids=nil
71
+ marking_vector( ids ).to_hash
72
+ end
73
+
74
+ # Marking of free places (as hash with place names as keys).
75
+ #
76
+ def p_marking ids=nil
77
+ marking_vector( ids ).to_h
78
+ end
79
+ alias pn_marking p_marking
80
+
81
+ # Modifies the marking vector. Like +#update_m+, but the places must be
82
+ # free places, and if the argument is an array, it must match the number
83
+ # of free places in the simulation's net.
84
+ #
85
+ def update_marking new_m
86
+ case new_m
87
+ when Hash then # assume { place => marking } hash
88
+ ( free_places( *new_m.keys ) >> new_m.values )
89
+ .each_pair { |id, val| m_vector.set( id, val ) }
90
+ when Array then
91
+ msg = "T be a collection with size == number of net's free places!"
92
+ fail TypeError, msg unless new_m.size == free_places.size
93
+ update_m( free_places >> new_m )
94
+ else # convert it with #each
95
+ update_marking( new_m.each.to_a )
96
+ end
97
+ end
98
+
99
+ # Expects a Δ marking vector for free places and performs the specified
100
+ # change on the marking vector of the simulation.
101
+ #
102
+ def increment_marking Δ_free
103
+ @m_vector += f2a * Δ_free
104
+ end
105
+ end # module Access
106
+ end # class YPetri::Simulation::MarkingVector
@@ -0,0 +1,156 @@
1
+ # Basic elements of a simulation, a mixin intended for YPetri::Simulation.
2
+ #
3
+ class YPetri::Simulation
4
+ class MarkingVector < Matrix
5
+ include Dependency
6
+
7
+ class << self
8
+ include Dependency
9
+
10
+ attr_reader :annotation
11
+
12
+ # Constructs a marking vector from a hash places >> values, or from
13
+ # an array, in which case, it is assumed that the marking vector
14
+ # corresponds to all the places in the simulation.
15
+ #
16
+ def [] arg
17
+ case arg
18
+ when Hash then annotated_with( arg.keys )[ arg.values ]
19
+ when Array then
20
+ if annotation then
21
+ msg = "The size of the argument (#{arg.size}) does not " +
22
+ "correspond to the annotation size (#{annotation.size})!"
23
+ fail ArgumentError, msg unless arg.size == annotation.size
24
+ column_vector arg
25
+ else
26
+ annotated_with( places )[ args ]
27
+ end
28
+ else
29
+ self[ args.each.to_a ]
30
+ end
31
+ end
32
+
33
+ # Returns a subclass of self annotated with the supplied places.
34
+ #
35
+ def annotated_with place_ids
36
+ annot = if annotation then
37
+ annotation.subset place_ids
38
+ else
39
+ places( place_ids )
40
+ end
41
+ Class.new self do @annotation = annot end
42
+ end
43
+
44
+ # Without arguments, constructs the starting marking vector for all places,
45
+ # using either initial values, or clamp values. Optionally, places can be
46
+ # specified, for which the starting vector is returned.
47
+ #
48
+ def starting place_ids=nil
49
+ st = -> p { p.free? ? p.initial_marking : p.clamp } # starting value
50
+ if place_ids.nil? then
51
+ return starting places if annotation.nil?
52
+ self[ annotation.map &st ]
53
+ else
54
+ annotated_with( place_ids ).starting
55
+ end
56
+ end
57
+
58
+ # Without arguments, constructs a zero marking vector for all places.
59
+ # Optionally, places can be specified, for which the zero vector is
60
+ # returned.
61
+ #
62
+ def zero( place_ids=nil )
63
+ starting( place_ids ) * 0
64
+ end
65
+ end
66
+
67
+ delegate :simulation, to: "self.class"
68
+
69
+ # Creates a subset of this marking vector.
70
+ #
71
+ def select place_ids, &block
72
+ if block_given? then
73
+ msg = "If block is given, arguments are not allowed!"
74
+ fail ArgumentError, msg unless place_ids.empty?
75
+ select annotation.select( &block )
76
+ else
77
+ pp = places( place_ids )
78
+ annotated_subcl = self.class.annotated_with( pp )
79
+ annotated_subcl[ pp.map { |p| fetch p } ]
80
+ end
81
+ end
82
+
83
+ # Modifying the vector elements.
84
+ #
85
+ def set id, value
86
+ self[ index( id ), 0 ] = value
87
+ end
88
+
89
+ # Whole vector is reset to a given collection of values. If no argument is
90
+ # given, starting vector is used.
91
+ #
92
+ def reset! arg=self.class.starting
93
+ arg.each.to_a.zip( annotation ).map { |value, place| set place, value }
94
+ end
95
+
96
+ # Access of the vector elements.
97
+ #
98
+ def fetch id
99
+ self[ index( id ), 0 ]
100
+ end
101
+
102
+ # Annotation.
103
+ #
104
+ def annotation
105
+ self.class.annotation
106
+ end
107
+
108
+ # Index of a place.
109
+ #
110
+ def index id
111
+ if id.is_a? Numeric then
112
+ fail RangeError, "Numeric index must be within 0..#{size}" unless
113
+ ( 0..size ) === id
114
+ else
115
+ annotation.index place( id )
116
+ end
117
+ end
118
+
119
+ # Marking vector size -- depends on the annotation.
120
+ #
121
+ def size
122
+ annotation.size
123
+ end
124
+
125
+ # Converts the marking vector (which is a column vector) into an array.
126
+ #
127
+ def to_a
128
+ ( 0..size - 1 ).map { |i| self[ i, 0 ] }
129
+ end
130
+
131
+ # Converts the marking vector into a hash annotation >> values.
132
+ #
133
+ def to_hash
134
+ annotation >> to_a
135
+ end
136
+
137
+ # Converts the marking vector into a hash annotation_names >> values.
138
+ #
139
+ def to_h
140
+ annotation.names( true ) >> to_a
141
+ end
142
+
143
+ # Converts the marking vector into a hash source places >> values.
144
+ #
145
+ def to_hash_with_source_places
146
+ annotation.sources >> to_a
147
+ end
148
+
149
+ # Builds the assignment closure.
150
+ #
151
+ def increment_closure
152
+ indices_of_free_places = annotation.free.map { |p| annotation.index p }
153
+ increment_at_indices_closure( indices: indices_of_free_places )
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,64 @@
1
+ #encoding: utf-8
2
+
3
+ require 'matrix'
4
+
5
+ # Patches the Matrix class with methods that generate code for direct vector
6
+ # access.
7
+ #
8
+ class Matrix
9
+ class << self
10
+ # Builds a code string for accessing the vector values at given indices.
11
+ #
12
+ def column_vector_access_code vector: (fail ArgumentError, "No vector!"),
13
+ indices: (fail ArgumentError, "No indices!")
14
+ indices.map { |i| "#{vector}[#{i}, 0]" }.join( ", " )
15
+ end
16
+
17
+ # Builds a code string for assigning to a vector at given indices.
18
+ #
19
+ def column_vector_assignment_code vector: (fail ArgumentError, "No vector!"),
20
+ indices: (fail ArgumentError, "No indices!"),
21
+ source: (fail ArgumentError, "No source!")
22
+ code_lines = indices.map.with_index do |i, source_pos|
23
+ "#{vector}.send( :[]=, #{i}, 0, #{source}.fetch( #{source_pos} ) )" if i
24
+ end
25
+ code_lines.compact.join( "\n" ) << "\n"
26
+ end
27
+
28
+ # Builds a code string for incrementing a vector at given indices. Source is
29
+ # a vector.
30
+ #
31
+ def column_vector_increment_code vector: (fail ArgumentError, "No vector!"),
32
+ indices: (fail ArgumentError, "No indices!"),
33
+ source: (fail ArgumentError, "No source!")
34
+ code_lines = indices.map.with_index do |i, source_pos|
35
+ "#{vector}.send( :[]=, #{i}, 0, %s )" %
36
+ "#{vector}[#{i}, 0] + #{source}[#{source_pos}, 0]" if i
37
+ end
38
+ code_lines.compact.join( "\n" ) << "\n"
39
+ end
40
+
41
+ # Builds a code string for incrementing a vector at given indices. Source is
42
+ # an array.
43
+ #
44
+ def column_vector_increment_by_array_code vector: (fail ArgumentError, "No vector!"),
45
+ indices: (fail ArgumentError, "No indices!"),
46
+ source: (fail ArgumentError, "No source!")
47
+ code_lines = indices.map.with_index do |i, source_pos|
48
+ "#{vector}.send( :[]=, #{i}, 0, %s )" %
49
+ "#{vector}[#{i}, 0] + #{source}[#{source_pos}]" if i
50
+ end
51
+ code_lines.compact.join( "\n" ) << "\n"
52
+ end
53
+ end
54
+
55
+ # Builds a closure for incrementing a column at given indices.
56
+ #
57
+ def increment_at_indices_closure indices: (fail ArgumentError, "No indices!")
58
+ v = self
59
+ eval "-> delta do\n%s\nend" %
60
+ self.class.column_vector_increment_code( vector: "v",
61
+ indices: indices,
62
+ source: "delta" )
63
+ end
64
+ end
@@ -0,0 +1,62 @@
1
+ # Manages the initial marking of a simulation.
2
+ #
3
+ class YPetri::Simulation
4
+ class PlaceMapping < Hash
5
+ include Dependency
6
+
7
+ class << self
8
+ # Initializes the initial marking from a hash.
9
+ #
10
+ def load hash
11
+ new.tap do |inst|
12
+ hash.with_values do |v|
13
+ v = v.marking if v.is_a? YPetri::Place
14
+ if v.is_a? Proc then v.call else v end
15
+ end.tap &inst.method( :load )
16
+ end
17
+ end
18
+ end
19
+
20
+ delegate :simulation, to: "self.class"
21
+
22
+ alias places keys
23
+
24
+ # Returns the initial marking as a column vector.
25
+ #
26
+ def vector
27
+ simulation.MarkingVector[ self ]
28
+ end
29
+ alias to_marking_vector vector
30
+
31
+ # Sets the mapping value for a given place to a given value.
32
+ #
33
+ def set place_id, to: (fail ArgumentError, "No :to value!")
34
+ update place( place_id ) => to
35
+ end
36
+
37
+ # Loads initial the mappings from a hash places >> values.
38
+ #
39
+ def load( hash )
40
+ hash.each { |place, value| set place, to: value }
41
+ end
42
+
43
+ # Fetches the value for a place.
44
+ #
45
+ def of place_id
46
+ fetch place( place_id )
47
+ end
48
+
49
+ # Deletes the value for a place.
50
+ #
51
+ def delete place_id
52
+ super place( place_id )
53
+ end
54
+
55
+ # Returns a hash, whose keys have been replaced with source places of
56
+ # the place representations in this place mapping.
57
+ #
58
+ def keys_to_source_places
59
+ with_keys do |key| key.source end
60
+ end
61
+ end # class InitialMarking
62
+ end # class YPetri::Simulation
@@ -0,0 +1,74 @@
1
+ #encoding: utf-8
2
+
3
+ # Representation of a YPetri::Place inside a YPetri::Simulation instance.
4
+ #
5
+ class YPetri::Simulation
6
+ class PlaceRepresentation < ElementRepresentation
7
+ # Index
8
+ def m_vector_index
9
+ places.index( self )
10
+ end
11
+
12
+ # Expect a single YPetri place as an argument.
13
+ #
14
+ def initialize net_place
15
+ super
16
+ end
17
+
18
+ # Setter of clamp.
19
+ #
20
+ def clamp=( value )
21
+ simulation.set_marking_clamp( of: self, to: value )
22
+ end
23
+
24
+ # Setter of initial marking.
25
+ #
26
+ def initial_marking=( value )
27
+ simulation.set_initial_marking( of: self, to: value )
28
+ end
29
+
30
+ # Marking clamp value (or nil, if the place is clamped).
31
+ #
32
+ def marking_clamp
33
+ simulation.marking_clamp of: self if clamped?
34
+ end
35
+ alias clamp marking_clamp
36
+
37
+ # Initial marking value (or nil, if the place is free).
38
+ #
39
+ def initial_marking
40
+ simulation.initial_marking[ self ] if free?
41
+ end
42
+
43
+ # Is the place free in the current simulation?
44
+ #
45
+ def free?
46
+ simulation.initial_marking.places.include? self
47
+ end
48
+
49
+ # Is the place clamped in the current simulation?
50
+ #
51
+ def clamped?
52
+ simulation.marking_clamps.places.include? self
53
+ end
54
+
55
+ # Set the marking of this place in the simulation.
56
+ #
57
+ def m=( value )
58
+ m_vector.set self, value
59
+ end
60
+
61
+ # Alias of #m=
62
+ #
63
+ def marking=( value )
64
+ m=( value )
65
+ end
66
+
67
+ # Get the current marking of this place in the simulation.
68
+ #
69
+ def m
70
+ m_vector[ self ]
71
+ end
72
+ alias marking m
73
+ end # class PlaceRepresentation
74
+ end # class YPetri::Simulation
@@ -0,0 +1,121 @@
1
+ #encoding: utf-8
2
+
3
+ # Simulation mixin providing access to places.
4
+ #
5
+ class YPetri::Simulation::Places
6
+ module Access
7
+ # With no arguments, a reader of @f2a -- the correspondence matrix between
8
+ # free places and all places. If argument is given, it is assumed to be
9
+ # a column vector, and multiplication is performed.
10
+ #
11
+ def f2a arg=nil
12
+ if arg.nil? then @f2a else @f2a * arg end
13
+ end
14
+
15
+ # With no arguments, a reader of @c2a -- the correspondence matrix between
16
+ # clamped places and all places. If argument is given, it is assumed to be
17
+ # a column vector, and multiplication is performed.
18
+ #
19
+ def c2a arg=nil
20
+ if arg.nil? then @c2a else @c2a * arg end
21
+ end
22
+
23
+ # Does a place belong to the simulation?
24
+ #
25
+ def includes_place? id
26
+ true.tap { begin; place id
27
+ rescue NameError, TypeError
28
+ return false
29
+ end }
30
+ end
31
+ alias include_place? includes_place?
32
+
33
+ # Place of the simulation (belonging to the net).
34
+ #
35
+ def p( id )
36
+ place( id ).source
37
+ end
38
+
39
+ # Places of the simulation (belonging to the net).
40
+ #
41
+ def pp( ids=nil )
42
+ places( ids ).sources
43
+ end
44
+
45
+ # Free places of the simulation (belonging to the net).
46
+ #
47
+ def free_pp( ids=nil )
48
+ free_places( ids ).sources
49
+ end
50
+
51
+ # Clamped places of the simulation (belonging to the net).
52
+ #
53
+ def clamped_pp( ids=nil )
54
+ clamped_places( ids ).sources
55
+ end
56
+
57
+ # Places' names. Arguments, if any, are treated as in +#places+ method.
58
+ #
59
+ def pn( ids=nil )
60
+ places( ids ).names
61
+ end
62
+
63
+ # Names of free places. Arguments are handled as with +#free_places+.
64
+ #
65
+ def nfree ids=nil
66
+ free_places( ids ).names
67
+ end
68
+ alias free_pn nfree
69
+
70
+ # Names of free places. Arguments are handled as with +#clamped_places+.
71
+ #
72
+ def nclamped ids=nil
73
+ clamped_places( ids ).names
74
+ end
75
+ alias clamped_pn nclamped
76
+
77
+ protected
78
+
79
+ # Place instance identification.
80
+ #
81
+ def place( id )
82
+ begin
83
+ Place().instance( id )
84
+ rescue NameError, TypeError
85
+ begin
86
+ pl = net.place( id )
87
+ places.find { |p_rep| p_rep.source == pl } ||
88
+ Place().instance( pl.name )
89
+ rescue NameError, TypeError => msg
90
+ raise
91
+ raise TypeError, "The argument #{id} (class #{id.class}) does not identify a " +
92
+ "place instance! (#{msg})"
93
+ end
94
+ end
95
+ end
96
+
97
+ # Without arguments, returns all the places. If arguments are given, they
98
+ # are converted to places before being returned.
99
+ #
100
+ def places( ids=nil )
101
+ return @places if ids.nil?
102
+ Places().load( ids.map { |id| place id } )
103
+ end
104
+
105
+ # Free places. If arguments are given, they must be identify free places,
106
+ # and are converted to them.
107
+ #
108
+ def free_places ids=nil
109
+ return places.free if ids.nil?
110
+ places.free.subset( ids )
111
+ end
112
+
113
+ # Clamped places. If arguments are given, they must be identify clamped
114
+ # places, and are converted to them.
115
+ #
116
+ def clamped_places ids=nil
117
+ return places.clamped if ids.nil?
118
+ places.clamped.subset( ids )
119
+ end
120
+ end # module Access
121
+ end # class YPetri::Simulation::Places
@@ -0,0 +1,8 @@
1
+ #encoding: utf-8
2
+
3
+ # A mixin for collections of free places.
4
+ #
5
+ class YPetri::Simulation::Places
6
+ module Type_clamped
7
+ end # Type_clamped
8
+ end # class YPetri::Simulation::Places
@@ -0,0 +1,8 @@
1
+ #encoding: utf-8
2
+
3
+ # A mixin for collections of free places.
4
+ #
5
+ class YPetri::Simulation::Places
6
+ module Type_free
7
+ end # Type_free
8
+ end # class YPetri::Simulation::Places
@@ -0,0 +1,25 @@
1
+ #encoding: utf-8
2
+
3
+ # A mixin with place type selectors.
4
+ #
5
+ class YPetri::Simulation
6
+ class Places < Elements
7
+ module Types
8
+ # Subset of free places, if any.
9
+ #
10
+ def free
11
+ ( @Type_free ||= Class.new( self.class ).tap do |klass|
12
+ klass.class_exec { include Type_free }
13
+ end ).load subset( &:free? )
14
+ end
15
+
16
+ # Subset of clamped places, if any.
17
+ #
18
+ def clamped
19
+ ( @Type_clamped ||= Class.new( self.class ).tap do |klass|
20
+ klass.class_exec { include Type_clamped }
21
+ end ).load subset( &:clamped? )
22
+ end
23
+ end # Types
24
+ end # class Places
25
+ end # class YPetri::Simulation
@@ -0,0 +1,41 @@
1
+ #encoding: utf-8
2
+
3
+ require_relative 'places/types'
4
+ require_relative 'places/free'
5
+ require_relative 'places/clamped'
6
+
7
+ # Place collection for YPetri::Simulation.
8
+ #
9
+ class YPetri::Simulation::Places
10
+ include Types
11
+
12
+ # Pushes a place to the collection.
13
+ #
14
+ def push place
15
+ p = begin
16
+ net.place( place )
17
+ rescue NameError, TypeError
18
+ return super place( place )
19
+ end
20
+ super p.name ? Place().new( p, name: p.name ) : Place().new( p )
21
+ end
22
+
23
+ # Ensures that all the places that are not clamped have their initial marking
24
+ # set. Optional argument :use_default_marking is set to _true_ by default, in
25
+ # which case own default marking of the source places is used if it was not
26
+ # specified when constructing the simulation. If set to _false_, then presence
27
+ # of places with missing initial marking simply raises errors.
28
+ #
29
+ def complete_initial_marking( use_default_marking: true )
30
+ missing = reject { |pl| ( free + clamped ).include? pl }
31
+ unless use_default_marking
32
+ fail TypeError, "All places must have default marking or clamp!" unless
33
+ missing.empty?
34
+ end
35
+ missing.each { |pl|
36
+ dflt = pl.source.default_marking
37
+ fail TypeError, "Source's default marking is missing (nil)!" if dflt.nil?
38
+ simulation.send :set_initial_marking, { of: pl, to: dflt }
39
+ }
40
+ end
41
+ end # class YPetri::Simulation::Places