y_petri 2.0.15 → 2.1.3
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.
- checksums.yaml +4 -4
- data/lib/y_petri/{manipulator → agent}/hash_key_pointer.rb +2 -2
- data/lib/y_petri/agent/petri_net_related.rb +115 -0
- data/lib/y_petri/{manipulator → agent}/selection.rb +2 -1
- data/lib/y_petri/{manipulator/simulation_related_methods.rb → agent/simulation_related.rb} +93 -110
- data/lib/y_petri/agent.rb +22 -0
- data/lib/y_petri/core/timed/euler.rb +20 -0
- data/lib/y_petri/core/timed/pseudo_euler.rb +31 -0
- data/lib/y_petri/core/timed/quasi_euler.rb +23 -0
- data/lib/y_petri/core/timed.rb +70 -0
- data/lib/y_petri/core/timeless/pseudo_euler.rb +20 -0
- data/lib/y_petri/core/timeless.rb +12 -0
- data/lib/y_petri/core.rb +100 -0
- data/lib/y_petri/dsl.rb +66 -0
- data/lib/y_petri/fixed_assets.rb +7 -0
- data/lib/y_petri/net/element_access.rb +239 -0
- data/lib/y_petri/net/state/feature/delta.rb +88 -0
- data/lib/y_petri/net/state/feature/firing.rb +57 -0
- data/lib/y_petri/net/state/feature/flux.rb +58 -0
- data/lib/y_petri/net/state/feature/gradient.rb +75 -0
- data/lib/y_petri/net/state/feature/marking.rb +62 -0
- data/lib/y_petri/net/state/feature.rb +79 -0
- data/lib/y_petri/net/state/features/dataset.rb +135 -0
- data/lib/y_petri/net/state/features/record.rb +50 -0
- data/lib/y_petri/net/state/features.rb +126 -0
- data/lib/y_petri/net/state.rb +121 -0
- data/lib/y_petri/net/timed.rb +8 -0
- data/lib/y_petri/net/visualization.rb +3 -3
- data/lib/y_petri/net.rb +73 -77
- data/lib/y_petri/place.rb +8 -3
- data/lib/y_petri/simulation/dependency.rb +107 -0
- data/lib/y_petri/simulation/element_representation.rb +20 -0
- data/lib/y_petri/simulation/elements/access.rb +57 -0
- data/lib/y_petri/simulation/elements.rb +45 -0
- data/lib/y_petri/simulation/feature_set.rb +21 -0
- data/lib/y_petri/simulation/initial_marking/access.rb +55 -0
- data/lib/y_petri/simulation/initial_marking.rb +15 -0
- data/lib/y_petri/simulation/marking_clamps/access.rb +34 -0
- data/lib/y_petri/simulation/marking_clamps.rb +18 -0
- data/lib/y_petri/simulation/marking_vector/access.rb +106 -0
- data/lib/y_petri/simulation/marking_vector.rb +156 -0
- data/lib/y_petri/simulation/matrix.rb +64 -0
- data/lib/y_petri/simulation/place_mapping.rb +62 -0
- data/lib/y_petri/simulation/place_representation.rb +74 -0
- data/lib/y_petri/simulation/places/access.rb +121 -0
- data/lib/y_petri/simulation/places/clamped.rb +8 -0
- data/lib/y_petri/simulation/places/free.rb +8 -0
- data/lib/y_petri/simulation/places/types.rb +25 -0
- data/lib/y_petri/simulation/places.rb +41 -0
- data/lib/y_petri/simulation/recorder.rb +54 -0
- data/lib/y_petri/simulation/timed/recorder.rb +53 -0
- data/lib/y_petri/simulation/timed.rb +161 -261
- data/lib/y_petri/simulation/timeless/recorder.rb +25 -0
- data/lib/y_petri/simulation/timeless.rb +35 -0
- data/lib/y_petri/simulation/transition_representation/A.rb +58 -0
- data/lib/y_petri/simulation/transition_representation/S.rb +45 -0
- data/lib/y_petri/simulation/transition_representation/T.rb +80 -0
- data/lib/y_petri/simulation/transition_representation/TS.rb +46 -0
- data/lib/y_petri/simulation/transition_representation/Ts.rb +32 -0
- data/lib/y_petri/simulation/transition_representation/a.rb +30 -0
- data/lib/y_petri/simulation/transition_representation/s.rb +29 -0
- data/lib/y_petri/simulation/transition_representation/t.rb +37 -0
- data/lib/y_petri/simulation/transition_representation/tS.rb +38 -0
- data/lib/y_petri/simulation/transition_representation/ts.rb +32 -0
- data/lib/y_petri/simulation/transition_representation/types.rb +62 -0
- data/lib/y_petri/simulation/transition_representation.rb +79 -0
- data/lib/y_petri/simulation/transitions/A.rb +40 -0
- data/lib/y_petri/simulation/transitions/S.rb +24 -0
- data/lib/y_petri/simulation/transitions/T.rb +34 -0
- data/lib/y_petri/simulation/transitions/TS.rb +57 -0
- data/lib/y_petri/simulation/transitions/Ts.rb +60 -0
- data/lib/y_petri/simulation/transitions/a.rb +8 -0
- data/lib/y_petri/simulation/transitions/access.rb +186 -0
- data/lib/y_petri/simulation/transitions/s.rb +9 -0
- data/lib/y_petri/simulation/transitions/t.rb +22 -0
- data/lib/y_petri/simulation/transitions/tS.rb +55 -0
- data/lib/y_petri/simulation/transitions/ts.rb +58 -0
- data/lib/y_petri/simulation/transitions/types.rb +98 -0
- data/lib/y_petri/simulation/transitions.rb +21 -0
- data/lib/y_petri/simulation.rb +176 -781
- data/lib/y_petri/transition/assignment.rb +7 -5
- data/lib/y_petri/transition/construction.rb +119 -187
- data/lib/y_petri/transition/init.rb +311 -0
- data/lib/y_petri/transition/ordinary_timeless.rb +8 -6
- data/lib/y_petri/transition/timed.rb +11 -18
- data/lib/y_petri/transition.rb +104 -132
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri/world/dependency.rb +40 -0
- data/lib/y_petri/world/petri_net_related.rb +61 -0
- data/lib/y_petri/{workspace/simulation_related_methods.rb → world/simulation_related.rb} +42 -49
- data/lib/y_petri/world.rb +27 -0
- data/lib/y_petri.rb +47 -99
- data/test/{manipulator_test.rb → agent_test.rb} +19 -17
- data/{lib/y_petri → test/examples}/demonstrator.rb +0 -0
- data/{lib/y_petri → test/examples}/demonstrator_2.rb +1 -0
- data/{lib/y_petri → test/examples}/demonstrator_3.rb +0 -0
- data/{lib/y_petri → test/examples}/demonstrator_4.rb +0 -0
- data/test/examples/example_2.rb +16 -0
- data/test/{manual_examples.rb → examples/manual_examples.rb} +0 -0
- data/test/net_test.rb +126 -121
- data/test/place_test.rb +1 -1
- data/test/sim_test +565 -0
- data/test/simulation_test.rb +338 -264
- data/test/transition_test.rb +77 -174
- data/test/world_mock.rb +12 -0
- data/test/{workspace_test.rb → world_test.rb} +19 -20
- data/test/y_petri_test.rb +4 -5
- metadata +101 -26
- data/lib/y_petri/dependency_injection.rb +0 -45
- data/lib/y_petri/manipulator/petri_net_related_methods.rb +0 -74
- data/lib/y_petri/manipulator.rb +0 -20
- data/lib/y_petri/net/selections.rb +0 -209
- data/lib/y_petri/simulation/collections.rb +0 -460
- data/lib/y_petri/workspace/parametrized_subclassing.rb +0 -22
- data/lib/y_petri/workspace/petri_net_related_methods.rb +0 -88
- data/lib/y_petri/workspace.rb +0 -16
- 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,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
|