lib/y_petri/transition.rb in y_petri-2.0.15 vs lib/y_petri/transition.rb in y_petri-2.1.3

- old
+ new

@@ -1,138 +1,120 @@ -# -*- coding: utf-8 -*- +# encoding: utf-8 -require_relative 'dependency_injection' require_relative 'transition/arcs' require_relative 'transition/cocking' -require_relative 'transition/construction' +require_relative 'transition/init' require_relative 'transition/timed' require_relative 'transition/ordinary_timeless' require_relative 'transition/assignment' # Transitions -- little boxes in Petri net drawings -- represent atomic # operations on the Petri net's marking. # # === Domain and codomin # # Each transition has a _domain_ (upstream places) and _codomain_ (downstream -# places). Upstream places are those, whose marking directly affects -# the transition. Downstream places are those, whose marking is directly affected -# by the transition. +# places). Upstream places are those, whose marking affects the transition. +# Downstream places are those affected by the transition. # # === Action and action vector # -# Every transition has an _action_ -- the operation it represents. The action -# of _non-stoichiometric_ transitions is directly specified by the _action_ +# Every transition _action_ -- the operation it represents. The action of +# _non-stoichiometric_ transitions is directly specified by its _action_ # _closure_ (whose output arity should match the codomain size.) For -# _stoichiometric_ transitions, the result of the action closure has to be -# multiplied by the transition's _stoichiometry_ _vector_ to obtain the action. -# Action of the _transitions_ _with_ _rate_ is specified indirectly by the -# _rate_ _closure_. +# _stoichiometric_ transitions, the action closure result must be multiplied +# by the transition's _stoichiometry_ _vector_. _Timed_ _transitions_ have +# _rate_ _closure_. Their action can be obtained by multiplying their rate +# by Δtime. # # === Rate # -# In YPetri domain model, marking is always a discrete number of _tokens_ -- as -# Carl Adam Petri handed it down to us. YPetri recognizes the usefulness of -# representing a large number of tokens by a floating point number, but sees it -# as a pragmatic measure only. Other Petri net implementations often make class -# distincion between discrete and continuous places, and also distinguish between -# _flux_ ("flow" of the continous transitions) and _propensity_ (firing -# probability of discrete transitions). In YPetri, flux and propensity are -# unified under the term _rate_, and the choice between discrete and stochastic -# computation is seen as a concern of the simulation, not of the model. +# In YPetri, marking is always considered a discrete number of _tokens_ (as +# C. A. Petri has handed it down to us). Usefulness of floating point numbers +# in representing larger amounts of tokens is acknowledged, but seen as a +# pragmatic measure, an implementation detail. There is no class distinction +# between discrete vs. continuous places / transitions. Often we see continuous +# transitions with their _flux_ (flow rate) ditinguished from discrete +# stochastic transitions with their _propensity_ (likelihood of firing in a +# time unit). In YPetri, flux and propensity are unified under a single term +# _rate_, and the choice between discrete and stochastic computation is a +# concern of the simulation, not of the object model. # # === Basic transition types # -# There are 6 basic types of transitions in YPetri: +# There are 4 basic transition types in YPetri: # -# * *ts* – timeless nonstoichiometric +# * *TS* – timed stoichiometric # * *tS* – timeless stoichiometric -# * *Tsr* – timed rateless nonstoichiometric -# * *TSr* – timed rateless stoichiometric -# * *sR* – nonstoichiometric with rate -# * *SR* – stoichiometric with rate +# * *Ts* – timed nonstoichiometric +# * *ts* – timeless nonstoichiometric # -# They arise by combining the 3 basic qualities: +# They arise by combining 2 qualities: # -# 1. *Stoichiometricity*: _stoichiometric_ (*S*) / _nonstoichiometric_ (*s*) -# 2. *Timedness*: _timed_ (*T*) / _timeless_ (*t*) -# 3. *Having* *rate*: having _rate_ (*R*) / not having rate (_rateless_) (*r*) +# 1. *Timedness*: _timed_ (*T*) / _timeless_ (*t*) +# 2. *Stoichiometricity*: _stoichiometric_ (*S*) / _nonstoichiometric_ (*s*) # -# ==== 1. Stoichiometricity +# ==== Timedness # -# * For *stoichiometric* transitions: -# - _either_ <b>rate vector</b> is obtained as -# <b>rate * stoichiometry vector</b>, -# - _or_ <b>action vector</b> is obtained as -# <b>action * stoichiometry vector</b> -# * For *non-stoichiometric* transitions: -# - _either_ <b>rate vector</b> is obtained as the <b>rate closure result</b>, -# - _or_ <b>action vector</b> is obtained as the <b>action closure result</b>. +# * Timed transitions have _rate_ _closure_, whose result is to be multiplied +# by +Δtime+. +# * Timeless transitions have _action_ _closure_, whose result does not need +# to be multiplied by time. +# +# Summary: Having vs. not having rate distinguishes the <em>need to multiply the +# closure result by Δ time</em>. # -# Summary: stoichiometricity distinguishes the <b>need to multiply the -# rate/action closure result by stoichiometry</b>. +# ==== Stoichiometricity # -# ==== 2. Having rate +# * *TS* transitions -- <b>rate vector = rate * stoichiometry vector</b> +# * *tS* transitions -- <b>action vector = action * stoichiometry vector</b> +# * *Ts* transitions -- <b>rate vector = rate closure result</b> +# * *ts* transitions -- <b>action vector = action closure result</b> # -# * Transitions *with* *rate* have a _rate_ _closure_, whose result is to be -# multiplied by +Δt+. -# * For transitions *without* *rate* (*rateless* transitions), the action -# closure specifies the action *directly*. -# -# Summary: Having vs. not having rate distinguishes the <b>need to multiply the -# closure result by Δ time</b> -- differentiability of the action by time. -# -# ==== 3. Timedness +# Summary: stoichiometricity distinguishes the <em>need to multiply the rate/action +# closure result by stoichiometry</em>. # -# * Timed transitions are defined as those, whose action has time as a parameter. -# - Transitions with rate are therefore always timed. -# - For rateless transitions, being timed means, that their action closure -# <b>expects Δt as its first argument</b> -- arity thus equals codomain -# size + 1. -# * Timeless transitions are those, whose action does not have time as -# a parameter. Timeless transitions are necessarily also rateless. +# === Assignment action # -# Summary: In rateless transitions, timedness distinguishes the <b>need to -# supply time step duration as the first argument to the action closure</b>. -# As the transitions with rate are necessarily timed, and timeless transitions -# necessarily rateless, there are only 6 instead of 2 ** 3 == 8 transition types. +# _Assignment_ _transitions_ (_*A*_ _transitions_) are special transitions, that +# _replace_ the codomain marking rather than modifying it -- they _assign_ new +# marking to their codomain, like we are used to from spreadsheets. Technically, +# this behavior is easily achievable with normal *ts* transitions, so the +# existence of separate *A* transitions is just a convenience, not a new type of +# a transition in the mathematical sense. # -# === Other transition attributes -# -# ==== Assignment transitions (_A_ _transitions_) -# If +:assignment_action+ option is set to _true_, it makes the transition -# entirely replace the codomain marking with its action closure result -- just -# like spreadsheet functions do. This, however, is just a convenience, and does -# not constitue a novel transition type, as it can be easily emulated by an -# ordinary ts transition caring to subtract the current domain marking before -# adding the desired values. -# # ==== _Functional_ / _functionless_ transitions -# Other Petri net implementation often make a distinction between "ordinary" -# and "functional" transitions, where "ordinary" ("functionless") are the -# transitions as Carl Adam Petri handed them down to us. YPetri transtions -# are generally "functional", but the possibility of functionless transitions -# is also provided -- stoichiometric transitions with no action or rate -# specified become functionless transitions. -# definition does not speak about transition "functions". The transitions are -# defined as timeless and more or less assumed to be stoichiometric. Therefore, -# in +YPetri::Transition+ constructor, stoichiometric transitions with no -# function specified become functionless vanilla Petri net transitions. # +# Other Petri net implementation often distinguies between "ordinary" (vanilla +# as per C. A. Petri) and _functional_ transitions, whose operation is governed +# by a function. In YPetri, transitions are generally _functional_, but there +# remains a possibility of creating vanilla (_functionless_) transitions by not +# specifying any rate / action, while specifying the stoichiometry. Action +# closure as per C. A. Petri is automatically constructed for these. +# class YPetri::Transition include NameMagic - include YPetri::DependencyInjection + include YPetri::World::Dependency + class << self + include YPetri::World::Dependency + end + + delegate :world, to: "self.class" + BASIC_TRANSITION_TYPES = { - ts: "timeless nonstoichiometric transition", - tS: "timeless stoichiometric transition", - Tsr: "timed rateless nonstoichiometric transition", - TSr: "timed rateless stoichiometric transition", - sR: "nonstoichiometric transition with rate", - SR: "stoichiometric transition with rate" + TS: "timed stoichiometric", + tS: "timeless stoichiometric", + Ts: "timed nonstoichiometric", + ts: "timeless nonstoichiometric" } + def TS?; type == :TS end + def Ts?; type == :Ts end + def tS?; type == :tS end + def ts?; type == :ts end + # Domain, or 'upstream arcs', is a collection of places, whose marking # directly affects the transition's action. # attr_reader :domain alias :domain_arcs :domain @@ -153,17 +135,18 @@ alias :action_arcs :codomain # Is the transition stoichiometric? # def stoichiometric?; @stoichiometric end - alias :s? :stoichiometric? + alias :S? :stoichiometric? # Is the transition nonstoichiometric? (Opposite of #stoichiometric?) # def nonstoichiometric? not stoichiometric? end + alias :s? :nonstoichiometric? # Stoichiometry (implies that the transition is stoichiometric). # attr_reader :stoichiometry @@ -179,22 +162,10 @@ # def s stoichio.with_keys { |k| k.name || k.object_id } end - # Does the transition have rate? - # - def has_rate? - @has_rate - end - - # Is the transition rateless? - # - def rateless? - not has_rate? - end - # In YPetri, _rate_ is a unifying term for both _flux_ and _propensity_, # both of which are treated as aliases of _rate_. The decision between # discrete and continuous computation is a concern of the simulation. # Rate closure arity should correspond to the transition's domain. # @@ -215,16 +186,18 @@ # Does the transition's action depend on delta time? # def timed? @timed end + alias T? timed? # Is the transition timeless? (Opposite of #timed?) # def timeless? not timed? end + alias t? timeless? # Is the transition functional? # Explanation: If rate or action closure is supplied, a transition is always # considered 'functional'. Otherwise, it is considered not 'functional'. # Note that even transitions that are not functional still have standard @@ -239,48 +212,39 @@ # def functionless? not functional? end - # Reports the transition's membership in one of 6 basic types : - # 1. ts ..... timeless nonstoichiometric - # 2. tS ..... timeless stoichiometric - # 3. Tsr .... timed rateless nonstoichiometric - # 4. TSr .... timed rateless stoichiometric - # 5. sR ..... nonstoichiometric with rate - # 6. SR ..... stoichiometric with rate + # Reports the transition's membership in one of the 4 basic types: # - def basic_type - if has_rate? then stoichiometric? ? :SR : :sR - elsif timed? then stoichiometric? ? :TSr : :Tsr - else stoichiometric? ? :tS : :ts end - end - - # Reports transition's type (basic type + whether it's an assignment - # transition). + # 1. TS .... timed stoichiometric + # 2. tS .... timeless stoichiometric + # 3. Ts .... timed nonstoichiometric + # 4. ts .... timeless nonstoichiometric + # + # plus the fifth type + # + # 5. A .... assignment transitions # def type - assignment_action? ? "A(ts)" : basic_type + return :A if assignment_action? + timed? ? ( stoichiometric? ? :TS : :Ts ) : ( stoichiometric? ? :tS : :ts ) end - # Is it an assignment transition? + # Is it an assignment transition? (Transitions with 'assignment action' + # completely replace their codomain's marking.) # - # A transition can be specified to have 'assignment action', in which case - # it completely replaces codomain marking with the objects resulting from - # the transition's action. Note that for numeric marking, specifying - # assignment action is a matter of convenience, not necessity, as it can - # be emulated by fully subtracting the present codomain values and adding - # the numbers computed by the transition to them. Assignment action flag - # is a matter of necessity only when codomain marking involves objects - # not supporting subtraction/addition (which is out of the scope of Petri's - # original specification anyway.) - # def assignment_action?; @assignment_action end alias :assignment? :assignment_action? + alias :A? :assignment_action? - # Zero action + # Is it a non-assignment transition? (Opposite of +#A?+) # + def a?; ! assignment_action? end + + # Zero action. + # def zero_action codomain.map { 0 } end # def lock @@ -323,10 +287,18 @@ # Conversion to a string. # def to_s "#<Transition: %s>" % - "#{name.nil? ? '' : '%s ' % name }(#{basic_type}%s)%s" % + "#{name.nil? ? '' : '%s ' % name }(#{type}%s)%s" % [ "#{assignment_action? ? ' Assign.' : ''}", "#{name.nil? ? ' id:%s' % object_id : ''}" ] + end + + def place id + super rescue Place().instance( id ) + end + + def transition id + super rescue Transition().instance( id ) end end # class YPetri::Transition