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