rgl 0.5.10 → 0.6.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
  SHA256:
3
- metadata.gz: dc32ab84139b87296c8e71d490843c6d90c83257e7876f42f25b23d0ae852cd8
4
- data.tar.gz: 44177136283480e8ba77c431343d7a6361d3ac79e58b1d5864d8a74556ca4bd6
3
+ metadata.gz: fe8f8fb223d89b38255ea2b695204a5fc6f686773c5f127945929d75013ac2bb
4
+ data.tar.gz: 8df8df91c990d1c9bf564069681f9ee1176636ff9507f470db5260032af768b1
5
5
  SHA512:
6
- metadata.gz: 51c96d180f5d570bfcaeaf5653749bf432fbcb3a82e75336f7883c0e45bc48de0d20e2ce6b26238fc9678bc0449e8564d7c1902f1dbd7101f6680d4481847850
7
- data.tar.gz: eb9dcbd3b6ee1d870c2a2afeaab045bc29107ef5b9fc1b9fa2dc356ca5961a87c0bcf8d7d32dca2fb5add0e466598bc167128a4fbebc6f4428970439adfcd02d
6
+ metadata.gz: 7f4caa6a12dc76b702c4f7d0219614d2617861fd331614446731bf2270fa71dd768d2f78d44b1a786c9fb5f9934ec61f1030b77ec16a2922c92f4051b5c9403f
7
+ data.tar.gz: 4343592e3a7bd1bbdfd45ab839a16b38f3dec3d336a0febc1f44876c889b058db052e3dff85323a5f4a10a87293e7ca4f9f05d6b5735a23ce75048c418dff3f8
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
- # Ruby Graph Library (RGL)[![Test](https://github.com/monora/rgl/actions/workflows/test.yml/badge.svg)](https://github.com/monora/rgl/actions/workflows/test.yml) [![Doc](https://github.com/monora/rgl/actions/workflows/doc.yml/badge.svg)](https://github.com/monora/rgl/actions/workflows/doc.yml) [<img src="https://codeclimate.com/github/monora/rgl/badges/coverage.svg" />](https://codeclimate.com/github/monora/rgl/coverage) [<img src="https://badge.fury.io/rb/rgl.svg" alt="Version"/>](https://badge.fury.io/rb/rgl) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/monora/rgl)
1
+ # Ruby Graph Library (RGL)
2
+ [![Test](https://github.com/monora/rgl/actions/workflows/test.yml/badge.svg)](https://github.com/monora/rgl/actions/workflows/test.yml) [![Doc](https://github.com/monora/rgl/actions/workflows/doc.yml/badge.svg)](https://github.com/monora/rgl/actions/workflows/doc.yml)
3
+ [![Version](https://badge.fury.io/rb/rgl.svg)](https://badge.fury.io/rb/rgl)
4
+ [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/monora/rgl)
5
+ [![Code Climate](https://img.shields.io/codeclimate/maintainability/monora/rgl)](https://codeclimate.com/github/monora/rgl)
2
6
 
3
7
  RGL is a framework for graph data structures and algorithms.
4
8
 
data/lib/rgl/adjacency.rb CHANGED
@@ -161,6 +161,7 @@ module RGL
161
161
 
162
162
  end # class AdjacencyGraph
163
163
 
164
+
164
165
  module Graph
165
166
 
166
167
  # Convert a general graph to an AdjacencyGraph. If the graph is directed,
data/lib/rgl/base.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # base.rb
2
2
 
3
3
  # version information
4
- RGL_VERSION = "0.5.10"
4
+ RGL_VERSION = "0.6.0"
5
5
 
6
6
  # Module {RGL} defines the namespace for all modules and classes of the graph
7
7
  # library. The main module is {Graph} which defines the abstract behavior of
@@ -192,6 +192,15 @@ module RGL
192
192
  include?(v) # inherited from enumerable
193
193
  end
194
194
 
195
+ # Returns true if +(u, v)+ is an edge of the graph.
196
+ # @param (see #each_edge)
197
+ def has_edge?(u, v)
198
+ each_adjacent(u) do |w|
199
+ return true if v == w
200
+ end
201
+ return false
202
+ end
203
+
195
204
  # Returns true if the graph has no vertices, i.e. num_vertices == 0.
196
205
  #
197
206
  def empty?
@@ -27,6 +27,7 @@ module RGL
27
27
 
28
28
  end
29
29
 
30
+ # This class implements {Graph#bellman_ford_shortest_paths}.
30
31
  class BellmanFordAlgorithm
31
32
 
32
33
  # Initializes Bellman-Ford algorithm for a _graph_ with provided edges weights map.
@@ -89,6 +90,7 @@ module RGL
89
90
 
90
91
  end # class BellmanFordAlgorithm
91
92
 
93
+
92
94
  module Graph
93
95
 
94
96
  # Finds the shortest paths from the _source_ to each vertex of the graph.
@@ -26,6 +26,20 @@ module RGL
26
26
  yield u
27
27
  end
28
28
 
29
+ alias :each_out_neighbor :each_adjacent
30
+
31
+ def has_in_edge?(u, v)
32
+ raise NotImplementedError
33
+ end
34
+
35
+ alias :has_out_edge? :has_edge?
36
+
37
+ def in_neighbors(v)
38
+ raise NotImplementedError
39
+ end
40
+
41
+ alias :out_neighbors :adjacent_vertices
42
+
29
43
  # Returns the number of in-edges (for directed graphs) or the number of
30
44
  # incident edges (for undirected graphs) of vertex _v_.
31
45
  # @return [int]
@@ -0,0 +1,74 @@
1
+ # bidirectional_adjacency.rb
2
+ #
3
+ require 'rgl/adjacency'
4
+ require 'rgl/bidirectional'
5
+
6
+ module RGL
7
+
8
+ # This implementation of {BidirectionalGraph} creates an internal
9
+ # {DirectedAdjacencyGraph} to store the in-edges and overrides methods
10
+ # to ensure that the out and in graphs remain synchronized.
11
+ #
12
+ class BidirectionalAdjacencyGraph < DirectedAdjacencyGraph
13
+
14
+ include BidirectionalGraph
15
+
16
+ # @see DirectedAdjacencyGraph#initialize
17
+ #
18
+ # In super method the in edges are also added since {add_edge} of this class
19
+ # also inserts edges in `@reverse`.
20
+ def initialize(edgelist_class = Set, *other_graphs)
21
+ @reverse = DirectedAdjacencyGraph.new(edgelist_class)
22
+ super(edgelist_class, *other_graphs)
23
+ end
24
+
25
+ # We don't need to override add_vertex() because the reverse graph doesn't need to
26
+ # contain any unconnected vertices. Vertices will be added by add_edge() as
27
+ # required.
28
+
29
+ # @see MutableGraph#add_edge.
30
+ def add_edge(u, v)
31
+ super(u, v)
32
+ @reverse.add_edge(v, u)
33
+ end
34
+
35
+ # @see MutableGraph#remove_vertex.
36
+ def remove_vertex(v)
37
+ super(v)
38
+ @reverse.remove_vertex(v)
39
+ end
40
+
41
+ # @see MutableGraph::remove_edge.
42
+ def remove_edge(u, v)
43
+ super(u, v)
44
+ @reverse.remove_edge(v, u)
45
+ end
46
+
47
+ # @see Graph#has_edge?
48
+ def has_in_edge?(u, v)
49
+ @reverse.has_edge?(u, v)
50
+ end
51
+
52
+ alias :has_out_edge? :has_edge?
53
+
54
+ # @see BidirectionalGraph#each_in_neighbor
55
+ def each_in_neighbor(v)
56
+ @reverse.each_adjacent(v)
57
+ end
58
+
59
+ alias :each_out_neighbor :each_adjacent
60
+
61
+ def in_neighbors(v)
62
+ @reverse.adjacent_vertices(v)
63
+ end
64
+
65
+ # Returns the number of in-edges (for directed graphs) or the number of
66
+ # incident edges (for undirected graphs) of vertex _v_.
67
+ # @return [int]
68
+ def in_degree(v)
69
+ @reverse.out_degree(v)
70
+ end
71
+
72
+ end
73
+
74
+ end
data/lib/rgl/bipartite.rb CHANGED
@@ -41,6 +41,7 @@ module RGL
41
41
 
42
42
  end # module Graph
43
43
 
44
+
44
45
  class BipartiteBFSIterator < BFSIterator
45
46
 
46
47
  attr_reader :bipartite_sets_map, :found_odd_cycle
data/lib/rgl/dijkstra.rb CHANGED
@@ -6,6 +6,7 @@ require 'pairing_heap'
6
6
 
7
7
  module RGL
8
8
 
9
+ # This class implements {Graph#dijkstra_shortest_path} and {Graph#dijkstra_shortest_paths}
9
10
  class DijkstraAlgorithm
10
11
 
11
12
  # Distance combinator is a lambda that accepts the distance (usually from the source) to vertex _u_ and the weight
@@ -103,6 +104,7 @@ module RGL
103
104
 
104
105
  end # class DijkstraAlgorithm
105
106
 
107
+
106
108
  module Graph
107
109
 
108
110
  # Finds the shortest path from the _source_ to the _target_ in the graph.
@@ -37,6 +37,7 @@ module RGL
37
37
 
38
38
  end # EdgePropertiesMap
39
39
 
40
+
40
41
  class NonNegativeEdgePropertiesMap < EdgePropertiesMap
41
42
 
42
43
  private
@@ -52,4 +53,4 @@ module RGL
52
53
 
53
54
  end
54
55
 
55
- end
56
+ end
@@ -116,6 +116,7 @@ module RGL
116
116
 
117
117
  end # class EdmondsKarpAlgorithm
118
118
 
119
+
119
120
  module Graph
120
121
 
121
122
  # Finds the maximum flow from the _source_ to the _sink_ in the graph.
data/lib/rgl/implicit.rb CHANGED
@@ -97,6 +97,7 @@ module RGL
97
97
 
98
98
  end # class ImplicitGraph
99
99
 
100
+
100
101
  module Graph
101
102
 
102
103
  # Returns a new {ImplicitGraph} which has as vertices all vertices of the
@@ -1,6 +1,6 @@
1
1
  module RGL
2
2
 
3
- class PathBuilder
3
+ class PathBuilder
4
4
 
5
5
  def initialize(source, parents_map)
6
6
  @source = source
data/lib/rgl/prim.rb CHANGED
@@ -34,6 +34,7 @@ module RGL
34
34
 
35
35
  end # class PrimAlgorithm
36
36
 
37
+
37
38
  module Graph
38
39
 
39
40
  # Finds the minimum spanning tree of the graph.
data/lib/rgl/topsort.rb CHANGED
@@ -8,10 +8,10 @@ module RGL
8
8
  #
9
9
  # The topological sort algorithm creates a linear ordering of the vertices
10
10
  # such that if edge (u,v) appears in the graph, then u comes before v in
11
- # the ordering. The graph must be a directed acyclic graph (DAG).
11
+ # the ordering. The graph must be a directed acyclic graph.
12
12
  #
13
13
  # The iterator can also be applied to an undirected graph or to a directed graph
14
- # which contains a cycle. In this case, the Iterator does not reach all
14
+ # which contains a cycle. In this case, the iterator does not reach all
15
15
  # vertices. The implementation of {Graph#acyclic?} uses this fact.
16
16
  #
17
17
  # @see Graph#topsort_iterator
@@ -60,6 +60,7 @@ module RGL
60
60
 
61
61
  end # class TopsortIterator
62
62
 
63
+
63
64
  module Graph
64
65
 
65
66
  # @return [TopsortIterator] for the graph.
data/lib/rgl/traversal.rb CHANGED
@@ -104,6 +104,7 @@ module RGL
104
104
 
105
105
  end # class BFSIterator
106
106
 
107
+
107
108
  module Graph
108
109
 
109
110
  # @return [BFSIterator] starting at vertex _v_.
@@ -161,6 +162,7 @@ module RGL
161
162
 
162
163
  end # class DFSVisitor
163
164
 
165
+
164
166
  module Graph
165
167
 
166
168
  # @return [DFSIterator] staring at vertex _v_.
@@ -0,0 +1,169 @@
1
+ require 'test_helper'
2
+
3
+ require 'rgl/bidirectional_adjacency'
4
+ require 'directed_graph_test'
5
+
6
+ include RGL
7
+ include RGL::Edge
8
+
9
+ class TestBidirectionalAdjacencyGraph < Test::Unit::TestCase
10
+ def setup
11
+ @edges = [[1, 2], [1, 3], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 7], [3, 8],
12
+ [5, 10], [6, 9], [7, 9], [7, 10], [8, 10]]
13
+ @out_neighbors = Hash.new { |h, k| h[k] = Set.new }
14
+ @in_neighbors = Hash.new { |h, k| h[k] = Set.new }
15
+ @edges.each do |e|
16
+ @out_neighbors[e[0]] << e[1]
17
+ @in_neighbors[e[1]] << e[0]
18
+ end
19
+ @dg = BidirectionalAdjacencyGraph.new
20
+ @edges.each do |(src, target)|
21
+ @dg.add_edge(src, target)
22
+ end
23
+ @eg = BidirectionalAdjacencyGraph.new
24
+ @gfa = BidirectionalAdjacencyGraph[1, 2, 3, 4]
25
+ end
26
+
27
+ def test_empty_graph
28
+ assert @eg.empty?
29
+ assert @eg.directed?
30
+ assert(!@eg.has_edge?(2, 1))
31
+ assert(!@eg.has_out_edge?(2, 1))
32
+ assert(!@eg.has_in_edge?(1, 2))
33
+ assert(!@eg.has_vertex?(3))
34
+ # Non existent vertex result in a Name Error because each_key is
35
+ # called for nil
36
+ assert_raises(NoVertexError) { @eg.out_degree(3) }
37
+ assert_raises(NoVertexError) { @eg.in_degree(3) }
38
+ assert_equal([], @eg.vertices)
39
+ assert_equal(0, @eg.size)
40
+ assert_equal(0, @eg.num_vertices)
41
+ assert_equal(0, @eg.num_edges)
42
+ assert_equal(DirectedEdge, @eg.edge_class)
43
+ assert_empty(@eg.edges)
44
+ end
45
+
46
+ def test_add
47
+ @eg.add_edge(1, 2)
48
+ assert(!@eg.empty?)
49
+ assert(@eg.has_edge?(1, 2))
50
+ assert(@eg.has_out_edge?(1, 2))
51
+ assert(@eg.has_in_edge?(2, 1))
52
+ assert(!@eg.has_edge?(2, 1))
53
+ assert(!@eg.has_out_edge?(2, 1))
54
+ assert(!@eg.has_in_edge?(1, 2))
55
+ assert(@eg.has_vertex?(1) && @eg.has_vertex?(2))
56
+ assert(!@eg.has_vertex?(3))
57
+
58
+ assert_equal([1, 2], @eg.vertices.sort)
59
+ assert([DirectedEdge.new(1, 2)].eql?(@eg.edges))
60
+ assert_equal("(1-2)", @eg.edges.join)
61
+
62
+ assert_equal([2], @eg.adjacent_vertices(1))
63
+ assert_equal([2], @eg.out_neighbors(1))
64
+ assert_equal([], @eg.in_neighbors(1))
65
+ assert_equal([], @eg.adjacent_vertices(2))
66
+ assert_equal([], @eg.out_neighbors(2))
67
+ assert_equal([1], @eg.in_neighbors(2))
68
+
69
+ assert_equal(1, @eg.out_degree(1))
70
+ assert_equal(0, @eg.in_degree(1))
71
+ assert_equal(0, @eg.out_degree(2))
72
+ assert_equal(1, @eg.in_degree(2))
73
+ end
74
+
75
+ def test_edges
76
+ assert_equal(14, @dg.edges.length)
77
+ assert_equal(@edges.map { |e| e[0] }.to_set, @dg.edges.map { |l| l.source }.to_set)
78
+ assert_equal(@edges.map { |e| e[1] }.to_set, @dg.edges.map { |l| l.target }.to_set)
79
+ assert_equal("(1-2)(1-3)(2-3)(2-4)(2-5)(2-6)(3-2)(3-7)(3-8)(5-10)(6-9)(7-10)(7-9)(8-10)", @dg.edges.map { |l| l.to_s }.sort.join)
80
+ end
81
+
82
+ def test_vertices
83
+ assert_equal(@edges.flatten.to_set, @dg.vertices.to_set)
84
+ end
85
+
86
+ def test_edges_from_to?
87
+ @edges.each do |u, v|
88
+ assert @dg.has_edge?(u, v)
89
+ assert @dg.has_out_edge?(u, v)
90
+ assert @dg.has_in_edge?(v, u)
91
+ end
92
+ end
93
+
94
+ def test_remove_edges
95
+ @dg.remove_edge 1, 2
96
+ assert !@dg.has_edge?(1, 2)
97
+ assert !@dg.has_out_edge?(1, 2)
98
+ assert !@dg.has_in_edge?(2, 1)
99
+ @dg.remove_edge 1, 2
100
+ assert !@dg.has_edge?(1, 2)
101
+ assert !@dg.has_out_edge?(1, 2)
102
+ assert !@dg.has_in_edge?(2, 1)
103
+ @dg.remove_vertex 3
104
+ assert !@dg.has_vertex?(3)
105
+ assert !@dg.has_edge?(2, 3)
106
+ assert !@dg.has_out_edge?(2, 3)
107
+ assert !@dg.has_in_edge?(3, 2)
108
+ assert_equal('(2-4)(2-5)(2-6)(5-10)(6-9)(7-9)(7-10)(8-10)', @dg.edges.join)
109
+ end
110
+
111
+ def test_add_vertices
112
+ @eg.add_vertices 1, 3, 2, 4
113
+ assert_equal @eg.vertices.sort, [1, 2, 3, 4]
114
+
115
+ @eg.remove_vertices 1, 3
116
+ assert_equal @eg.vertices.sort, [2, 4]
117
+ end
118
+
119
+ def test_creating_from_array
120
+ assert_equal([1, 2, 3, 4], @gfa.vertices.sort)
121
+ assert_equal('(1-2)(3-4)', @gfa.edges.join)
122
+ end
123
+
124
+ def test_creating_from_graphs
125
+ dg2 = BidirectionalAdjacencyGraph.new(Set, @dg, @gfa)
126
+ assert_equal(dg2.vertices.to_set, (@dg.vertices + @gfa.vertices).to_set)
127
+ assert_equal(dg2.edges.to_set, (@dg.edges + @gfa.edges).to_set)
128
+ end
129
+
130
+ def test_reverse
131
+ # Add isolated vertex
132
+ @dg.add_vertex(42)
133
+ reverted = @dg.reverse
134
+
135
+ @dg.each_edge do |u, v|
136
+ assert(reverted.has_edge?(v, u))
137
+ end
138
+
139
+ assert(reverted.has_vertex?(42), 'Reverted graph should contain isolated Vertex 42')
140
+ end
141
+
142
+ def test_to_undirected
143
+ undirected = @dg.to_undirected
144
+ assert_equal '(1=2)(1=3)(2=3)(2=4)(2=5)(2=6)(3=7)(3=8)(5=10)(6=9)(7=9)(7=10)(8=10)', undirected.edges.sort.join
145
+ end
146
+
147
+ def test_neighbors
148
+ @edges.flatten.to_set.each do |v|
149
+ assert_equal @out_neighbors[v], @dg.out_neighbors(v).to_set
150
+ assert_equal @in_neighbors[v], @dg.in_neighbors(v).to_set
151
+ end
152
+ end
153
+
154
+ def test_each_neighbor
155
+ @edges.flatten.to_set.each do |v|
156
+ assert_equal @out_neighbors[v], @dg.each_out_neighbor(v).inject(Set.new) { |s, v| s << v }
157
+ assert_equal @in_neighbors[v], @dg.each_in_neighbor(v).inject(Set.new) { |s, v| s << v }
158
+ end
159
+ end
160
+
161
+ def test_degrees
162
+ @edges.flatten.to_set.each do |v|
163
+ assert_equal @out_neighbors[v].size, @dg.out_degree(v)
164
+ assert_equal @in_neighbors[v].size, @dg.in_degree(v)
165
+ assert_equal @out_neighbors[v].size + @in_neighbors[v].size, @dg.degree(v)
166
+ end
167
+ end
168
+
169
+ end
@@ -11,6 +11,7 @@ class TestDirectedGraph < Test::Unit::TestCase
11
11
  [[1, 2], [2, 3], [3, 2], [2, 4]].each do |(src, target)|
12
12
  @dg.add_edge(src, target)
13
13
  end
14
+ @gfa = DirectedAdjacencyGraph[1, 2, 3, 4]
14
15
  end
15
16
 
16
17
  def test_empty_graph
@@ -86,17 +87,23 @@ class TestDirectedGraph < Test::Unit::TestCase
86
87
 
87
88
  def test_add_vertices
88
89
  dg = DirectedAdjacencyGraph.new
89
- dg.add_vertices 1, 3, 2, 4
90
- assert_equal dg.vertices.sort, [1, 2, 3, 4]
90
+ dg.add_vertices(1, 3, 2, 4)
91
+ assert_equal(dg.vertices.sort, [1, 2, 3, 4])
91
92
 
92
- dg.remove_vertices 1, 3
93
- assert_equal dg.vertices.sort, [2, 4]
93
+ dg.remove_vertices(1, 3)
94
+ assert_equal(dg.vertices.sort, [2, 4])
94
95
  end
95
96
 
96
97
  def test_creating_from_array
97
- dg = DirectedAdjacencyGraph[1, 2, 3, 4]
98
- assert_equal([1, 2, 3, 4], dg.vertices.sort)
99
- assert_equal('(1-2)(3-4)', dg.edges.join)
98
+ assert_equal([1, 2, 3, 4], @gfa.vertices.sort)
99
+ assert_equal('(1-2)(3-4)', @gfa.edges.join)
100
+ end
101
+
102
+ def test_creating_from_graphs
103
+ @gfa.each_edge { |e| @dg.add_edge(e[0], e[1])}
104
+ dg = DirectedAdjacencyGraph.new(Set, @dg, @gfa)
105
+ assert_equal(dg.vertices.to_set, (@dg.vertices + @gfa.vertices).to_set)
106
+ assert_equal(dg.edges.to_set, (@dg.edges + @gfa.edges).to_set)
100
107
  end
101
108
 
102
109
  def test_reverse
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.10
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Horst Duchene
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire: rgl/base
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-01-02 00:00:00.000000000 Z
12
+ date: 2023-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: stream
@@ -191,6 +191,7 @@ files:
191
191
  - lib/rgl/base.rb
192
192
  - lib/rgl/bellman_ford.rb
193
193
  - lib/rgl/bidirectional.rb
194
+ - lib/rgl/bidirectional_adjacency.rb
194
195
  - lib/rgl/bipartite.rb
195
196
  - lib/rgl/condensation.rb
196
197
  - lib/rgl/connected_components.rb
@@ -215,6 +216,7 @@ files:
215
216
  - lib/rgl/traversal.rb
216
217
  - rakelib/dep_graph.rake
217
218
  - test/bellman_ford_test.rb
219
+ - test/bidirectional_graph_test.rb
218
220
  - test/bipartite_test.rb
219
221
  - test/components_test.rb
220
222
  - test/cycles_test.rb