ruby-graphviz 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,9 +37,7 @@ class GraphViz
37
37
  'undirected' => :graph
38
38
  }
39
39
 
40
- #
41
40
  # Create a new GraphViz object from a GraphML file of string
42
- #
43
41
  def initialize( file_or_str )
44
42
  data = ((File.file?( file_or_str )) ? File::new(file_or_str) : file_or_str)
45
43
  @xmlDoc = REXML::Document::new( data )
@@ -221,4 +219,4 @@ class GraphViz
221
219
  }
222
220
  end
223
221
  end
224
- end
222
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Gregoire Lejeune <gregoire.lejeune@free.fr>
1
+ # Copyright (C) 2004 - 2011 Gregoire Lejeune <gregoire.lejeune@free.fr>
2
2
  #
3
3
  # This program is free software; you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -18,153 +18,139 @@ require 'graphviz/attrs'
18
18
  require 'graphviz/constants'
19
19
 
20
20
  class GraphViz
21
- class Node
22
- include Constants
23
- @xNodeName
24
- @oAttrNode
25
- @oGParrent
26
-
27
- #
28
- # Create a new node
29
- #
30
- # In:
31
- # * xNodeName : ID of the node
32
- # * oGParrent : Graph
33
- #
34
- def initialize( xNodeName, oGParrent )
35
- @xNodeName = xNodeName
36
- @oGParrent = oGParrent
37
- @oAttrNode = GraphViz::Attrs::new( nil, "node", NODESATTRS )
38
- @index = nil
39
- end
40
-
41
- #
42
- # Get the node ID
43
- #
44
- def id
45
- @xNodeName.clone
46
- end
47
-
48
- #
49
- # Return the node index
50
- #
51
- def index
52
- @index
53
- end
54
- def index=(i) #:nodoc:
55
- @index = i if @index == nil
56
- end
57
-
58
- #
59
- # Return the root graph
60
- #
61
- def root_graph
62
- return( (self.pg.nil?) ? nil : self.pg.root_graph )
63
- end
64
-
65
- #
66
- # Set value +xAttrValue+ to the node attribut +xAttrName+
67
- #
68
- def []=( xAttrName, xAttrValue )
69
- xAttrValue = xAttrValue.to_s if xAttrValue.class == Symbol
70
- @oAttrNode[xAttrName.to_s] = xAttrValue
71
- end
72
-
73
- #
74
- # Get the value of the node attribut +xAttrName+
75
- #
76
- def []( xAttrName )
77
- if Hash === xAttrName
78
- xAttrName.each do |key, value|
79
- self[key] = value
80
- end
81
- return self
82
- else
83
- (@oAttrNode[xAttrName.to_s].nil?)?nil:@oAttrNode[xAttrName.to_s].clone
21
+ class Node
22
+ include Constants
23
+
24
+ # List of nodes that are directly accessible from given node (in a directed graph neighbors == incidents)
25
+ attr_reader :neighbors
26
+ # List of nodes that are incident to the given node (in a directed graph neighbors == incidents)
27
+ attr_reader :incidents
28
+
29
+ # Create a new node
30
+ #
31
+ # * node_id : ID of the node
32
+ # * parent_graph : Graph
33
+ def initialize( node_id, parent_graph )
34
+ @neighbors = []
35
+ @incidents = []
36
+ @node_id = node_id
37
+ @parent_graph = parent_graph
38
+ @node_attributs = GraphViz::Attrs::new( nil, "node", NODESATTRS )
39
+ @index = nil
40
+ end
41
+
42
+ # Get the node ID
43
+ def id
44
+ @node_id.clone
45
+ end
46
+
47
+ # Return the node index
48
+ def index
49
+ @index
50
+ end
51
+ def index=(i) #:nodoc:
52
+ @index = i if @index == nil
53
+ end
54
+
55
+ # Return the root graph
56
+ def root_graph
57
+ return( (self.pg.nil?) ? nil : self.pg.root_graph )
58
+ end
59
+
60
+ # Set value +attribut_value+ to the node attribut +attribut_name+
61
+ def []=( attribut_name, attribut_value )
62
+ attribut_value = attribut_value.to_s if attribut_value.class == Symbol
63
+ @node_attributs[attribut_name.to_s] = attribut_value
84
64
  end
