lib/y_petri/simulation/timed.rb in y_petri-2.1.3 vs lib/y_petri/simulation/timed.rb in y_petri-2.1.6

- old
+ new

@@ -1,184 +1,185 @@ # encoding: utf-8 -class YPetri::Simulation - # A mixin for timed simulations, used by an +#extend+ call during init. - # - module Timed - require_relative 'timed/recorder' +# A mixin for timed simulations, used by an +#extend+ call during init. +# +module YPetri::Simulation::Timed + require_relative 'timed/recorder' - DEFAULT_SETTINGS = -> do { step: 0.1, sampling: 5, time: 0..60 } end + DEFAULT_SETTINGS = -> do { step: 0.1, sampling: 5, time: 0..60 } end - def self.included receiver - receiver.Recording.class_exec { prepend Recording } - end + # True for timed simulations. + # + def timed? + true + end - # True for timed simulations. - # - def timed? - true - end + attr_reader :time, + :time_unit, + :initial_time, + :target_time, + :step, + :default_sampling - attr_reader :time, - :time_unit, - :initial_time, - :target_time, - :step, - :default_sampling + alias starting_time initial_time + alias ending_time target_time - alias starting_time initial_time - alias ending_time target_time + delegate :flux_vector_TS, + :gradient_TS, + :gradient_Ts, + :gradient, + :flux_vector, + to: :core - delegate :flux_vector_TS, - :gradient_TS, - :gradient_Ts, - :gradient, - :flux_vector, - to: :core + delegate :sampling, to: :recorder - delegate :sampling, to: :recorder + # Reads the time range (initial_time..target_time) of the simulation. + # + def time_range + initial_time..target_time + end - # Reads the time range (initial_time..target_time) of the simulation. - # - def time_range - initial_time..target_time - end + # Returnst the settings pertaining to the Timed aspect of the simulation, + # that is, +:step+, +:sampling+ and +:time+. + # + def settings all=false + super.update( step: step, + sampling: sampling, + time: time_range ) + end - # Returnst the settings pertaining to the Timed aspect of the simulation, - # that is, +:step+, +:sampling+ and +:time+. - # - def settings all=false - super.update( step: step, - sampling: sampling, - time: time_range ) - end + # Same as +#run!+, but guards against run upto infinity. + # + def run( upto: target_time, final_step: :exact ) + fail "Upto time equals infinity!" if upto == Float::INFINITY + run!( upto: upto, final_step: final_step ) + end - # Same as +#run!+, but guards against run upto infinity. - # - def run( upto: target_time, final_step: :exact ) - fail "Upto time equals infinity!" if upto == Float::INFINITY - run!( upto: upto, final_step: final_step ) - end + # Near alias for +#run_upto+. Accepts +:upto+ named argument, using + # @target_time attribute as a default. The second optional argument, + # +:final_step+, has the same options as in +#run_upto+ method. + # + def run!( upto: target_time, final_step: :exact ) + run_upto( upto, final_step: final_step ) + end - # Near alias for +#run_upto+. Accepts +:upto+ named argument, using - # @target_time attribute as a default. The second optional argument, - # +:final_step+, has the same options as in +#run_upto+ method. - # - def run!( upto: target_time, final_step: :exact ) - run_upto( upto, final_step: final_step ) + # Runs the simulation until the target time. Named argument :final_step has + # options :just_before, :just_after and :exact, and tunes the simulation + # behavior towards the end of the run. + # + # just_before: last step has normal size, simulation stops before or just + # on the target time + # just_after: last step has normal size, simulation stops after or just + # on the target time_step + # exact: simulation stops exactly on the prescribed time, last step + # is shortened if necessary + # + def run_upto( target_time, final_step: :exact ) + case final_step + when :before then + step! while time + step <= target_time + when :exact then + step! while time + step < target_time + step!( target_time - time ) + @time = target_time + when :after then + step! while time < target_time + else + fail ArgumentError, "Unrecognized :final_step option: #{final_step}" end + end - # Runs the simulation until the target time. Named argument :final_step has - # options :just_before, :just_after and :exact, and tunes the simulation - # behavior towards the end of the run. - # - # just_before: last step has normal size, simulation stops before or just - # on the target time - # just_after: last step has normal size, simulation stops after or just - # on the target time_step - # exact: simulation stops exactly on the prescribed time, last step - # is shortened if necessary - # - def run_upto( target_time, final_step: :exact ) - case final_step - when :before then - step! while time + step <= target_time - when :exact then - step! while time + step < target_time - step!( target_time - time ) - @time = target_time - when :after then - step! while time < target_time - else - fail ArgumentError, "Unrecognized :final_step option: #{final_step}" - end - end + # String representation of this timed simulation. + # + def to_s + "#<Simulation: time: %s, pp: %s, tt: %s, oid: %s>" % + [ time, pp.size, tt.size, object_id ] + end - # String representation of this timed simulation. - # - def to_s - "#<Simulation: time: %s, pp: %s, tt: %s, oid: %s>" % - [ time, pp.size, tt.size, object_id ] - end + # Increments the simulation's time and alerts the recorder. + # + def increment_time! Δt=step + @time += Δt + recorder.alert + end - # Increments the simulation's time and alerts the recorder. - # - def increment_time! Δt=step - @time += Δt - recorder.alert - end + # Resets the timed simulation. + # + def reset! **nn + @time = initial_time || time_unit * 0 + super + end - # Resets the timed simulation. - # - def reset! - @time = initial_time || time_unit * 0 - super - end + # Customized dup method that allows to modify the attributes of + # the duplicate upon creation. + # + def dup time: time, **nn + super( **nn ).tap { |i| i.reset_time! time } + end + alias at dup - # Customized dup method that allows to modify the attributes of - # the duplicate upon creation. - # - def dup time: time, **nn - super( **nn ).tap { |i| i.reset_time! time } - end - alias at dup + # Returns the zero gradient. Optionally, places can be specified, for which + # the zero vector is returned. + # + def zero_gradient places: nil + return zero_gradient places: places() if places.nil? + places.map { |id| + p = place( id ) + ( p.free? ? p.initial_marking : p.clamp ) * 0 / time_unit + }.to_column_vector + end + alias zero_∇ zero_gradient - # Returns the zero gradient. Optionally, places can be specified, for which - # the zero vector is returned. - # - def zero_gradient places: nil - return zero_gradient places: places() if places.nil? - places.map { |id| - p = place( id ) - ( p.free? ? p.initial_marking : p.clamp ) * 0 / time_unit - }.to_column_vector - end - alias zero_∇ zero_gradient + private - private - - # Initialization subroutine for timed simulations. Expects named arguments - # +:time+ (alias +:time_range+), meaning the simulation time range (a Range - # of initial_time..target_time), +:step+, meaning time step of the - # simulation, and +:sampling+, meaning sampling period of the simulation. - # - # Initializes the time-related attributes @initial_time, @target_time, - # @time_unit and @time (via +#reset_time!+ call). Also sets up the - # parametrized subclasses +@Core+ and +@Recorder+, and initializes the - # +@recorder+ attribute. - # - def init **settings - if settings.has? :time, syn!: :time_range then # time range given + # Initialization subroutine for timed simulations. Expects named arguments + # +:time+ (alias +:time_range+), meaning the simulation time range (a Range + # of initial_time..target_time), +:step+, meaning time step of the + # simulation, and +:sampling+, meaning sampling period of the simulation. + # + # Initializes the time-related attributes @initial_time, @target_time, + # @time_unit and @time (via +#reset_time!+ call). Also sets up the + # parametrized subclasses +@Core+ and +@Recorder+, and initializes the + # +@recorder+ attribute. + # + def init **settings + if settings.has? :time, syn!: :time_range then # time range given + case settings[:time] + when Range then time_range = settings[:time] @initial_time, @target_time = time_range.begin, time_range.end - @time_unit = target_time / target_time.to_f + @time_unit = initial_time.class.one else - anything = settings[:step] || settings[:sampling] - msg = "The simulation is timed, but the constructor lacks any of the " + - "time-related arguments: :time, :step, or :sampling!" - fail ArgumentError, msg unless anything - @time_unit = anything / anything.to_f - @initial_time, @target_time = time_unit * 0, time_unit * Float::INFINITY + @initial_time = settings[:time] + @time_unit = initial_time.class.one + @target_time = time_unit * Float::INFINITY end - init_core_and_recorder_subclasses - reset_time! - @step = settings[:step] || time_unit - @default_sampling = settings[:sampling] || step - @recorder = Recorder().new sampling: settings[:sampling] + else + anything = settings[:step] || settings[:sampling] + msg = "The simulation is timed, but the constructor lacks any of the " + + "time-related arguments: :time, :step, or :sampling!" + fail ArgumentError, msg unless anything + @time_unit = anything.class.one + @initial_time, @target_time = time_unit * 0, time_unit * Float::INFINITY end + init_core_and_recorder_subclasses + reset_time! + @step = settings[:step] || time_unit + @default_sampling = settings[:sampling] || step + @recorder = Recorder().new sampling: settings[:sampling] + end - # Sets up subclasses of +Core+ (the simulator) and +Recorder+ (the sampler) - # for timed simulations. - # - def init_core_and_recorder_subclasses - param_class( { Core: YPetri::Core::Timed, - Recorder: Recorder }, - with: { simulation: self } ) - end + # Sets up subclasses of +Core+ (the simulator) and +Recorder+ (the sampler) + # for timed simulations. + # + def init_core_and_recorder_subclasses + param_class( { Core: YPetri::Core::Timed, + Recorder: Recorder }, + with: { simulation: self } ) + end - # Resets the time to initial time, or to the argument (if provided). - # - def reset_time! time=nil - @time = time.nil? ? initial_time : time - end - end # module Timed + # Resets the time to initial time, or to the argument (if provided). + # + def reset_time! time=nil + @time = time.nil? ? initial_time : time + end end # module YPetri::Simulation::Timed