ogr 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83cf5471104a54bfb6ed4f87203f21af7b6c0dc1
4
- data.tar.gz: ecf312736e5b4a2a950fed9157d563625ff2d266
3
+ metadata.gz: ffca6a82d71e20952e078e9805c5ad30bc1bdc73
4
+ data.tar.gz: 8c1e23fc9bfed9e0c4d798318bff2f8f23962307
5
5
  SHA512:
6
- metadata.gz: 7c6a05934278805233e4a72479bd1aa6e1f8d172a25a5498da9c714acf61b9391723205d7a105a2910b87821408d3b9fc9c909ed1bb56fc2d72c23c463c7a5dc
7
- data.tar.gz: 1c56b4b496bb8c60b237599c7c8d06597f5620fda246804f9b097114997ff1a4662b19d0d8e519252c750d6e9f3ddf51e3e2647cc09a6c00d0ecbfafc99253d3
6
+ metadata.gz: d22658bd055558b8678099d3188ac4cfa1dbc8c318fe9b0ca2cdb9d71c8ab436e88eeb4e23f5031cfae0750723188b5c4e37febfa84c40cc344ecb0c0222fff8
7
+ data.tar.gz: 34d97eeaaad02a14e25a129154e47ceefeca43c8af16525ec9fb6eb067660db59dc4ea3084a55eb5b26f5a50e7877001800be076d768968352f9a4c89b83ae42
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
1
  Metrics/LineLength:
2
2
  Max: 100
3
3
 
4
+ Lint/AssignmentInCondition:
5
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,10 +1,19 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.2.2
4
+ - 2.1.5
5
5
  - 2.2.3
6
6
  - 2.3.0
7
7
  - jruby-head
8
+ env:
9
+ - BENCH=false
10
+ - BENCH=true
11
+ matrix:
12
+ exclude:
13
+ rvm: jruby-head
14
+ env: BENCH=true
15
+ allow_failures:
16
+ - env: BENCH=true
8
17
  script:
9
18
  - bundle exec rake
10
19
  before_install:
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Ogr
2
2
 
