y_petri 2.1.3 → 2.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/y_petri/agent/petri_net_related.rb +25 -5
  3. data/lib/y_petri/agent/selection.rb +12 -10
  4. data/lib/y_petri/agent/simulation_related.rb +14 -58
  5. data/lib/y_petri/agent.rb +15 -17
  6. data/lib/y_petri/core/timed/euler.rb +13 -15
  7. data/lib/y_petri/core/timed/pseudo_euler.rb +22 -24
  8. data/lib/y_petri/core/timed/quasi_euler.rb +15 -17
  9. data/lib/y_petri/core/timed.rb +42 -44
  10. data/lib/y_petri/core/timeless/pseudo_euler.rb +12 -14
  11. data/lib/y_petri/core/timeless.rb +10 -7
  12. data/lib/y_petri/core.rb +3 -3
  13. data/lib/y_petri/dsl.rb +46 -46
  14. data/lib/y_petri/fixed_assets.rb +8 -0
  15. data/lib/y_petri/net/data_set.rb +238 -0
  16. data/lib/y_petri/net/own_state.rb +63 -0
  17. data/lib/y_petri/net/state/feature/delta.rb +98 -71
  18. data/lib/y_petri/net/state/feature/firing.rb +51 -54
  19. data/lib/y_petri/net/state/feature/flux.rb +51 -55
  20. data/lib/y_petri/net/state/feature/gradient.rb +55 -59
  21. data/lib/y_petri/net/state/feature/marking.rb +55 -59
  22. data/lib/y_petri/net/state/feature.rb +65 -67
  23. data/lib/y_petri/net/state/features/record.rb +150 -43
  24. data/lib/y_petri/net/state/features.rb +252 -96
  25. data/lib/y_petri/net/state.rb +114 -106
  26. data/lib/y_petri/net/visualization.rb +3 -2
  27. data/lib/y_petri/net.rb +29 -24
  28. data/lib/y_petri/place/arcs.rb +3 -3
  29. data/lib/y_petri/place/guard.rb +35 -117
  30. data/lib/y_petri/place/guarded.rb +86 -0
  31. data/lib/y_petri/place.rb +6 -3
  32. data/lib/y_petri/simulation/element_representation.rb +2 -2
  33. data/lib/y_petri/simulation/elements.rb +3 -1
  34. data/lib/y_petri/simulation/feature_set.rb +3 -1
  35. data/lib/y_petri/simulation/marking_vector.rb +3 -1
  36. data/lib/y_petri/simulation/place_mapping.rb +3 -1
  37. data/lib/y_petri/simulation/places.rb +1 -1
  38. data/lib/y_petri/simulation/recorder.rb +60 -54
  39. data/lib/y_petri/simulation/timed/recorder.rb +12 -1
  40. data/lib/y_petri/simulation/timed.rb +173 -172
  41. data/lib/y_petri/simulation/transitions/access.rb +97 -29
  42. data/lib/y_petri/simulation.rb +11 -9
  43. data/lib/y_petri/transition/{assignment.rb → A.rb} +2 -2
  44. data/lib/y_petri/transition/{timed.rb → T.rb} +2 -2
  45. data/lib/y_petri/transition/arcs.rb +3 -3
  46. data/lib/y_petri/transition/cocking.rb +3 -3
  47. data/lib/y_petri/transition/{init.rb → construction_convenience.rb} +6 -53
  48. data/lib/y_petri/transition/{ordinary_timeless.rb → t.rb} +2 -2
  49. data/lib/y_petri/transition/type.rb +103 -0
  50. data/lib/y_petri/transition/type_information.rb +103 -0
  51. data/lib/y_petri/transition/types.rb +107 -0
  52. data/lib/y_petri/transition/usable_without_world.rb +14 -0
  53. data/lib/y_petri/transition.rb +87 -101
  54. data/lib/y_petri/version.rb +1 -1
  55. data/lib/y_petri/world/dependency.rb +30 -28
  56. data/lib/y_petri/world.rb +10 -8
  57. data/test/acceptance/basic_usage_test.rb +3 -3
  58. data/test/acceptance/simulation_test.rb +3 -3
  59. data/test/acceptance/simulation_with_physical_units_test.rb +2 -2
  60. data/test/acceptance/token_game_test.rb +2 -2
  61. data/test/acceptance/visualization_test.rb +3 -3
  62. data/test/acceptance_tests.rb +2 -2
  63. data/test/agent_test.rb +1 -1
  64. data/test/net_test.rb +41 -17
  65. data/test/place_test.rb +1 -1
  66. data/test/simulation_test.rb +39 -39
  67. data/test/transition_test.rb +1 -1
  68. data/test/world_test.rb +1 -1
  69. data/test/y_petri_test.rb +1 -1
  70. metadata +13 -8
  71. data/lib/y_petri/net/state/features/dataset.rb +0 -135
  72. data/lib/y_petri/transition/construction.rb +0 -311
