y_petri 2.1.3 → 2.1.6

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