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

- old
+ new

@@ -1,143 +1,139 @@ #encoding: utf-8 -require_relative 'dependency_injection' require_relative 'net/visualization' -require_relative 'net/selections' +require_relative 'net/element_access' +require_relative 'net/state' # 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. +# considered a property of transitions. Therefore in +YPetri::Net+, you won't +# find arcs as first-class citizens, but only as a synonym denoting nearest +# neighbors of elements (places or transitions). # class YPetri::Net include NameMagic - include YPetri::DependencyInjection - - attr_reader :places, :transitions + include YPetri::World::Dependency # it is important for the Dependency + include ElementAccess # to be below ElementAccess + class << self + include YPetri::World::Dependency + + # Constructs a net containing a particular set of elements. + # + def of *elements + new.tap { |inst| elements.each { |e| inst << e } } + end + end + + delegate :world, to: "self.class" + + # Takes 2 arguments (+:places+ and +:transitions+) and builds a net from them. + # def initialize( places: [], transitions: [] ) - @places, @transitions = places, transitions + param_class( { State: State }, with: { net: self } ) + @places, @transitions = [], [] + places.each &method( :include_place ) + transitions.each &method( :include_transition ) + param_class( { Simulation: YPetri::Simulation }, + with: { net: self } ) 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 + def include_place id + pl = Place().instance( id ) + return false if includes_place? pl + true.tap { @places << pl } 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 + def include_transition id + tr = Transition().instance( id ) + return false if includes_transition? tr + true.tap { @transitions << tr } 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 + def exclude_place id + pl = Place().instance( id ) + msg = "Unable to exclude #{pl} from #{self}: Transition(s) depend on it!" + fail msg if transitions.any? { |tr| tr.arcs.include? pl } + false.tap { return true if @places.delete( pl ) } 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 + def exclude_transition id + tr = Transition().instance( id ) + false.tap { return true if @transitions.delete( tr ) } end - # Includes an object (either place or transition) in the net. Acts by calling - # +#include_place!+ or +#include_transition!+, as needed, swallowing errors. + # Includes an element in the net. # - 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 + def << element_id + element_type, element = begin + [ :place, + self.class.place( element_id ) ] + rescue NameError, TypeError + begin + [ :transition, + self.class.transition( element_id ) ] + rescue NameError, TypeError => err + msg = "Current world contains no place or" + + "transition identified by #{element_id}!" + raise TypeError, "#{msg} (#{err})" + end + end + case element_type + when :place then include_place( element ) + when :transition then include_transition( element ) + else fail "Mangled method YPetri::Net#<<!" end 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 <em>timed</em>? # def timed? - transitions.all? { |t| t.timed? } + transitions.any? { |t| t.timed? } end # Creates a new simulation from the net. # - def new_simulation( **nn ) - YPetri::Simulation.new **nn.merge( net: self ) + def simulation( **settings ) + Simulation().__new__ **settings 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?( ç ) + return false unless other.class_complies?( self.class ) places == other.places && transitions == other.transitions end # Returns a string briefly describing the net. # def to_s - "#<Net: " + ( name.nil? ? "%s" : "name: #{name}, %s" ) % - "#{places.size} places, #{transitions.size} transitions" + ">" + "#<Net: " + + ( name.nil? ? "%s" : "name: #{name}, %s" ) % + "#{pp.size rescue '∅'} places, #{tt.size rescue '∅'} transitions" + ">" end # Inspect string of the instance. # - def inspect; to_s end + def inspect + to_s + end end # class YPetri::Net