y_petri 2.0.14 → 2.0.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
- # A descendant class of YPetri::Simulation that introduces timekeeping.
2
+
3
+ # A mixin for timed simulations.
3
4
  #
4
- class YPetri::TimedSimulation < YPetri::Simulation
5
- SAMPLING_TIME_DECIMAL_PLACES = SAMPLING_DECIMAL_PLACES
5
+ module YPetri::Simulation::Timed
6
+ SAMPLING_TIME_DECIMAL_PLACES = 5
6
7
  SIMULATION_METHODS =
7
8
  [
8
9
  [ :Euler ],
@@ -41,9 +42,9 @@ class YPetri::TimedSimulation < YPetri::Simulation
41
42
  # (:step_size, :sampling_period and :time_range).
42
43
  #
43
44
  def settings
44
- { step_size: step_size,
45
- sampling_period: sampling_period,
46
- time_range: time_range }
45
+ { step: step_size,
46
+ sampling: sampling_period,
47
+ time: time_range }
47
48
  end
48
49
  alias simulation_settings settings
49
50
 
@@ -72,26 +73,6 @@ class YPetri::TimedSimulation < YPetri::Simulation
72
73
  # Δ_Euler_free
73
74
  # end
74
75
 
75
- # In addition to the arguments required by the regular simulation
76
- # constructor, timed simulation constructor also expects :step_size
77
- # (alias :step), :sampling_period (alias :sampling), and :target_time
78
- # named arguments.
79
- #
80
- def initialize( **named_args )
81
- named_args.must_have :step_size, syn!: :step
82
- named_args.must_have :sampling_period, syn!: :sampling
83
- named_args.may_have :target_time
84
- named_args.may_have :initial_time
85
- @step_size = named_args.delete :step_size
86
- @sampling_period = named_args.delete :sampling_period
87
- @target_time = named_args.delete :target_time
88
- @initial_time = named_args.delete( :initial_time ) ||
89
- @target_time.nil? ? nil : @sampling_period * 0 # @target_time.class.zero
90
- super( **named_args )
91
- @zero_gradient = @zero_ᴍ.map { |e| step_size.to_f / step_size * e }
92
- end
93
- # LATER: transition clamps
94
-
95
76
  # Allows to explore the system at different state / time. Creates a double,
96
77
  # which is set to the required state / time. In addition to the parent class,
97
78
  # this version alseo sets time.
@@ -100,11 +81,43 @@ class YPetri::TimedSimulation < YPetri::Simulation
100
81
  super( **oo ).tap { |duplicate| duplicate.send :set_time, time }
101
82
  end
102
83
 
103
- # At the moment, near alias for #run_to_arget_time!
84
+ # Near alias for #run!, checks against infinite run.
104
85
  #
105
- def run! until_time=target_time
106
- run_until_target_time! until_time
107
- return self
86
+ def run( until_time=target_time, final_step: :exact )
87
+ fail "Target time equals infinity!" if target_time = Float::INFINITY
88
+ run! until_time, final_step: final_step
89
+ end
90
+
91
+ # Near alias for #run_until, uses @target_time as :until_time by default.
92
+ #
93
+ def run!( until_time=target_time, final_step: :exact )
94
+ run_until until_time, final_step: final_step
95
+ end
96
+
97
+ # Runs the simulation until the target time, using step! method. The second
98
+ # optional parameter tunes the behavior towards the end of the run, with
99
+ # alternatives :just_before, :just_after and :exact (default).
100
+ #
101
+ # just_before: all steps have normal size, simulation stops
102
+ # before or just on the target time
103
+ # just_after: all steps have normal size, simulation stops
104
+ # after or just on the target time_step
105
+ # exact: simulation stops exactly on the prescribed time,
106
+ # to make this possible last step is shortened if necessary
107
+ #
108
+ def run_until( target_time, final_step: :exact )
109
+ case final_step
110
+ when :before then # step until on or just before the target
111
+ step! while @time + @step_size <= target_time
112
+ when :exact then # simulate to exact time
113
+ step! while @time + @step_size < target_time
114
+ step!( target_time - @time ) # make a short last step as required
115
+ @time = target_time # to get exactly on the prescribed time
116
+ when :after then # step until on or after target
117
+ step! while @time < target_time
118
+ else
119
+ fail ArgumentError, "Unrecognized :final_step option: #{final_step}"
120
+ end
108
121
  end
109
122
 
110
123
  # Scalar field gradient for free places.
@@ -112,9 +125,9 @@ class YPetri::TimedSimulation < YPetri::Simulation
112
125
  def gradient_for_free_places
113
126
  g_sR = gradient_for_sR
114
127
  if g_sR then
115
- S_for_SR() * flux_vector_for_SR + g_sR
128
+ S_SR() * flux_vector_for_SR + g_sR
116
129
  else
117
- S_for_SR() * flux_vector_for_SR
130
+ S_SR() * flux_vector_for_SR
118
131
  end
119
132
  end
120
133
 
@@ -135,8 +148,8 @@ class YPetri::TimedSimulation < YPetri::Simulation
135
148
  #
136
149
  def Δ_Euler_for_free_places( Δt=step_size )
137
150
  # Here, ∂ represents all R transitions, to which TSr and Tsr are added:
138
- g_free = gradient_for_free_places * Δt
139
- g_free + Δ_for_TSr( Δt ) + Δ_for_Tsr( Δt )
151
+ delta_free = gradient_for_free_places * Δt
152
+ delta_free + Δ_TSr( Δt ) + Δ_Tsr( Δt )
140
153
  end
141
154
  alias Δ_euler_for_free_places Δ_Euler_for_free_places
142
155
  alias ΔE Δ_Euler_for_free_places
@@ -189,13 +202,13 @@ class YPetri::TimedSimulation < YPetri::Simulation
189
202
  note_state_change!
190
203
  when :Euler_with_timeless_transitions_firing_after_each_step,
191
204
  :pseudo_Euler then
192
- Euler_step!
205
+ Euler_step! Δt
193
206
  timeless_transitions_all_fire!
194
207
  note_state_change!
195
208
  when :Euler_with_timeless_transitions_firing_after_each_time_tick,
196
209
  :quasi_Euler then
197
210
  raise # FIXME: quasi_Euler doesn't work yet
198
- Euler_step!
211
+ Euler_step! Δt
199
212
  # if time tick has elapsed, call #timeless_transitions_all_fire!
200
213
  note_state_change!
201
214
  else
@@ -204,41 +217,16 @@ class YPetri::TimedSimulation < YPetri::Simulation
204
217
  return self
205
218
  end
206
219
 
207
- # Runs the simulation until the target time, using step! method. The second
208
- # optional parameter tunes the behavior towards the end of the run, with
209
- # alternatives :just_before, :just_after and :exact (default).
210
- #
211
- # just_before: all steps have normal size, simulation stops
212
- # before or just on the target time
213
- # just_after: all steps have normal size, simulation stops
214
- # after or just on the target time_step
215
- # exact: simulation stops exactly on the prescribed time,
216
- # to make this possible last step is shortened if necessary
217
- #
218
- def run_until_target_time!( t=target_time, stepping_opt=:exact )
219
- case stepping_opt
220
- when :just_before then # step until on or just before the target
221
- step! while @time + @step_size <= t
222
- when :exact then # simulate to exact time
223
- step! while @time + @step_size < t
224
- step!( t - @time ) # make a short last step as required
225
- @time = t # to get exactly on the prescribed time
226
- when :just_after then # step until on or after target
227
- step! while @time < t
228
- else raise "Invalid stepping option: #{stepping_opt}" end
229
- end
230
- alias run_until! run_until_target_time!
231
-
232
220
  # Produces the inspect string for this timed simulation.
233
221
  #
234
222
  def inspect
235
- "#<YPetri::TimedSimulation: #{pp.size} places, #{tt.size} " +
236
- "transitions, time: #{time}, object id: #{object_id} >"
223
+ "#<Simulation: Time: #{time}, #{pp.size} places, #{tt.size} " +
224
+ "transitions, object id: #{object_id}>"
237
225
  end
238
226
 
239
227
  # Produces a string brief
240
228
  def to_s # :nodoc:
241
- "TimedSimulation[ #{pp.size} pp, #{tt.size} tt, T: #{time} ]"
229
+ "Simulation[T: #{time}, pp: #{pp.size}, tt: #{tt.size}]"
242
230
  end
243
231
 
244
232
  private
@@ -270,15 +258,14 @@ class YPetri::TimedSimulation < YPetri::Simulation
270
258
  @time = t
271
259
  end
272
260
 
273
- # Duplicate creation. TODO: Like with Simulation#duplicate, this should
274
- # be thought over, whether this should actually be #dup or #clone method.
261
+ # Duplicate creation.
275
262
  #
276
- def duplicate
263
+ def dup
277
264
  instance = super
278
265
  instance.send :set_time, time
279
266
  return instance
280
267
  end
281
- end # class YPetri::TimedSimulation
268
+ end # module YPetri::Simulation::Timed
282
269
 
283
270
  # In general, it is not required that all net elements are simulated with the
284
271
  # same method. Practically, ODE systems have many good simulation methods