class PetriNet::Net

Attributes

arcs[R]

List of arcs

description[RW]

Description

filename[RW]

Storage filename

markings[R]

List of markings !depricated!

name[RW]

Human readable name

places[R]

List of places

transitions[R]

List of transitions

Public Class Methods

new(options = {}) { |self| ... } click to toggle source

Create new Petri Net definition.

options may be

  • name used as a human usable identifier (defaults to ‘petri_net’)

  • filename (defaults to the name)

  • description (defaults to ‘Petri Net’)

Accepts a block and yields itself

# File lib/petri_net/net.rb, line 36
def initialize(options = {}, &block)
    @name = (options[:name] or 'petri_net')
    @filename = (options[:filename] or @name)
    @description = (options[:description] or 'Petri Net')
    @places = Hash.new
    @arcs = Hash.new
    @transitions = Hash.new
    @markings = Hash.new
    @objects = Array.new
    @up_to_date = false
    @w_up_to_date = false

    yield self unless block == nil
end

Public Instance Methods

<<(object) click to toggle source

Adds an object to the Petri Net. You can add

The Objects are added by PetriNet::Net#add_place, PetriNet::Net#add_arc and PetriNet::Net#add_transition, refer to these to get more information on how they are added raises an RuntimeError if a wring Type is given

returns itself

# File lib/petri_net/net.rb, line 62
def <<(object)
    return if object.nil?  #TODO WORKAROUND There should never be a nil here, even while merging.
    case object.class.to_s
    when "Array"
        object.each {|o| self << o}
    when "PetriNet::Place" 
        add_place(object)
    when "PetriNet::Arc" 
        add_arc(object)
    when "PetriNet::Transition" 
        add_transition(object)
    else 
        raise "(PetriNet) Unknown object #{object.class}."
    end
    self
end
Also aliased as: add_object
add_arc(arc) click to toggle source

Add an arc to the list of arcs.

see PetriNet::Net#add_place

# File lib/petri_net/net.rb, line 98
def add_arc(arc)
    if (arc.validate self) && !@arcs.include?(arc.name)
        if arc.need_update? self
            arc.update self
        end
        @arcs[arc.name] = arc.id
        @objects[arc.id] = arc
        arc.net = self
        return arc.id
    end
    changed_structure
    return false
end
add_object(object)
Alias for: <<
add_place(place) click to toggle source

Adds a place to the list of places. Adds the place only if the place is valid and unique in the objects-list of the net

This Method changes the structure of the PetriNet, you will have to recalculate all cached functions

# File lib/petri_net/net.rb, line 84
def add_place(place)
    if place.validate && !@places.include?(place.name) 
        @places[place.name] = place.id
        @objects[place.id] = place
        place.net = self
        return place.id
    end
    changed_structure
    return false
end
add_transition(transition) click to toggle source

Add a transition to the list of transitions.

see PetriNet::Net#add_place

# File lib/petri_net/net.rb, line 115
def add_transition(transition)
    if transition.validate && !@transitions.include?(transition.name)
        @transitions[transition.name] = transition.id
        @objects[transition.id] = transition
        transition.net = self
        return transition.id
    end
    changed_structure
    return false
end
delta() click to toggle source
# File lib/petri_net/net.rb, line 373
def delta
    if @delta.nil?
        generate_delta
    end
    @delta
end
fire(transition) click to toggle source
# File lib/petri_net/net.rb, line 369
def fire transition
    get_transition(transition).fire
end
generate_coverability_graph() click to toggle source
# File lib/petri_net/net.rb, line 254
def generate_coverability_graph()
    startmarkings = get_markings
    @graph = PetriNet::CoverabilityGraph.new(self)
    @graph.add_node current_node = PetriNet::CoverabilityGraph::Node.new(@graph, markings: get_markings, start: true)

    coverability_helper startmarkings, current_node

    set_markings startmarkings
    @graph 
