networkr 0.0.1 → 0.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.
- checksums.yaml +4 -4
- data/.yardoc/checksums +10 -0
- data/.yardoc/complete +0 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/Gemfile.lock +1 -1
- data/README.md +148 -11
- data/doc/BinaryMinHeap.html +870 -0
- data/doc/Networkr.html +1035 -0
- data/doc/Networkr/DiGraph.html +1013 -0
- data/doc/Networkr/Graph.html +1285 -0
- data/doc/Networkr/MultiGraph.html +532 -0
- data/doc/Networkr/Tracker.html +573 -0
- data/doc/NetworkrError.html +211 -0
- data/doc/_index.html +187 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +481 -0
- data/doc/file.README.html +128 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +128 -0
- data/doc/js/app.js +243 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +555 -0
- data/doc/top-level-namespace.html +114 -0
- data/lib/networkr/algorithms/dijkstra.rb +8 -6
- data/lib/networkr/algorithms/karger.rb +19 -18
- data/lib/networkr/algorithms/kosaraju.rb +52 -38
- data/lib/networkr/algorithms/prim.rb +17 -14
- data/lib/networkr/graphs/digraph.rb +9 -12
- data/lib/networkr/graphs/graph.rb +11 -20
- data/lib/networkr/graphs/multigraph.rb +25 -30
- data/lib/networkr/version.rb +1 -1
- data/lib/utils/heap.rb +1 -1
- data/networkr.gemspec +7 -2
- metadata +37 -5
@@ -0,0 +1,114 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.5
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<iframe id="search_frame" src="class_list.html"></iframe>
|
63
|
+
|
64
|
+
<div id="content"><h1>Top Level Namespace
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
</h1>
|
69
|
+
<div class="box_info">
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
</div>
|
82
|
+
|
83
|
+
<h2>Defined Under Namespace</h2>
|
84
|
+
<p class="children">
|
85
|
+
|
86
|
+
|
87
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Networkr.html" title="Networkr (module)">Networkr</a></span>
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
<strong class="classes">Classes:</strong> <span class='object_link'><a href="BinaryMinHeap.html" title="BinaryMinHeap (class)">BinaryMinHeap</a></span>, <span class='object_link'><a href="NetworkrError.html" title="NetworkrError (class)">NetworkrError</a></span>
|
92
|
+
|
93
|
+
|
94
|
+
</p>
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
</div>
|
105
|
+
|
106
|
+
<div id="footer">
|
107
|
+
Generated on Sun Jul 24 17:23:15 2016 by
|
108
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
109
|
+
0.9.5 (ruby-2.1.2).
|
110
|
+
</div>
|
111
|
+
|
112
|
+
</div>
|
113
|
+
</body>
|
114
|
+
</html>
|
@@ -1,10 +1,12 @@
|
|
1
|
-
# dijkstra
|
2
|
-
# single-source shortest path
|
3
|
-
|
4
|
-
#Takes undirected, weighted graph, nonnegative weights
|
5
|
-
# O(|V|**2)
|
6
|
-
|
7
1
|
module Networkr
|
2
|
+
|
3
|
+
# Dijkstra's algorithm for computing the shortest paths from a single source.
|
4
|
+
#
|
5
|
+
# @param g [Networkr::Graph] an undirected, weighted graph. Weights must be non-negative.
|
6
|
+
# @param source_node node in the graph, can be any hashable object
|
7
|
+
# @return [Hash] with destination nodes as keys and distances as values
|
8
|
+
#
|
9
|
+
# Complexity: O(|V|**2)
|
8
10
|
class << self
|
9
11
|
def dijkstra(g, source_node)
|
10
12
|
nodes_processed = [source_node]
|
@@ -1,12 +1,12 @@
|
|
1
|
-
=begin
|
2
|
-
Karger's algorithm
|
3
|
-
|
4
|
-
computes a minumum cut of a connected graph
|
5
|
-
|
6
|
-
takes undirected multigraph
|
7
|
-
=end
|
8
|
-
|
9
1
|
module Networkr
|
2
|
+
|
3
|
+
# Karger's algorithm for computing a minimum cut of a connected graph
|
4
|
+
#
|
5
|
+
# @param g [Networkr::MultiGraph] an undirected multigraph
|
6
|
+
# @return [Numeric] the number of edges crossed by minimum cut
|
7
|
+
# @note Karger's algorithm is a randomized algorithm and does not guarantee to return the minimum cut. However, running the algorithm |V|**2 log|V| times produces a minimum cut with high probability. Use Networkr::karger to run the algorithm once. Use Networkr::karger_repeated to run it |V|**2 log|V| times.
|
8
|
+
#
|
9
|
+
# Complexity (of running Networkr::karger once): O(|V|**2)
|
10
10
|
class << self
|
11
11
|
def karger(g)
|
12
12
|
while g.length > 2
|
@@ -20,24 +20,25 @@ module Networkr
|
|
20
20
|
g.adj[node1][node2].length
|
21
21
|
end
|
22
22
|
|
23
|
-
def contract(g, node1, node2)
|
24
|
-
g.children_of(node2).each_key do |node|
|
25
|
-
g.add_edge(node1, node) if node != node1
|
26
|
-
g.adj[node].delete(node2)
|
27
|
-
end
|
28
|
-
g.adj.delete(node2)
|
29
|
-
g.nodes.delete(node2)
|
30
|
-
end
|
31
|
-
|
32
23
|
def karger_repeated(g)
|
33
24
|
g_copy = g.deep_copy
|
34
25
|
|
35
26
|
n = g.length
|
36
27
|
mincut = n
|
37
|
-
(n **
|
28
|
+
(n ** 2 * Math.log(n)).to_i.times do
|
38
29
|
mincut = karger(g_copy) if karger(g_copy) < mincut
|
39
30
|
end
|
40
31
|
mincut
|
41
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def contract(g, node1, node2)
|
36
|
+
g.children_of(node2).each_key do |node|
|
37
|
+
g.add_edge(node1, node) if node != node1
|
38
|
+
g.adj[node].delete(node2)
|
39
|
+
end
|
40
|
+
g.adj.delete(node2)
|
41
|
+
g.nodes.delete(node2)
|
42
|
+
end
|
42
43
|
end
|
43
44
|
end
|
@@ -1,30 +1,50 @@
|
|
1
1
|
require "set"
|
2
2
|
|
3
|
-
# O(V+E), finds strongly connected components of a directed graph
|
4
|
-
|
5
3
|
module Networkr
|
6
|
-
class Tracker
|
7
|
-
attr_accessor :explored, :current_source, :leaders, :current_time,
|
8
|
-
:finishing_times
|
9
4
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
# Kosaraju's algorithm for finding the strongly connected components of a directed graph.
|
6
|
+
#
|
7
|
+
# Complexity: O(V+E)
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# @param g [Networkr::DiGraph] a directed graph
|
11
|
+
# @param g_rev [Networkr::DiGraph] reversed graph of g
|
12
|
+
# @return [Array<Numeric>] sizes (numbers of nodes) of strongly connected components in descending order
|
13
|
+
def kosaraju_scc_sizes(original_g, g_rev)
|
14
|
+
tracker1 = Tracker.new
|
15
|
+
tracker2 = Tracker.new
|
16
|
+
tracker2 = kosaraju(original_g, g_rev, tracker1, tracker2)
|
17
|
+
sizes(tracker2)
|
16
18
|
end
|
17
|
-
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
# @param g [Networkr::DiGraph] a directed graph
|
21
|
+
# @param g_rev [Networkr::DiGraph] reversed graph of g
|
22
|
+
# @return [Numeric] number of strongly connected components
|
23
|
+
def kosaraju_num_scc(original_g, g_rev)
|
24
|
+
tracker1 = Tracker.new
|
25
|
+
tracker2 = Tracker.new
|
26
|
+
tracker2 = kosaraju(original_g, g_rev, tracker1, tracker2)
|
27
|
+
num_scc(tracker2)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def kosaraju(original_g, g_rev, tracker1, tracker2)
|
32
|
+
dfs_loop(g_rev, tracker1)
|
33
|
+
sorted_g_adj = Hash[original_g.adj.sort_by { |k, v| tracker1.finishing_times[k] }]
|
34
|
+
sorted_g = DiGraph.new
|
35
|
+
sorted_g.adj = sorted_g_adj
|
36
|
+
dfs_loop(sorted_g, tracker2)
|
37
|
+
tracker2
|
38
|
+
end
|
39
|
+
|
40
|
+
def dfs_loop(g, tracker)
|
41
|
+
g.adj.keys.reverse_each do |i|
|
22
42
|
stack = [i]
|
23
43
|
tracker.current_source = i
|
24
44
|
while !stack.empty?
|
25
45
|
v = stack.last
|
26
46
|
if !tracker.explored.include?(v)
|
27
|
-
dfs(
|
47
|
+
dfs(g, stack, v, tracker)
|
28
48
|
else
|
29
49
|
if tracker.finishing_times[v] == nil
|
30
50
|
tracker.leaders[v] = tracker.current_source
|
@@ -37,15 +57,15 @@ module Networkr
|
|
37
57
|
end
|
38
58
|
end
|
39
59
|
|
40
|
-
def dfs(
|
60
|
+
def dfs(g, stack, v, tracker)
|
41
61
|
tracker.explored << v
|
42
|
-
if !
|
62
|
+
if !g.adj[v]
|
43
63
|
tracker.leaders[v] = v
|
44
64
|
tracker.current_time += 1
|
45
65
|
tracker.finishing_times[v] = tracker.current_time
|
46
66
|
stack.pop
|
47
67
|
else
|
48
|
-
|
68
|
+
g.adj[v].each_key do |w|
|
49
69
|
if !tracker.explored.include?(w)
|
50
70
|
stack << w
|
51
71
|
end
|
@@ -53,25 +73,6 @@ module Networkr
|
|
53
73
|
end
|
54
74
|
end
|
55
75
|
|
56
|
-
def kosaraju(original_graph, graph_rev, tracker1, tracker2)
|
57
|
-
dfs_loop(graph_rev, tracker1)
|
58
|
-
sorted_graph_adj = Hash[original_graph.adj.sort_by { |k, v| tracker1.finishing_times[k] }]
|
59
|
-
sorted_graph = DiGraph.new
|
60
|
-
sorted_graph.adj = sorted_graph_adj
|
61
|
-
dfs_loop(sorted_graph, tracker2)
|
62
|
-
tracker2
|
63
|
-
end
|
64
|
-
|
65
|
-
def kosaraju_scc_sizes(original_graph, graph_rev, tracker1, tracker2)
|
66
|
-
tracker2 = kosaraju(original_graph, graph_rev, tracker1, tracker2)
|
67
|
-
sizes(tracker2)
|
68
|
-
end
|
69
|
-
|
70
|
-
def kosaraju_num_scc(original_graph, graph_rev, tracker1, tracker2)
|
71
|
-
tracker2 = kosaraju(original_graph, graph_rev, tracker1, tracker2)
|
72
|
-
num_scc(tracker2)
|
73
|
-
end
|
74
|
-
|
75
76
|
def sizes(tracker2)
|
76
77
|
frequencies = Hash.new(0)
|
77
78
|
tracker2.leaders.each do |k, v|
|
@@ -85,4 +86,17 @@ module Networkr
|
|
85
86
|
tracker2.leaders.length
|
86
87
|
end
|
87
88
|
end
|
89
|
+
|
90
|
+
class Tracker
|
91
|
+
attr_accessor :explored, :current_source, :leaders, :current_time,
|
92
|
+
:finishing_times
|
93
|
+
|
94
|
+
def initialize
|
95
|
+
@explored = Set.new
|
96
|
+
@current_source = nil
|
97
|
+
@leaders = {}
|
98
|
+
@current_time = 0
|
99
|
+
@finishing_times = {}
|
100
|
+
end
|
101
|
+
end
|
88
102
|
end
|
@@ -1,29 +1,32 @@
|
|
1
|
-
=begin
|
2
|
-
Prim's algorithm for calculating minimum spanning tree.
|
3
|
-
|
4
|
-
takes weighted, undirected graph
|
5
|
-
returns tree
|
6
|
-
=end
|
7
1
|
module Networkr
|
2
|
+
|
3
|
+
# Prim's algorithm for finding a minimum spanning tree for a weighted undirected graph.
|
4
|
+
#
|
5
|
+
# @param g [Networkr::Graph] weighted, undirected graph
|
6
|
+
# @param source_node random node in graph, can be any hashable object
|
7
|
+
# @return [Networkr::Graph] minimum spanning tree
|
8
|
+
#
|
9
|
+
# Complexity: O(|V|**2)
|
8
10
|
class << self
|
9
|
-
def prim(g,
|
10
|
-
|
11
|
+
def prim(g, source_node)
|
12
|
+
nodes_spanned = [source_node]
|
11
13
|
tree_so_far = Graph.new
|
12
|
-
while
|
13
|
-
e = min_edge(g,
|
14
|
+
while nodes_spanned.length != g.length
|
15
|
+
e = min_edge(g, nodes_spanned)
|
14
16
|
tree_so_far.add_edge(e[0][0], e[0][1], weight: e[1])
|
15
|
-
|
17
|
+
nodes_spanned << e[0][1]
|
16
18
|
end
|
17
19
|
tree_so_far
|
18
20
|
end
|
19
21
|
|
20
|
-
|
22
|
+
private
|
23
|
+
def min_edge(g, nodes_spanned)
|
21
24
|
min_edge = nil
|
22
25
|
min_cost = 1.0/0
|
23
|
-
|
26
|
+
nodes_spanned.each do |u|
|
24
27
|
if g.adj[u]
|
25
28
|
g.adj[u].each do |v, options|
|
26
|
-
if !
|
29
|
+
if !nodes_spanned.include?(v) && options[:weight] < min_cost
|
27
30
|
min_edge = [u, v]
|
28
31
|
min_cost = options[:weight]
|
29
32
|
end
|
@@ -1,16 +1,13 @@
|
|
1
|
-
# require_relative "graph.rb"
|
2
|
-
=begin
|
3
|
-
Class for directed graphs.
|
4
|
-
|
5
|
-
DiGraphs hold directed edges. Self loops are allowed but parallel edges are not.
|
6
|
-
|
7
|
-
See Also
|
8
|
-
--------
|
9
|
-
Graph
|
10
|
-
MultiGraph
|
11
|
-
=end
|
12
|
-
|
13
1
|
module Networkr
|
2
|
+
|
3
|
+
# Class for directed graphs.
|
4
|
+
#
|
5
|
+
# DiGraphs hold directed edges. Self loops are allowed but parallel edges are not.
|
6
|
+
#
|
7
|
+
# See Also
|
8
|
+
# --------
|
9
|
+
# Graph
|
10
|
+
# MultiGraph
|
14
11
|
class DiGraph < Graph
|
15
12
|
|
16
13
|
attr_accessor :pred, :succ
|
@@ -1,12 +1,14 @@
|
|
1
|
+
module Networkr
|
2
|
+
|
1
3
|
# Class for undirected graphs.
|
2
4
|
#
|
3
5
|
# A Graph stores nodes and edges with optional attributes.
|
4
6
|
#
|
5
|
-
# Graphs hold undirected edges. Self loops are allowed but parallel
|
7
|
+
# Graphs hold undirected edges. Self loops are allowed but parallel edges are not.
|
6
8
|
#
|
7
9
|
# Nodes can be arbitrary hashable Ruby objects with optional attributes.
|
8
10
|
#
|
9
|
-
# Edges are represented as links between nodes with
|
11
|
+
# Edges are represented as links between nodes with optional attributes.
|
10
12
|
#
|
11
13
|
# Parameters
|
12
14
|
# ----------
|
@@ -15,12 +17,13 @@
|
|
15
17
|
# See Also
|
16
18
|
# --------
|
17
19
|
# DiGraph
|
20
|
+
# MultiGraph
|
18
21
|
#
|
19
22
|
# Examples
|
20
23
|
# --------
|
21
24
|
# Create an empty graph with no nodes and edges.
|
22
25
|
#
|
23
|
-
# >>> g = Graph
|
26
|
+
# >>> g = Networkr::Graph.new
|
24
27
|
#
|
25
28
|
# g can be grown in several ways
|
26
29
|
#
|
@@ -36,7 +39,7 @@
|
|
36
39
|
#
|
37
40
|
# >>> g.add_edge(1, 2)
|
38
41
|
#
|
39
|
-
# If some edges connect nodes not yet in the graph, the nodes are added automatically. There are no
|
42
|
+
# If some edges connect nodes not yet in the graph, the nodes are added automatically. There are no errors when adding nodes or edges that already exist.
|
40
43
|
#
|
41
44
|
# **Attributes:**
|
42
45
|
#
|
@@ -55,7 +58,7 @@
|
|
55
58
|
# >>> g.nodes[1][:score] = 10
|
56
59
|
# >>> g.nodes[1].delete(:score) # remove attribute
|
57
60
|
# >>> g.nodes
|
58
|
-
# { 1
|
61
|
+
# { 1 => { username: "janedoe" }, 3 => { username: "johndoe" } }
|
59
62
|
#
|
60
63
|
# Add/update edge attributes using add_edge or g.adj:
|
61
64
|
#
|
@@ -63,21 +66,6 @@
|
|
63
66
|
# >>> g.adj[1][2][:weight] = 4
|
64
67
|
# >>> g.adj[1][2]
|
65
68
|
# { weight: 4 }
|
66
|
-
#
|
67
|
-
# **Representation:**
|
68
|
-
# :TODO
|
69
|
-
# g.to_s
|
70
|
-
#
|
71
|
-
# 1-2 { weight: 4 }
|
72
|
-
# 2-6 { weight: 10 }
|
73
|
-
# 4-6 { weight: 8 }
|
74
|
-
# 3-5 { weight: 5 }
|
75
|
-
# 5-6 { weight: 1 }
|
76
|
-
|
77
|
-
class NetworkrError < RuntimeError
|
78
|
-
end
|
79
|
-
|
80
|
-
module Networkr
|
81
69
|
class Graph
|
82
70
|
attr_accessor :graph, :nodes, :adj
|
83
71
|
|
@@ -181,3 +169,6 @@ module Networkr
|
|
181
169
|
end
|
182
170
|
end
|
183
171
|
end
|
172
|
+
|
173
|
+
class NetworkrError < RuntimeError
|
174
|
+
end
|