class YPetri::Net
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::Net
, you won't find arcs as first-class citizens, but only as a synonym denoting nearest neighbors of nodes (places or transitions).
Public Class Methods
Takes 2 arguments (:places
and :transitions
) and builds a net from them.
# File lib/y_petri/net.rb, line 38 def initialize( places: [], transitions: [] ) param_class!( { State: State, Simulation: YPetri::Simulation }, with: { net: self } ) @places, @transitions = [], [] places.each &method( :include_place ) transitions.each &method( :include_transition ) end
Constructs a net containing a particular set of nodes.
# File lib/y_petri/net.rb, line 28 def of nodes new.tap { |inst| nodes.each { |node| inst << node } } end
Public Instance Methods
Creates a new net that contains all the places and transitions of both operands.
# File lib/y_petri/net.rb, line 135 def + other self.class.send( :new ).tap do |net| net.merge! self net.merge! other end end
Returns a new net that is the result of subtraction of the net given as argument from this net.
# File lib/y_petri/net.rb, line 145 def - other self.class.send( :new ).tap do |net| net.include_net self net.exclude_net other end end
Includes a node (place or transition) in the receiver net.
# File lib/y_petri/net.rb, line 112 def << node begin type = :place place = self.class.place node rescue NameError, TypeError begin type = :transition transition = self.class.transition node rescue NameError, TypeError => err raise TypeError, "Current world contains no place or " + "transition #{node}! (#{err})" end end case type # Factored out to minimize the code inside the rescue clause. when :place then include_place( place ) when :transition then include_transition( transition ) else fail "Implementation error!" end return self # important to enable chaining, eg. foo_net << p1 << p2 << t1 end
Networks are equal when their places and transitions are equal.
# File lib/y_petri/net.rb, line 173 def == other return false unless other.class_complies? self.class places == other.places && transitions == other.transitions end
Excludes another net from the receiver net. Returns true if successful (ie. if there was any change to the receiver net), false if the receiver net contained no node of the argument net.
# File lib/y_petri/net.rb, line 103 def exclude_net id net = Net().instance( id ) rescue YPetri::Net.instance( net ) t_rslt = net.tt.map { |t| exclude_transition t }.reduce :| p_rslt = net.pp.map { |p| exclude_place p }.reduce :| p_rslt || t_rslt end
Excludes a place from the receiver. Returns true if successful, false if the place was not found in the receiver net. A place may not be excluded from the receiver so long as any transitions therein connect to it.
# File lib/y_petri/net.rb, line 72 def exclude_place place place = Place().instance( place ) fail "Unable to exclude #{place} from #{self}: Transitions depend on it!" if transitions.any? { |transition| transition.arcs.include? place } false.tap { return true if @places.delete( place ) } end
Excludes a transition from the receiver. Returns true if successful, false if the transition was not found in the receiver net.
# File lib/y_petri/net.rb, line 82 def exclude_transition transition transition = Transition().instance( transition ) false.tap { return true if @transitions.delete( transition ) } end
Is the net functional?
# File lib/y_petri/net.rb, line 154 def functional? transitions.any? &:functional? end
Includes another net in the receiver net. Returns true if successful (ie. if there was any change to the receiver net), false if the receiver net already includes the argument net.
# File lib/y_petri/net.rb, line 91 def include_net net net = Net().instance( net ) rescue YPetri::Net.instance( net ) p_results = net.pp.map &method( :include_place ) t_results = net.tt.map &method( :include_transition ) ( p_results + t_results ).reduce :| end
Includes a place in the receiver. Returns true if successful, false if the place is already included in the receiver net.
# File lib/y_petri/net.rb, line 50 def include_place place place = Place().instance( place ) return false if include_place? place true.tap { @places << place } end
Includes a transition in the receiver. 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 receiver net.
# File lib/y_petri/net.rb, line 60 def include_transition transition transition = Transition().instance( transition ) return false if include_transition? transition fail "Transition #{transition} has arcs to places outside #{self}!" unless transition.arcs.all? { |place| include_place? place } true.tap { @transitions << transition } end
Inspect string of the instance.
# File lib/y_petri/net.rb, line 189 def inspect to_s end
Creates a new simulation from the net.
# File lib/y_petri/net.rb, line 166 def simulation( **settings ) Simulation().__new__ **settings end
Is the net timed?
# File lib/y_petri/net.rb, line 160 def timed? transitions.any? &:timed? end
Returns a string briefly describing the net.
# File lib/y_petri/net.rb, line 180 def to_s form = "#<Net: %s>" content = ( name.nil? ? "%s" : "name: #{name}, %s" ) % "#{pp.size rescue '∅'} places, #{tt.size rescue '∅'} transitions" form % content end