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