#encoding: utf-8 # Represents a Petri net: A collection of places and # transitions. The connector arrows – called arcs in # classical Petri net terminology – are considered a property # of transitions. In YPetri, 'arcs' is a synonym for # places / transitions connected to a given transition / place. # class YPetri::Net include NameMagic 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 # Names of transitions in the net. # def tt; transitions.map &:name end # Includes a place in the net. Returns true if successful, # false if the place is already included in the net. # def include_place! place p = place( place ) return false if @places.include? p @places << p return true end # 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; t = transition( transition ) return false if @transitions.include? t raise TypeError, "Unable to include the transition #{t} in #{self}: " + "It connects to one or more places outside the net." unless t.arcs.all? { |p| include? p } @transitions << t return true end # 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 p = place( place ) raise "Unable to exclude #{p} from #{self}: One or more transitions" + "depend on it" if transitions.any? { |t| t.arcs.include? p } return true if @places.delete p return false end # Excludes a transition from the net. Returns true if successful, # false if the transition was not found in the net. # def exclude_transition! transition t = transition( transition ) return true if @transitions.delete t 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. # 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}" end end return self end # Inquirer whether the net includes a place / transition. # def include? place_or_transition p = begin place( place_or_transition ) rescue NameError nil end return places.include? p if p t = begin transition( place_or_transition ) rescue NameError nil end return transitions.include? t if t return false end # ---------------------------------------------------------------------- # Methods exposing transition collections acc. to their properties: # Array of ts transitions in the net. # def timeless_nonstoichiometric_transitions transitions.select{ |t| t.timeless? and t.nonstoichiometric? } end alias ts_transitions timeless_nonstoichiometric_transitions # Names of ts transitions in the net. # def timeless_nonstoichiometric_tt timeless_nonstoichiometric_transitions.map &:name end alias ts_tt timeless_nonstoichiometric_tt # Array of tS transitions in the net. # def timeless_stoichiometric_transitions transitions.select{ |t| t.timeless? and t.stoichiometric? } end alias tS_transitions timeless_stoichiometric_transitions # Names of tS transitions in the net. # def timeless_stoichiometric_tt timeless_stoichiometric_transitions.map &:name end alias tS_tt timeless_stoichiometric_tt # Array of Tsr transitions in the net. # def timed_nonstoichiometric_transitions_without_rate transitions.select{ |t| t.timed? and t.nonstoichiometric? and t.rateless? } end alias timed_rateless_nonstoichiometric_transitions \ timed_nonstoichiometric_transitions_without_rate alias Tsr_transitions timed_nonstoichiometric_transitions_without_rate # Names of Tsr 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 TSr transitions in the net. # def timed_stoichiometric_transitions_without_rate transitions.select { |t| t.timed? and t.stoichiometric? and t.rateless? } end alias timed_rateless_stoichiometric_transitions \ timed_stoichiometric_transitions_without_rate alias TSr_transitions timed_stoichiometric_transitions_without_rate # Names of TSr 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 sR transitions in the net. # def nonstoichiometric_transitions_with_rate transitions.select { |t| t.has_rate? and t.nonstoichiometric? } end alias sR_transitions nonstoichiometric_transitions_with_rate # Names of sR 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 SR 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 SR 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 explicit assignment action # (A transitions) in the net. # def transitions_with_explicit_assignment_action transitions.select { |t| t.assignment_action? } end alias transitions_with_assignment_action \ transitions_with_explicit_assignment_action alias assignment_transitions transitions_with_explicit_assignment_action alias A_transitions transitions_with_explicit_assignment_action # Names of transitions with explicit assignment action # (A transitions) in the net. # def tt_with_explicit_assignment_action transitions_with_explicit_assignment_action.map &:name end alias tt_with_assignment_action tt_with_explicit_assignment_action alias assignment_tt tt_with_assignment_action alias A_tt tt_with_assignment_action # Array of stoichiometric transitions in the net. # def stoichiometric_transitions transitions.select &:stoichiometric? end alias S_transitions stoichiometric_transitions # Names of stoichiometric transitions in the net. # def stoichiometric_tt stoichiometric_transitions.map &:name end alias S_tt stoichiometric_tt # Array of nonstoichiometric transitions in the net. # def nonstoichiometric_transitions transitions.select &:nonstoichiometric? end alias s_transitions nonstoichiometric_transitions # Names of nonstoichimetric transitions in the net. # def nonstoichiometric_tt nonstoichiometric_transitions.map &:name end alias s_tt nonstoichiometric_tt # Array of timed transitions in the net. # def timed_transitions; transitions.select &:timed? end alias T_transitions timed_transitions # Names of timed transitions in the net. # def timed_tt; timed_transitions.map &:name end alias T_tt timed_tt # Array of timeless transitions in the net. # def timeless_transitions; transitions.select &:timeless? end alias t_transitions timeless_transitions # Names of timeless transitions in the net. # def timeless_tt; timeless_transitions.map &:name end alias t_tt timeless_tt # Array of transitions with rate in the net. # def transitions_with_rate; transitions.select &:has_rate? end alias R_transitions transitions_with_rate # Names of transitions with rate in the net. # def tt_with_rate; transitions_with_rate.map &:name end alias R_tt tt_with_rate # Array of rateless transitions in the net. # def rateless_transitions; transitions.select &:rateless? end alias transitions_without_rate rateless_transitions alias r_transitions rateless_transitions # Names of rateless 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 functional? # def functional?; transitions.all? { |t| t.functional? } end # Is the net timed? # def timed?; transitions.all? { |t| t.timed? } end # ==== Simulation constructors # Creates a new simulation from the net. # def new_simulation *args oo = args.extract_options! YPetri::Simulation.new *args, oo.merge( net: self ) end # Creates a new timed simulation from the net. # def new_timed_simulation *args oo = args.extract_options! YPetri::TimedSimulation.new oo.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 end # Returns a string briefly describing the net. # def to_s "#" end def visualize require 'graphviz' γ = GraphViz.new :G # creating a new graph # main = γ.add_nodes( "main", shape: "box" ) # parse = γ.add_nodes( "parse", fillcolor: "yellow", style: "rounded,filled", shape: "diamond" ) # execute = γ.add_nodes( "execute", shape: "record", label: "{ a | b | c }", style: "rounded" ) # init = γ.add_nodes( "init", fillcolor: "yellow", style: "filled" ) # # set global node options # g.node[:color] = "#ddaa66" # g.node[:style] = "filled" # g.node[:shape] = "box" # g.node[:penwidth] = "1" # g.node[:fontname] = "Trebuchet MS" # g.node[:fontsize] = "8" # g.node[:fillcolor] = "#ffeecc" # g.node[:fontcolor] = "#775500" # g.node[:margin] = "0.0" # # set global edge options # g.edge[:color] = "#999999" # g.edge[:weight] = "1" # g.edge[:fontsize] = "6" # g.edge[:fontcolor] = "#444444" # g.edge[:fontname] = "Verdana" # g.edge[:dir] = "forward" # g.edge[:arrowsize] = "0.5" # add place nodes place_nodes = Hash[ places.zip places.map { |p| γ.add_nodes p.name.to_s, fillcolor: 'lightgrey', color: 'grey', style: 'filled' } ] # add transition nodes transition_nodes = Hash[ transitions.zip transitions.map { |t| γ.add_nodes( t.name.to_s, shape: 'box', fillcolor: if t.assignment? then 'yellow' elsif t.basic_type == :SR then 'lightcyan' else 'ghostwhite' end, color: if t.assignment? then 'goldenrod' elsif t.basic_type == :SR then 'cyan' else 'grey' end, style: 'filled' ) } ] # add edges transition_nodes.each { |t, t_node| if t.assignment? then t.codomain.each { |p| γ.add_edges t_node, place_nodes[p], color: 'goldenrod' } ( t.domain - t.codomain ).each { |p| γ.add_edges t_node, place_nodes[p], color: 'grey', arrowhead: 'none' } elsif t.basic_type == :SR then t.codomain.each { |p| if t.stoichio[p] > 0 then # producing arc γ.add_edges t_node, place_nodes[p], color: 'cyan' elsif t.stoichio[p] < 0 then # consuming arc γ.add_edges place_nodes[p], t_node, color: 'cyan' else γ.add_edges place_nodes[p], t_node, color: 'grey', arrowhead: 'none' end } ( t.domain - t.codomain ).each { |p| γ.add_edges t_node, place_nodes[p], color: 'grey', arrowhead: 'none' } end } # place_collection.each { |place_name, place_label| # place_instance = place( place_name ) # place_instance.upstream_places.each { |upstream_place| # node = nodes[ place_name ] # next unless set_of_places.map { |ɴ, _| ɴ }.include?( upstream_place.name ) # next if upstream_place == place_instance # upstream_node = nodes[ upstream_place.name ] # node << upstream_node # } # } # Generate output image γ.output png: "y_petri_graph.png" 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