lib/y_petri/net.rb in y_petri-2.0.7 vs lib/y_petri/net.rb in y_petri-2.0.14.p1
- old
+ new
@@ -1,45 +1,39 @@
#encoding: utf-8
-# Represents a <em>Petri net</em>: A collection of places and
-# transitions. The connector arrows – called <em>arcs</em> in
-# classical Petri net terminology – are considered a property
-# of transitions. In <tt>YPetri</tt>, 'arcs' is a synonym for
-# places / transitions connected to a given transition / place.
+require_relative 'dependency_injection'
+require_relative 'net/visualization'
+require_relative 'net/selections'
+
+# Represents a _Petri net_: A collection of places and transitions. The
+# connector arrows – called _arcs_ in classical Petri net terminology – can be
+# considered a property of transitions. Therefore in +YPetri+, term 'arcs' is
+# mostly used as a synonym denoting neighboring places / transitions.
#
class YPetri::Net
include NameMagic
+ include YPetri::DependencyInjection
- def initialize *args; oo = args.extract_options!
- @places, @transitions = [], [] # empty arrays
- # LATER: let the places/transitions be specified upon init
- end
-
attr_reader :places, :transitions
- # Names of places in the net.
- #
- def pp; places.map &:name end
+ def initialize( places: [], transitions: [] )
+ @places, @transitions = places, transitions
+ end
- # Names of transitions in the net.
+ # Includes a place in the net. Returns _true_ if successful, _false_ if the
+ # place is already included in the net.
#
- def tt; transitions.map &:name end
-
- # Includes a place in the net. Returns <em>true</em> if successful,
- # <em>false</em> if the place is already included in the net.
- #
def include_place! place
pl = place( place )
return false if @places.include? pl
@places << pl
return true
end
- # Includes a transition in the net. Returns <em>true</em> if successful,
- # <em>false</em> if the transition is already included in the net. The
- # arcs of the transition being included may only connect to the places
- # already in the net.
+ # Includes a transition in the net. Returns _true_ if successful, _false_ if
+ # the transition is already included in the net. The arcs of the transition
+ # being included may only connect to the places already in the net.
#
def include_transition! transition;
tr = transition( transition )
return false if @transitions.include? tr
raise TypeError, "Unable to include the transition #{tr} in #{self}: " +
@@ -47,45 +41,43 @@
tr.arcs.all? { |pl| include? pl }
@transitions << tr
return true
end
- # Excludes a place from the net. Returns <em>true<em> if successful,
- # <em>false</em> if the place was not found in the net. A place may
- # not be excluded from the net so long as any transitions in the
- # net connect to it.
+ # Excludes a place from the net. Returns _true_ if successful, _false_ if the
+ # place was not found in the net. A place may not be excluded from the net so
+ # long as any transitions in the net connect to it.
#
def exclude_place! place
pl = place( place )
raise "Unable to exclude #{pl} from #{self}: One or more transitions" +
"depend on it" if transitions.any? { |tr| tr.arcs.include? pl }
return true if @places.delete pl
return false
end
- # Excludes a transition from the net. Returns <em>true</em> if successful,
- # <em>false</em> if the transition was not found in the net.
+ # Excludes a transition from the net. Returns _true_ if successful, _false_ if
+ # the transition was not found in the net.
#
def exclude_transition! transition
tr = transition( transition )
return true if @transitions.delete tr
return false
end
- # Includes an object (either place or transition) in the net. Acts by
- # calling #include_place! or #include_transition!, as needed, the
- # difference being, that errors from bad arguments are swallowed.
+ # Includes an object (either place or transition) in the net. Acts by calling
+ # +#include_place!+ or +#include_transition!+, as needed, swallowing errors.
#
def << place_or_transition
begin
include_place! place_or_transition
rescue NameError
begin
include_transition! place_or_transition
rescue NameError
- raise NameError,
- "Unrecognized place or transition: #{place_or_transition}"
+ raise NameError, "Unrecognized place/transition: #{place_or_transition}"
+ # TODO: Exceptional Ruby
end
end
return self
end
@@ -105,218 +97,22 @@
end
return transitions.include? tr if tr
return false
end
- # ----------------------------------------------------------------------
- # Methods exposing transition collections acc. to their properties:
-
- # Array of <em>ts</em> transitions in the net.
+ # Is the net _functional_?
#
- def timeless_nonstoichiometric_transitions
- transitions.select { |t| t.timeless? && t.nonstoichiometric? }
+ def functional?
+ transitions.all? { |t| t.functional? }
end
- alias ts_transitions timeless_nonstoichiometric_transitions
-
- # Names of <em>ts</em> transitions in the net.
- #
- def timeless_nonstoichiometric_tt
- timeless_nonstoichiometric_transitions.map &:name
- end
- alias ts_tt timeless_nonstoichiometric_tt
-
- # Array of <em>tsa</em> transitions in the net.
- #
- def timeless_nonstoichiometric_nonassignment_transitions
- transitions.select { |t|
- t.timeless? && t.nonstoichiometric? && ! t.assignment_action?
- }
- end
- alias tsa_transitions timeless_nonstoichiometric_nonassignment_transitions
-
- # Names of <em>tsa</em> transitions in the net.
- #
- def timeless_nonstoichiometric_nonassignment_tt
- timeless_nonstoichiometric_nonassignment_transitions.map &:name
- end
- alias tsa_tt timeless_nonstoichiometric_nonassignment_tt
-
- # Array of <em>tS</em> transitions in the net.
- #
- def timeless_stoichiometric_transitions
- transitions.select { |t| t.timeless? && t.stoichiometric? }
- end
- alias tS_transitions timeless_stoichiometric_transitions
-
- # Names of <em>tS</em> transitions in the net.
- #
- def timeless_stoichiometric_tt
- timeless_stoichiometric_transitions.map &:name
- end
- alias tS_tt timeless_stoichiometric_tt
-
- # Array of <em>Tsr</em> transitions in the net.
- #
- def timed_nonstoichiometric_transitions_without_rate
- transitions.select { |t| t.timed? && t.nonstoichiometric? && t.rateless? }
- end
- alias timed_rateless_nonstoichiometric_transitions \
- timed_nonstoichiometric_transitions_without_rate
- alias Tsr_transitions timed_nonstoichiometric_transitions_without_rate
-
- # Names of <em>Tsr</em> transitions in the net.
- #
- def timed_nonstoichiometric_tt_without_rate
- timed_nonstoichiometric_transitions_without_rate.map &:name
- end
- alias timed_rateless_nonstoichiometric_tt \
- timed_nonstoichiometric_tt_without_rate
- alias Tsr_tt timed_nonstoichiometric_tt_without_rate
-
- # Array of <em>TSr</em> transitions in the net.
- #
- def timed_stoichiometric_transitions_without_rate
- transitions.select { |t| t.timed? && t.stoichiometric? && t.rateless? }
- end
- alias timed_rateless_stoichiometric_transitions \
- timed_stoichiometric_transitions_without_rate
- alias TSr_transitions timed_stoichiometric_transitions_without_rate
-
- # Names of <em>TSr</em> transitions in the net.
- #
- def timed_stoichiometric_tt_without_rate
- timed_stoichiometric_transitions_without_rate.map &:name
- end
- alias timed_rateless_stoichiometric_tt timed_stoichiometric_tt_without_rate
- alias Tsr_tt timed_stoichiometric_tt_without_rate
-
- # Array of <em>sR</em> transitions in the net.
- #
- def nonstoichiometric_transitions_with_rate
- transitions.select { |t| t.has_rate? && t.nonstoichiometric? }
- end
- alias sR_transitions nonstoichiometric_transitions_with_rate
-
- # Names of <em>sR</em> transitions in the net.
- #
- def nonstoichiometric_tt_with_rate
- nonstoichiometric_transitions_with_rate.map &:name
- end
- alias sR_tt nonstoichiometric_tt_with_rate
-
- # Array of <em>SR</em> transitions in the net.
- #
- def stoichiometric_transitions_with_rate
- transitions.select { |t| t.has_rate? and t.stoichiometric? }
- end
- alias SR_transitions stoichiometric_transitions_with_rate
-
- # Names of <em>SR</em> transitions in the net.
- #
- def stoichiometric_tt_with_rate
- stoichiometric_transitions_with_rate.map &:name
- end
- alias SR_tt stoichiometric_tt_with_rate
-
- # Array of transitions with <em>explicit assignment action</em>
- # (<em>A</em> transitions) in the net.
- #
- def assignment_transitions
- transitions.select { |t| t.assignment_action? }
- end
- alias A_transitions assignment_transitions
-
- # Names of transitions with <em>explicit assignment action</em>
- # (<em>A</em> transitions) in the net.
- #
- def assignment_tt
- assignment_transitions.map &:name
- end
- alias A_tt assignment_tt
-
- # Array of <em>stoichiometric</em> transitions in the net.
- #
- def stoichiometric_transitions
- transitions.select &:stoichiometric?
- end
- alias S_transitions stoichiometric_transitions
-
- # Names of <em>stoichiometric</em> transitions in the net.
- #
- def stoichiometric_tt
- stoichiometric_transitions.map &:name
- end
- alias S_tt stoichiometric_tt
-
- # Array of <em>nonstoichiometric</em> transitions in the net.
- #
- def nonstoichiometric_transitions
- transitions.select &:nonstoichiometric?
- end
- alias s_transitions nonstoichiometric_transitions
-
- # Names of <em>nonstoichimetric</em> transitions in the net.
- #
- def nonstoichiometric_tt
- nonstoichiometric_transitions.map &:name
- end
- alias s_tt nonstoichiometric_tt
-
- # Array of <em>timed</em> transitions in the net.
- #
- def timed_transitions; transitions.select &:timed? end
- alias T_transitions timed_transitions
-
- # Names of <em>timed</em> transitions in the net.
- #
- def timed_tt; timed_transitions.map &:name end
- alias T_tt timed_tt
-
- # Array of <em>timeless</em> transitions in the net.
- #
- def timeless_transitions; transitions.select &:timeless? end
- alias t_transitions timeless_transitions
-
- # Names of <em>timeless</em> transitions in the net.
- #
- def timeless_tt; timeless_transitions.map &:name end
- alias t_tt timeless_tt
-
- # Array of <em>transitions with rate</em> in the net.
- #
- def transitions_with_rate; transitions.select &:has_rate? end
- alias R_transitions transitions_with_rate
-
- # Names of <em>transitions with rate</em> in the net.
- #
- def tt_with_rate; transitions_with_rate.map &:name end
- alias R_tt tt_with_rate
-
- # Array of <em>rateless</em> transitions in the net.
- #
- def rateless_transitions; transitions.select &:rateless? end
- alias transitions_without_rate rateless_transitions
- alias r_transitions rateless_transitions
-
- # Names of <em>rateless</em> transitions in the net.
- #
- def rateless_tt; rateless_transitions.map &:name end
- alias tt_without_rate rateless_tt
- alias r_tt rateless_tt
-
- # ==== Inquirer methods about net qualities
-
- # Is the net <em>functional</em>?
- #
- def functional?; transitions.all? { |t| t.functional? } end
# Is the net <em>timed</em>?
#
- def timed?; transitions.all? { |t| t.timed? } end
+ def timed?
+ transitions.all? { |t| t.timed? }
+ end
- # ==== Simulation constructors
-
# Creates a new simulation from the net.
#
def new_simulation( **named_args )
YPetri::Simulation.new **named_args.merge( net: self )
end
@@ -325,12 +121,10 @@
#
def new_timed_simulation( **named_args )
YPetri::TimedSimulation.new **named_args.merge( net: self )
end
- # ==== Sundry methods
-
# Networks are equal when their places and transitions are equal.
#
def == other
return false unless other.class_complies?( ç )
places == other.places && transitions == other.transitions
@@ -338,84 +132,12 @@
# Returns a string briefly describing the net.
#
def to_s
"#<Net: " + ( name.nil? ? "%s" : "name: #{name}, %s" ) %
- "#{places.size} places, #{transitions.size} transitions" + " >"
+ "#{places.size} places, #{transitions.size} transitions" + ">"
end
- def visualize
- require 'graphviz'
- γ = GraphViz.new :G
- # Add places and transitions.
- place_nodes = places.map.with_object Hash.new do |pl, ꜧ|
- ꜧ[pl] = γ.add_nodes pl.name.to_s,
- fillcolor: 'lightgrey',
- color: 'grey',
- style: 'filled'
- end
- transition_nodes = transitions.map.with_object Hash.new do |tr, ꜧ|
- ꜧ[tr] = γ.add_nodes tr.name.to_s,
- shape: 'box',
- fillcolor: if tr.assignment? then 'yellow'
- elsif tr.basic_type == :SR then 'lightcyan'
- else 'ghostwhite' end,
- color: if tr.assignment? then 'goldenrod'
- elsif tr.basic_type == :SR then 'cyan'
- else 'grey' end,
- style: 'filled'
- end
- # Add Petri net arcs.
- transition_nodes.each { |tr, tr_node|
- if tr.assignment? then
- tr.codomain.each { |pl|
- γ.add_edges tr_node, place_nodes[pl], color: 'goldenrod'
- }
- ( tr.domain - tr.codomain ).each { |pl|
- γ.add_edges tr_node, place_nodes[pl], color: 'grey', arrowhead: 'none'
- }
- elsif tr.basic_type == :SR then
- tr.codomain.each { |pl|
- if tr.stoichio[pl] > 0 then # producing arc
- γ.add_edges tr_node, place_nodes[pl], color: 'cyan'
- elsif tr.stoichio[pl] < 0 then # consuming arc
- γ.add_edges place_nodes[pl], tr_node, color: 'cyan'
- else
- γ.add_edges place_nodes[pl], tr_node, color: 'grey', arrowhead: 'none'
- end
- }
- ( tr.domain - tr.codomain ).each { |pl|
- γ.add_edges tr_node, place_nodes[pl], color: 'grey', arrowhead: 'none'
- }
- end
- }
- # Generate output image.
- γ.output png: File.expand_path( "~/y_petri_graph.png" )
- # require 'y_support/kde'
- YSupport::KDE.show_file_with_kioclient File.expand_path( "~/y_petri_graph.png" )
- end
-
# Inspect string of the instance.
#
def inspect; to_s end
-
- private
-
- # Display a file with kioclient (KDE).
- #
- def show_file_with_kioclient( file_name )
- system "sleep 0.2; kioclient exec 'file:%s'" %
- File.expand_path( '.', file_name )
- end
-
- # Place, Transition, Net classes.
- #
- def Place; ::YPetri::Place end
- def Transition; ::YPetri::Transition end
- def Net; ::YPetri::Net end
-
- # Instance identification methods.
- #
- def place( which ); Place().instance( which ) end
- def transition( which ); Transition().instance( which ) end
- def net( which ); Net().instance( which ) end
end # class YPetri::Net