end
generate_gv() click to toggle source
# File lib/petri_net/net.rb, line 189
def generate_gv
    g = GraphViz.new( :G, :type => :digraph )

    @places.each_value do |place|
        gv_node = g.add_nodes( @objects[place].name )
    end
    @transitions.each_value do |transition|
        gv_node = g.add_nodes( @objects[transition].name)
        gv_node.shape = :box
        gv_node.fillcolor = :grey90
    end
    @arcs.each_value do |arc|
        gv_edge = g.add_edges( @objects[arc].source.name, @objects[arc].destination.name )
    end
    g
end
generate_reachability_graph() click to toggle source
# File lib/petri_net/net.rb, line 265
def generate_reachability_graph()
    startmarkings = get_markings
    @graph = PetriNet::ReachabilityGraph.new(self)
    @graph.add_node current_node = PetriNet::ReachabilityGraph::Node.new(@graph, markings: get_markings, start: true)

    reachability_helper startmarkings, current_node

    set_markings startmarkings
    @graph 
end
generate_weight_function() click to toggle source
# File lib/petri_net/net.rb, line 276
def generate_weight_function
    @weight = Hash.new
    @arcs.each_value do |id|
        arc = @objects[id]
        @weight[[arc.source.id,arc.destination.id]] = arc.weight
    end
    @w_up_to_date = true
    @weight
end
get_arc(name) click to toggle source

returns the arc refered by the given name or false if there is no arc with this name

# File lib/petri_net/net.rb, line 142
def get_arc(name)
    arc = @objects[@arcs[name]]
    arc.nil? ? false : arc
end
get_marking(places) click to toggle source
# File lib/petri_net/net.rb, line 310
def get_marking(places)
    unless places.class.to_s == "Array"
        places = [places]
    end
    if places.first.class.to_s == "Fixnum"
        places.map!{|p| get_place p}
    end
    res = Array.new
    get_place_list.map{|place| if places.include? place.name then res << 1 else res << 0 end}
    res
end
get_markings() click to toggle source
# File lib/petri_net/net.rb, line 306
def get_markings
    @places.map{|key,pid| @objects[pid].markings.size}
end
get_object(id) click to toggle source
# File lib/petri_net/net.rb, line 349
def get_object(id)
    @objects[id]
end
get_objects() click to toggle source
# File lib/petri_net/net.rb, line 353
def get_objects
    @objects.clone
end
get_place(name) click to toggle source

Returns the place refered by the given name or false if there is no place with this name

# File lib/petri_net/net.rb, line 128
def get_place(name)
    place = @objects[@places[name]]
    place.nil? ? false : place
end
get_place_from_marking(marking) click to toggle source
# File lib/petri_net/net.rb, line 335
def get_place_from_marking(marking)
    return marking if marking.count(1) != 1
    get_place_list[marking.index(1)].name
end
get_place_list() click to toggle source
# File lib/petri_net/net.rb, line 331
def get_place_list
    @places.map{|key,pid| @objects[pid]}
end
get_transition(name) click to toggle source

Returns the transition refered by the given name or false if there is no transition with this name

# File lib/petri_net/net.rb, line 135
def get_transition(name)
    trans = @objects[@transitions[name]]
    trans.nil? ? false : trans
end
load(filename) click to toggle source
# File lib/petri_net/net.rb, line 365
def load filename
    @net = YAML.load(File.read(filename))
end
merge(net) click to toggle source

Merges two PetriNets Places, transitions and arcs are equal if they have the same name and description, arcs need to have the same source and destination too). With this definition of equality the resultung net will have unique ojects. ATTENTION conflicting capabilities and weights will be lost and the properies of the net you merge to will be used in future TODO add a parameter to affect this!

# File lib/petri_net/net.rb, line 239
def merge(net)
    return self if self.equal? net
    return false if net.class.to_s != "PetriNet::Net"
    self << net.get_objects
    self
end
objects_find_index(object) click to toggle source
# File lib/petri_net/net.rb, line 357
def objects_find_index(object)
    @objects.find_index object
end
objects_include?(object) click to toggle source
# File lib/petri_net/net.rb, line 345
def objects_include?(object)
    @objects.include?(object)