85
- end
86
-
87
- #
88
- # Calls block once for each attribut of the node, passing the name and value to the
89
- # block as a two-element array.
90
- #
91
- # If global is set to false, the block does not receive the attributs set globally
92
- #
93
- def each_attribut(global = true, &b)
94
- attrs = @oAttrNode.to_h
95
- if global
96
- attrs = pg.node.to_h.merge attrs
65
+
66
+ # Get the value of the node attribut +attribut_name+
67
+ def []( attribut_name )
68
+ if Hash === attribut_name
69
+ attribut_name.each do |key, value|
70
+ self[key] = value
71
+ end
72
+ return self
73
+ else
74
+ (@node_attributs[attribut_name.to_s].nil?)?nil:@node_attributs[attribut_name.to_s].clone
75
+ end
97
76
  end
98
- attrs.each do |k,v|
99
- yield(k,v)
77
+
78
+ # Calls block once for each attribut of the node, passing the name and value to the
79
+ # block as a two-element array.
80
+ #
81
+ # If global is set to false, the block does not receive the attributs set globally
82
+ def each_attribut(global = true, &b)
83
+ attrs = @node_attributs.to_h
84
+ if global
85
+ attrs = pg.node.to_h.merge attrs
86
+ end
87
+ attrs.each do |k,v|
88
+ yield(k,v)
89
+ end
100
90
  end
101
- end
102
-
103
- #
104
- # Create an edge between the current node and the node +oNode+
105
- #
106
- def <<( oNode )
107
- if( oNode.class == Array )
108
- oNode.each do |no|
109
- self << no
110
- end
111
- else
112
- return GraphViz::commonGraph( oNode, self ).add_edge( self, oNode )
91
+
92
+ # Create an edge between the current node and the node +node+
93
+ def <<( node )
94
+ if( node.class == Array )
95
+ node.each do |no|
96
+ self << no
97
+ end
98
+ else
99
+ return GraphViz::commonGraph( node, self ).add_edge( self, node )
100
+ end
113
101
  end
114
- end
115
- alias :> :<<
116
- alias :- :<<
117
- alias :>> :<<
118
-
119
- #
120
- # Set node attributs
121
- #
122
- # Example :
123
- # n = graph.add_node( ... )
124
- # ...
125
- # n.set { |_n|
126
- # _n.color = "blue"
127
- # _n.fontcolor = "red"
128
- # }
129
- #
130
- def set( &b )
131
- yield( self )
132
- end
133
-
134
- # Add node options
135
- # use node.<option>=<value> or node.<option>( <value> )
136
- def method_missing( idName, *args, &block ) #:nodoc:
137
- xName = idName.id2name
138
-
139
- self[xName.gsub( /=$/, "" )]=args[0]
140
- end
141
-
142
- def pg #:nodoc:
143
- @oGParrent
144
- end
145
-
146
- def output #:nodoc:
147
- #xNodeName = @xNodeName.clone
148
- #xNodeName = '"' << xNodeName << '"' if xNodeName.match( /^[a-zA-Z_]+[a-zA-Z0-9_\.]*$/ ).nil?
149
- xNodeName = GraphViz.escape(@xNodeName)
150
-
151
- xOut = "" << xNodeName
152
- xAttr = ""
153
- xSeparator = ""
154
-
155
- if @oAttrNode.data.has_key?("label") and @oAttrNode.data.has_key?("html")
156
- @oAttrNode.data.delete("label")
102
+ alias :> :<<
103
+ alias :- :<<
104
+ alias :>> :<<
105
+
106
+ # Set node attributs
107
+ #
108
+ # Example :
109
+ # n = graph.add_node( ... )
110
+ # ...
111
+ # n.set { |_n|
112
+ # _n.color = "blue"
113
+ # _n.fontcolor = "red"
114
+ # }
115
+ #
116
+ def set( &b )
117
+ yield( self )
157
118
  end
