Class: PetriNet::Net
- Includes:
- LUSolve
- Defined in:
- lib/petri_net/net.rb
Instance Attribute Summary collapse
-
#arcs ⇒ Object
readonly
List of arcs.
-
#description ⇒ Object
Description.
-
#filename ⇒ Object
Storage filename.
-
#markings ⇒ Object
readonly
List of markings !depricated!.
-
#name ⇒ Object
Human readable name.
-
#places ⇒ Object
readonly
List of places.
-
#transitions ⇒ Object
readonly
List of transitions.
Attributes inherited from Base
Instance Method Summary collapse
-
#<<(object) ⇒ Object
(also: #add_object)
Adds an object to the Petri Net.
-
#add_arc(arc) ⇒ Object
Add an arc to the list of arcs.
-
#add_place(place) ⇒ Object
Adds a place to the list of places.
-
#add_transition(transition) ⇒ Object
Add a transition to the list of transitions.
- #delta ⇒ Object
- #fire(transition) ⇒ Object
- #generate_coverability_graph ⇒ Object
- #generate_gv ⇒ Object
- #generate_reachability_graph ⇒ Object
- #generate_weight_function ⇒ Object
-
#get_arc(name) ⇒ Object
returns the arc refered by the given name or false if there is no arc with this name.
- #get_marking(places) ⇒ Object
- #get_markings ⇒ Object
- #get_object(id) ⇒ Object
- #get_objects ⇒ Object
-
#get_place(name) ⇒ Object
Returns the place refered by the given name or false if there is no place with this name.
- #get_place_from_marking(marking) ⇒ Object
- #get_place_list ⇒ Object
-
#get_transition(name) ⇒ Object
Returns the transition refered by the given name or false if there is no transition with this name.
-
#initialize(options = {}) {|_self| ... } ⇒ Net
constructor
Create new Petri Net definition.
- #load(filename) ⇒ Object
-
#merge(net) ⇒ Object
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).
- #objects_find_index(object) ⇒ Object
- #objects_include?(object) ⇒ Boolean
- #objects_size ⇒ Object
-
#ordinary? ⇒ Boolean
Is this Petri Net ordinary? A Petri Net is said to be ordinary if all of its arc weights are 1’s.
-
#pure? ⇒ Boolean
Is this Petri Net pure? A Petri Net is said to be pure if it has no self-loops.
- #reachability_graph ⇒ Object
- #s_invariant ⇒ Object
- #save(filename) ⇒ Object
- #set_markings(markings) ⇒ Object
- #t_invariants ⇒ Object
-
#to_gv ⇒ Object
Generate GraphViz dot string.
- #to_gv_new(output = 'png', filename = '') ⇒ Object
-
#to_s ⇒ Object
Stringify this Petri Net.
- #update ⇒ Object
-
#update? ⇒ Boolean
(also: #up_to_date)
is true if, and only if, the cached elements are calculated AND the net hasn’t changed.
- #w0(x, y) ⇒ Object
Methods inherited from Base
Constructor Details
#initialize(options = {}) {|_self| ... } ⇒ Net
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
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/petri_net/net.rb', line 36 def initialize( = {}, &block) @name = ([:name] or 'petri_net') @filename = ([:filename] or @name) @description = ([: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 |
Instance Attribute Details
#arcs ⇒ Object (readonly)
List of arcs
17 18 19 |
# File 'lib/petri_net/net.rb', line 17 def arcs @arcs end |
#description ⇒ Object
Description
13 14 15 |
# File 'lib/petri_net/net.rb', line 13 def description @description end |
#filename ⇒ Object
Storage filename
11 12 13 |
# File 'lib/petri_net/net.rb', line 11 def filename @filename end |
#markings ⇒ Object (readonly)
List of markings !depricated!
22 23 24 |
# File 'lib/petri_net/net.rb', line 22 def markings @markings end |
#name ⇒ Object
Human readable name
9 10 11 |
# File 'lib/petri_net/net.rb', line 9 def name @name end |
#places ⇒ Object (readonly)
List of places
15 16 17 |
# File 'lib/petri_net/net.rb', line 15 def places @places end |
#transitions ⇒ Object (readonly)
List of transitions
19 20 21 |
# File 'lib/petri_net/net.rb', line 19 def transitions @transitions end |
Instance Method Details
#<<(object) ⇒ Object Also known as: add_object
Adds an object to the Petri Net. You can add
-
PetriNet::Place
-
PetriNet::Arc
-
PetriNet::Transition
-
Array of these
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
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# 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 |
#add_arc(arc) ⇒ Object
Add an arc to the list of arcs.
see PetriNet::Net#add_place
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# 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_place(place) ⇒ Object
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
84 85 86 87 88 89 90 91 92 93 |
# 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) ⇒ Object
Add a transition to the list of transitions.
see PetriNet::Net#add_place
115 116 117 118 119 120 121 122 123 124 |
# 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 ⇒ Object
373 374 375 376 377 378 |
# File 'lib/petri_net/net.rb', line 373 def delta if @delta.nil? generate_delta end @delta end |
#fire(transition) ⇒ Object
369 370 371 |
# File 'lib/petri_net/net.rb', line 369 def fire transition get_transition(transition).fire end |
#generate_coverability_graph ⇒ Object
254 255 256 257 258 259 260 261 262 263 |
# 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 ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# 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 ⇒ Object
265 266 267 268 269 270 271 272 273 274 |
# 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 ⇒ Object
276 277 278 279 280 281 282 283 284 |
# 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) ⇒ Object
returns the arc refered by the given name or false if there is no arc with this name
142 143 144 145 |
# File 'lib/petri_net/net.rb', line 142 def get_arc(name) arc = @objects[@arcs[name]] arc.nil? ? false : arc end |
#get_marking(places) ⇒ Object
310 311 312 313 314 315 316 317 318 319 320 |
# 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 ⇒ Object
306 307 308 |
# File 'lib/petri_net/net.rb', line 306 def get_markings @places.map{|key,pid| @objects[pid].markings.size} end |
#get_object(id) ⇒ Object
349 350 351 |
# File 'lib/petri_net/net.rb', line 349 def get_object(id) @objects[id] end |
#get_objects ⇒ Object
353 354 355 |
# File 'lib/petri_net/net.rb', line 353 def get_objects @objects.clone end |
#get_place(name) ⇒ Object
Returns the place refered by the given name or false if there is no place with this name
128 129 130 131 |
# 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) ⇒ Object
335 336 337 338 |
# 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 ⇒ Object
331 332 333 |
# File 'lib/petri_net/net.rb', line 331 def get_place_list @places.map{|key,pid| @objects[pid]} end |
#get_transition(name) ⇒ Object
Returns the transition refered by the given name or false if there is no transition with this name
135 136 137 138 |
# File 'lib/petri_net/net.rb', line 135 def get_transition(name) trans = @objects[@transitions[name]] trans.nil? ? false : trans end |
#load(filename) ⇒ Object
365 366 367 |
# File 'lib/petri_net/net.rb', line 365 def load filename @net = YAML.load(File.read(filename)) end |
#merge(net) ⇒ Object
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!
239 240 241 242 243 244 |
# 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) ⇒ Object
357 358 359 |
# File 'lib/petri_net/net.rb', line 357 def objects_find_index(object) @objects.find_index object end |
#objects_include?(object) ⇒ Boolean
345 346 347 |
# File 'lib/petri_net/net.rb', line 345 def objects_include?(object) @objects.include?(object) end |
#objects_size ⇒ Object
341 342 343 |
# File 'lib/petri_net/net.rb', line 341 def objects_size @objects.count{|o| !o.nil?} end |
#ordinary? ⇒ Boolean
Is this Petri Net ordinary? A Petri Net is said to be ordinary if all of its arc weights are 1’s.
155 156 157 |
# File 'lib/petri_net/net.rb', line 155 def ordinary? raise "Not implemented yet" end |
#pure? ⇒ Boolean
Is this Petri Net pure? A Petri Net is said to be pure if it has no self-loops.
149 150 151 |
# File 'lib/petri_net/net.rb', line 149 def pure? raise "Not implemented yet" end |
#reachability_graph ⇒ Object
246 247 248 249 250 251 252 |
# 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 ⇒ Object
393 394 395 |
# File 'lib/petri_net/net.rb', line 393 def s_invariant raise "Not jet implemented" end |
#save(filename) ⇒ Object
361 362 363 |
# File 'lib/petri_net/net.rb', line 361 def save filename File.open(filename, 'w') {|f| @net.to_yaml} end |
#set_markings(markings) ⇒ Object
322 323 324 325 326 327 328 329 |
# 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 ⇒ Object
380 381 382 383 384 385 386 387 388 389 390 391 |
# 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 ⇒ Object
Generate GraphViz dot string.
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# 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 = '') ⇒ Object
180 181 182 183 184 185 186 187 |
# 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 ⇒ Object
Stringify this Petri Net.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# 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 |
#update ⇒ Object
291 292 293 294 |
# File 'lib/petri_net/net.rb', line 291 def update generate_weight_function @up_to_date = true end |
#update? ⇒ Boolean Also known as: up_to_date
is true if, and only if, the cached elements are calculated AND the net hasn’t changed
297 298 299 300 301 302 303 |
# 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 |
#w0(x, y) ⇒ Object
286 287 288 289 |
# 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 |