graphsrb 0.1.0

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +7 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +37 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +338 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/examples/ApproxAlgs/TSP/tsp.rb +45 -0
  15. data/examples/ApproxAlgs/VertexCover/main.rb +34 -0
  16. data/examples/ApproxAlgs/VertexCover/vertex_cover.rb +31 -0
  17. data/examples/Apts/artc_points.rb +59 -0
  18. data/examples/Apts/main.rb +51 -0
  19. data/examples/BackEdges/backedges.rb +37 -0
  20. data/examples/BackEdges/main.rb +41 -0
  21. data/examples/BipartMatching/bipart_matching.rb +34 -0
  22. data/examples/BipartMatching/main.rb +58 -0
  23. data/examples/EdgeConnectivity/econ.rb +31 -0
  24. data/examples/EdgeConnectivity/main.rb +34 -0
  25. data/examples/Euler/euler_tour.rb +36 -0
  26. data/examples/Euler/main.rb +19 -0
  27. data/examples/FundCircuits/fund_circuits.rb +49 -0
  28. data/examples/FundCircuits/main.rb +34 -0
  29. data/examples/FundCutsets/fund_cutsets.rb +50 -0
  30. data/examples/FundCutsets/main.rb +26 -0
  31. data/examples/MaxFlow/edmonds_karp.rb +91 -0
  32. data/examples/MaxFlow/main.rb +79 -0
  33. data/examples/PrimMST/main.rb +46 -0
  34. data/examples/PrimMST/prim.rb +82 -0
  35. data/examples/ProbAlgs/LargeCustset/large_cutset.rb +59 -0
  36. data/examples/ProbAlgs/LargeCustset/main.rb +45 -0
  37. data/graphsrb.gemspec +39 -0
  38. data/lib/graphsrb.rb +11 -0
  39. data/lib/graphsrb/adjacency_list.rb +78 -0
  40. data/lib/graphsrb/base_graph.rb +167 -0
  41. data/lib/graphsrb/diedge.rb +6 -0
  42. data/lib/graphsrb/digraph.rb +93 -0
  43. data/lib/graphsrb/edge.rb +34 -0
  44. data/lib/graphsrb/exceptions.rb +5 -0
  45. data/lib/graphsrb/graph.rb +46 -0
  46. data/lib/graphsrb/node.rb +21 -0
  47. data/lib/graphsrb/version.rb +3 -0
  48. data/lib/graphsrb/vertex.rb +32 -0
  49. metadata +149 -0
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "graphsrb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,45 @@
1
+ require 'graphsrb'
2
+ require_relative '../../PrimMST/prim'
3
+ include Graphsrb
4
+
5
+ # 2-approximation for TSP
6
+ module ApproxAlgs
7
+ module TSP
8
+ def self.run(graph)
9
+ edges = PrimMST.run(graph)
10
+ #Create a spanning tree
11
+ @spanning_tree = Graph.new
12
+ edges.each{|e| @spanning_tree.add_edge(e.initial_vertex.id, e.terminal_vertex.id)}
13
+
14
+ puts "Spanning tree:"
15
+ puts @spanning_tree.edges
16
+ puts "-"*25
17
+ compute_path(edges.first.initial_vertex)
18
+ end
19
+
20
+ def self.compute_path(start)
21
+ @stack = [start]
22
+ @visited = []
23
+ dfs(start)
24
+ return @stack.uniq
25
+ end
26
+
27
+ def self.dfs(v)
28
+ @stack.push(v)
29
+ @visited[v.id] = true
30
+ @spanning_tree.adjacent_vertices(v).each do |v|
31
+ dfs(v) if !@visited[v.id]
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ edges = [
38
+ [1,2,6], [1,3,3], [1,4,5],[1,5,5],
39
+ [2,3,4], [2,4,4], [2,5,2],
40
+ [3,4,3], [3,5,4],
41
+ [4,5,4]
42
+ ]
43
+
44
+
45
+ puts ApproxAlgs::TSP.run(Graph.new(edges:edges))
@@ -0,0 +1,34 @@
1
+ require_relative 'vertex_cover'
2
+
3
+ def run_example(example_title, graph)
4
+ puts "------- #{example_title} ------ "
5
+ puts "The graph has #{graph.vertex_count} vertices and #{graph.edge_count} edges"
6
+ ApproxAlgs::VertexCover.run(graph)
7
+ end
8
+
9
+
10
+ def main
11
+ edges = [
12
+ [1,2],[1,4],
13
+ [2,3],[2,5],
14
+ [3,5],[3,6],[3,7],
15
+ [5,6]
16
+ ]
17
+ vertices = run_example('Example 1', Graph.new(edges:edges))
18
+ vertices.each {|v| puts v}
19
+
20
+
21
+ edges = [[1,2],[2,3],[3,4],[4,5]]
22
+ vertices = run_example('Example 2', Graph.new(edges:edges))
23
+ vertices.each {|v| puts v}
24
+
25
+ edges = [[1,2],[3,4],[5,6],[7,8]]
26
+ vertices = run_example('Example 3', Graph.new(edges:edges))
27
+ vertices.each {|v| puts v}
28
+
29
+ edges = [[1,2],[1,3],[1,4],[1,5]]
30
+ vertices = run_example('Example 4', Graph.new(edges:edges))
31
+ vertices.each {|v| puts v}
32
+ end
33
+
34
+ main
@@ -0,0 +1,31 @@
1
+ require 'graphsrb'
2
+ include Graphsrb
3
+
4
+ # 2-approximation for vertex-cover problem
5
+ module ApproxAlgs
6
+ module VertexCover
7
+ def self.run(graph)
8
+ vertex_cover = []
9
+ edges = graph.edges
10
+
11
+ while edges.size > 0
12
+ edge = edges.first
13
+ v = edge.initial_vertex
14
+ u = edge.terminal_vertex
15
+ vertex_cover.concat([v,u])
16
+ edges = remove_incident_edges(edges, u, v)
17
+ end
18
+ vertex_cover
19
+ end
20
+
21
+ def self.remove_incident_edges(edges, v, u)
22
+ remaining_edges = []
23
+ edges.each do |e|
24
+ next if e.initial_vertex == v || e.terminal_vertex == v
25
+ next if e.initial_vertex == u || e.terminal_vertex == u
26
+ remaining_edges << e
27
+ end
28
+ remaining_edges
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ require 'graphsrb'
2
+ include Graphsrb
3
+
4
+ #Computes articulation points
5
+ module ArtcPoints
6
+ def self.run(g)
7
+ init(g)
8
+ root = @graph.vertices.first
9
+ dfs(root)
10
+ @apts = @apts - [root]
11
+ @apts << root if root_artc_point?(root)
12
+ @apts
13
+ end
14
+
15
+ def self.init(g)
16
+ @graph = g
17
+ @apts = []
18
+ @dfi = []
19
+ @low = []
20
+ @preds = []
21
+ @index = 1
22
+
23
+ @graph.vertices.each do |u|
24
+ @dfi[u.id] = 0
25
+ end
26
+ end
27
+
28
+ def self.root_artc_point?(root)
29
+ count = 0
30
+ @graph.vertices.each do |u|
31
+ next if root == u
32
+ count+=1 if @preds[u.id] == root.id
33
+ end
34
+
35
+ return count > 1
36
+ end
37
+
38
+ def self.dfs(v)
39
+ @dfi[v.id] = @index
40
+ min = @index
41
+ @index += 1
42
+
43
+ @graph.vertices.each do |u|
44
+ if @graph.has_edge?(v.id, u.id)
45
+ if @dfi[u.id] == 0
46
+ @preds[u.id] = v.id
47
+ dfs(u)
48
+ @apts << v if @low[u.id] >= @dfi[v.id]
49
+ min = @low[u.id] if @low[u.id] < min
50
+ else #found a backedge
51
+ if u.id != @preds[v.id]
52
+ min = @dfi[u.id] if @dfi[u.id] < min
53
+ end
54
+ end
55
+ end
56
+ end
57
+ @low[v.id] = min
58
+ end
59
+ end
@@ -0,0 +1,51 @@
1
+ require_relative 'artc_points'
2
+
3
+ def run_example(example_title, graph)
4
+ puts "------- #{example_title} ------ "
5
+ puts "The graph has #{graph.vertex_count} vertices and #{graph.edge_count} edges"
6
+ apts = ArtcPoints.run(graph)
7
+ puts "Articulation points:"
8
+ apts.each{|v| puts v}
9
+ end
10
+
11
+ def main
12
+ edges = [
13
+ [1,2],[1,8],
14
+ [2,3],[2,7],
15
+ [3,4],
16
+ [4,5],[4,7],[4,6],
17
+ [5,6],
18
+ [7,8]
19
+ ]
20
+ run_example('Example 1', Graph.new(edges:edges))
21
+
22
+ edges = [
23
+ [1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],
24
+ [2,5],[2,6],[2,8],
25
+ [3,4],[3,7]
26
+ ]
27
+ run_example('Example 2', Graph.new(edges:edges))
28
+
29
+ edges = [
30
+ [9,10],[9,13],
31
+ [10,11],[10,12],[10,13],
32
+ [11,12]
33
+ ]
34
+ run_example('Example 3', Graph.new(edges:edges))
35
+
36
+ edges = [[1,2], [2,3], [3,4]]
37
+ run_example('Example 4', Graph.new(edges:edges))
38
+
39
+ edges = [
40
+ [1,2],[1,3],
41
+ [2,3],
42
+ [3,4],[3,5],
43
+ [4,5]
44
+ ]
45
+ run_example('Example 5', Graph.new(edges:edges))
46
+
47
+ edges = [[1,2], [2,3], [3,4], [4,1]]
48
+ run_example('Example 6', Graph.new(edges:edges))
49
+ end
50
+
51
+ main
@@ -0,0 +1,37 @@
1
+ require 'graphsrb'
2
+ include Graphsrb
3
+
4
+ module BackEdges
5
+ def self.run(graph)
6
+ init(graph)
7
+ @graph.vertices.each do |v|
8
+ dfs(v) if @dfi[v.id] == 0
9
+ end
10
+ @forest
11
+ end
12
+
13
+
14
+ def self.init(graph)
15
+ @graph = graph
16
+ @forest = []
17
+ @index = 1
18
+ @dfi = []
19
+
20
+ @graph.vertices.each do |v|
21
+ @dfi[v.id] = 0
22
+ end
23
+ end
24
+
25
+ def self.dfs(v)
26
+ @dfi[v.id] = @index
27
+ @index += 1
28
+
29
+ vertices = @graph.adjacent_vertices(v)
30
+ vertices.each do |u|
31
+ if @dfi[u.id] == 0
32
+ @forest << @graph.edge(v, u)
33
+ dfs(u)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'backedges'
2
+
3
+ def run_example(example_title, graph)
4
+ puts "------- #{example_title} ------ "
5
+ puts "The graph has #{graph.vertex_count} vertices and #{graph.edge_count} edges"
6
+ #Compute forest edges using depth first search algorithm
7
+ forest = BackEdges.run(graph)
8
+ puts "Forest:"
9
+ forest.each{|edge| puts edge}
10
+ #Compute back edges
11
+ bedges = graph.edges - forest
12
+ puts "Back edges:"
13
+ bedges.each{|edge| puts edge}
14
+ end
15
+
16
+ def main
17
+ edges = [
18
+ [1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],
19
+ [2,5],[2,6],[2,8],
20
+ [3,4],[3,7],
21
+ [9,10],[9,13],
22
+ [10,11],[10,12],[10,13],
23
+ [11,12]
24
+ ]
25
+ run_example('Example 1 (undirected graph)', Graph.new(edges:edges))
26
+
27
+ diedges = [
28
+ [1,3],[1,5],
29
+ [2,1],
30
+ [3,2],
31
+ [4,3],
32
+ [5,4],[5,6],
33
+ [6,4],
34
+ [7,8],[7,9],
35
+ [9,6],[9,8]
36
+ ]
37
+
38
+ run_example('Example 2 (directed graph)', Digraph.new(edges:diedges))
39
+ end
40
+
41
+ main
@@ -0,0 +1,34 @@
1
+ require 'graphsrb'
2
+ require_relative '../MaxFlow/edmonds_karp'
3
+ include Graphsrb
4
+
5
+
6
+ module BipartiteMatching
7
+ def self.run(graph, part1)
8
+ init(graph, part1)
9
+ EdmondsKarp.run(@graph, @source, @target)
10
+ end
11
+
12
+ def self.init(graph, part1)
13
+ @graph = Digraph.new
14
+ max_id = graph.vertices.map{|v| v.id}.max
15
+
16
+ @source = Vertex.new(max_id + 1)
17
+ @target = Vertex.new(max_id + 2)
18
+
19
+ @graph.add_vertex(@source.id)
20
+ @graph.add_vertex(@target.id)
21
+
22
+ graph.edges.each do |e|
23
+ u,v = e.initial_vertex, e.terminal_vertex
24
+ u,v = v,u unless part1.include?(e.initial_vertex)
25
+
26
+ # source ==> u
27
+ @graph.add_edge(@source.id, u.id, weight:1)
28
+ # u ==> v
29
+ @graph.add_edge(u.id, v.id, weight:1)
30
+ # v ==> target
31
+ @graph.add_edge(v.id, @target.id, weight:1)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'bipart_matching'
2
+
3
+ def run_example(example_title, graph, part1)
4
+ puts "------- #{example_title} ------ "
5
+ puts "The graph has #{graph.vertex_count} vertices and #{graph.edge_count} edges"
6
+ puts "Size of max bipartite matching: #{BipartiteMatching.run(graph, part1)}"
7
+ end
8
+
9
+ def main
10
+
11
+ edges = [
12
+ [1,2],
13
+ [3,2], [3,6],
14
+ [5,4], [5,6], [5,8],
15
+ [7,6],
16
+ [9,6]
17
+ ]
18
+ part1 = []
19
+ [1,3,5,7,9].each{|id| part1 << Vertex.new(id)}
20
+ run_example('Example 1', Graph.new(edges:edges), part1)
21
+
22
+
23
+ edges = [
24
+ [1,2],
25
+ [3,4],
26
+ [5,6],
27
+ [7,8]
28
+ ]
29
+ part1 = []
30
+ [1,3,5,7].each{|id| part1 << Vertex.new(id)}
31
+ run_example('Example 2', Graph.new(edges:edges), part1)
32
+
33
+ edges = [
34
+ [1,2],
35
+ [3,2],
36
+ [5,2],
37
+ [7,2]
38
+ ]
39
+ part1 = []
40
+ [1,3,5,7].each{|id| part1 << Vertex.new(id)}
41
+ run_example('Example 3', Graph.new(edges:edges), part1)
42
+
43
+
44
+ edges = [
45
+ [1,7],
46
+ [2,6],
47
+ [3,8],
48
+ [4,7],
49
+ [5,9],
50
+ [10,8]
51
+ ]
52
+ part1 = []
53
+ [1,2,3,4,5,10].each{|id| part1 << Vertex.new(id)}
54
+ run_example('Example 4', Graph.new(edges:edges), part1)
55
+
56
+ end
57
+
58
+ main
@@ -0,0 +1,31 @@
1
+ require 'graphsrb'
2
+ require_relative '../MaxFlow/edmonds_karp'
3
+ include Graphsrb
4
+
5
+ # The edge-connectivity λ(G) of a connected graph G is the smallest number of edges
6
+ # whose removal disconnects G.
7
+ module EdgeConnectivity
8
+ MAX_INT = (2**(0.size * 8 -2) -1)
9
+
10
+ def self.run(graph)
11
+ init(graph)
12
+ min_maxflow = MAX_INT
13
+ u = graph.vertices.first
14
+
15
+ graph.vertices.each do |v|
16
+ next if u == v
17
+ maxflow = EdmondsKarp.run(@graph, u, v)
18
+ min_maxflow = maxflow if min_maxflow > maxflow
19
+ end
20
+
21
+ min_maxflow
22
+ end
23
+
24
+ def self.init(graph)
25
+ @graph = Digraph.new
26
+ graph.edges.each do |e|
27
+ @graph.add_edge(e.initial_vertex.id, e.terminal_vertex.id, weight:1)
28
+ @graph.add_edge(e.terminal_vertex.id, e.initial_vertex.id, weight:1)
29
+ end
30
+ end
31
+ end