158
- @oAttrNode.data.each do |k, v|
159
- xAttr << xSeparator + k + " = " + v.to_gv
160
- xSeparator = ", "
119
+
120
+ # Add node options
121
+ # use node.<option>=<value> or node.<option>( <value> )
122
+ def method_missing( idName, *args, &block ) #:nodoc:
123
+ xName = idName.id2name
124
+
125
+ self[xName.gsub( /=$/, "" )]=args[0]
161
126
  end
162
- if xAttr.length > 0
163
- xOut << " [" + xAttr + "]"
127
+
128
+ def pg #:nodoc:
129
+ @parent_graph
164
130
  end
165
- xOut << ";"
166
131
 
167
- return( xOut )
168
- end
169
- end
132
+ def output #:nodoc:
133
+ #node_id = @node_id.clone
134
+ #node_id = '"' << node_id << '"' if node_id.match( /^[a-zA-Z_]+[a-zA-Z0-9_\.]*$/ ).nil?
135
+ node_id = GraphViz.escape(@node_id)
136
+
137
+ xOut = "" << node_id
138
+ xAttr = ""
139
+ xSeparator = ""
140
+
141
+ if @node_attributs.data.has_key?("label") and @node_attributs.data.has_key?("html")
142
+ @node_attributs.data.delete("label")
143
+ end
144
+ @node_attributs.data.each do |k, v|
145
+ xAttr << xSeparator + k + " = " + v.to_gv
146
+ xSeparator = ", "
147
+ end
148
+ if xAttr.length > 0
149
+ xOut << " [" + xAttr + "]"
150
+ end
151
+ xOut << ";"
152
+
153
+ return( xOut )
154
+ end
155
+ end
170
156
  end
@@ -1,252 +1,286 @@
1
1
  require 'graphviz/math/matrix'
2
2
 
3
3
  class GraphViz