end
objects_size() click to toggle source
# File lib/petri_net/net.rb, line 341
def objects_size
    @objects.count{|o| !o.nil?}
end
ordinary?() click to toggle source

Is this Petri Net ordinary? A Petri Net is said to be ordinary if all of its arc weights are 1’s.

# File lib/petri_net/net.rb, line 155
def ordinary?
    raise "Not implemented yet"
end
pure?() click to toggle source

Is this Petri Net pure? A Petri Net is said to be pure if it has no self-loops.

# File lib/petri_net/net.rb, line 149
def pure?
    raise "Not implemented yet"
end
reachability_graph() click to toggle source
# File lib/petri_net/net.rb, line 246
def reachability_graph
    if !@up_to_date
        update
    end
    generate_reachability_graph unless (@graph && @up_to_date)
    @graph
end
s_invariant() click to toggle source
# File lib/petri_net/net.rb, line 393
def s_invariant
    raise "Not jet implemented"
end
save(filename) click to toggle source
# File lib/petri_net/net.rb, line 361
def save filename
    File.open(filename, 'w') {|f| @net.to_yaml}
end
set_markings(markings) click to toggle source
# File lib/petri_net/net.rb, line 322
def set_markings(markings)
    i = 0
    @places.each_value do |pid| 
        @objects[pid].set_marking markings[i]
        i = i+1
    end
    changed_state
end
t_invariants() click to toggle source
# File lib/petri_net/net.rb, line 380
def t_invariants
    delta = self.delta
    zero_vector = Array.new
    delta.row_count.times { zero_vector << 0 }
    zero = BigDecimal("0.0")
    one  = BigDecimal("1.0")

    ps = ludecomp(delta.t.to_a.flatten.map{|i|BigDecimal(i,16)},delta.row_count, zero, one)
    x = lusolve(delta.t.to_a.flatten.map{|i|BigDecimal(i,16)},zero_vector.map{|i|BigDecimal(i,16)},ps, zero)

    x
end
to_gv() click to toggle source

Generate GraphViz dot string.

# File lib/petri_net/net.rb, line 207
def to_gv
    # General graph options
    str = "digraph #{@name} {\n"
    str += "\t// General graph options\n"
    str += "\trankdir = LR;\n"
    str += "\tsize = \"10.5,7.5\";\n"
    str += "\tnode [ style = filled, fillcolor = white, fontsize = 8.0 ]\n"
    str += "\tedge [ arrowhead = vee, arrowsize = 0.5, fontsize = 8.0 ]\n"
    str += "\n"

    str += "\t// Places\n"
    str += "\tnode [ shape = circle ];\n"
    @places.each_value {|id| str += @objects[id].to_gv }
    str += "\n"

    str += "\t// Transitions\n"
    str += "\tnode [ shape = box, fillcolor = grey90 ];\n"
    @transitions.each_value {|id| str += @objects[id].to_gv }
    str += "\n"

    str += "\t// Arcs\n"
    @arcs.each_value {|id| str += @objects[id].to_gv }
    str += "}\n"    # Graph closure

    return str
end
to_gv_new(output = 'png', filename = '') click to toggle source
# File lib/petri_net/net.rb, line 180
def to_gv_new(output = 'png', filename = '')
    g = generate_gv
    if filename.empty?
        filename = "#{@name}_net.png"
    end
    g.output( :png => filename ) if output == 'png'
    g.output
end
to_s() click to toggle source

Stringify this Petri Net.

# File lib/petri_net/net.rb, line 160
    def to_s
        str = 
