#encoding: utf-8 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 attr_reader :places, :transitions def initialize( places: [], transitions: [] ) @places, @transitions = places, transitions 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 pl = place( place ) return false if @places.include? pl @places << pl 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; tr = transition( transition ) return false if @transitions.include? tr raise TypeError, "Unable to include the transition #{tr} in #{self}: " + "It connects to one or more places outside the net." unless tr.arcs.all? { |pl| include? pl } @transitions << tr 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 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 _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, 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/transition: #{place_or_transition}" # TODO: Exceptional Ruby end end return self end # Inquirer whether the net includes a place / transition. # def include? place_or_transition pl = begin place( place_or_transition ) rescue NameError nil end return places.include? pl if pl tr = begin transition( place_or_transition ) rescue NameError nil end return transitions.include? tr if tr return false end # Is the net _functional_? # def functional? transitions.all? { |t| t.functional? } end # Is the net timed? # def timed? transitions.all? { |t| t.timed? } end # Creates a new simulation from the net. # def new_simulation( **nn ) YPetri::Simulation.new **nn.merge( net: self ) end # Creates a new timed simulation from the net. # def new_timed_simulation( **nn ) new_simulation( **nn ).aT &:timed? end # 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 # Inspect string of the instance. # def inspect; to_s end end # class YPetri::Net