4
- class Theory
5
- def initialize( graph )
6
- @graph = graph
7
- end
8
-
9
- #
10
- # Return the adjancy matrix of the graph
11
- #
12
- def adjancy_matrix
13
- matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
14
-
15
- @graph.each_edge { |e|
16
- x = @graph.get_node(e.node_one( false )).index
17
- y = @graph.get_node(e.node_two( false )).index
18
- matrix[x+1, y+1] = 1
19
- matrix[y+1, x+1] = 1 if @graph.type == "graph"
20
- }
21
-
22
- return matrix
23
- end
24
-
25
- #
26
- # Return the incidence matrix of the graph
27
- #
28
- def incidence_matrix
29
- tail = (@graph.type == "digraph") ? -1 : 1
30
- matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.edge_count )
31
-
32
- @graph.each_edge { |e|
33
- x = e.index
34
-
35
- nstart = @graph.get_node(e.node_one( false )).index
36
- nend = @graph.get_node(e.node_two( false )).index
37
-
38
- matrix[nstart+1, x+1] = 1
39
- matrix[nend+1, x+1] = tail
40
- matrix[nend+1, x+1] = 2 if nstart == nend
41
- }
42
-
43
- return matrix
44
- end
45
-
46
- #
47
- # Return the degree of the given node
48
- #
49
- def degree( node )
50
- degree = 0
51
- name = node
52
- if node.kind_of?(GraphViz::Node)
53
- name = node.id
54
- end
55
-
56
- @graph.each_edge do |e|
57
- degree += 1 if e.node_one(false) == name or e.node_two(false) == name
58
- end
59
-
60
- return degree
61
- end
62
-
63
- #
64
- # Return the laplacian matrix of the graph
65
- #
66
- def laplacian_matrix
67
- return degree_matrix - adjancy_matrix
68
- end
69
-
70
- #
71
- # Return <tt>true</tt> if the graph if symmetric, <tt>false</tt> otherwise
72
- #
73
- def symmetric?
74
- adjancy_matrix == adjancy_matrix.transpose
75
- end
76
-
77
- #
78
- # moore_dijkstra(source, destination)
79
- #
80
- def moore_dijkstra( dep, arv )
81
- dep = @graph.get_node(dep) unless dep.kind_of?(GraphViz::Node)
82
- arv = @graph.get_node(arv) unless arv.kind_of?(GraphViz::Node)
83
-
84
- m = distance_matrix
85
- n = @graph.node_count
86
- # Table des sommets à choisir
87
- c = [dep.index]
88
- # Table des distances
89
- d = []
90
- d[dep.index] = 0
91
-
92
- # Table des predecesseurs
93
- pred = []
94
-
95
- @graph.each_node do |name, k|
96
- if k != dep
97
- d[k.index] = m[dep.index+1,k.index+1]
98
- pred[k.index] = dep
99
- end
100
- end
101
-
102
- while c.size < n
103
- # trouver y tel que d[y] = min{d[k]; k sommet tel que k n'appartient pas à c}
104
- mini = 1.0/0.0
105
- y = nil
106
- @graph.each_node do |name, k|
107
- next if c.include?(k.index)
108
- if d[k.index] < mini
109
- mini = d[k.index]
110
- y = k
111
- end
112
- end
113
-
114
- # si ce minimum est ∞ alors sortir de la boucle fin si
115
- break unless mini.to_f.infinite?.nil?
116
-
117
- c << y.index
118
- @graph.each_node do |name, k|
119
- next if c.include?(k.index)
120
- if d[k.index] > d[y.index] + m[y.index+1,k.index+1]
121
- d[k.index] = d[y.index] + m[y.index+1,k.index+1]
122
- pred[k.index] = y
123
- end
124
- end
125
- end
126
-
127
- # Construction du chemin le plus court
128
- ch = []
129
- k = arv
130
- while k.index != dep.index
131
- ch.unshift(k.id)
132
- k = pred[k.index]
133
- end
134
- ch.unshift(dep.id)
135
-
136
- if d[arv.index].to_f.infinite?
137
- return nil
138
- else
139
- return( {
140
- :path => ch,
141
- :distance => d[arv.index]
142
- } )
143
- end
144
- end
145
-
146
- #
147
- # Return a liste of range
148
- #
149
- # If the returned array include nil values, there is one or more circuits in the graph
150
- #
151
- def range
152
- matrix = adjancy_matrix
153
- unseen = (1..matrix.columns).to_a
154
- result = Array.new(matrix.columns)
155
- r = 0
156
-
157
- range_recursion( matrix, unseen, result, r )
158
- end
159
-
160
- #
161
- # Return the critical path for a PERT network
162
- #
163
- # If the given graph is not a PERT network, return nul
164
- #
165
- def critical_path
166
- return nil if range.include?(nil) or @graph.type != "digraph"
167
- r = [ [0, [1]] ]
168
-
169
- critical_path_recursion( distance_matrix, adjancy_matrix, r, [], 0 ).inject( {:distance => 0, :path => []} ) { |r, item|
170
- (r[:distance] < item[0]) ? { :distance => item[0], :path => item[1] } : r
171
- }
172
- end
173
-
174
- private
175
- def distance_matrix
176
- type = @graph.type
177
- matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count, (1.0/0.0) )
178
-
179
- @graph.each_edge { |e|
180
- x = @graph.get_node(e.node_one( false )).index
181
- y = @graph.get_node(e.node_two( false )).index
182
- unless x == y
183
- weight = ((e[:weight].nil?) ? 1 : e[:weight].to_f)
184
- matrix[x+1, y+1] = weight
185
- matrix[y+1, x+1] = weight if type == "graph"
186
- end
187
- }
188
-
189
- return matrix
190
- end
191
-
192
- def degree_matrix
193
- matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
194
- @graph.each_node do |name, node|
195
- i = node.index
196
- matrix[i+1, i+1] = degree(node)
197
- end
198
- return matrix
199
- end
200
-
201
- def range_recursion(matrix, unseen, result, r)
202
- remove = []
203
- matrix.columns.times do |c|
204
- if matrix.sum_of_column(c+1) == 0
205
- result[unseen[c]-1] = r
206
- remove.unshift( c + 1 )
207
- end
208
- end
209
-
210
- remove.each do |rem|
211
- matrix = matrix.remove_line(rem).remove_column(rem)
212
- unseen.delete_at(rem-1)
213
- end
214
-
215
- if matrix.columns == 1 and matrix.lines == 1
216
- if matrix.sum_of_column(1) == 0
217
- result[unseen[0]-1] = r+1
218
- end
219
- elsif remove.size > 0
220
- range_recursion( matrix, unseen, result, r+1 )
221
- end
222
-
223
- return result
224
- end
225
-
226
- def index_of_item( array, item )
227
- array.inject( [0,[]] ){|a,i|
228
- a[1] << a[0] if i == item
229
- a[0] += 1
230
- a
231
- }[1]
232
- end
233
-
234
- def critical_path_recursion( d, a, r, result, level )
235
- r.each do |p|
236
- node = p[1][-1]
237
- index_of_item( a.line(node), 1 ).each do |c|
238
- succ = c+1
239
-
240
- cpath = [ (p[0] + d[node,succ]), (p[1].clone << succ) ]
241
-
242
- if index_of_item( a.line(succ), 1 ).size > 0
243
- capth = critical_path_recursion( d, a, [cpath], result, level+1 )
244
- else
245
- result << cpath
246
- end
247
- end
248
- end
249
- return result
250
- end
251
- end
252
- end
4
+ class Theory
5
+ def initialize( graph )
6
+ @graph = graph
7
+ end
8
+
9
+ # Return the adjancy matrix of the graph
10
+ def adjancy_matrix
11
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
12
+
13
+ @graph.each_edge { |e|
14
+ x = @graph.get_node(e.node_one( false )).index
15
+ y = @graph.get_node(e.node_two( false )).index
16
+ matrix[x+1, y+1] = 1
17
+ matrix[y+1, x+1] = 1 if @graph.type == "graph"
18
+ }
19
+
20
+ return matrix
21
+ end
22
+
23
+ # Return the incidence matrix of the graph
24
+ def incidence_matrix
25
+ tail = (@graph.type == "digraph") ? -1 : 1
26
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.edge_count )
27
+
28
+ @graph.each_edge { |e|
29
+ x = e.index
30
+
31
+ nstart = @graph.get_node(e.node_one( false )).index
32
+ nend = @graph.get_node(e.node_two( false )).index
33
+
34
+ matrix[nstart+1, x+1] = 1
35
+ matrix[nend+1, x+1] = tail
36
+ matrix[nend+1, x+1] = 2 if nstart == nend
37
+ }
38
+
39
+ return matrix
40
+ end
41
+
42
+ # Return the degree of the given node
43
+ def degree( node )
44
+ degree = 0
45
+ name = node
46
+ if node.kind_of?(GraphViz::Node)
47
+ name = node.id
48
+ end
49
+
50
+ @graph.each_edge do |e|
51
+ degree += 1 if e.node_one(false) == name or e.node_two(false) == name
52
+ end
53
+
54
+ return degree
55
+ end
56
+
57
+ # Return the laplacian matrix of the graph
58
+ def laplacian_matrix
59
+ return degree_matrix - adjancy_matrix
60
+ end
61
+
62
+ # Return <tt>true</tt> if the graph if symmetric, <tt>false</tt> otherwise
63
+ def symmetric?
64
+ adjancy_matrix == adjancy_matrix.transpose
65
+ end
66
+
67
+ # moore_dijkstra(source, destination)
68
+ def moore_dijkstra( dep, arv )
69
+ dep = @graph.get_node(dep) unless dep.kind_of?(GraphViz::Node)
70
+ arv = @graph.get_node(arv) unless arv.kind_of?(GraphViz::Node)
71
+
72
+ m = distance_matrix
73
+ n = @graph.node_count
74
+ # Table des sommets à choisir
75
+ c = [dep.index]
76
+ # Table des distances
77
+ d = []
78
+ d[dep.index] = 0
79
+
80
+ # Table des predecesseurs
81
+ pred = []
82
+
83
+ @graph.each_node do |name, k|
84
+ if k != dep
85
+ d[k.index] = m[dep.index+1,k.index+1]
86
+ pred[k.index] = dep
87
+ end
88
+ end
89
+
90
+ while c.size < n
91
+ # trouver y tel que d[y] = min{d[k]; k sommet tel que k n'appartient pas à c}
92
+ mini = 1.0/0.0
93
+ y = nil
94
+ @graph.each_node do |name, k|
95
+ next if c.include?(k.index)
96
+ if d[k.index] < mini
97
+ mini = d[k.index]
98
+ y = k
99
+ end
100
+ end
101
+
102
+ # si ce minimum est ∞ alors sortir de la boucle fin si
103
+ break unless mini.to_f.infinite?.nil?
104
+
105
+ c << y.index
106
+ @graph.each_node do |name, k|
107
+ next if c.include?(k.index)
108
+ if d[k.index] > d[y.index] + m[y.index+1,k.index+1]
109
+ d[k.index] = d[y.index] + m[y.index+1,k.index+1]
110
+ pred[k.index] = y
111
+ end
112
+ end
113
+ end
114
+
115
+ # Construction du chemin le plus court
116
+ ch = []
117
+ k = arv
118
+ while k.index != dep.index
119
+ ch.unshift(k.id)
120
+ k = pred[k.index]
121
+ end
122
+ ch.unshift(dep.id)
123
+
124
+ if d[arv.index].to_f.infinite?
125
+ return nil
126
+ else
127
+ return( {
128
+ :path => ch,
129
+ :distance => d[arv.index]
130
+ } )
131
+ end
132
+ end
133
+
134
+ # Return a liste of range
135
+ #
136
+ # If the returned array include nil values, there is one or more circuits in the graph
137
+ def range
138
+ matrix = adjancy_matrix
139
+ unseen = (1..matrix.columns).to_a
140
+ result = Array.new(matrix.columns)
141
+ r = 0
142
+
143
+ range_recursion( matrix, unseen, result, r )
144
+ end
145
+
146
+ # Return the critical path for a PERT network
147
+ #
148
+ # If the given graph is not a PERT network, return nul
149
+ def critical_path
150
+ return nil if range.include?(nil) or @graph.type != "digraph"
151
+ r = [ [0, [1]] ]
152
+
153
+ critical_path_recursion( distance_matrix, adjancy_matrix, r, [], 0 ).inject( {:distance => 0, :path => []} ) { |r, item|
154
+ (r[:distance] < item[0]) ? { :distance => item[0], :path => item[1] } : r
155
+ }
156
+ end
157
+
158
+ # Return the PageRank in an directed graph.
159
+ #
160
+ # * damping_factor: PageRank dumping factor.
161
+ # * max_iterations: Maximum number of iterations.
162
+ # * min_delta: Smallest variation required to have a new iteration.
163
+ def pagerank(damping_factor = 0.85, max_iterations = 100, min_delta = 0.00001)
164
+ return nil unless @graph.directed?
165
+
166
+ min_value = (1.0-damping_factor)/@graph.node_count
167
+
168
+ pagerank = {}
169
+ @graph.each_node { |_, node|
170
+ pagerank[node] = 1.0/@graph.node_count
171
+ }
172
+
173
+ max_iterations.times { |_|
174
+ diff = 0
175
+ @graph.each_node { |_, node|
176
+ rank = min_value
177
+ incidents(node).each { |referent|
178
+ rank += damping_factor * pagerank[referent] / neighbors(referent).size
179
+ }
180
+
181
+ diff += (pagerank[node] - rank).abs
182
+ pagerank[node] = rank
183
+ }
184
+ break if diff < min_delta
185
+ }
186
+
187
+ return pagerank
188
+ end
189
+
190
+ # Return the list of nodes that are directly accessible from given node
191
+ def neighbors(node)
192
+ if node.class == String
193
+ @graph.get_node(node).neighbors
194
+ else
195
+ node.neighbors
196
+ end
197
+ end
198
+
199
+ # Return the list of nodes that are incident to the given node (in a directed graph neighbors == incidents)
200
+ def incidents(node)
201
+ if node.class == String
202
+ @graph.get_node(node).incidents
203
+ else
204
+ node.incidents
205
+ end
206
+ end
207
+
208
+ private
209
+ def distance_matrix
210
+ type = @graph.type
211
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count, (1.0/0.0) )
212
+
213
+ @graph.each_edge { |e|
214
+ x = @graph.get_node(e.node_one( false )).index
215
+ y = @graph.get_node(e.node_two( false )).index
216
+ unless x == y
217
+ weight = ((e[:weight].nil?) ? 1 : e[:weight].to_f)
218
+ matrix[x+1, y+1] = weight
219
+ matrix[y+1, x+1] = weight if type == "graph"
220
+ end
221
+ }
222
+
223
+ return matrix
224
+ end
225
+
226
+ def degree_matrix
227
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
228
+ @graph.each_node do |name, node|
229
+ i = node.index
230
+ matrix[i+1, i+1] = degree(node)
231
+ end
232
+ return matrix
233
+ end
234
+
235
+ def range_recursion(matrix, unseen, result, r)
236
+ remove = []
237
+ matrix.columns.times do |c|
238
+ if matrix.sum_of_column(c+1) == 0
239
+ result[unseen[c]-1] = r
240
+ remove.unshift( c + 1 )
241
+ end
242
+ end
243
+
244
+ remove.each do |rem|
245
+ matrix = matrix.remove_line(rem).remove_column(rem)
246
+ unseen.delete_at(rem-1)
247
+ end
248
+
249
+ if matrix.columns == 1 and matrix.lines == 1
250
+ if matrix.sum_of_column(1) == 0
251
+ result[unseen[0]-1] = r+1
252
+ end
253
+ elsif remove.size > 0
254
+ range_recursion( matrix, unseen, result, r+1 )
255
+ end
256
+
257
+ return result
258
+ end
259
+
260
+ def index_of_item( array, item )
261
+ array.inject( [0,[]] ){|a,i|
262
+ a[1] << a[0] if i == item
263
+ a[0] += 1
264
+ a
265
+ }[1]
266
+ end
267
+
268
+ def critical_path_recursion( d, a, r, result, level )
269
+ r.each do |p|
270
+ node = p[1][-1]
271
+ index_of_item( a.line(node), 1 ).each do |c|
272
+ succ = c+1
273
+
274
+ cpath = [ (p[0] + d[node,succ]), (p[1].clone << succ) ]
275
+
276
+ if index_of_item( a.line(succ), 1 ).size > 0
277
+ capth = critical_path_recursion( d, a, [cpath], result, level+1 )
278
+ else
279
+ result << cpath
280
+ end
281
+ end
282
+ end
283
+ return result
284
+ end
285
+ end
286
+ end