@@ -1,8 +1,10 @@
1
+ # encoding: utf-8
2
+
1
3
  # Basic elements of a simulation, a mixin intended for YPetri::Simulation.
2
4
  #
3
5
  class YPetri::Simulation
4
6
  class Elements < Array
5
- include Dependency
7
+ Dependency
6
8
 
7
9
  class << self
8
10
  # New collection constructor
@@ -1,10 +1,12 @@
1
+ # encoding: utf-8
2
+
1
3
  # Basic elements of a simulation, a mixin intended for YPetri::Simulation.
2
4
  #
3
5
  class YPetri::Simulation
4
6
  # Represents a set of features of a simulation state.
5
7
  #
6
8
  class FeatureSet
7
- include DependencyInjection
9
+ DependencyInjection
8
10
 
9
11
  attr_reader :marking, :firing, :delta
10
12
 
@@ -1,8 +1,10 @@
1
+ # encoding: utf-8
2
+
1
3
  # Basic elements of a simulation, a mixin intended for YPetri::Simulation.
2
4
  #
3
5
  class YPetri::Simulation
4
6
  class MarkingVector < Matrix
5
- include Dependency
7
+ Dependency
6
8
 
7
9
  class << self
8
10
  include Dependency
@@ -1,8 +1,10 @@
1
+ # encoding: utf-8
2
+
1
3
  # Manages the initial marking of a simulation.
2
4
  #
3
5
  class YPetri::Simulation
4
6
  class PlaceMapping < Hash
5
- include Dependency
7
+ Dependency
6
8
 
7
9
  class << self
8
10
  # Initializes the initial marking from a hash.
@@ -7,7 +7,7 @@ require_relative 'places/clamped'
7
7
  # Place collection for YPetri::Simulation.
8
8
  #
9
9
  class YPetri::Simulation::Places
10
- include Types
10
+ Types
11
11
 
12
12
  # Pushes a place to the collection.
13
13
  #
