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.
- 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
|