petri_net_2020 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +12 -0
  5. data/CHANGELOG +8 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +97 -0
  9. data/Rakefile +32 -0
  10. data/lib/petri_net/arc.rb +143 -0
  11. data/lib/petri_net/base.rb +30 -0
  12. data/lib/petri_net/coverability_graph/edge.rb +14 -0
  13. data/lib/petri_net/coverability_graph/graph.rb +52 -0
  14. data/lib/petri_net/coverability_graph/node.rb +123 -0
  15. data/lib/petri_net/coverability_graph.rb +8 -0
  16. data/lib/petri_net/graph/edge.rb +64 -0
  17. data/lib/petri_net/graph/graph.rb +324 -0
  18. data/lib/petri_net/graph/node.rb +141 -0
  19. data/lib/petri_net/graph.rb +7 -0
  20. data/lib/petri_net/marking.rb +27 -0
  21. data/lib/petri_net/net.rb +457 -0
  22. data/lib/petri_net/place.rb +131 -0
  23. data/lib/petri_net/reachability_graph/edge.rb +14 -0
  24. data/lib/petri_net/reachability_graph/graph.rb +24 -0
  25. data/lib/petri_net/reachability_graph/node.rb +14 -0
  26. data/lib/petri_net/reachability_graph.rb +8 -0
  27. data/lib/petri_net/transition.rb +135 -0
  28. data/lib/petri_net/version.rb +8 -0
  29. data/lib/petri_net.rb +36 -0
  30. data/petri_net.gemspec +23 -0
  31. data/test/create.rb +64 -0
  32. data/test/reachability_graph/tc_edge.rb +0 -0
  33. data/test/reachability_graph/tc_graph.rb +201 -0
  34. data/test/reachability_graph/tc_node.rb +65 -0
  35. data/test/tc_arc.rb +0 -0
  36. data/test/tc_petri_net.rb +371 -0
  37. data/test/tc_place.rb +0 -0
  38. data/test/tc_transition.rb +7 -0
  39. data/test/ts_all.rb +4 -0
  40. data/test/ts_petri_net.rb +6 -0
  41. data/test/ts_reachability_graph.rb +5 -0
  42. metadata +137 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 84efe45538b89da15a248ef1c52cfb8ffe686c1b432979f52914e3b9db978a4f