@@ -1,54 +1,60 @@
1
- class YPetri::Simulation
2
- # A machine that receives alerts during simulation and records a recording
3
- # according to its implementation. Alerts are received via +#alert+ method.
4
- # The recording bein recorded is stored in @recording instance variable.
5
- # This can be reset by +#reset!+ method, which also accepts arguments to
6
- # change the recorder settings and/or insert another recording.
7
- #
8
- class Recorder
9
- include Dependency
10
-
11
- SAMPLING_DECIMAL_PLACES = 5
12
-
13
- attr_reader :features, :recording
14
- delegate :simulation, to: "self.class"
15
- delegate :reconstruct, :reduce, to: :recording
16
-
17
- # Initializes the recorder. Takes 2 arguments: +:features+ expecting the
18
- # feature set to record during simulation, and +:recording+, expecting the
19
- # initial state of the recording.
20
- #
21
- def initialize features: net.State.marking( free_pp ),
22
- recording: features.new_dataset,
23
- **nn
24
- @features = net.State.features( features )
25
- reset! recording: recording
26
- end
27
-
28
- # Assigns to @recording a new Dataset instance. Without arguments, the new
29
- # recording is empty. With +:recording+ named argument supplied, the new
30
- # recording is filled with the prescribed contents.
31
- #
32
- def reset! **nn
33
- @features = net.State.features( nn[:features] || @features )
34
- @recording = features.new_dataset
35
- @recording.update Hash[ nn[:recording] ] if nn[:recording]
36
- end
37
-
38
- # Hook to be called by simulators whenever there is a state change. The
39
- # decision to sample is then the business of the recorder.
40
- #
41
- def alert
42
- sample! # vanilla recorder samples at every occasion
43
- end
44
-
45
- private
46
-
47
- # Records the current state as a pair { sampling_event => system_state }.
48
- #
49
- def sample! event
50
- record = simulation.get_features( features )
51
- recording[ event ] = record.dump( precision: SAMPLING_DECIMAL_PLACES )
52
- end
53
- end # class Recorder
54
- end # YPetri::Simulation
1
+ # encoding: utf-8
2
+
3
+ # A machine that receives alerts during simulation and records a recording
4
+ # according to its implementation. Alerts are received via +#alert+ method.
5
+ # The recording bein recorded is stored in @recording instance variable.
6
+ # This can be reset by +#reset!+ method, which also accepts arguments to
7
+ # change the recorder settings and/or insert another recording.
8
+ #
9
+ class YPetri::Simulation::Recorder
10
+ ★ YPetri::Simulation::Dependency
11
+
12
+ SAMPLING_DECIMAL_PLACES = 5
13
+
14
+ attr_reader :features, :recording
15
+ delegate :simulation, to: "self.class"
16
+ delegate :reconstruct, :reduce, to: :recording
17
+
18
+ # Initializes the recorder. Takes 2 arguments: +:features+ expecting the
19
+ # feature set to record during simulation, and +:recording+, expecting the
20
+ # initial state of the recording.
21
+ #
22
+ def initialize features: net.State.marking( free_pp ),
23
+ recording: nil,
24
+ **nn
25
+ @features = net.State.features( features )
26
+ if recording then reset! recording: recording else reset! end
27
+ end
28
+
29
+ # Construct a new recording based on +features+.
30
+ #
31
+ def new_recording
32
+ features.new_dataset
33
+ end
34
+
35
+ # Assigns to @recording a new Dataset instance. Without arguments, the new
36
+ # recording is empty. With +:recording+ named argument supplied, the new
37
+ # recording is filled with the prescribed contents.
38
+ #
39
+ def reset! **nn
40
+ @features = net.State.features( nn[:features] || @features )
41
+ @recording = new_recording
42
+ @recording.update Hash[ nn[:recording] ] if nn[:recording]
43
+ end
44
+
45
+ # Hook to be called by simulators whenever there is a state change. The
46
+ # decision to sample is then the business of the recorder.
47
+ #
48
+ def alert
49
+ sample! # vanilla recorder samples at every occasion
50
+ end
51
+
52
+ private
53
+
54
+ # Records the current state as a pair { sampling_event => system_state }.
55
+ #
56
+ def sample! event
57
+ record = simulation.get_features( features )
58
+ recording[ event ] = record.dump( precision: SAMPLING_DECIMAL_PLACES )
59
+ end
60
+ end # class YPetri::Simulation::Recorder
@@ -19,6 +19,12 @@ module YPetri::Simulation::Timed
19
19
  @next_time = next_time
20
20
  end
21
21
 
22
+ # Construct a new recording based on +features+.
23
+ #
24
+ def new_recording
25
+ features.new_dataset type: :timed
26
+ end
27
+
22
28
  # Like +YPetri::Simulation::Recorder#reset+, but allowing for an additional
23
29
  # named argument +:next_time+ that sets the next sampling time, and
24
30
  # +:sampling:, resetting the sampling period.
@@ -37,7 +43,12 @@ module YPetri::Simulation::Timed
37
43
  t2 = next_time.round( 9 )
38
44
  if t >= t2 then # it's time to sample
39
45
  sample!
40
- @next_time += sampling
46
+ begin
47
+ @next_time += sampling
48
+ rescue NoMethodError => err
49
+ ( puts "Here go error #{err}"; Kernel::p @next_time; Kernel::p sampling )
50
+ end
51
+
41
52
  end
42
53
  end
43
54
 
@@ -1,184 +1,185 @@
1
1
  # encoding: utf-8
2
2
 
