petri_net 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3862dd137aeee506ef93dc6c0247d5f872bb5dba
4
+ data.tar.gz: 1159a8fa6abde650583c95cd80a9d54a749b57e3
5
+ SHA512:
6
+ metadata.gz: ad0e40f4bfb501824223f2f36fc0dc32aa42391e8903fd2a21f5805f88ec946b91f7cf238124d6f7fb06da055d65c50301f44f3ca2b9fd9279469a683e0b2885
7
+ data.tar.gz: c43775deaab72b0f5a8c56a7040665d2762d7ac4ecbd07230bb4382cab51998fc9fd81fd4c653f32153dded901baab56d5761b8f69a1a12d3f7bf785075b01aa
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0
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/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,93 @@
1
+ = PTNet: Petri-net Simulation in Ruby
2
+ ===== based on the code by Brian D Nelson <bdnelson@wildcoder.com>
3
+ ===== Christian Clausen cclausen@tzi.de
4
+
5
+ == Version 0.5
6
+ I implemented most of the basics you need for playing with PetriNets but there are a lot things to add.
7
+ Next big step will be a stochastic analysis of the PetriNet.
8
+
9
+ == Overview
10
+ This package provides a ruby based simulation package for Petri nets.
11
+ You can build PetriNets, fire transitions and calculate statistica or solve problems in the net.
12
+ It also provides a visualization of the net (and even the Reachability Graph of the given net)
13
+
14
+
15
+ == Petri Net Resources
16
+ * http://en.wikipedia.org/wiki/Petri_net - Wikipedia
17
+
18
+ == Usage
19
+ === Creation
20
+ At first you need to create a blank petrinet:
21
+ net = PetriNet::Net.new
22
+ Then you can add places and transitions:
23
+ net << PetriNet::Place.new
24
+ net << PetriNet::Transition.new
25
+ 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:
26
+ net << PetriNet::Place.new(name: "A")
27
+ net << PetriNet::Transition.new(name: "a")
28
+ net << PetriNet::Arc.new(source: "A", destination: "a")
29
+ 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.
30
+ You can get a place/transition/arc by
31
+ net.get_place( name )
32
+ net.get_transition( name )
33
+ net.get_arc( name )
34
+ Or if you know the id (but not the name) you can use
35
+ net.get_object(id)
36
+ Of course you can save the Objects while creating them and add them afterwards:
37
+ place_B = PetriNet::Place.new(name: "B")
38
+ net << place_B
39
+ or
40
+ net.add_object place_B
41
+ or
42
+ net.add_place place_B
43
+ if you want to use this.
44
+ PetriNet#add_object even accepts arrays of accepted objects
45
+
46
+ 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.
47
+
48
+ === Markings
49
+ !!! 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.
50
+
51
+ !!! 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.
52
+
53
+ You can create markings like other PetriNet::Base objects with
54
+ marking = PetriNet::Marking.new
55
+ And add them to a place with
56
+ place_B.add_marking(marking)
57
+
58
+ But since I see no sence in creating the specific markings you can do
59
+ place_B.add_marking(3)
60
+ to add three markings to a place. Without any argument it will add just one marking.
61
+
62
+ 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.
63
+ You can even set the markings with
64
+ net.set_markings([1,3,2,4]
65
+ 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)
66
+
67
+ === Visualization
68
+ You can just print yout PetriNet with
69
+ net.to_s
70
+ as you should know this means you can write
71
+ puts net
72
+
73
+ For a more fancy way to show off with your PetriNet you should try
74
+ net.to_gv
75
+ which generates the GraphViz-Code for the PetriNet.
76
+ It is planned to use the GraphViz-gem in the future to create png and stuff like that directly.
77
+
78
+ === Reachability Graph
79
+ 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.
80
+ You can generate the reachablility Graph with
81
+ net.generate_reachability_graph
82
+ As a PetriNet itself you can to_s and to_gv the reachablility Graph too.
83
+
84
+ === More documentation will come soon
85
+
86
+ == Contributing
87
+ Neither the library nor the documentation is finished by now, so please feel free to contribute
88
+
89
+ Just write an email and/or fork this project. Active contributors will get write-access to this repository too.
90
+
91
+
92
+ == Gem
93
+ This library is available on rubygems.org soon
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'rake/testtask'
3
+ require 'hanna/rdoctask'
4
+ require 'net/sftp'
5
+ require 'fileutils'
6
+
7
+ desc 'Default task'
8
+ task :default => [:test, :rdoc, :push, :clean]
9
+
10
+ task(:test) { puts "==> Running main test suite" }
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.test_files = FileList['test/tc_*.rb']
13
+ t.ruby_opts = ['-rubygems'] if defined? Gem
14
+ end
15
+
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_files.include('LICENSE', 'CHANGELOG', 'README', 'lib/')
18
+ rdoc.title = "PetriNet Documentation"
19
+ rdoc.options << '--webcvs=http://svn.wildcoder.com/svn/petri/trunk/'
20
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
21
+ end
22
+
23
+ desc 'Clean up unused files.'
24
+ task :clean => :clobber_rdoc do
25
+ end
26
+
27
+ desc 'Run tests.'
28
+ task :test do
29
+ end
30
+
@@ -0,0 +1,133 @@
1
+ module PetriNet
2
+ # Arc
3
+ class Arc < PetriNet::Base
4
+ # Unique ID
5
+ attr_reader :id
6
+ # human readable name
7
+ attr_accessor :name
8
+ # Description
9
+ attr_accessor :description
10
+ # Arc weight
11
+ attr_accessor :weight
12
+ # Source-object
13
+ attr_reader :source
14
+ # Source-object
15
+ attr_reader :destination
16
+ # The net this arc belongs to
17
+ attr_writer :net
18
+
19
+ # Creates an arc.
20
+ # 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
21
+ def initialize(options = {}, &block)
22
+ @id = next_object_id
23
+ @name = (options[:name] or "Arc#{@id}")
24
+ @description = (options[:description] or "Arc #{@id}")
25
+ @weight = (options[:weight] or 1)
26
+ self.add_source(options[:source]) unless options[:source].nil?
27
+ self.add_destination(options[:destination]) unless options[:destination].nil?
28
+
29
+ yield self unless block == nil
30
+ end
31
+
32
+ # Add a source object to this arc. Validation of the source object will be performed
33
+ # before the object is added to the arc and an exception will be raised.
34
+ def add_source(object)
35
+ if object.class.to_s == "String"
36
+ object = (net.get_place object or net.get_transition object)
37
+ end
38
+ if validate_source_destination(object)
39
+ @source = object
40
+ object.add_output(self)
41
+ else
42
+ raise "Invalid arc source object: #{object.class}"
43
+ end
44
+ end
45
+
46
+ # Add a destination object
47
+ def add_destination(object)
48
+ if object.class.to_s == "String"
49
+ object = (net.get_place object or net.get_transition object)
50
+ end
51
+ if validate_source_destination(object)
52
+ @destination = object
53
+ object.add_input(self)
54
+ else
55
+ raise "Invalid arc destination object: #{object.class}"
56
+ end
57
+ end
58
+
59
+ # A Petri Net is said to be ordinary if all of its arc weights are 1's.
60
+ # Is this arc ordinary?
61
+ def ordinary?
62
+ @weight == 1
63
+ end
64
+
65
+ # Validate this arc.
66
+ def validate(net)
67
+ return false if @id < 1
68
+ return false if @name.nil? or @name.length <= 0
69
+ return false if @weight < 1
70
+ return false if @source.nil? or @destination.nil?
71
+ return false if @source == @destination
72
+ return false if @source.class == @destination.class
73
+
74
+ if @source.class.to_s == "PetriNet::Place"
75
+ return net.objects_include? @source
76
+ elsif @source.class.to_s == "PetriNet::Transition"
77
+ return net.objects_include? @source
78
+ else
79
+ return false
80
+ end
81
+ if @destination.class.to_s == "PetriNet::Place"
82
+ return net.objects.include? @destination
83
+ elsif @destination.class.to_s == "PetriNet::Transition"
84
+ return net.objects.include? @destination
85
+ else
86
+ return false
87
+ end
88
+ return true
89
+ end
90
+
91
+ # Stringify this arc.
92
+ def to_s
93
+ "#{@id}: #{@name} (#{@weight}) #{@source.id} -> #{@destination.id}"
94
+ end
95
+
96
+ # Gives the GraphViz-representation of this arc as string of a GV-Edge
97
+ def to_gv
98
+ "\t#{@source.gv_id} -> #{@destination.gv_id} [ label = \"#{@name}\", headlabel = \"#{@weight}\" ];\n"
99
+ end
100
+
101
+ # Checks if the information in this arc are still correct.
102
+ # The information can get wrong if you merge two nets together.
103
+ def need_update? net
104
+ if net.get_object(@source.id).nil? || (@source.name != net.get_object(@source.id).name)
105
+ return true
106
+ end
107
+ if net.get_object(@destination.id).nil? || (@destination.name != net.get_object(@destination.id).name)
108
+ return true
109
+ end
110
+ end
111
+
112
+ # Updates the information in this arc
113
+ # Should only be necessary if PetriNet::Arc#need_update? is true
114
+ # affects source and destination
115
+ def update net
116
+ @source.id = net.objects_find_index @source
117
+ @destination.id = net.objects_find_index @destination
118
+ end
119
+
120
+ private
121
+
122
+ # Validate source or destination object
123
+ def validate_source_destination(object)
124
+ return false if object.nil?
125
+
126
+ return object.class.to_s == "PetriNet::Place" || object.class.to_s == "PetriNet::Transition"
127
+
128
+ #return if @source.nil? or @source.class.to_s == object.class.to_s
129
+ #return if @destination.nil? or @destination.class.to_s == object.class.to_s
130
+ return true
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,28 @@
1
+ module PetriNet
2
+ # Common structure
3
+ class Base
4
+ # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class.
5
+ attr_accessor :logger
6
+
7
+ # Global object count.
8
+ @@object_count = 0
9
+
10
+ # Initialize the base class.
11
+ def initialize(options = {})
12
+ @logger = Logger.new(STDOUT)
13
+ @logger.level = Logger::INFO
14
+ end
15
+
16
+ # Get the next object ID (object count).
17
+ def next_object_id
18
+ @@object_count += 1
19
+ end
20
+
21
+ # Resets the object-count
22
+ # This should not be used without extreme care
23
+ # It's made for testing-purposes only
24
+ def reset
25
+ @@object_count = 0
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ class PetriNet::ReachabilityGraph::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
+
9
+ # Creates an edge for PetriNet::ReachabilityGraph
10
+ def initialize(options = {}, &block)
11
+ @id = next_object_id
12
+ @name = (options[:name] or "Edge#{@id}")
13
+ @description = (options[:description] or "Edge #{@id}")
14
+ @source = options[:source]
15
+ @destination = options[:destination]
16
+ @label = (options[:label] or @name)
17
+
18
+ yield self unless block.nil?
19
+ end
20
+
21
+ # Validates the data holded by this edge, this will be used while adding the edge to the graph
22
+ def validate
23
+ true
24
+ end
25
+
26
+ def to_gv
27
+ "\t#{@source.gv_id} -> #{@destination.gv_id};\n"
28
+ end
29
+
30
+ def ==(object)
31
+ return false unless object.class.to_s == "PetriNet::ReachabilityGraph::Edge"
32
+ (@source == object.yource && @destination == oject.destination)
33
+ end
34
+ def to_s
35
+ "#{@id}: #{@name} #{@source.id} -> #{@destination} )"
36
+ end
37
+
38
+ end
@@ -0,0 +1,28 @@
1
+ module PetriNet
2
+ # Marking
3
+ class Marking < PetriNet::Base
4
+ # depricated
5
+ attr_accessor :id # Unique ID
6
+ # depricated
7
+ attr_accessor :name # Human readable name
8
+ # depricated
9
+ attr_accessor :description # Description
10
+ # depricated
11
+ attr_accessor :timestep # Marking timestep
12
+
13
+ # Create a new marking.
14
+ # depricated
15
+ def initialize(options = {}, &block)
16
+
17
+ yield self unless block == nil
18
+ end
19
+
20
+ # Validate this marking.
21
+ def validate
22
+ end
23
+
24
+ # Stringify this marking.
25
+ def to_s
26
+ end
27
+ end
28
+ end