rgl 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +74 -0
- data/Makefile +72 -0
- data/README +240 -0
- data/Rakefile +210 -0
- data/TAGS +209 -0
- data/examples/canvas.rb +103 -0
- data/examples/codegraph +238 -0
- data/examples/example.jpg +0 -0
- data/examples/examples.rb +112 -0
- data/examples/graph.dot +54 -0
- data/examples/graph.png +0 -0
- data/examples/module_graph.jpg +0 -0
- data/examples/north.rb +12 -0
- data/examples/north/Graph.log +128 -0
- data/examples/north/g.10.0.graphml +28 -0
- data/examples/north/g.10.1.graphml +28 -0
- data/examples/north/g.10.11.graphml +31 -0
- data/examples/north/g.10.12.graphml +27 -0
- data/examples/north/g.10.13.graphml +27 -0
- data/examples/north/g.10.14.graphml +27 -0
- data/examples/north/g.10.15.graphml +26 -0
- data/examples/north/g.10.16.graphml +26 -0
- data/examples/north/g.10.17.graphml +26 -0
- data/examples/north/g.10.19.graphml +37 -0
- data/examples/north/g.10.2.graphml +28 -0
- data/examples/north/g.10.20.graphml +38 -0
- data/examples/north/g.10.22.graphml +43 -0
- data/examples/north/g.10.24.graphml +30 -0
- data/examples/north/g.10.25.graphml +45 -0
- data/examples/north/g.10.27.graphml +38 -0
- data/examples/north/g.10.28.graphml +30 -0
- data/examples/north/g.10.29.graphml +38 -0
- data/examples/north/g.10.3.graphml +26 -0
- data/examples/north/g.10.30.graphml +34 -0
- data/examples/north/g.10.31.graphml +42 -0
- data/examples/north/g.10.34.graphml +42 -0
- data/examples/north/g.10.37.graphml +28 -0
- data/examples/north/g.10.38.graphml +38 -0
- data/examples/north/g.10.39.graphml +36 -0
- data/examples/north/g.10.4.graphml +26 -0
- data/examples/north/g.10.40.graphml +37 -0
- data/examples/north/g.10.41.graphml +37 -0
- data/examples/north/g.10.42.graphml +26 -0
- data/examples/north/g.10.45.graphml +28 -0
- data/examples/north/g.10.46.graphml +32 -0
- data/examples/north/g.10.5.graphml +31 -0
- data/examples/north/g.10.50.graphml +30 -0
- data/examples/north/g.10.56.graphml +29 -0
- data/examples/north/g.10.57.graphml +32 -0
- data/examples/north/g.10.58.graphml +32 -0
- data/examples/north/g.10.6.graphml +26 -0
- data/examples/north/g.10.60.graphml +32 -0
- data/examples/north/g.10.61.graphml +34 -0
- data/examples/north/g.10.62.graphml +34 -0
- data/examples/north/g.10.68.graphml +30 -0
- data/examples/north/g.10.69.graphml +32 -0
- data/examples/north/g.10.7.graphml +29 -0
- data/examples/north/g.10.70.graphml +26 -0
- data/examples/north/g.10.71.graphml +27 -0
- data/examples/north/g.10.72.graphml +28 -0
- data/examples/north/g.10.74.graphml +29 -0
- data/examples/north/g.10.75.graphml +29 -0
- data/examples/north/g.10.78.graphml +27 -0
- data/examples/north/g.10.79.graphml +34 -0
- data/examples/north/g.10.8.graphml +29 -0
- data/examples/north/g.10.80.graphml +34 -0
- data/examples/north/g.10.82.graphml +35 -0
- data/examples/north/g.10.83.graphml +32 -0
- data/examples/north/g.10.85.graphml +34 -0
- data/examples/north/g.10.86.graphml +34 -0
- data/examples/north/g.10.88.graphml +37 -0
- data/examples/north/g.10.89.graphml +29 -0
- data/examples/north/g.10.9.graphml +26 -0
- data/examples/north/g.10.90.graphml +32 -0
- data/examples/north/g.10.91.graphml +31 -0
- data/examples/north/g.10.92.graphml +26 -0
- data/examples/north/g.10.93.graphml +32 -0
- data/examples/north/g.10.94.graphml +34 -0
- data/examples/north/g.12.8.graphml +40 -0
- data/examples/north/g.14.9.graphml +36 -0
- data/examples/north2.rb +21 -0
- data/examples/rdep-rgl.rb +395 -0
- data/install.rb +49 -0
- data/lib/rgl/adjacency.rb +151 -0
- data/lib/rgl/base.rb +299 -0
- data/lib/rgl/connected_components.rb +125 -0
- data/lib/rgl/dot.rb +63 -0
- data/lib/rgl/graphxml.rb +52 -0
- data/lib/rgl/implicit.rb +151 -0
- data/lib/rgl/mutable.rb +54 -0
- data/lib/rgl/rdot.rb +264 -0
- data/lib/rgl/topsort.rb +61 -0
- data/lib/rgl/transitiv_closure.rb +34 -0
- data/lib/rgl/traversal.rb +296 -0
- data/tests/TestComponents.rb +67 -0
- data/tests/TestDirectedGraph.rb +100 -0
- data/tests/TestEdge.rb +33 -0
- data/tests/TestGraphXML.rb +57 -0
- data/tests/TestImplicit.rb +52 -0
- data/tests/TestTransitiveClosure.rb +29 -0
- data/tests/TestTraversal.rb +222 -0
- data/tests/TestUnDirectedGraph.rb +98 -0
- metadata +163 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
# This file contains the algorithms for the connected components of an
|
2
|
+
# undirected graph (each_connected_component) and strongly connected components
|
3
|
+
# for directed graphs (strongly_connected_components).
|
4
|
+
#
|
5
|
+
require 'rgl/traversal'
|
6
|
+
|
7
|
+
module RGL
|
8
|
+
module Graph
|
9
|
+
# Compute the connected components of an undirected graph using a DFS-based
|
10
|
+
# approach. A <b>connected component</b> of an undirected graph is a set of
|
11
|
+
# vertices that are all reachable from each other.
|
12
|
+
#
|
13
|
+
# The function is implemented as an iterator which calls the client with an
|
14
|
+
# array of vertices for each component.
|
15
|
+
#
|
16
|
+
# It raises an exception if the graph is directed.
|
17
|
+
def each_connected_component
|
18
|
+
raise NotUndirectedError, "each_connected_component only works for undirected graphs." if directed?
|
19
|
+
comp = []
|
20
|
+
vis = DFSVisitor.new(self)
|
21
|
+
vis.set_finish_vertex_event_handler {|v| comp << v}
|
22
|
+
vis.set_start_vertex_event_handler {|v|
|
23
|
+
yield comp unless comp.empty?
|
24
|
+
comp = []
|
25
|
+
}
|
26
|
+
depth_first_search(vis) {|v|}
|
27
|
+
yield comp unless comp.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
# This GraphVisitor is used by strongly_connected_components to compute the
|
31
|
+
# strongly connected components of a directed graph.
|
32
|
+
#
|
33
|
+
#
|
34
|
+
class TarjanSccVisitor < DFSVisitor
|
35
|
+
attr_reader :comp_map
|
36
|
+
|
37
|
+
# Creates a new TarjanSccVisitor for graph _g_, which should be directed.
|
38
|
+
def initialize(g)
|
39
|
+
super g
|
40
|
+
@root_map = {}
|
41
|
+
@comp_map = {}
|
42
|
+
@discover_time_map = {}
|
43
|
+
@dfs_time = 0
|
44
|
+
@c_index = 0
|
45
|
+
@stack = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_examine_vertex(v)
|
49
|
+
@root_map[v] = v
|
50
|
+
@comp_map[v] = -1
|
51
|
+
@dfs_time += 1
|
52
|
+
@discover_time_map[v] = @dfs_time
|
53
|
+
@stack.push v
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_finish_vertex(v)
|
57
|
+
# Search adjacent vertex w with earliest discover time
|
58
|
+
root_v = @root_map[v]
|
59
|
+
graph.each_adjacent(v) do |w|
|
60
|
+
if @comp_map[w] == -1
|
61
|
+
root_v = min_discover_time(root_v,@root_map[w])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@root_map[v] = root_v
|
65
|
+
if root_v == v # v is topmost vertex of a SCC
|
66
|
+
begin # pop off all vertices until v
|
67
|
+
w = @stack.pop
|
68
|
+
@comp_map[w] = @c_index
|
69
|
+
end until w == v
|
70
|
+
@c_index += 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return the number of components found so far.
|
75
|
+
def num_comp
|
76
|
+
@c_index
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def min_discover_time(u,v)
|
82
|
+
@discover_time_map[u] < @discover_time_map[v] ? u : v
|
83
|
+
end
|
84
|
+
end # TarjanSccVisitor
|
85
|
+
|
86
|
+
# This is Tarjan's algorithm for strongly connected components
|
87
|
+
# from his paper "Depth first search and linear graph algorithms".
|
88
|
+
# It calculates the components in a single application of DFS.
|
89
|
+
# We implement the algorithm with the help of the DFSVisitor
|
90
|
+
# TarjanSccVisitor.
|
91
|
+
#
|
92
|
+
# === Definition
|
93
|
+
#
|
94
|
+
# A <b>strongly connected component</b> of a directed graph G=(V,E) is a
|
95
|
+
# maximal set of vertices U which is in V such that for every pair of
|
96
|
+
# vertices u and v in U, we have both a path from u to v and path from v to
|
97
|
+
# u. That is to say that u and v are reachable from each other.
|
98
|
+
#
|
99
|
+
# @Article{Tarjan:1972:DFS,
|
100
|
+
# author = "R. E. Tarjan",
|
101
|
+
# key = "Tarjan",
|
102
|
+
# title = "Depth First Search and Linear Graph Algorithms",
|
103
|
+
# journal = "SIAM Journal on Computing",
|
104
|
+
# volume = "1",
|
105
|
+
# number = "2",
|
106
|
+
# pages = "146--160",
|
107
|
+
# month = jun,
|
108
|
+
# year = "1972",
|
109
|
+
# CODEN = "SMJCAT",
|
110
|
+
# ISSN = "0097-5397 (print), 1095-7111 (electronic)",
|
111
|
+
# bibdate = "Thu Jan 23 09:56:44 1997",
|
112
|
+
# bibsource = "Parallel/Multi.bib, Misc/Reverse.eng.bib",
|
113
|
+
# }
|
114
|
+
#
|
115
|
+
# The output of the algorithm is recorded in a TarjanSccVisitor _vis_.
|
116
|
+
# vis.comp_map will contain numbers giving the component ID assigned to each
|
117
|
+
# vertex. The number of components is vis.num_comp.
|
118
|
+
def strongly_connected_components
|
119
|
+
raise NotDirectedError, "strong_components only works for directed graphs." unless directed?
|
120
|
+
vis = TarjanSccVisitor.new(self)
|
121
|
+
depth_first_search(vis) {|v|}
|
122
|
+
vis
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/rgl/dot.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#
|
2
|
+
# $Id: dot.rb,v 1.4 2002/11/13 21:53:27 monora Exp $
|
3
|
+
#
|
4
|
+
# Minimal Dot support based on Dave Thomas dot module (included in
|
5
|
+
# rdoc). rdot.rb is a modified version which also contains support for
|
6
|
+
# undirected graphs.
|
7
|
+
|
8
|
+
require 'rgl/rdot'
|
9
|
+
|
10
|
+
module RGL
|
11
|
+
module Graph
|
12
|
+
# Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an
|
13
|
+
# undirected Graph. _params_ can contain any graph property specified in
|
14
|
+
# rdot.rb.
|
15
|
+
def to_dot_graph( params = {} )
|
16
|
+
params['name'] ||= self.class.name.gsub(/:/,'_')
|
17
|
+
fontsize = params['fontsize'] ? params['fontsize'] : '8'
|
18
|
+
graph = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
|
19
|
+
edge_class = directed? ? DOT::DOTDirectedEdge : DOT::DOTEdge
|
20
|
+
each_vertex do |v|
|
21
|
+
name = v.to_s
|
22
|
+
graph << DOT::DOTNode.new('name' => '"' + name + '"',
|
23
|
+
'fontsize' => fontsize,
|
24
|
+
'label' => name)
|
25
|
+
end
|
26
|
+
each_edge do |u,v|
|
27
|
+
graph << edge_class.new('from' => '"'+ u.to_s + '"',
|
28
|
+
'to' => '"'+ v.to_s + '"',
|
29
|
+
'fontsize' => fontsize)
|
30
|
+
end
|
31
|
+
graph
|
32
|
+
end
|
33
|
+
|
34
|
+
# Output the DOT-graph to stream _s_.
|
35
|
+
def print_dotted_on (params = {}, s=$stdout)
|
36
|
+
s << to_dot_graph(params).to_s << "\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Call +dotty+ for the graph which is written to the file 'graph.dot' in the
|
40
|
+
# current directory.
|
41
|
+
def dotty( params = {} )
|
42
|
+
dotfile = "graph.dot"
|
43
|
+
File.open(dotfile, "w") {|f|
|
44
|
+
print_dotted_on(params, f)
|
45
|
+
}
|
46
|
+
system("dotty", dotfile)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Use +do+ to create a graphical representation of the graph. Returns the
|
50
|
+
# filename of the graphics file.
|
51
|
+
def write_to_graphic_file(fmt='png', dotfile="graph")
|
52
|
+
src = dotfile + ".dot"
|
53
|
+
dot = dotfile + "." + fmt
|
54
|
+
|
55
|
+
File.open(src, 'w') do |f|
|
56
|
+
f << self.to_dot_graph.to_s << "\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
system( "dot -T#{fmt} #{src} -o #{dot}" )
|
60
|
+
dot
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/rgl/graphxml.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# This file contains minimal support for creating RGL graphs from the GraphML
|
2
|
+
# format (see http://www.graphdrawing.org/graphml). The main purpose is to
|
3
|
+
# have a rich set of example graphs to have some more tests.
|
4
|
+
#
|
5
|
+
# See the examples directory which contains a subdirectory _north_ with the
|
6
|
+
# Graph catalog GraphViz (see http://www.research.att.com/sw/tools/graphviz/refs.html).
|
7
|
+
#
|
8
|
+
# We use REXML::StreamListener from the REXML library
|
9
|
+
# (http://www.germane-software.com/software/rexml) to parse the grapml files.
|
10
|
+
|
11
|
+
require 'rgl/mutable'
|
12
|
+
require 'rexml/document'
|
13
|
+
require 'rexml/streamlistener'
|
14
|
+
|
15
|
+
module RGL
|
16
|
+
# Module GraphXML adds to each class including module MutableGraph a class
|
17
|
+
# method from_graphxml.
|
18
|
+
#
|
19
|
+
# Attention: Because append_features is used to provide the
|
20
|
+
# functionality GraphXML must be loaded before the concrete class
|
21
|
+
# implementing including MutableGraph is loaded.
|
22
|
+
module GraphXML
|
23
|
+
class MutableGraphParser
|
24
|
+
include REXML::StreamListener
|
25
|
+
attr_reader :graph
|
26
|
+
def initialize(graph)
|
27
|
+
@graph = graph
|
28
|
+
end
|
29
|
+
|
30
|
+
def tag_start(name, attrs)
|
31
|
+
case name
|
32
|
+
when 'edge'
|
33
|
+
@graph.add_edge(attrs['source'],
|
34
|
+
attrs['target'])
|
35
|
+
when 'node'
|
36
|
+
@graph.add_vertex(attrs['id'])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def MutableGraph.append_features(includingClass)
|
42
|
+
super
|
43
|
+
|
44
|
+
# Create a new MutableGraph from the XML-Source _source_.
|
45
|
+
def includingClass.from_graphxml (source)
|
46
|
+
listener = MutableGraphParser.new(self.new)
|
47
|
+
REXML::Document.parse_stream(source, listener)
|
48
|
+
listener.graph
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/rgl/implicit.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# This file contains the definition of the class RGL::ImplicitGraph which
|
2
|
+
# defines vertex and edge iterators using blocks (which again call blocks).
|
3
|
+
#
|
4
|
+
# An ImplicitGraph provides a handy way to define graphs on the fly using two
|
5
|
+
# blocks for the two iterators defining a graph. The directed cyclic graph with
|
6
|
+
# 5 vertices can be created as follows:
|
7
|
+
#
|
8
|
+
# g = RGL::ImplicitGraph.new { |g|
|
9
|
+
# g.vertex_iterator { |b| 0.upto(4,&b) }
|
10
|
+
# g.adjacent_iterator { |x, b| b.call((x+1)%5) }
|
11
|
+
# g.directed = true
|
12
|
+
# }
|
13
|
+
# g.to_s => "(0-1)(1-2)(2-3)(3-4)(4-0)"
|
14
|
+
#
|
15
|
+
# Other examples are given by the methods vertices_filtered_by and
|
16
|
+
# edges_filtered_by, which can be applied to any graph.
|
17
|
+
require 'rgl/base'
|
18
|
+
|
19
|
+
module RGL
|
20
|
+
class ImplicitGraph
|
21
|
+
include Graph
|
22
|
+
|
23
|
+
attr_writer :directed
|
24
|
+
|
25
|
+
EMPTY_VERTEX_ITERATOR = proc { |b| }
|
26
|
+
EMPTY_NEIGHBOR_ITERATOR = proc { |x, b| }
|
27
|
+
|
28
|
+
# Create a new ImplicitGraph, which is by default empty. The caller should
|
29
|
+
# configure the with vertex and neighbor iterators. If the graph is directed
|
30
|
+
# the client should set directed to true. The default value for _directed_
|
31
|
+
# is false.
|
32
|
+
def initialize
|
33
|
+
@directed = false
|
34
|
+
@vertex_iterator = EMPTY_VERTEX_ITERATOR
|
35
|
+
@adjacent_iterator = EMPTY_NEIGHBOR_ITERATOR
|
36
|
+
yield self if block_given? # let client overwrite defaults
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the value of @directed.
|
40
|
+
def directed?; @directed; end
|
41
|
+
|
42
|
+
def each_vertex (&block) # :nodoc:
|
43
|
+
@vertex_iterator.call(block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def each_adjacent (v, &block) # :nodoc:
|
47
|
+
@adjacent_iterator.call(v,block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def each_edge (&block) # :nodoc:
|
51
|
+
if defined? @edge_iterator
|
52
|
+
@edge_iterator.call(block)
|
53
|
+
else
|
54
|
+
super # use default implementation
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sets the vertex_iterator to _block_ which must be a block of one parameter
|
59
|
+
# which again is the block called by each_vertex.
|
60
|
+
def vertex_iterator (&block)
|
61
|
+
@vertex_iterator = block
|
62
|
+
end
|
63
|
+
|
64
|
+
# Sets the adjacent_iterator to _block_ which must be a block of two
|
65
|
+
# parameters:
|
66
|
+
# The first parameter is the vertex the neighbors of which are to be
|
67
|
+
# traversed. The second is the block which will be called for each neighbor
|
68
|
+
# of this vertex.
|
69
|
+
def adjacent_iterator (&block)
|
70
|
+
@adjacent_iterator = block
|
71
|
+
end
|
72
|
+
|
73
|
+
# Sets the edge_iterator to _block_ which must be a block of two parameters:
|
74
|
+
# The first parameter is the source of the edges an the second is the target
|
75
|
+
# of the edge.
|
76
|
+
def edge_iterator (&block)
|
77
|
+
@edge_iterator = block
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module Graph
|
82
|
+
# ---
|
83
|
+
# === Graph adaptors
|
84
|
+
#
|
85
|
+
# Return a new ImplicitGraph which has as vertices all vertices of the
|
86
|
+
# receiver which satisfy the predicate _filter_.
|
87
|
+
#
|
88
|
+
# The methods provides similar functionaty as the BGL graph adapter
|
89
|
+
# filtered_graph (see BOOST_DOC/filtered_graph.html).
|
90
|
+
#
|
91
|
+
# ==== Example
|
92
|
+
#
|
93
|
+
# def complete (n)
|
94
|
+
# set = n.integer? ? (1..n) : n
|
95
|
+
# RGL::ImplicitGraph.new { |g|
|
96
|
+
# g.vertex_iterator { |b| set.each(&b) }
|
97
|
+
# g.adjacent_iterator { |x, b|
|
98
|
+
# set.each { |y| b.call(y) unless x == y }
|
99
|
+
# }
|
100
|
+
# }
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# complete(4).to_s => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
|
104
|
+
# complete(4).vertices_filtered_by {|v| v != 4}.to_s => "(1=2)(1=3)(2=3)"
|
105
|
+
def vertices_filtered_by (&filter)
|
106
|
+
implicit_graph {|g|
|
107
|
+
g.vertex_iterator { |b|
|
108
|
+
self.each_vertex { |v| b.call(v) if filter.call(v) }
|
109
|
+
}
|
110
|
+
g.adjacent_iterator { |v, b|
|
111
|
+
self.each_adjacent(v) { |u| b.call(u) if filter.call(u) }
|
112
|
+
}
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return a new ImplicitGraph which has as edges all edges of the receiver
|
117
|
+
# which satisfy the predicate _filter_ (a block with to parameters).
|
118
|
+
#
|
119
|
+
# ==== Example
|
120
|
+
#
|
121
|
+
# g = complete(7).edges_filtered_by {|u,v| u+v == 7}
|
122
|
+
# g.to_s => "(1=6)(2=5)(3=4)"
|
123
|
+
# g.vertices => [1, 2, 3, 4, 5, 6, 7]
|
124
|
+
def edges_filtered_by (&filter)
|
125
|
+
implicit_graph {
|
126
|
+
|g|
|
127
|
+
g.adjacent_iterator { |v, b|
|
128
|
+
self.each_adjacent(v) { |u|
|
129
|
+
b.call(u) if filter.call(v,u)
|
130
|
+
}
|
131
|
+
}
|
132
|
+
g.edge_iterator { |b|
|
133
|
+
self.each_edge {|u,v| b.call(u,v) if filter.call(u,v)}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
# Return a new ImplicitGraph which is isomorphic (i.e. has same edges and
|
139
|
+
# vertices) to the receiver. It is a shortcut also used by
|
140
|
+
# edges_filtered_by and vertices_filtered_by.
|
141
|
+
def implicit_graph
|
142
|
+
result = ImplicitGraph.new {|g|
|
143
|
+
g.vertex_iterator { |b| self.each_vertex(&b)}
|
144
|
+
g.adjacent_iterator { |v, b| self.each_adjacent(v,&b)}
|
145
|
+
g.directed = self.directed?
|
146
|
+
}
|
147
|
+
yield result if block_given? # let client overwrite defaults
|
148
|
+
result
|
149
|
+
end
|
150
|
+
end # module Graph
|
151
|
+
end
|
data/lib/rgl/mutable.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rgl/base'
|
2
|
+
|
3
|
+
module RGL
|
4
|
+
# A MutableGraph can be changed via the addition or removal of edges and
|
5
|
+
# vertices.
|
6
|
+
module MutableGraph
|
7
|
+
include Graph
|
8
|
+
|
9
|
+
# Add a new vertex _v_ to the graph. If the vertex is already in (using
|
10
|
+
# eql?) the method does nothing.
|
11
|
+
def add_vertex(v); raise NotImplementedError; end
|
12
|
+
|
13
|
+
# Inserts the edge (u,v) into the graph.
|
14
|
+
#
|
15
|
+
# Note that for undirected graphs, (u,v) is the same edge as (v,u), so after
|
16
|
+
# a call to the function add_edge(), this implies that edge (u,v) will
|
17
|
+
# appear in the out-edges of u and (u,v) (or equivalently (v,u)) will appear
|
18
|
+
# in the out-edges of
|
19
|
+
# v. Put another way, v will be adjacent to u and u will be adjacent to v.
|
20
|
+
def add_edge(u, v); raise NotImplementedError; end
|
21
|
+
|
22
|
+
# Add all objects in _a_ to the vertex set.
|
23
|
+
def add_vertices (*a)
|
24
|
+
a.each {|v| add_vertex v}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Add all edges in the _edges_ array to the edge set. Element of the array
|
28
|
+
# can be both two element arrays or instances of DirectedEdge or
|
29
|
+
# UnDirectedEdge.
|
30
|
+
def add_edges (*edges)
|
31
|
+
edges.each {|edge| add_edge(edge[0],edge[1])}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Remove u from the vertex set of the graph. All edges who's target is _v_
|
35
|
+
# are also removed from the edge set of the graph.
|
36
|
+
#
|
37
|
+
# Postcondition: num_vertices is one less, _v_ no longer appears in the
|
38
|
+
# vertex set of the graph and there no edge with source or target _v_.
|
39
|
+
def remove_vertex(v); raise NotImplementedError; end
|
40
|
+
|
41
|
+
# Remove the edge (u,v) from the graph. If the graph allows parallel edges
|
42
|
+
# this remove all occurrences of (u,v).
|
43
|
+
#
|
44
|
+
# Precondition: u and v are vertices in the graph.
|
45
|
+
# Postcondition: (u,v) is no longer in the edge set for g.
|
46
|
+
def remove_edge(u, v); raise NotImplementedError; end
|
47
|
+
|
48
|
+
# Remove all vertices specified by the array a from the graph calling
|
49
|
+
# remove_vertex.
|
50
|
+
def remove_vertices (*a)
|
51
|
+
a.each {|v| remove_vertex v}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|