3
- class YPetri::Simulation
4
- # A mixin for timed simulations, used by an +#extend+ call during init.
5
- #
6
- module Timed
7
- require_relative 'timed/recorder'
8
-
9
- DEFAULT_SETTINGS = -> do { step: 0.1, sampling: 5, time: 0..60 } end
10
-
11
- def self.included receiver
12
- receiver.Recording.class_exec { prepend Recording }
13
- end
14
-
15
- # True for timed simulations.
16
- #
17
- def timed?
18
- true
19
- end
20
-
21
- attr_reader :time,
22
- :time_unit,
23
- :initial_time,
24
- :target_time,
25
- :step,
26
- :default_sampling
27
-
28
- alias starting_time initial_time
29
- alias ending_time target_time
30
-
31
- delegate :flux_vector_TS,
32
- :gradient_TS,
33
- :gradient_Ts,
34
- :gradient,
35
- :flux_vector,
36
- to: :core
37
-
38
- delegate :sampling, to: :recorder
39
-
40
- # Reads the time range (initial_time..target_time) of the simulation.
41
- #
42
- def time_range
43
- initial_time..target_time
44
- end
45
-
46
- # Returnst the settings pertaining to the Timed aspect of the simulation,
47
- # that is, +:step+, +:sampling+ and +:time+.
48
- #
49
- def settings all=false
50
- super.update( step: step,
51
- sampling: sampling,
52
- time: time_range )
53
- end
54
-
55
- # Same as +#run!+, but guards against run upto infinity.
56
- #
57
- def run( upto: target_time, final_step: :exact )
58
- fail "Upto time equals infinity!" if upto == Float::INFINITY
59
- run!( upto: upto, final_step: final_step )
60
- end
61
-
62
- # Near alias for +#run_upto+. Accepts +:upto+ named argument, using
63
- # @target_time attribute as a default. The second optional argument,
64
- # +:final_step+, has the same options as in +#run_upto+ method.
65
- #
66
- def run!( upto: target_time, final_step: :exact )
67
- run_upto( upto, final_step: final_step )
68
- end
69
-
70
- # Runs the simulation until the target time. Named argument :final_step has
71
- # options :just_before, :just_after and :exact, and tunes the simulation
72
- # behavior towards the end of the run.
73
- #
74
- # just_before: last step has normal size, simulation stops before or just
75
- # on the target time
76
- # just_after: last step has normal size, simulation stops after or just
77
- # on the target time_step
78
- # exact: simulation stops exactly on the prescribed time, last step
79
- # is shortened if necessary
80
- #
81
- def run_upto( target_time, final_step: :exact )
82
- case final_step
83
- when :before then
84
- step! while time + step <= target_time
85
- when :exact then
86
- step! while time + step < target_time
87
- step!( target_time - time )
88
- @time = target_time
89
- when :after then
90
- step! while time < target_time
91
- else
92
- fail ArgumentError, "Unrecognized :final_step option: #{final_step}"
93
- end
94
- end
95
-
96
- # String representation of this timed simulation.
97
- #
98
- def to_s
99
- "#<Simulation: time: %s, pp: %s, tt: %s, oid: %s>" %
100
- [ time, pp.size, tt.size, object_id ]
101
- end
3
+ # A mixin for timed simulations, used by an +#extend+ call during init.
4
+ #
5
+ module YPetri::Simulation::Timed
6
+ require_relative 'timed/recorder'
102
7
 
103
- # Increments the simulation's time and alerts the recorder.
104
- #
105
- def increment_time! Δt=step
106
- @time += Δt
107
- recorder.alert
108
- end
8
+ DEFAULT_SETTINGS = -> do { step: 0.1, sampling: 5, time: 0..60 } end
109
9
 
