petri_net 0.7.2 → 0.7.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/petri_net/arc.rb +8 -2
- data/lib/petri_net/coverability_graph/edge.rb +13 -0
- data/lib/petri_net/coverability_graph/graph.rb +54 -0
- data/lib/petri_net/coverability_graph/node.rb +127 -0
- data/lib/petri_net/coverability_graph.rb +6 -0
- data/lib/petri_net/graph/edge.rb +57 -0
- data/lib/petri_net/graph/graph.rb +108 -0
- data/lib/petri_net/graph/node.rb +129 -0
- data/lib/petri_net/graph.rb +5 -0
- data/lib/petri_net/net.rb +84 -11
- data/lib/petri_net/place.rb +15 -2
- data/lib/petri_net/reachability_graph/edge.rb +3 -40
- data/lib/petri_net/reachability_graph/graph.rb +11 -105
- data/lib/petri_net/reachability_graph/node.rb +6 -112
- data/lib/petri_net/reachability_graph.rb +3 -94
- data/lib/petri_net/transition.rb +16 -2
- data/lib/petri_net/version.rb +2 -2
- data/lib/petri_net.rb +9 -8
- data/petri_net.gemspec +3 -2
- data/test/reachability_graph/tc_graph.rb +124 -0
- data/test/tc_petri_net.rb +4 -1
- metadata +39 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 424a324ddce6aa016935fbf72566df141a908ac0
|
4
|
+
data.tar.gz: f642d0f9451834d2d4ceb602c56ee2ade52e649c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 203e591a97198ae311563099b29305b0499f16024e57984a9152dff16fa929739e049a9ef00e6c0f0c58f61f67df3ff440e1e57960fc7d1026774fed0c8583df
|
7
|
+
data.tar.gz: 21a108f4151259a0e9bdefaa693e93b777524b13971b6fd8d61142c81f8c1e5956889458b2ff46c7196651e9f72fc2fbadd84c51690410bc833516d8f4ba08c9
|
data/lib/petri_net/arc.rb
CHANGED
@@ -33,7 +33,7 @@ module PetriNet
|
|
33
33
|
# before the object is added to the arc and an exception will be raised.
|
34
34
|
def add_source(object)
|
35
35
|
if object.class.to_s == "String"
|
36
|
-
object = (net.get_place object or net.get_transition object)
|
36
|
+
object = (@net.get_place object or @net.get_transition object)
|
37
37
|
end
|
38
38
|
if validate_source_destination(object)
|
39
39
|
@source = object
|
@@ -46,7 +46,7 @@ module PetriNet
|
|
46
46
|
# Add a destination object
|
47
47
|
def add_destination(object)
|
48
48
|
if object.class.to_s == "String"
|
49
|
-
object = (net.get_place object or net.get_transition object)
|
49
|
+
object = (@net.get_place object or @net.get_transition object)
|
50
50
|
end
|
51
51
|
if validate_source_destination(object)
|
52
52
|
@destination = object
|
@@ -117,6 +117,12 @@ module PetriNet
|
|
117
117
|
@destination.id = net.objects_find_index @destination
|
118
118
|
end
|
119
119
|
|
120
|
+
def <=>(object)
|
121
|
+
return false unless object.class.to_s == "PetriNet::Arc"
|
122
|
+
return false unless object.source == self.source && object.destination == self.destination
|
123
|
+
return object.weight <=> self.weight
|
124
|
+
end
|
125
|
+
|
120
126
|
private
|
121
127
|
|
122
128
|
# Validate source or destination object
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class PetriNet::CoverabilityGraph::Edge < PetriNet::Base
|
2
|
+
|
3
|
+
# Creates an edge for PetriNet::CoverabilityGraph
|
4
|
+
def initialize(options = {}, &block)
|
5
|
+
super(options)
|
6
|
+
yield self unless block.nil?
|
7
|
+
end
|
8
|
+
|
9
|
+
# Validates the data holded by this edge, this will be used while adding the edge to the graph
|
10
|
+
def validate
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'graphviz'
|
2
|
+
|
3
|
+
class PetriNet::CoverabilityGraph < PetriNet::Base
|
4
|
+
def initialize(net, options = Hash.new)
|
5
|
+
@objects = Array.new
|
6
|
+
@nodes = Hash.new
|
7
|
+
@edges = Hash.new
|
8
|
+
@name = net.name
|
9
|
+
if options['unlimited'].nil?
|
10
|
+
@unlimited = true
|
11
|
+
else
|
12
|
+
@unlimited = options['unlimited']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_node(node)
|
17
|
+
double = false
|
18
|
+
inf = false
|
19
|
+
@nodes.each_value do |n|
|
20
|
+
begin
|
21
|
+
if node > @objects[n]
|
22
|
+
if @unlimited
|
23
|
+
double = n
|
24
|
+
break
|
25
|
+
#return @objects[n].id *-1
|
26
|
+
else
|
27
|
+
raise PetriNet::Graph::InfiniteReachabilityGraphError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
if -Float::INFINITY == (node <=> @objects[n])
|
31
|
+
inf = true
|
32
|
+
end
|
33
|
+
rescue ArgumentError
|
34
|
+
#just two different markings, completly ok
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# if there was a smaller marking
|
38
|
+
return (@objects[double].id * -1) if double
|
39
|
+
node_index = @objects.index node
|
40
|
+
# if there already is a node with this marking
|
41
|
+
return @objects[node_index].id * -1 unless node_index.nil?
|
42
|
+
|
43
|
+
return -Float::INFINITY if inf
|
44
|
+
|
45
|
+
if (node.validate && (!@nodes.include? node.name))
|
46
|
+
@objects[node.id] = node
|
47
|
+
@nodes[node.name] = node.id
|
48
|
+
node.graph = self
|
49
|
+
return node.id
|
50
|
+
end
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
class PetriNet::CoverabilityGraph::Node < PetriNet::Base
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
# human readable name
|
5
|
+
attr_reader :name
|
6
|
+
# unique ID
|
7
|
+
attr_reader :id
|
8
|
+
# Makking this node represents
|
9
|
+
attr_reader :markings
|
10
|
+
# The graph this node belongs to
|
11
|
+
attr_accessor :graph
|
12
|
+
# Omega-marked node (unlimited Petrinet -> coverabilitygraph)
|
13
|
+
attr_reader :omega_marked
|
14
|
+
# Incoming edges
|
15
|
+
attr_reader :inputs
|
16
|
+
# Outgoing edges
|
17
|
+
attr_reader :outputs
|
18
|
+
# Label of the node
|
19
|
+
attr_reader :label
|
20
|
+
# True if this is the start-marking
|
21
|
+
attr_reader :start
|
22
|
+
|
23
|
+
def initialize(options = {}, &block)
|
24
|
+
@id = next_object_id
|
25
|
+
@name = (options[:name] or "Node#{@id}")
|
26
|
+
@description = (options[:description] or "Node #{@id}")
|
27
|
+
@inputs = Array.new
|
28
|
+
@outputs = Array.new
|
29
|
+
@label = (options[:label] or @name)
|
30
|
+
@markings = options[:markings]
|
31
|
+
@start = (options[:start] or false)
|
32
|
+
if @markings.nil?
|
33
|
+
raise ArgumentError.new "Every Node needs markings"
|
34
|
+
end
|
35
|
+
if @markings.include? Float::INFINITY
|
36
|
+
@omega_marked = true
|
37
|
+
else
|
38
|
+
@omega_marked = false
|
39
|
+
end
|
40
|
+
|
41
|
+
yield self unless block.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add an omega-marking to a specified place
|
45
|
+
def add_omega object
|
46
|
+
ret = Array.new
|
47
|
+
if object.class.to_s == "PetriNet::CoverabilityGraph::Node"
|
48
|
+
if self < object
|
49
|
+
counter = 0
|
50
|
+
object.markings.each do |marking|
|
51
|
+
if @markings[counter] < marking
|
52
|
+
@markings[counter] = Float::INFINITY
|
53
|
+
ret << counter
|
54
|
+
end
|
55
|
+
counter += 1
|
56
|
+
end
|
57
|
+
else
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
elsif object.class.to_s == "Array"
|
61
|
+
object.each do |place|
|
62
|
+
markings[place] = Float::INFINITY
|
63
|
+
ret = object
|
64
|
+
end
|
65
|
+
elsif object.class.to_s == "Fixnum"
|
66
|
+
markings[object] = Float::INFINITY
|
67
|
+
ret = [object]
|
68
|
+
end
|
69
|
+
@omega_marked = true
|
70
|
+
ret
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def gv_id
|
78
|
+
"N#{@id}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_gv
|
82
|
+
"\t#{self.gv_id} [ label = \"#{@markings}\" ];\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
# Compare-operator, other Operators are available through comparable-mixin
|
86
|
+
def <=>(object)
|
87
|
+
return nil unless object.class.to_s == "PetriNet::CoverabilityGraph::Node"
|
88
|
+
if @markings == object.markings
|
89
|
+
return 0
|
90
|
+
end
|
91
|
+
|
92
|
+
counter = 0
|
93
|
+
less = true
|
94
|
+
self.markings.each do |marking|
|
95
|
+
if marking <= object.markings[counter] && less
|
96
|
+
less = true
|
97
|
+
else
|
98
|
+
less = false
|
99
|
+
break
|
100
|
+
end
|
101
|
+
counter += 1
|
102
|
+
end
|
103
|
+
if less
|
104
|
+
return -1
|
105
|
+
end
|
106
|
+
counter = 0
|
107
|
+
more = true
|
108
|
+
self.markings.each do |marking|
|
109
|
+
if marking >= object.markings[counter] && more
|
110
|
+
more = true
|
111
|
+
else
|
112
|
+
more = false
|
113
|
+
break
|
114
|
+
end
|
115
|
+
counter += 1
|
116
|
+
end
|
117
|
+
if more
|
118
|
+
return 1
|
119
|
+
end
|
120
|
+
return nil
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_s
|
124
|
+
"#{@id}: #{@name} (#{@markings})"
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class PetriNet::Graph::Edge < PetriNet::Base
|
2
|
+
# Human readable name
|
3
|
+
attr_reader :name
|
4
|
+
# Unique ID
|
5
|
+
attr_reader :id
|
6
|
+
# Graph this edge belongs to
|
7
|
+
attr_accessor :graph
|
8
|
+
# Probability of the relating transition
|
9
|
+
attr_accessor :probability
|
10
|
+
# Source of the edge
|
11
|
+
attr_reader :source
|
12
|
+
# Destination of the edge
|
13
|
+
attr_reader :destination
|
14
|
+
# Transition this edge is representing
|
15
|
+
attr_reader :transition
|
16
|
+
|
17
|
+
# Creates an edge for PetriNet::Graph
|
18
|
+
def initialize(options = {}, &block)
|
19
|
+
@id = next_object_id
|
20
|
+
@name = (options[:name] or "Edge#{@id}")
|
21
|
+
@description = (options[:description] or "Edge #{@id}")
|
22
|
+
@source = options[:source]
|
23
|
+
@destination = options[:destination]
|
24
|
+
@label = (options[:label] or @name)
|
25
|
+
@probability = options[:probability]
|
26
|
+
@transition = (options[:transition] or "")
|
27
|
+
|
28
|
+
yield self unless block.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Validates the data holded by this edge, this will be used while adding the edge to the graph
|
32
|
+
def validate
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_gv
|
37
|
+
"\t#{@source.gv_id} -> #{@destination.gv_id}#{probability_to_gv};\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(object)
|
41
|
+
return false unless object.class.to_s == "PetriNet::ReachabilityGraph::Edge"
|
42
|
+
(@source == object.yource && @destination == oject.destination)
|
43
|
+
end
|
44
|
+
def to_s
|
45
|
+
"#{@id}: #{@name} #{@source.id} -> #{@destination} )"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def probability_to_gv
|
50
|
+
if @probability
|
51
|
+
" [ label = \"#{@probability.to_s}\" ] "
|
52
|
+
else
|
53
|
+
''
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'graphviz'
|
2
|
+
|
3
|
+
class PetriNet::InfiniteReachabilityGraphError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class PetriNet::Graph < PetriNet::Base
|
7
|
+
def initialize(net, options = Hash.new)
|
8
|
+
@objects = Array.new
|
9
|
+
@nodes = Hash.new
|
10
|
+
@edges = Hash.new
|
11
|
+
@name = net.name
|
12
|
+
@type = "Reachability"
|
13
|
+
if options['unlimited'].nil?
|
14
|
+
@unlimited = true
|
15
|
+
else
|
16
|
+
@unlimited = options['unlimited']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_node(node)
|
21
|
+
if node.validate && (!@objects.include? node)
|
22
|
+
@objects[node.id] = node
|
23
|
+
@nodes[node.name] = node.id
|
24
|
+
node.graph = self
|
25
|
+
return node.id
|
26
|
+
end
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
alias_method :add_node!, :add_node
|
30
|
+
|
31
|
+
def add_edge(edge)
|
32
|
+
if (edge.validate && (!@edges.include? edge.name))
|
33
|
+
@objects[edge.id] = edge
|
34
|
+
@edges[edge.name] = edge.id
|
35
|
+
edge.graph = self
|
36
|
+
return edge.id
|
37
|
+
end
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add an object to the Petri Net.
|
42
|
+
def <<(object)
|
43
|
+
case object.class.to_s
|
44
|
+
when "Array"
|
45
|
+
object.each {|o| self << o}
|
46
|
+
when "PetriNet::ReachabilityGraph::Edge"
|
47
|
+
add_edge(object)
|
48
|
+
when "PetriNet::ReachabilityGraph::Node"
|
49
|
+
add_node(object)
|
50
|
+
else
|
51
|
+
raise "(PetriNet::ReachabilityGraph) Unknown object #{object.class}."
|
52
|
+
end
|
53
|
+
self
|
54
|
+
end
|
55
|
+
alias_method :add_object, :<<
|
56
|
+
|
57
|
+
def get_node(id)
|
58
|
+
return @objects[id]
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_gv(output = 'png', filename = '')
|
62
|
+
g = generate_gv
|
63
|
+
if filename.empty?
|
64
|
+
filename = "#{@name}_graph.png"
|
65
|
+
end
|
66
|
+
g.output( :png => filename ) if output == 'png'
|
67
|
+
g.output
|
68
|
+
end
|
69
|
+
|
70
|
+
def generate_gv
|
71
|
+
g = GraphViz.new( :G, :type => :digraph )
|
72
|
+
|
73
|
+
@nodes.each_value do |node|
|
74
|
+
gv_node = g.add_nodes( @objects[node].markings.to_s )
|
75
|
+
gv_node.set do |n|
|
76
|
+
n.label = '*' + @objects[node].markings.to_s + '*' if @objects[node].start
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@edges.each_value do |edge|
|
80
|
+
gv_edge = g.add_edges( @objects[edge].source.markings.to_s, @objects[edge].destination.markings.to_s )
|
81
|
+
gv_edge.set do |e|
|
82
|
+
e.label = @objects[edge].transition
|
83
|
+
end
|
84
|
+
end
|
85
|
+
g
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
str = "#{@type} Graph [#{@name}]\n"
|
90
|
+
str += "----------------------------\n"
|
91
|
+
str += "Description: #{@description}\n"
|
92
|
+
str += "Filename: #{@filename}\n"
|
93
|
+
str += "\n"
|
94
|
+
|
95
|
+
str += "Nodes\n"
|
96
|
+
str += "----------------------------\n"
|
97
|
+
@nodes.each_value {|p| str += @objects[p].to_s + "\n" }
|
98
|
+
str += "\n"
|
99
|
+
|
100
|
+
str += "Edges\n"
|
101
|
+
str += "----------------------------\n"
|
102
|
+
@edges.each_value {|t| str += @objects[t].to_s + "\n" }
|
103
|
+
str += "\n"
|
104
|
+
|
105
|
+
return str
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
class PetriNet::Graph::Node < PetriNet::Base
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
# human readable name
|
5
|
+
attr_reader :name
|
6
|
+
# unique ID
|
7
|
+
attr_reader :id
|
8
|
+
# Makking this node represents
|
9
|
+
attr_reader :markings
|
10
|
+
# The graph this node belongs to
|
11
|
+
attr_accessor :graph
|
12
|
+
# Omega-marked node (unlimited Petrinet -> coverabilitygraph)
|
13
|
+
attr_reader :omega_marked
|
14
|
+
# Incoming edges
|
15
|
+
attr_reader :inputs
|
16
|
+
# Outgoing edges
|
17
|
+
attr_reader :outputs
|
18
|
+
# Label of the node
|
19
|
+
attr_reader :label
|
20
|
+
# True if this is the start-marking
|
21
|
+
attr_reader :start
|
22
|
+
|
23
|
+
def initialize(options = {}, &block)
|
24
|
+
@id = next_object_id
|
25
|
+
@name = (options[:name] or "Node#{@id}")
|
26
|
+
@description = (options[:description] or "Node #{@id}")
|
27
|
+
@inputs = Array.new
|
28
|
+
@outputs = Array.new
|
29
|
+
@label = (options[:label] or @name)
|
30
|
+
@markings = options[:markings]
|
31
|
+
@start = (options[:start] or false)
|
32
|
+
if @markings.nil?
|
33
|
+
raise ArgumentError.new "Every Node needs markings"
|
34
|
+
end
|
35
|
+
if @markings.include? Float::INFINITY
|
36
|
+
@omega_marked = true
|
37
|
+
else
|
38
|
+
@omega_marked = false
|
39
|
+
end
|
40
|
+
|
41
|
+
yield self unless block.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add an omega-marking to a specified place
|
45
|
+
def add_omega object
|
46
|
+
ret = Array.new
|
47
|
+
if object.class.to_s == "PetriNet::CoverabilityGraph::Node"
|
48
|
+
if self < object
|
49
|
+
counter = 0
|
50
|
+
object.markings.each do |marking|
|
51
|
+
if @markings[counter] < marking
|
52
|
+
@markings[counter] = Float::INFINITY
|
53
|
+
ret << counter
|
54
|
+
end
|
55
|
+
counter += 1
|
56
|
+
end
|
57
|
+
else
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
elsif object.class.to_s == "Array"
|
61
|
+
object.each do |place|
|
62
|
+
markings[place] = Float::INFINITY
|
63
|
+
ret = object
|
64
|
+
end
|
65
|
+
elsif object.class.to_s == "Fixnum"
|
66
|
+
markings[object] = Float::INFINITY
|
67
|
+
ret = [object]
|
68
|
+
elsif object.class.to_s == "PetriNet::ReachabilityGraph::Node"
|
69
|
+
raise PetriNet::Graph::InfinityError("ReachabilityGraphs do not support omega-markings")
|
70
|
+
end
|
71
|
+
@omega_marked = true
|
72
|
+
ret
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def gv_id
|
80
|
+
"N#{@id}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_gv
|
84
|
+
"\t#{self.gv_id} [ label = \"#{@markings}\" ];\n"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Compare-operator, other Operators are available through comparable-mixin
|
88
|
+
def <=>(object)
|
89
|
+
return nil unless object.class.to_s == "PetriNet::ReachabilityGraph::Node"
|
90
|
+
if @markings == object.markings
|
91
|
+
return 0
|
92
|
+
end
|
93
|
+
|
94
|
+
counter = 0
|
95
|
+
less = true
|
96
|
+
self.markings.each do |marking|
|
97
|
+
if marking <= object.markings[counter] && less
|
98
|
+
less = true
|
99
|
+
else
|
100
|
+
less = false
|
101
|
+
break
|
102
|
+
end
|
103
|
+
counter += 1
|
104
|
+
end
|
105
|
+
if less
|
106
|
+
return -1
|
107
|
+
end
|
108
|
+
counter = 0
|
109
|
+
more = true
|
110
|
+
self.markings.each do |marking|
|
111
|
+
if marking >= object.markings[counter] && more
|
112
|
+
more = true
|
113
|
+
else
|
114
|
+
more = false
|
115
|
+
break
|
116
|
+
end
|
117
|
+
counter += 1
|
118
|
+
end
|
119
|
+
if more
|
120
|
+
return 1
|
121
|
+
end
|
122
|
+
return nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_s
|
126
|
+
"#{@id}: #{@name} (#{@markings})"
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
data/lib/petri_net/net.rb
CHANGED
@@ -17,8 +17,8 @@ class PetriNet::Net < PetriNet::Base
|
|
17
17
|
# !depricated!
|
18
18
|
attr_reader :markings
|
19
19
|
|
20
|
-
# should not be public available attr_reader :objects # Array of all objects in net
|
21
|
-
# attr_reader :up_to_date # is true if, and only if, the cached elements are calculated AND the net hasn't changed
|
20
|
+
# should not be public available attr_reader :objects # Array of all objects in net
|
21
|
+
# attr_reader :up_to_date # is true if, and only if, the cached elements are calculated AND the net hasn't changed
|
22
22
|
|
23
23
|
|
24
24
|
# Create new Petri Net definition.
|
@@ -173,6 +173,32 @@ Arcs
|
|
173
173
|
return str
|
174
174
|
end
|
175
175
|
|
176
|
+
def to_gv_new(output = 'png', filename = '')
|
177
|
+
g = generate_gv
|
178
|
+
if filename.empty?
|
179
|
+
filename = "#{@name}_net.png"
|
180
|
+
end
|
181
|
+
g.output( :png => filename ) if output == 'png'
|
182
|
+
g.output
|
183
|
+
end
|
184
|
+
|
185
|
+
def generate_gv
|
186
|
+
g = GraphViz.new( :G, :type => :digraph )
|
187
|
+
|
188
|
+
@places.each_value do |place|
|
189
|
+
gv_node = g.add_nodes( @objects[place].name )
|
190
|
+
end
|
191
|
+
@transitions.each_value do |transition|
|
192
|
+
gv_node = g.add_nodes( @objects[transition].name)
|
193
|
+
gv_node.shape = :box
|
194
|
+
gv_node.fillcolor = :grey90
|
195
|
+
end
|
196
|
+
@arcs.each_value do |arc|
|
197
|
+
gv_edge = g.add_edges( @objects[arc].source.name, @objects[arc].destination.name )
|
198
|
+
end
|
199
|
+
g
|
200
|
+
end
|
201
|
+
|
176
202
|
# Generate GraphViz dot string.
|
177
203
|
def to_gv
|
178
204
|
# General graph options
|
@@ -201,6 +227,7 @@ Arcs
|
|
201
227
|
return str
|
202
228
|
end
|
203
229
|
|
230
|
+
|
204
231
|
# Merges two PetriNets
|
205
232
|
# 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.
|
206
233
|
# ATTENTION conflicting capabilities and weights will be lost and the properies of the net you merge to will be used in future
|
@@ -212,17 +239,33 @@ Arcs
|
|
212
239
|
self
|
213
240
|
end
|
214
241
|
|
215
|
-
def
|
216
|
-
|
242
|
+
def reachability_graph
|
243
|
+
generate_reachability_graph unless (@graph && @up_to_date)
|
244
|
+
@graph
|
245
|
+
end
|
246
|
+
|
247
|
+
def generate_coverability_graph()
|
248
|
+
startmarkings = get_markings
|
249
|
+
@graph = PetriNet::CoverabilityGraph.new(self)
|
250
|
+
@graph.add_node current_node = PetriNet::CoverabilityGraph::Node.new(markings: get_markings, start: true)
|
251
|
+
|
252
|
+
coverability_helper startmarkings, current_node
|
253
|
+
|
254
|
+
set_markings startmarkings
|
255
|
+
@graph
|
256
|
+
end
|
257
|
+
|
258
|
+
def generate_reachability_graph()
|
217
259
|
startmarkings = get_markings
|
218
260
|
@graph = PetriNet::ReachabilityGraph.new(self)
|
219
|
-
@graph.add_node current_node = PetriNet::ReachabilityGraph::Node.new(markings: get_markings)
|
261
|
+
@graph.add_node current_node = PetriNet::ReachabilityGraph::Node.new(markings: get_markings, start: true)
|
220
262
|
|
221
263
|
reachability_helper startmarkings, current_node
|
222
264
|
|
223
265
|
set_markings startmarkings
|
224
266
|
@graph
|
225
267
|
end
|
268
|
+
|
226
269
|
def generate_weight_function
|
227
270
|
@weight = Hash.new
|
228
271
|
@arcs.each_value do |id|
|
@@ -242,7 +285,7 @@ Arcs
|
|
242
285
|
generate_weight_function
|
243
286
|
@up_to_date = true
|
244
287
|
end
|
245
|
-
|
288
|
+
|
246
289
|
# is true if, and only if, the cached elements are calculated AND the net hasn't changed
|
247
290
|
def update?
|
248
291
|
if @w_up_to_date && true #all up_to_date-caches!!!
|
@@ -310,15 +353,45 @@ Arcs
|
|
310
353
|
end
|
311
354
|
|
312
355
|
def reachability_helper(markings, source)
|
356
|
+
@transitions.each_value do |tid|
|
357
|
+
raise PetriNet::ReachabilityGraph::InfinityGraphError if @objects[tid].inputs.empty? && !@objects[tid].outputs.empty?
|
358
|
+
next if @objects[tid].inputs.empty?
|
359
|
+
if @objects[tid].fire
|
360
|
+
current_node = PetriNet::ReachabilityGraph::Node.new(markings: get_markings)
|
361
|
+
begin
|
362
|
+
node_id = @graph.add_node current_node
|
363
|
+
rescue
|
364
|
+
@graph.add_node! current_node
|
365
|
+
@graph.add_edge PetriNet::ReachabilityGraph::Edge.new(source: source, destination: current_node)
|
366
|
+
infinity_node = PetriNet::ReachabilityGraph::InfinityNode.new
|
367
|
+
@graph.add_node infinity_node
|
368
|
+
@graph.add_edge PetriNet::ReachabilityGraph::Edge.new(source: current_node, destination: infinity_node)
|
369
|
+
next
|
370
|
+
end
|
371
|
+
@graph.add_edge PetriNet::ReachabilityGraph::Edge.new(source: source, destination: current_node)
|
372
|
+
reachability_helper get_markings, current_node unless node_id
|
373
|
+
end
|
374
|
+
set_markings markings
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def coverability_helper(markings, source, added_omega = false)
|
313
379
|
@transitions.each_value do |tid|
|
314
380
|
if @objects[tid].fire
|
315
381
|
current_node = PetriNet::ReachabilityGraph::Node.new(markings: get_markings)
|
316
|
-
current_node_id = @graph.add_node current_node
|
317
|
-
@graph.add_edge PetriNet::ReachabilityGraph::Edge.new(source: source, destination: current_node, probability: @objects[tid].probability)
|
318
|
-
|
319
|
-
|
382
|
+
current_node_id = @graph.add_node current_node
|
383
|
+
@graph.add_edge PetriNet::ReachabilityGraph::Edge.new(source: source, destination: current_node, probability: @objects[tid].probability, transition: @objects[tid].name) if (!(current_node_id < 0))
|
384
|
+
omega = false
|
385
|
+
if current_node_id != -Float::INFINITY && current_node_id < 0 && @graph.get_node(current_node_id * -1) != current_node
|
386
|
+
omega = true
|
387
|
+
added_omega_old = added_omega
|
388
|
+
added_omega = @graph.get_node(current_node_id * -1).add_omega current_node
|
389
|
+
if added_omega_old == added_omega
|
390
|
+
break
|
391
|
+
end
|
392
|
+
@graph.add_edge PetriNet::ReachabilityGraph::Edge.new(source: source, destination: @graph.get_node(current_node_id * -1), probability: @objects[tid].probability, transition: @objects[tid].name)
|
320
393
|
end
|
321
|
-
|
394
|
+
coverability_helper get_markings, @graph.get_node(current_node_id.abs), added_omega if ((!(current_node_id < 0) || !omega) && current_node_id != -Float::INFINITY )
|
322
395
|
end
|
323
396
|
set_markings markings
|
324
397
|
end
|