4
+ data.tar.gz: c19c84722a8071d9ab7e0e076b05390b2a14826e36b653da149447de03eee4d8
5
+ SHA512:
6
+ metadata.gz: 73f04577f5c74c937a5e0a912e0c047dbea201e9957f3dc5d8b4965bba5d808ad21e0a14b53148b67bc0ee36258d25a2f7beff3f897e509ebd55320bd812b6fb
7
+ data.tar.gz: 14712b4c660e8435f8c38556dde62c859267edc74a02254e43249a4f6616e8b0858feba60917e051b6904f40dae0b7078b3b82b0463af0b0b38622e3ca557c9e
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ pkg/*.gem
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-19mode # JRuby in 1.9 mode
5
+ - 2.0.0
6
+
7
+ before_install:
8
+ - gem install net-sftp
9
+ - sudo apt-get install graphviz
10
+
11
+ script:
12
+ - rake test
data/CHANGELOG ADDED
@@ -0,0 +1,8 @@
1
+ 2009-08-14 Brian D. Nelson <bdnelson@wildcoder.com>
2
+ * Initial project creation.
3
+
4
+ 2010-08-26 Brian D. Nelson <bdnelson@wildcoder.com>
5
+ * Restart of project
6
+
7
+ 2013-13.12 Christian Clausen <cclausen@tzi.de>
8
+ * Fork project to create a petrinet library to use for my Bachelor-Thesis
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in petri.gemspec
6
+ gemspec
7
+ gem 'rake'
8
+ gem 'rgl', "~>0.5.6"
9
+ #gem 'rgl', git: 'https://github.com/monora/rgl.git'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2013, Christian Clausen (cclausen@tzi.de)
2
+
3
+ Copyright (c) 2009, Brian D. Nelson (bdnelson@wildcoder.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,97 @@
1
+ {<img src="https://travis-ci.org/cclausen/petri_net.png" />}[https://travis-ci.org/cclausen/petri_net]
2
+
3
+ {<img src="https://codeclimate.com/github/cclausen/petri_net.png" />}[https://codeclimate.com/github/cclausen/petri_net]
4
+
5
+ = PTNet: Petri-net Simulation in Ruby
6
+ ===== based on the code by Brian D Nelson <bdnelson@wildcoder.com>
7
+ ===== Christian Clausen <cclausen@tzi.de>
8
+
9
+ == Version 0.6
10
+ I implemented most of the basics you need for playing with PetriNets but there are a lot things to add.
11
+ Next big step will be a stochastic analysis of the PetriNet.
12
+
13
+ == Overview
14
+ This package provides a ruby based simulation package for Petri nets.
15
+ You can build PetriNets, fire transitions and calculate statistica or solve problems in the net.
16
+ It also provides a visualization of the net (and even the Reachability Graph of the given net)
17
+
18
+
19
+ == Petri Net Resources
20
+ * http://en.wikipedia.org/wiki/Petri_net - Wikipedia
21
+
22
+ == Usage
23
+ === Creation
24
+ At first you need to create a blank petrinet:
25
+ net = PetriNet::Net.new
26
+ Then you can add places and transitions:
27
+ net << PetriNet::Place.new
28
+ net << PetriNet::Transition.new
29
+ It's a good idea to name the places and transitions, as you need to refer to them to add, so the better way will be:
30
+ net << PetriNet::Place.new(name: "A")
31
+ net << PetriNet::Transition.new(name: "a")
32
+ net << PetriNet::Arc.new(source: "A", destination: "a")
33
+ As you see, an arc needs to get a source and a destination. You can, but you don't need to name your arcs, as you don't need to refer to them later in most cases.
34
+ You can get a place/transition/arc by
35
+ net.get_place( name )
36
+ net.get_transition( name )
37
+ net.get_arc( name )
38
+ Or if you know the id (but not the name) you can use
39
+ net.get_object(id)
40
+ Of course you can save the Objects while creating them and add them afterwards:
41
+ place_B = PetriNet::Place.new(name: "B")
42
+ net << place_B
43
+ or
44
+ net.add_object place_B
45
+ or
46
+ net.add_place place_B
47
+ if you want to use this.
48
+ PetriNet#add_object even accepts arrays of accepted objects
49
+
50
+ To create an arc you do not need to specify source and destination, you can add them with "add_source" and "add_destination" later on, but an arc has to have both before being added to a net.
51
+
52
+ === Markings
53
+ !!! Attention, I'm not sure how I will implement markings in the end, this part might be wrong because I changed something. I'm not happy with the way I handle markings/token currently. Currently are PetriNet::Base-Objects which makes no sence in my opinion.
54
+
55
+ !!! Attention, Markings are inconsistens at the moment. In the original code markings are what I call "token" or "tokken" and a marking is the "state" of a petrinet, which means how many token are in which places. It's hard to understand which markings are meant as currently everything is called "marking" I will refactor this some time.
56
+
57
+ You can create markings like other PetriNet::Base objects with
58
+ marking = PetriNet::Marking.new
59
+ And add them to a place with
60
+ place_B.add_marking(marking)
61
+
62
+ But since I see no sence in creating the specific markings you can do
63
+ place_B.add_marking(3)
64
+ to add three markings to a place. Without any argument it will add just one marking.
65
+
66
+ You can get the current marking with net.get_markings. This will give you an Array of state-markings. [1,3,2,4] would mean, the first place (in order of id's, but be careful, every PetriNet::Base-object has a unique id) will hold one marking (or token) the second place will hold 3 and so on.
67
+ You can even set the markings with
68
+ net.set_markings([1,3,2,4]
69
+ but be carefull with this one, maybe this should be private in future but it can be very usefull to save the initial state or to set the net to a specific state for some algorithms (e.g. for generating the Reachability Graph)
70
+
71
+ === Visualization
72
+ You can just print yout PetriNet with
73
+ net.to_s
74
+ as you should know this means you can write
75
+ puts net
76
+
77
+ For a more fancy way to show off with your PetriNet you should try
78
+ net.to_gv
79
+ which generates the GraphViz-Code for the PetriNet.
80
+ It is planned to use the GraphViz-gem in the future to create png and stuff like that directly.
81
+
82
+ === Reachability Graph
83
+ The Reachablility Graph is a Graph with nodes representing reachable markings of the net in the current state and edges reresenting the transitions you need to get from one node to another.
84
+ You can generate the reachablility Graph with
85
+ net.generate_reachability_graph
86
+ As a PetriNet itself you can to_s and to_gv the reachablility Graph too.
87
+
88
+ === More documentation will come soon
89
+
90
+ == Contributing
91
+ Neither the library nor the documentation is finished by now, so please feel free to contribute
92
+
93
+ Just write an email and/or fork this project. Active contributors will get write-access to this repository too.
94
+
95
+
96
+ == Gem
97
+ This library is available on rubygems.org soon
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "bundler/setup"
5
+ rescue LoadError
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
+ end
8
+
9
+ require "rdoc/task"
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = "rdoc"
13
+ rdoc.title = "Wf"
14
+ rdoc.options << "--line-numbers"
15
+ rdoc.rdoc_files.include("README.md")
16
+ rdoc.rdoc_files.include("lib/**/*.rb")
17
+ end
18
+
19
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
20
+
21
+
22
+ require "bundler/gem_tasks"
23
+
24
+ require "rake/testtask"
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << "test"
28
+ t.pattern = "test/**/*_test.rb"
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PetriNet
4
+ # Arc
5
+ class Arc < PetriNet::Base
6
+ # Unique ID
7
+ attr_reader :id
8
+ # human readable name
9
+ attr_accessor :name
10
+ # Description
11
+ attr_accessor :description
12
+ # Arc weight
13
+ attr_accessor :weight
14
+ # Source-object
15
+ attr_reader :source
16
+ # Source-object
17
+ attr_reader :destination
18
+ # The net this arc belongs to
19
+ attr_writer :net
20
+
21
+ # Creates an arc.
22
+ # An arc is an directed edge between a place and a transition (or visa versa) and can have a weight which indicates how many token it comsumes or produces from/to the place
23
+ def initialize(options = {}, &block)
24
+ @id = next_object_id
25
+ @name = (options[:name] || "Arc#{@id}")
26
+ @description = (options[:description] || "Arc #{@id}")
27
+ @weight = (options[:weight] || 1)
28
+ add_source(options[:source]) unless options[:source].nil?
29
+ add_destination(options[:destination]) unless options[:destination].nil?
30
+
31
+ yield self unless block.nil?
32
+ end
33
+
34
+ # Add a source object to this arc. Validation of the source object will be performed
35
+ # before the object is added to the arc and an exception will be raised.
36
+ def add_source(object)
37
+ if object.class.to_s == 'String'
38
+ object = (@net.get_place(object) || @net.get_transition(object))
39
+ end
40
+ if validate_source_destination(object)
41
+ @source = object
42
+ object.add_output(self)
43
+ else
44
+ raise "Invalid arc source object: #{object.class}"
45
+ end
46
+ end
47
+
48
+ # Add a destination object
49
+ def add_destination(object)
50
+ if object.class.to_s == 'String'
51
+ object = (@net.get_place(object) || @net.get_transition(object))
52
+ end
53
+ if validate_source_destination(object)
54
+ @destination = object
55
+ object.add_input(self)
56
+ else
57
+ raise "Invalid arc destination object: #{object.class}"
58
+ end
59
+ end
60
+
61
+ # A Petri Net is said to be ordinary if all of its arc weights are 1's.
62
+ # Is this arc ordinary?
63
+ def ordinary?
64
+ @weight == 1
65
+ end
66
+
67
+ # Validate this arc.
68
+ def validate(net)
69
+ return false if @id < 1
70
+ return false if @name.nil? || (@name.length <= 0)
71
+ return false if @weight < 1
72
+ return false if @source.nil? || @destination.nil?
73
+ return false if @source == @destination
74
+ return false if @source.class == @destination.class
75
+
76
+ if @source.class.to_s == 'PetriNet::Place'
77
+ return net.objects_include? @source
78
+ elsif @source.class.to_s == 'PetriNet::Transition'
79
+ return net.objects_include? @source
80
+ else
81
+ return false
82
+ end
83
+ if @destination.class.to_s == 'PetriNet::Place'
84
+ return net.objects.include? @destination
85
+ elsif @destination.class.to_s == 'PetriNet::Transition'
86
+ return net.objects.include? @destination
87
+ else
88
+ return false
89
+ end
90
+
91
+ true
92
+ end
93
+
94
+ # Stringify this arc.
95
+ def to_s
96
+ "#{@id}: #{@name} (#{@weight}) #{@source.id} -> #{@destination.id}"
97
+ end
98
+
99
+ # Gives the GraphViz-representation of this arc as string of a GV-Edge
100
+ def to_gv
101
+ "\t#{@source.gv_id} -> #{@destination.gv_id} [ label = \"#{@name}\", headlabel = \"#{@weight}\" ];\n"
102
+ end
103
+
104
+ # Checks if the information in this arc are still correct.
105
+ # The information can get wrong if you merge two nets together.
106
+ def need_update?(net)
107
+ if net.get_object(@source.id).nil? || (@source.name != net.get_object(@source.id).name)
108
+ return true
109
+ end
110
+ if net.get_object(@destination.id).nil? || (@destination.name != net.get_object(@destination.id).name)
111
+ return true
112
+ end
113
+ end
114
+
115
+ # Updates the information in this arc
116
+ # Should only be necessary if PetriNet::Arc#need_update? is true
117
+ # affects source and destination
118
+ def update(net)
119
+ @source.id = net.objects_find_index @source
120
+ @destination.id = net.objects_find_index @destination
121
+ end
122
+
123
+ def <=>(object)
124
+ return false unless object.class.to_s == 'PetriNet::Arc'
125
+ return false unless object.source == source && object.destination == destination
126
+
127
+ object.weight <=> weight
128
+ end
129
+
130
+ private
131
+
132
+ # Validate source or destination object
133
+ def validate_source_destination(object)
134
+ return false if object.nil?
135
+
136
+ return object.class.to_s == 'PetriNet::Place' || object.class.to_s == 'PetriNet::Transition'
137
+
138
+ # return if @source.nil? or @source.class.to_s == object.class.to_s
139
+ # return if @destination.nil? or @destination.class.to_s == object.class.to_s
140
+ true
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PetriNet
4
+ # Common structure
5
+ class Base
6
+ # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class.
7
+ attr_accessor :logger
8
+
9
+ # Global object count.
10
+ @@object_count = 0
11
+
12
+ # Initialize the base class.
13
+ def initialize(_options = {})
14
+ @logger = Logger.new(STDOUT)
15
+ @logger.level = Logger::INFO
16
+ end
17
+
18
+ # Get the next object ID (object count).
19
+ def next_object_id
20
+ @@object_count += 1
21
+ end
22
+
23
+ # Resets the object-count
24
+ # This should not be used without extreme care
25
+ # It's made for testing-purposes only
26
+ def reset
27
+ @@object_count = 0
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PetriNet::CoverabilityGraph::Edge < PetriNet::Base
4
+ # Creates an edge for PetriNet::CoverabilityGraph
5
+ def initialize(options = {}, &block)
6
+ super(options)
7
+ yield self unless block.nil?
8
+ end
9
+
10
+ # Validates the data holded by this edge, this will be used while adding the edge to the graph
11
+ def validate
12
+ super
13
+ end
14
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphviz'
4
+
5
+ class PetriNet::CoverabilityGraph < PetriNet::Base
6
+ def initialize(net, options = {})
7
+ @objects = []
8
+ @nodes = {}
9
+ @edges = {}
10
+ @name = net.name
11
+ @unlimited = if options['unlimited'].nil?
12
+ true
13
+ else
14
+ options['unlimited']
15
+ end
16
+ end
17
+
18
+ def add_node(node)
19
+ double = false
20
+ inf = false
21
+ @nodes.each_value do |n|
22
+ if node > @objects[n]
23
+ if @unlimited
24
+ double = n
25
+ break
26
+ # return @objects[n].id *-1
27
+ else
28
+ raise PetriNet::Graph::InfiniteReachabilityGraphError
29
+ end
30
+ end
31
+ inf = true if -Float::INFINITY == (node <=> @objects[n])
32
+ rescue ArgumentError
33
+ # just two different markings, completly ok
34
+ end
35
+ # if there was a smaller marking
36
+ return (@objects[double].id * -1) if double
37
+
38
+ node_index = @objects.index node
39
+ # if there already is a node with this marking
40
+ return @objects[node_index].id * -1 unless node_index.nil?
41
+
42
+ return -Float::INFINITY if inf
43
+
44
+ if node.validate && (!@nodes.include? node.name)
45
+ @objects[node.id] = node
46
+ @nodes[node.name] = node.id
47
+ node.graph = self
48
+ return node.id
49
+ end
50
+ false
51
+ end
52
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PetriNet::CoverabilityGraph::Node < PetriNet::Base
4
+ include Comparable
5
+
6
+ # human readable name
7
+ attr_reader :name
8
+ # unique ID
9
+ attr_reader :id
10
+ # Makking this node represents
11
+ attr_reader :markings
12
+ # The graph this node belongs to
13
+ attr_accessor :graph
14
+ # Omega-marked node (unlimited Petrinet -> coverabilitygraph)
15
+ attr_reader :omega_marked
16
+ # Incoming edges
17
+ attr_reader :inputs
18
+ # Outgoing edges
19
+ attr_reader :outputs
20
+ # Label of the node
21
+ attr_reader :label
22
+ # True if this is the start-marking
23
+ attr_reader :start
24
+
25
+ def initialize(options = {}, &block)
26
+ @id = next_object_id
27
+ @name = (options[:name] || "Node#{@id}")
28
+ @description = (options[:description] || "Node #{@id}")
29
+ @inputs = []
30
+ @outputs = []
31
+ @label = (options[:label] || @name)
32
+ @markings = options[:markings]
33
+ @start = (options[:start] || false)
34
+ raise ArgumentError, 'Every Node needs markings' if @markings.nil?
35
+
36
+ @omega_marked = if @markings.include? Float::INFINITY
37
+ true
38
+ else
39
+ false
40
+ end
41
+
42
+ yield self unless block.nil?
43
+ end
44
+
45
+ # Add an omega-marking to a specified place
46
+ def add_omega(object)
47
+ ret = []
48
+ if object.class.to_s == 'PetriNet::CoverabilityGraph::Node'
49
+ if self < object
50
+ counter = 0
51
+ object.markings.each do |marking|
52
+ if @markings[counter] < marking
53
+ @markings[counter] = Float::INFINITY
54
+ ret << counter
55
+ end
56
+ counter += 1
57
+ end
58
+ else
59
+ return false
60
+ end
61
+ elsif object.class.to_s == 'Array'
62
+ object.each do |place|
63
+ markings[place] = Float::INFINITY
64
+ ret = object
65
+ end
66
+ elsif object.class.to_s == 'Fixnum'
67
+ markings[object] = Float::INFINITY
68
+ ret = [object]
69
+ end
70
+ @omega_marked = true
71
+ ret
72
+ end
73
+
74
+ def validate
75
+ true
76
+ end
77
+
78
+ def gv_id
79
+ "N#{@id}"
80
+ end
81
+
82
+ def to_gv
83
+ "\t#{gv_id} [ label = \"#{@markings}\" ];\n"
84
+ end
85
+
86
+ # Compare-operator, other Operators are available through comparable-mixin
87
+ def <=>(object)
88
+ return nil unless object.class.to_s == 'PetriNet::CoverabilityGraph::Node'
89
+ return 0 if @markings == object.markings
90
+
91
+ counter = 0
92
+ less = true
93
+ markings.each do |marking|
94
+ if marking <= object.markings[counter] && less
95
+ less = true
96
+ else
97
+ less = false
98
+ break
99
+ end
100
+ counter += 1
101
+ end
102
+ return -1 if less
103
+
104
+ counter = 0
105
+ more = true
106
+ markings.each do |marking|
107
+ if marking >= object.markings[counter] && more
108
+ more = true
109
+ else
110
+ more = false
111
+ break
112
+ end
113
+ counter += 1
114
+ end
115
+ return 1 if more
116
+
117
+ nil
118
+ end
119
+
120
+ def to_s
121
+ "#{@id}: #{@name} (#{@markings})"
122
+ end
123
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'graph'
4
+ require_relative 'coverability_graph/graph'
5
+ require_relative 'coverability_graph/node'
6
+ require_relative 'coverability_graph/edge'
7
+ # class PetriNet::CoverabilityGraph < PetriNet::Base
8
+ # end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PetriNet::Graph::Edge < PetriNet::Base
4
+ # Human readable name
5
+ attr_reader :name
6
+ # Unique ID
7
+ attr_reader :id
8
+ # Graph this edge belongs to
9
+ attr_accessor :graph
10
+ # Probability of the relating transition
11
+ attr_accessor :probability
12
+ # Source of the edge
13
+ attr_reader :source
14
+ # Destination of the edge
15
+ attr_reader :destination
16
+ # Transition this edge is representing
17
+ attr_reader :transition
18
+
19
+ # Creates an edge for PetriNet::Graph
20
+ def initialize(graph, options = {}, &block)
21
+ @graph = graph
22
+ @id = next_object_id
23
+ @name = (options[:name] || "Edge#{@id}")
24
+ @description = (options[:description] || "Edge #{@id}")
25
+ @source = options[:source]
26
+ @destination = options[:destination]
27
+ @label = (options[:label] || @name)
28
+ @probability = options[:probability]
29
+ @transition = (options[:transition] || '')
30
+
31
+ yield self unless block.nil?
32
+ end
33
+
34
+ # Validates the data holded by this edge, this will be used while adding the edge to the graph
35
+ def validate
36
+ return false unless @graph.nodes.key?(@source.name) && @graph.nodes.key?(@destination.name)
37
+
38
+ true
39
+ end
40
+
41
+ def to_gv
42
+ "\t#{@source.gv_id} -> #{@destination.gv_id}#{probability_to_gv};\n"
43
+ end
44
+
45
+ def ==(object)
46
+ return false unless object.class.to_s == 'PetriNet::ReachabilityGraph::Edge'
47
+
48
+ (@source == object.yource && @destination == oject.destination)
49
+ end
50
+
51
+ def to_s
52
+ "#{@id}: #{@name} #{@source} -> #{@destination} )"
53
+ end
54
+
55
+ private
56
+
57
+ def probability_to_gv
58
+ if @probability
59
+ " [ label = \"#{@probability}\" ] "
60
+ else
61
+ ''
62
+ end
63
+ end
64
+ end