110
- # Resets the timed simulation.
111
- #
112
- def reset!
113
- @time = initial_time || time_unit * 0
114
- super
10
+ # True for timed simulations.
11
+ #
12
+ def timed?
13
+ true
14
+ end
15
+
16
+ attr_reader :time,
17
+ :time_unit,
18
+ :initial_time,
19
+ :target_time,
20
+ :step,
21
+ :default_sampling
22
+
23
+ alias starting_time initial_time
24
+ alias ending_time target_time
25
+
26
+ delegate :flux_vector_TS,
27
+ :gradient_TS,
28
+ :gradient_Ts,
29
+ :gradient,
30
+ :flux_vector,
31
+ to: :core
32
+
33
+ delegate :sampling, to: :recorder
34
+
35
+ # Reads the time range (initial_time..target_time) of the simulation.
36
+ #
37
+ def time_range
38
+ initial_time..target_time
39
+ end
40
+
41
+ # Returnst the settings pertaining to the Timed aspect of the simulation,
42
+ # that is, +:step+, +:sampling+ and +:time+.
43
+ #
44
+ def settings all=false
45
+ super.update( step: step,
46
+ sampling: sampling,
47
+ time: time_range )
48
+ end
49
+
50
+ # Same as +#run!+, but guards against run upto infinity.
51
+ #
52
+ def run( upto: target_time, final_step: :exact )
53
+ fail "Upto time equals infinity!" if upto == Float::INFINITY
54
+ run!( upto: upto, final_step: final_step )
55
+ end
56
+
57
+ # Near alias for +#run_upto+. Accepts +:upto+ named argument, using
58
+ # @target_time attribute as a default. The second optional argument,
59
+ # +:final_step+, has the same options as in +#run_upto+ method.
60
+ #
61
+ def run!( upto: target_time, final_step: :exact )
62
+ run_upto( upto, final_step: final_step )
63
+ end
64
+
65
+ # Runs the simulation until the target time. Named argument :final_step has
66
+ # options :just_before, :just_after and :exact, and tunes the simulation
67
+ # behavior towards the end of the run.
68
+ #
69
+ # just_before: last step has normal size, simulation stops before or just
70
+ # on the target time
71
+ # just_after: last step has normal size, simulation stops after or just
72
+ # on the target time_step
73
+ # exact: simulation stops exactly on the prescribed time, last step
74
+ # is shortened if necessary
75
+ #
76
+ def run_upto( target_time, final_step: :exact )
77
+ case final_step
78
+ when :before then
79
+ step! while time + step <= target_time
80
+ when :exact then
81
+ step! while time + step < target_time
82
+ step!( target_time - time )
83
+ @time = target_time
84
+ when :after then
85
+ step! while time < target_time
86
+ else
87
+ fail ArgumentError, "Unrecognized :final_step option: #{final_step}"
115
88
  end
89
+ end
116
90
 
117
- # Customized dup method that allows to modify the attributes of
118
- # the duplicate upon creation.
119
- #
120
- def dup time: time, **nn
121
- super( **nn ).tap { |i| i.reset_time! time }
122
- end
123
- alias at dup
124
-
125
- # Returns the zero gradient. Optionally, places can be specified, for which
126
- # the zero vector is returned.
127
- #
128
- def zero_gradient places: nil
129
- return zero_gradient places: places() if places.nil?
130
- places.map { |id|
131
- p = place( id )
132
- ( p.free? ? p.initial_marking : p.clamp ) * 0 / time_unit
133
- }.to_column_vector
134
- end
135
- alias zero_∇ zero_gradient
136
-
137
- private
138
-
139
- # Initialization subroutine for timed simulations. Expects named arguments
140
- # +:time+ (alias +:time_range+), meaning the simulation time range (a Range
141
- # of initial_time..target_time), +:step+, meaning time step of the
142
- # simulation, and +:sampling+, meaning sampling period of the simulation.
143
- #
144
- # Initializes the time-related attributes @initial_time, @target_time,
145
- # @time_unit and @time (via +#reset_time!+ call). Also sets up the
146
- # parametrized subclasses +@Core+ and +@Recorder+, and initializes the
147
- # +@recorder+ attribute.
148
- #
149
- def init **settings
150
- if settings.has? :time, syn!: :time_range then # time range given
91
+ # String representation of this timed simulation.
92
+ #
93
+ def to_s
94
+ "#<Simulation: time: %s, pp: %s, tt: %s, oid: %s>" %
95
+ [ time, pp.size, tt.size, object_id ]
96
+ end
97
+
98
+ # Increments the simulation's time and alerts the recorder.
99
+ #
100
+ def increment_time! Δt=step
101
+ @time += Δt
102
+ recorder.alert
103
+ end
104
+
105
+ # Resets the timed simulation.
106
+ #
107
+ def reset! **nn
108
+ @time = initial_time || time_unit * 0
109
+ super
110
+ end
111
+
112
+ # Customized dup method that allows to modify the attributes of
113
+ # the duplicate upon creation.
114
+ #
115
+ def dup time: time, **nn
116
+ super( **nn ).tap { |i| i.reset_time! time }
117
+ end
118
+ alias at dup
119
+
120
+ # Returns the zero gradient. Optionally, places can be specified, for which
121
+ # the zero vector is returned.
122
+ #
123
+ def zero_gradient places: nil
124
+ return zero_gradient places: places() if places.nil?
125
+ places.map { |id|
126
+ p = place( id )
127
+ ( p.free? ? p.initial_marking : p.clamp ) * 0 / time_unit
128
+ }.to_column_vector
129
+ end
130
+ alias zero_∇ zero_gradient
131
+
132
+ private
133
+
134
+ # Initialization subroutine for timed simulations. Expects named arguments
135
+ # +:time+ (alias +:time_range+), meaning the simulation time range (a Range
136
+ # of initial_time..target_time), +:step+, meaning time step of the
137
+ # simulation, and +:sampling+, meaning sampling period of the simulation.
138
+ #
139
+ # Initializes the time-related attributes @initial_time, @target_time,
140
+ # @time_unit and @time (via +#reset_time!+ call). Also sets up the
141
+ # parametrized subclasses +@Core+ and +@Recorder+, and initializes the
142
+ # +@recorder+ attribute.
143
+ #
144
+ def init **settings
145
+ if settings.has? :time, syn!: :time_range then # time range given
146
+ case settings[:time]
147
+ when Range then
151
148
  time_range = settings[:time]