3
- General graph library for Ruby. Provides sparse(or dense), directed(or undirected) and weighted graphs for Ruby.
3
+ [![Build Status](https://travis-ci.org/knife/ogr.svg?branch=master)](https://travis-ci.org/knife/ogr)
4
+ [![Code Climate](https://codeclimate.com/github/knife/ogr/badges/gpa.svg)](https://codeclimate.com/github/knife/ogr)
5
+
6
+ General graph library for Ruby. Provides sparse(or dense), directed(or undirected) and weighted(or normal) graphs.
7
+ Graph processing algorithms like BFS, DFS, ShortestPaths, MinimumSpanningTree are also included.
8
+ This gem depends only on [DS Gem](https://github.com/knife/ds) which contains other data structures
9
+ not implemented in Ruby Standard Library.
4
10
 
5
11
  ## Installation
6
12
 
@@ -15,7 +21,7 @@ General graph library for Ruby. Provides sparse(or dense), directed(or undirecte
15
21
  graph = Ogr::Graph.new
16
22
  ```
17
23
 
18
- To not have to type "Ogr::" before each class, use:
24
+ To not have to type "Ogr::" before each class:
19
25
 
20
26
  ```ruby
21
27
  include Ogr
@@ -25,47 +31,66 @@ To not have to type "Ogr::" before each class, use:
25
31
 
26
32
  ## Graph
27
33
 
28
- Creating new Graph
34
+ Creating new Graph is easy.
29
35
 
30
- First define edges:
36
+ First define edges(weights are optional):
31
37
 
32
38
  ```ruby
33
39
  edges = []
34
- edges << Edge.new('Jim','Bob')
35
- edges << Edge.new('Jim','Tom')
36
- edges << Edge.new('Bob','Jack')
37
- edges << Edge.new('Tom','Bob')
40
+ edges << Edge.new('Jim','Bob', 12)
41
+ edges << Edge.new('Jim','Tom', 3)
42
+ edges << Edge.new('Bob','Jack', 8)
43
+ edges << Edge.new('Tom','Bob', 5)
38
44
  ```
39
45
  or
40
46
 
41
47
  ```ruby
42
48
  edges = [
43
- ['Jim','Bob'],
44
- ['Jim','Tom'],
45
- ['Bob','Jack'],
46
- ['Tom','Bob']
49
+ ['Jim','Bob', 12],
50
+ ['Jim','Tom', 3],
51
+ ['Bob','Jack', 8],
52
+ ['Tom','Bob', 5]
47
53
  ]
48
54
  ```
49
55
 
50
- New undirected graph (implemented as adjency list)
56
+ Next create new graph:
51
57
 
52
58
  ```ruby
53
59
  graph = Graph.new(edges)
54
60
  ```
55
61
 
56
- New undirected dense graph (implemented as triangular matrix)
62
+ By default graphs are implemented as adjacency lists. This implementation works in most situations.
63
+ However, sometimes triangular matrix may be better choice for internal graph representation (for e.g. dense graphs).
64
+ You can set graph internal representation by passing second argument to initializer or using special constructor.
57
65
 
58
66
  ```ruby
59
- graph = Graph.create(edges)
67
+ graph = Graph.new_dense(edges)
60
68
  ```
61
69
  or
62
70
 
63
71
  ```ruby
64
72
  graph = Graph.new(edges, :tri_matrix)
65
-
66
73
  ```
67
74
 
75
+
76
+ ### Graph API
77
+
78
+ Some methods defined on graph object:
79
+
80
+ * degree
81
+ * edge?
82
+ * add_edge
83
+ * add_edges
84
+ * get_edge
85
+ * vertex_size
86
+ * remove
87
+ * add
88
+ * neighbors
89
+ * vertexes
90
+ * edges
91
+
68
92
  Examples:
93
+
69
94
  ```ruby
70
95
  graph.vertex_size #=> 4
71
96
  graph.degree("Bob") #=> 3
@@ -74,19 +99,22 @@ Examples:
74
99
  graph.add_edge(Edge.new("Bob", "Kate"))
75
100
  graph.remove("Bob", "Jack")
76
101
  graph.neighbors('Tom') #=> ["Bob", "Jim"]
102
+ graph.add("Bob", "Jack")
77
103
  ```
78
104
 
79
- Iterating
105
+ Iterators:
80
106
 
81
107
  ```ruby
82
- graph.each_edge{ |e| p e }
83
- graph.each_vertex{ |v| p v }
108
+ graph.each_edge { |e| p e }
109
+ graph.each_vertex { |v| p v }
84
110
  ```
85
111
 
86
112
 
87
113
  ## Digraph
88
114
 
89
- Directed Weighted Graph
115
+ Digraph (Directed Graph) is graph with directed edges.
116
+
117
+ Creating new directed graph (implemented as adjacency list):
90
118
 
91
119
  ```ruby
92
120
  edges = []
@@ -104,38 +132,94 @@ Directed Weighted Graph
104
132
  edges << Edge.new(:F, :B, 7)
105
133
  ```
106
134
 
107
- New directed graph (implemented as adjency list)
108
-
109
135
  ```ruby
110
- wdigraph = Digraph.new(edges)
136
+ digraph = Digraph.new(edges)
111
137
  ```
112
138
 
113
- New directed dense graph (implemented as matrix)
139
+ New directed dense graph (implemented as matrix):
114
140
  ```ruby
115
- wdigraph = Digraph.create(edges)
141
+ digraph = Digraph.new_dense(edges)
116
142
  ```
117
143
  or
118
144
  ```ruby
119
- wdigraph = Digraph.new(edges, :matrix)
145
+ digraph = Digraph.new(edges, :matrix)
120
146
  ```
121
147
 
148
+ ### Digraph API
149
+
150
+ Digraph inherits from Graph so all methods defined in Graph are available.
151
+ Digraph defines some additional methods specific to directed graphs:
152
+
153
+ * in_degree
154
+ * out_degree
155
+
122
156
  Examples
123
157
  ```ruby
124
- wdigraph.get_edge(:D, :C).weight #=> 11
125
- wdigraph.degree(:E) #=> 4
126
- wdigraph.in_degree(:E) #=> 3
127
- wdigraph.out_degree(:E) #=> 1
158
+ digraph.get_edge(:D, :C).weight #=> 11
159
+ digraph.degree(:E) #=> 4
160
+ digraph.in_degree(:E) #=> 3
161
+ digraph.out_degree(:E) #=> 1
128
162
  ```
129
163
 
130
164
  ## Searching
131
165
 
132
166
  Breadth First Search:
133
167
  ```ruby
134
- BreadthFirstSearch.new(wdigraph).search(:A) #=> [:A, :C, :D, :G, :E, :F, :B]
168
+ BreadthFirstSearch.new(digraph).search(:A) #=> [:A, :C, :D, :G, :E, :F, :B]
135
169
  ```
136
170
 
137
171
  Depth First Search:
138
172
  ```ruby
139
- DepthFirstSearch.new(wdigraph).search(:A) #=> [:A, :G, :B, :E, :D, :C, :F]
140
- `
173
+ DepthFirstSearch.new(digraph).search(:A) #=> [:A, :G, :B, :E, :D, :C, :F]
174
+ ```
175
+
176
+ You can also pass block to search methods:
177
+ ```ruby
178
+ DepthFirstSearch.new(digraph).search(:A) { |v| v.to_s.downcase }
179
+ ```
180
+
181
+ If source vertex is not given, search method iterates over all vertexes in graph.
182
+
183
+ ## Topological Sort
184
+
185
+ Topological Sort sorts vertexes in topological order (all edges in graph points in the same direction).
186
+ Works only for digraphs without cycles (Directed Acyclic Graphs)
187
+
188
+ ```ruby
189
+ TopologicalSort.new(graph).sort #=> array of vertexes in topological order
190
+ ```
191
+
192
+ ## Connected Compontents
193
+
194
+ ConnectedComponents finds all connected components in graph.
195
+
196
+ ```ruby
197
+ cc = ConnectedComponents.new(graph)
198
+ cc.count # => 1
199
+ cc.connected?(:a, :b) # => true
200
+ ```
201
+
202
+ ## Minimum Spanning Tree
203
+
204
+ MinimumSpanningTree finds tree connecting all vertexes in graph with minimal weights.
205
+ Implements Kruskal's algorithm.
206
+
207
+ ```ruby
208
+ tree = MinimumSpanningTree.new(graph).calculate #=> array of edges
209
+ ```
210
+
211
+
212
+ ## Shortest Paths
213
+
214
+ Finds shortest paths from source to all vertexes in graph. Implements Dijkstra's algorithm and
215
+ works only for digraphs with positive weights.
216
+
217
+ Finding shortest paths in graph from vertex 0:
218
+ ```ruby
219
+ sp = ShortestPaths.new(digraph, 0)
220
+ sp.distance_to(7) #=> returns shortest distance from vertex 0 to vertex 7
221
+ sp.has_path?(7) #=> returns true if shortest path to 7 exists
222
+ sp.path_to(4) #=> returns path from vertex 0 to vertex 4 (array of vertexes)
223
+ ```
224
+
141
225
 
data/lib/ogr.rb CHANGED
@@ -9,8 +9,13 @@ require 'ogr/graphs/graph_as_tri_matrix'
9
9
  require 'ogr/graphs/edge_bag'
10
10
  require 'ogr/graphs/graph'
11
11
  require 'ogr/graphs/digraph'
12
- require 'ogr/graphs/breadth_first_search'
13
- require 'ogr/graphs/depth_first_search'
12
+ require 'ogr/breadth_first_search'
13
+ require 'ogr/depth_first_search'
14
+ require 'ogr/topological_sort'
15
+ require 'ogr/connected_components'
16
+ require 'ogr/shortest_pahts'
17
+ require 'ogr/minimum_spanning_tree'
18
+ require 'ogr/union_find'
14
19
 
15
20
  # Main module namespace
16
21
  module Ogr
@@ -1,27 +1,22 @@
1
1
  module Ogr
2
2
  # Class implements Breadth First Search in graphs
3
3
  class BreadthFirstSearch
4
- attr_accessor :parents, :visited, :distance
5
- private :parents=, :visited=, :distance=
4
+ attr_reader :parents, :visited, :distance
6
5
 
7
6
  def initialize(graph)
8
7
  @graph = graph
9
- @colors = {}
8
+ @colors = Hash.new(:white)
10
9
  @parents = {}
11
10
  @visited = []
12
- @distance = {}
11
+ @distance = Hash.new(Float::INFINITY)
13
12
  @to_visit = SimpleQueue.new
14
13
  end
15
14
 
16
- def search(s)
17
- # TODO: Check if source exists in graph
18
- reset!
19
- visit_source(s)
20
- until to_visit.empty?
21
- v = to_visit.dequeue
22
- visit_neighbors(v)
23
- colors[v] = :black
24
- visited << (block_given? ? yield(v) : v)
15
+ def search(source = nil, &block)
16
+ if source
17
+ visit_source(source, &block)
18
+ else
19
+ graph.each_vertex { |v| visit_source(v, &block) unless visited?(v) }
25
20
  end
26
21
  visited
27
22
  end
@@ -30,20 +25,21 @@ module Ogr
30
25
 
31
26
  attr_accessor :graph, :to_visit, :colors
32
27
 
33
- def reset!
34
- self.visited = []
35
- graph.each_vertex do |v|
36
- colors[v] = :white
37
- parents[v] = nil
38
- distance[v] = Float::INFINITY
39
- end
40
- end
41
-
42
28
  def visit_source(s)
43
- colors[s] = :white
44
- parents[s] = nil
45
29
  distance[s] = 0
46
30
  to_visit.enqueue s
31
+ until to_visit.empty?
32
+ v = to_visit.dequeue
33
+ visit_neighbors(v)
34
+ colors[v] = :black
35
+ visited << (block_given? ? yield(v) : v)
36
+ end
37
+ end
38
+
39
+ def visit_neighbors(u)
40
+ graph.neighbors(u).each do |v|
41
+ visit_node(v, u) unless visited?(v)
42
+ end
47
43
  end
48
44
 
49
45
  def visit_node(v, from)
@@ -53,14 +49,8 @@ module Ogr
53
49
  to_visit.enqueue v
54
50
  end
55
51
 
56
- def visit_neighbors(u)
57
- graph.neighbors(u).each do |v|
58
- visit_node(v, u) if not_visited?(v)
59
- end
60
- end
61
-
62
- def not_visited?(v)
63
- colors[v] == :white
52
+ def visited?(v)
53
+ colors[v] != :white
64
54
  end
65
55
  end
66
56
  end
@@ -0,0 +1,58 @@
1
+ module Ogr
2
+ # ConnectedComponents class finds graph components
3
+ class ConnectedComponents
4
+ attr_reader :graph, :visited, :counter, :stack
5
+ private :graph, :visited, :counter, :stack
6
+
7
+ def initialize(graph)
8
+ @graph = graph
9
+ @visited = {}
10
+ @counter = 0
11
+ find_components
12
+ end
13
+
14
+ def connected?(v, u)
15
+ visited[v] == visited[u]
16
+ end
17
+
18
+ def component(v)
19
+ visited[v]
20
+ end
21
+
22
+ def components
23
+ visited
24
+ end
25
+
26
+ def count
27
+ counter
28
+ end
29
+
30
+ private
31
+
32
+ def find_components
33
+ vertexes.each do |v|
34
+ unless visited[v]
35
+ dfs(v)
36
+ @counter += 1
37
+ end
38
+ end
39
+ end
40
+
41
+ def dfs(v)
42
+ @stack = [v]
43
+ while u = stack.pop
44
+ visit(u)
45
+ end
46
+ end
47
+
48
+ def visit(v)
49
+ return if visited[v]
50
+ visited[v] = counter
51
+ stack.concat(graph.neighbors(v))
52
+ end
53
+
54
+ def vertexes
55
+ @vertexes ||= graph.vertexes
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,38 @@
1
+ module Ogr
2
+ # Class implements Depth First Search in graphs
3
+ class DepthFirstSearch
4
+ attr_reader :graph, :stack, :marked, :visited
5
+ private :graph, :stack, :marked
6
+
7
+ def initialize(graph)
8
+ @graph = graph
9
+ @marked = {}
10
+ @visited = []
11
+ end
12
+
13
+ def search(source = nil, &block)
14
+ if source
15
+ dfs(source, &block)
16
+ else
17
+ graph.vertexes.each { |v| dfs(v, &block) unless marked[v] }
18
+ end
19
+ visited
20
+ end
21
+
22
+ private
23
+
24
+ def dfs(v, &block)
25
+ @stack = [v]
26
+ while u = stack.pop
27
+ visit(u, &block)
28
+ end
29
+ end
30
+
31
+ def visit(v)
32
+ return if marked[v]
33
+ visited << (block_given? ? yield(v) : v)
34
+ marked[v] = true
35
+ stack.concat(graph.neighbors(v))
36
+ end
37
+ end
38
+ end
@@ -12,6 +12,7 @@ module Ogr
12
12
  add_edges(edges)
13
13
  end
14
14
 
15
+ # Creates new graph implemented as matrix.
15
16
  def self.new_dense(args)
16
17
  new(args, :matrix)
17
18
  end
@@ -24,15 +24,16 @@ module Ogr
24
24
  new(edges, :tri_matrix)
25
25
  end
26
26
 
27
- # Adds new edge to graph.
27
+ # Creates new edge in graph.
28
28
  def add(x, y, weight = 1)
29
+ weight ||= 1
29
30
  @g.add(push(x), push(y), weight)
30
31
  end
31
32
 
32
33
  # Adds new edges to graph.
33
34
  def add_edges(edges)
34
35
  if edges[0].is_a? Array
35
- edges.each { |e| add(e[0], e[1]) }
36
+ edges.each { |e| add(e[0], e[1], e[2]) }
36
37
  else
37
38
  edges.each { |e| add(e.from, e.to, e.weight) }
38
39
  end
@@ -70,34 +71,45 @@ module Ogr
70
71
  Edge.new(x, y, w) if w
71
72
  end
72
73
 
73
- def vc
74
- (0...vertexes.size)
74
+ # Vertex iterator
75
+ def each_vertex
76
+ vc.each { |v| yield vertexes[v] }
75
77
  end
76
78
 
79
+ # Edge iterator
80
+ def each_edge(&block)
81
+ @g.each_edge(vertexes, &block)
82
+ end
83
+
84
+ # Returns array of all graph vertexes
77
85
  def vertexes
78
86
  @map.to_a
79
87
  end
80
88
 
89
+ # Vertex size
81
90
  def vertex_size
82
91
  vertexes.size
83
92
  end
84
93
 
85
- # Vertex iterator
86
- def each_vertex
87
- vc.each { |v| yield vertexes[v] }
94
+ # Vertex numbers
95
+ def vc
96
+ (0...vertexes.size)
88
97
  end
89
98
 
90
- # Edge iterator
91
- def each_edge(&block)
92
- @g.each_edge(vertexes, &block)
99
+ # Returns array of all graph edges
100
+ def edges
101
+ arr = []
102
+ each_edge { |e| arr << e }
103
+ arr
93
104
  end
94
105
 
95
- private
96
-
106
+ # Internal numeric representation of vertex
97
107
  def index(x)
98
108
  @map.index(x)
99
109
  end
100
110
 
111
+ private
112
+
101
113
  def push(x)
102
114
  @map.push(x)
103
115
  end
@@ -37,6 +37,7 @@ module Ogr
37
37
 
38
38
  # Returns all neighbors for given vertex.
39
39
  def neighbors(x)
40
+ return [] unless @store[x]
40
41
  @store[x].map { |edge| edge[:v] }
41
42
  end
42
43
 
@@ -44,8 +45,7 @@ module Ogr
44
45
  # edges, :out - outcoming edges, :all - incoming and outcoming edges.
45
46
  def degree(x, direction = :all)
46
47
  r = Hash.new(0)
47
- vc = (0..@store.size)
48
- vc.each do |i|
48
+ (0..@store.size).each do |i|
49
49
  r[:in] += 1 if connected?(i, x)
50
50
  r[:out] += 1 if connected?(x, i)
51
51
  end
@@ -0,0 +1,32 @@
1
+ module Ogr
2
+ # Class implements Kruskal algorithm for finding Minimum Spanning Tree
3
+ class MinimumSpanningTree
4
+ attr_reader :graph, :uf
5
+ private :graph, :uf
6
+
7
+ def initialize(graph)
8
+ @graph = graph
9
+ @uf = UnionFind.new(@graph.vertexes.size)
10
+ end
11
+
12
+ def calculate
13
+ tree = []
14
+ while edge = edges.shift
15
+ from = graph.index(edge.from)
16
+ to = graph.index(edge.to)
17
+
18
+ unless uf.connected?(from, to)
19
+ uf.union(from, to)
20
+ tree << edge
21
+ end
22
+ end
23
+ tree
24
+ end
25
+
26
+ private
27
+
28
+ def edges
29
+ @edges ||= @graph.edges.sort_by(&:weight)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,63 @@
1
+ module Ogr
2
+ # Finds shortest paths in graph using Dijkstra algorithm
3
+ class ShortestPaths
4
+ attr_reader :parent, :distance, :graph, :queue
5
+ private :parent, :distance, :graph, :queue
6
+
7
+ def initialize(graph, source)
8
+ @graph = graph
9
+ @queue = IndexedPriorityQueue.min
10
+ @parent = {}
11
+ @distance = {}
12
+ @graph.vertexes.each { |v| @distance[v] = Float::INFINITY }
13
+
14
+ find_paths(source)
15
+ end
16
+
17
+ def distance_to(goal)
18
+ distance[goal]
19
+ end
20
+
21
+ def from(goal)
22
+ parent[goal]
23
+ end
24
+
25
+ def path?(goal)
26
+ distance[goal] < Float::INFINITY
27
+ end
28
+
29
+ def path_to(goal)
30
+ v = goal
31
+ path = [v]
32
+ path.push v while v = parent[v]
33
+ path.reverse
34
+ end
35
+
36
+ def find_paths(source)
37
+ distance[source] = 0
38
+ queue.push(source, 0)
39
+
40
+ while v = queue.shift
41
+ graph.neighbors(v).each do |u|
42
+ relax(graph.get_edge(v, u))
43
+ end
44
+ end
45
+ end
46
+
47
+ def relax(edge)
48
+ new_distance = distance[edge.from] + edge.weight
49
+ found_better(edge, new_distance) if new_distance < distance[edge.to]
50
+ end
51
+
52
+ def found_better(edge, new_distance)
53
+ v = edge.to
54
+ distance[v] = new_distance
55
+ parent[v] = edge.from
56
+ if queue.include?(v)
57
+ queue.update(v, new_distance)
58
+ else
59
+ queue.push(v, new_distance)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,28 @@
1
+ module Ogr
2
+ # Sorts graph vertexes in topological order
3
+ class TopologicalSort
4
+ attr_reader :graph, :sorted, :marked
5
+ private :graph, :sorted, :marked
6
+
7
+ def initialize(graph)
8
+ @graph = graph
9
+ @marked = {}
10
+ @sorted = []
11
+ end
12
+
13
+ def sort
14
+ graph.vertexes.each { |v| dfs(v) unless marked[v] }
15
+ sorted.reverse
16
+ end
17
+
18
+ private
19
+
20
+ def dfs(v)
21
+ marked[v] = true
22
+ graph.neighbors(v).reverse_each do |u|
23
+ dfs(u) unless marked[u]
24
+ end
25
+ sorted.push v
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module Ogr
2
+ # Class implements Union Find algorithm
3
+ class UnionFind
4
+ attr_reader :store, :sizes
5
+ private :store, :sizes
6
+
7
+ def initialize(n)
8
+ @store = (0..n).to_a
9
+ @sizes = [1] * n
10
+ end
11
+
12
+ def connected?(x, y)
13
+ root(x) == root(y)
14
+ end
15
+
16
+ def union(x, y)
17
+ root_x = root(x)
18
+ root_y = root(y)
19
+ if sizes[root_y] > sizes[root_x]
20
+ update_sizes(root_x, root_y)
21
+ else
22
+ update_sizes(root_y, root_x)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def update_sizes(x, y)
29
+ store[x] = y
30
+ sizes[y] += sizes[x]
31
+ end
32
+
33
+ def root(x)
34
+ parent = store[x]
35
+ parent = store[parent] while parent != store[parent]
36
+ parent
37
+ end
38
+ end
39
+ end
data/lib/ogr/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ogr
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
data/ogr.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ['lib']
31
31
 
32
- spec.add_runtime_dependency 'ds', '~> 0.0'
32
+ spec.add_runtime_dependency 'ds', '>= 0.0.7'
33
33
 
34
34
  spec.add_development_dependency 'bundler', '~> 1.11'
35
35
  spec.add_development_dependency 'rake', '~> 10.0'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ogr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - knife
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-02 00:00:00.000000000 Z
11
+ date: 2016-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ds
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0.0'
19
+ version: 0.0.7
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0.0'
26
+ version: 0.0.7
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -83,8 +83,9 @@ files:
83
83
  - bin/console
84
84
  - bin/setup
85
85
  - lib/ogr.rb
86
- - lib/ogr/graphs/breadth_first_search.rb
87
- - lib/ogr/graphs/depth_first_search.rb
86
+ - lib/ogr/breadth_first_search.rb
87
+ - lib/ogr/connected_components.rb
88
+ - lib/ogr/depth_first_search.rb
88
89
  - lib/ogr/graphs/digraph.rb
89
90
  - lib/ogr/graphs/edge.rb
90
91
  - lib/ogr/graphs/edge_bag.rb
@@ -92,6 +93,10 @@ files:
92
93
  - lib/ogr/graphs/graph_as_list.rb
93
94
  - lib/ogr/graphs/graph_as_matrix.rb
94
95
  - lib/ogr/graphs/graph_as_tri_matrix.rb
96
+ - lib/ogr/minimum_spanning_tree.rb
97
+ - lib/ogr/shortest_pahts.rb
98
+ - lib/ogr/topological_sort.rb
99
+ - lib/ogr/union_find.rb
95
100
  - lib/ogr/version.rb
96
101
  - ogr.gemspec
97
102
  homepage: https://github.com/knife/ogr
@@ -1,40 +0,0 @@
1
- module Ogr
2
- # Class implements Breadth First Search in graphs
3
- class DepthFirstSearch
4
- attr_accessor :parents, :visited, :distance, :marked
5
- private :parents=, :visited=, :distance=, :marked=
6
-
7
- def initialize(graph)
8
- @graph = graph
9
- @parents = {}
10
- @marked = {}
11
- @visited = []
12
- @distance = {}
13
- end
14
-
15
- def search(u, &block)
16
- reset!
17
- dfs(u, &block)
18
- visited
19
- end
20
-
21
- def dfs(v, from = nil, &block)
22
- marked[v] = true
23
- visited << (block_given? ? yield(v) : v)
24
- parents[v] = from
25
- graph.neighbors(v).reverse_each do |u|
26
- dfs(u, v, &block) unless marked[u]
27
- end
28
- end
29
-
30
- private
31
-
32
- attr_reader :graph
33
-
34
- def reset!
35
- self.visited = []
36
- self.parents = {}
37
- self.marked = {}
38
- end
39
- end
40
- end