module YPetri::Core::Timed::RungeKutta

Runge-Kutta method. Like vanilla Euler method, assumes that only T transitions are in the net.

Public Instance Methods

alert_user!(object) click to toggle source
# File lib/y_petri/core/timed/runge_kutta.rb, line 108
def alert_user! object
  # TODO: As soon as more core's method begin relying on core's own state,
  # this method will be moved to Core module.
  @user_alert_closure.call( object )
end
delta(Δt) click to toggle source

Computes delta by Runge-Kutta 4th order method.

# File lib/y_petri/core/timed/runge_kutta.rb, line 8
def delta Δt
  # The f below is from the equation state' = f( state )
  f = lambda do |mv| # mv is the marking vector of the free places
    # Delta from s transitions.
    # TODO: This is only array now. Make it something else. One possibility
    # would be to use simulation's MarkingVector class, but core should
    # actually have its own marking vector class, probably parametrized by
    # the net. It does not matter because alone I won't be able to exhaust
    # all the possibilities.
    delta_s = simulation.MarkingVector.zero( simulation.free_pp )
    # Here, we get the nonstoichiometric transitions of the simulation.
    nonstoichio_tt = simulation.s_tt
    # Now, let's get the delta contribution of the nonstoichio. tt.
    nonstoichio_tt.each { |t|
      domain, codomain = t.domain, t.codomain # transition's domain
      function = t.rate_closure # transition's function
      output = Array function.call( *domain.map { |p| mv.fetch p } )
      codomain.each_with_index do |p, i|
        delta_s.set( p, delta_s.fetch( p ) + output[i] )
      end
      # TODO: The above code is suboptimal, needlessly computing
      # MarkingVector#index and #fetch( place ) each time.
      # The array incrementing might not be the best choice either,
      # and most of all, the whole thing would need to be compiled
      # into assembly language or at least FORTRAN.
    }

    # Delta from S transitions.
    # TODO: (Same remark as for s transitions, see above.)
    delta_S = simulation.MarkingVector.zero( simulation.free_pp )
    # Here, we get the stoichiometric transitions of the simulation
    stoichio_tt = simulation.S_tt
    # Now, let's get the delta contribution of the stoichio. tt.
    stoichio_tt.each { |t|
      domain, codomain = t.domain, t.codomain # transition's domain
      function = t.rate_closure # transition's function
      s = t.stoichiometry
      flux = function.call( *domain.map { |place| mv.fetch place } )
      codomain.each_with_index do |p, i|
        delta_S.set( p, delta_S.fetch( p ) + flux * s[i] )
      end
      # TODO: Again, the above code is suboptimal.
    }

    return delta_s + delta_S
  end

  y = marking_of_free_places

  k1 = f.( y ) # puts "k1 ( = f( y ) ) is #{k1}"
  k2 = f.( y + Δt / 2 * k1 ) # puts "k2 is #{k2}"
  k3 = f.( y + Δt / 2 * k2 ) # puts "k3 is #{k3}"
  k4 = f.( y + Δt * k3 ) # puts "k4 is #{k4}"

  rslt = Δt / 6 * ( k1 + 2 * k2 + 2 * k3 + k4 ) # puts "rslt is #{rslt}"

  return rslt                 # Marking vector of free places
end
Also aliased as: Δ
increment_marking_of_free_places(by) click to toggle source
# File lib/y_petri/core/timed/runge_kutta.rb, line 79
def increment_marking_of_free_places by
  # TODO: Same remark as above.
  @marking_of_free_places += by
end
increment_time!(by) click to toggle source
# File lib/y_petri/core/timed/runge_kutta.rb, line 84
def increment_time! by
  # TODO: Once other timed methods than runge_kutta are reasonable, this
  # should be moved to core/timed.rb
  @time += by
end
reset_time!(to=0.0) click to toggle source
# File lib/y_petri/core/timed/runge_kutta.rb, line 90
def reset_time! to=0.0
  # TODO: Once other timed methods than runge_kutta are reasonable, this
  # should be moved to core/timed.rb
  @time = to
end
set_user_alert_closure(&block) click to toggle source
# File lib/y_petri/core/timed/runge_kutta.rb, line 96
def set_user_alert_closure &block
  # TODO: Core's runge_kutta method is special for now, and even
  # simulation recognizes that. With runge_kutta method, core uses
  # single @user_alert_closure which it calls whenever the state
  # of the core progresses. It is the business of the user to supply,
  # before using the core, that does what the user wants. It is also
  # imaginable that different core's modes of operation would have
  # different sensitivity with regard to alerting the user, but for now,
  # the user is alerted whenever anything happens at all.
  @user_alert_closure = block
end
step!(Δt=simulation.step) click to toggle source
# File lib/y_petri/core/timed/runge_kutta.rb, line 68
def step! Δt=simulation.step
  # TODO: Thus far, runge_kutta method is an exception in the core in
  # that it works with core's own state. (Core used to work with
  # simulation's state before and rely on the simulation to provide
  # state increment and assign closures.) This is how whole core should
  # work.
  increment_marking_of_free_places Δ( Δt )
  increment_time! Δt
  alert_user! marking_of_free_places
end
Δ(Δt)
Alias for: delta