152
149
  @initial_time, @target_time = time_range.begin, time_range.end
153
- @time_unit = target_time / target_time.to_f
150
+ @time_unit = initial_time.class.one
154
151
  else
155
- anything = settings[:step] || settings[:sampling]
156
- msg = "The simulation is timed, but the constructor lacks any of the " +
157
- "time-related arguments: :time, :step, or :sampling!"
158
- fail ArgumentError, msg unless anything
159
- @time_unit = anything / anything.to_f
160
- @initial_time, @target_time = time_unit * 0, time_unit * Float::INFINITY
152
+ @initial_time = settings[:time]
153
+ @time_unit = initial_time.class.one
154
+ @target_time = time_unit * Float::INFINITY
161
155
  end
162
- init_core_and_recorder_subclasses
163
- reset_time!
164
- @step = settings[:step] || time_unit
165
- @default_sampling = settings[:sampling] || step
166
- @recorder = Recorder().new sampling: settings[:sampling]
167
- end
168
-
169
- # Sets up subclasses of +Core+ (the simulator) and +Recorder+ (the sampler)
170
- # for timed simulations.
171
- #
172
- def init_core_and_recorder_subclasses
173
- param_class( { Core: YPetri::Core::Timed,
174
- Recorder: Recorder },
175
- with: { simulation: self } )
156
+ else
157
+ anything = settings[:step] || settings[:sampling]
158
+ msg = "The simulation is timed, but the constructor lacks any of the " +
159
+ "time-related arguments: :time, :step, or :sampling!"
160
+ fail ArgumentError, msg unless anything
161
+ @time_unit = anything.class.one
162
+ @initial_time, @target_time = time_unit * 0, time_unit * Float::INFINITY
176
163
  end
177
-
178
- # Resets the time to initial time, or to the argument (if provided).
179
- #
180
- def reset_time! time=nil
181
- @time = time.nil? ? initial_time : time
182
- end
183
- end # module Timed
164
+ init_core_and_recorder_subclasses
165
+ reset_time!
166
+ @step = settings[:step] || time_unit
167
+ @default_sampling = settings[:sampling] || step
168
+ @recorder = Recorder().new sampling: settings[:sampling]
169
+ end
170
+
171
+ # Sets up subclasses of +Core+ (the simulator) and +Recorder+ (the sampler)
172
+ # for timed simulations.
173
+ #
174
+ def init_core_and_recorder_subclasses
175
+ param_class( { Core: YPetri::Core::Timed,
176
+ Recorder: Recorder },
177
+ with: { simulation: self } )
178
+ end
179
+
180
+ # Resets the time to initial time, or to the argument (if provided).
181
+ #
182
+ def reset_time! time=nil
183
+ @time = time.nil? ? initial_time : time
184
+ end
184
185
  end # module YPetri::Simulation::Timed