%{Petri Net [#{@name}]
----------------------------
Description: #{@description}
Filename: #{@filename}

Places
----------------------------
#{str = ''; @places.each_value {|p| str += @objects[p].to_s + "\n"}; str }
Transitions
----------------------------
#{str = ''; @transitions.each_value {|t| str += @objects[t].to_s + "\n" }; str }
Arcs
----------------------------
#{str = ''; @arcs.each_value {|a| str += @objects[a].to_s + "\n" }; str}
}
        return str
    end
up_to_date()
Alias for: update?
update() click to toggle source
# File lib/petri_net/net.rb, line 291
def update
    generate_weight_function
    @up_to_date = true
end
update?() click to toggle source

is true if, and only if, the cached elements are calculated AND the net hasn’t changed

# File lib/petri_net/net.rb, line 297
def update?
    if @w_up_to_date && true #all up_to_date-caches!!!
        @up_to_date = true
        return @up_to_date
    end
    false
end
Also aliased as: up_to_date
w0(x,y) click to toggle source
# File lib/petri_net/net.rb, line 286
def w0(x,y)
    generate_weight_function unless @w_up_to_date
    return @weight[[x,y]].nil? ? 0 : @weight[[x,y]]
end

Private Instance Methods

changed_state() click to toggle source
# File lib/petri_net/net.rb, line 418
def changed_state
    @up_to_date = false
end
changed_structure() click to toggle source
# File lib/petri_net/net.rb, line 413
def changed_structure
    @w_up_to_date = false
    @up_to_date = false
end
coverability_helper(markings, source, added_omega = false) click to toggle source
# File lib/petri_net/net.rb, line 447
def coverability_helper(markings, source, added_omega = false)
    @transitions.each_value do |tid|
        if @objects[tid].fire
            current_node = PetriNet::ReachabilityGraph::Node.new(@graph, markings: get_markings)
            current_node_id = @graph.add_node current_node
            @graph.add_edge PetriNet::ReachabilityGraph::Edge.new(@graph, source: source, destination: current_node, probability: @objects[tid].probability, transition: @objects[tid].name) if (!(current_node_id < 0))
            omega = false
            if current_node_id != -Float::INFINITY && current_node_id < 0 && @graph.get_node(current_node_id * -1) != current_node
                omega = true
                added_omega_old = added_omega
                added_omega = @graph.get_node(current_node_id * -1).add_omega current_node
                if added_omega_old == added_omega
                    break
                end
                @graph.add_edge PetriNet::ReachabilityGraph::Edge.new(@graph, source: source, destination: @graph.get_node(current_node_id * -1), probability: @objects[tid].probability, transition: @objects[tid].name)
            end
            coverability_helper get_markings, @graph.get_node(current_node_id.abs), added_omega if ((!(current_node_id < 0) || !omega) && current_node_id != -Float::INFINITY )
        end
        set_markings markings
    end
end
generate_delta() click to toggle source
# File lib/petri_net/net.rb, line 399
def generate_delta
    d = Array.new(@places.size){Array.new(@transitions.size)}
    i = 0
    @places.each do |p_key,p_value|
        j = 0
        @transitions.each do |t_key,t_value|
            d[i][j] = w0(t_value, p_value) - w0(p_value,t_value)
            j += 1
        end
        i += 1
    end
    @delta = Matrix[d]
end
reachability_helper(markings, source) click to toggle source
# File lib/petri_net/net.rb, line 421
def reachability_helper(markings, source)
    @transitions.each_value do |tid|
        raise PetriNet::ReachabilityGraph::InfinityGraphError if @objects[tid].inputs.empty? && !@objects[tid].outputs.empty?
        next if @objects[tid].inputs.empty?
        if @objects[tid].fire
            current_node = PetriNet::ReachabilityGraph::Node.new(@graph, markings: get_markings)
            begin
                node_id = @graph.add_node current_node
            rescue
                @graph.add_node! current_node
                @graph.add_edge PetriNet::ReachabilityGraph::Edge.new(@graph, source: source, destination: current_node)
                infinity_node = PetriNet::ReachabilityGraph::InfinityNode.new(@graph)
                @graph.add_node infinity_node 
                @graph.add_edge PetriNet::ReachabilityGraph::Edge.new(@graph, source: current_node, destination: infinity_node)
                next 
            end
            if node_id < 0
                current_node = @graph.get_node node_id.abs
            end
            @graph.add_edge PetriNet::ReachabilityGraph::Edge.new(@graph, source: source, destination: current_node, probability: @objects[tid].probability)# if node_id
            reachability_helper get_markings, current_node if node_id >= 0
        end
        set_markings markings
    end
end