graphunk 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2fbceaea640b3b555fba08b526a211d0078a3dfd
4
- data.tar.gz: 63fd21c8a5e0bf2b5f90de2cc9c848780f7e520a
3
+ metadata.gz: 5c8b58585a2175ae4116953c6f823d0bd3887efc
4
+ data.tar.gz: af62b1d472c236cabcb03b7e1dc1ab44967e89b8
5
5
  SHA512:
6
- metadata.gz: ffd51fc13f3a6c5d9e24ed05ed97f5958c53921b4f28099a924c40fc03006e0fa1a8d618f870fad83e6600ca0975f992b6a343d7d66ec3facc0e5d69114ff99f
7
- data.tar.gz: 91a642dc7941b6697855302dcb5a8924f6864d7401d1b6ad44de9a7a3f5eb89c2bf9a4a5f2fa2998ed0604df706341e6134cccda09c92e60735ada49103abd5f
6
+ metadata.gz: b40e4673e48bc00dcf9b39570da7318ceed67f0fa2308ba9d038820b4155e511144f083afe5ea01714c1d5138b7c4cafe810a69ffdcbfdfb3aa6ba034752d4e9
7
+ data.tar.gz: 15f2947ffea732b89b6f7f53e6963ef565f93bb99a4cd63b93fe2390dcbe988a47f1733b430410ce8a0316a95e2f142986b2f2658ebb63bd1827dfbd30158852
data/README.md CHANGED
@@ -4,18 +4,18 @@ Graphunk defines simple and fully-tested graph classes in Ruby which you can use
4
4
 
5
5
  ## Defining a Graph
6
6
 
7
- There are two kinds of graphs supported by this system, directed graphs and undirected graphs.
7
+ ### Unweighted Graphs
8
8
 
9
- Graphs inherit from Hash, so you can define a graph in the same way you would define a Hash:
9
+ Graphs are internally represented as a hash, so you can define a graph similarly to how you would define a Hash:
10
10
 
11
11
  ```
12
- UndirectedGraph[
12
+ UndirectedGraph.new({
13
13
  'a' => ['b','c'],
14
14
  'b' => ['c', 'd', 'e'],
15
15
  'c' => ['d'],
16
16
  'd' => ['e'],
17
17
  'e' => []
18
- ]
18
+ })
19
19
  ```
20
20
 
21
21
  Each key is a string representing a vertex, and the value is a list
@@ -29,12 +29,12 @@ In a directed graph, the order in an edge matters. A construction of a directed
29
29
  might look like this:
30
30
 
31
31
  ```
32
- DirectedGraph[
32
+ DirectedGraph.new({
33
33
  'a' => ['b','c'],
34
34
  'b' => ['a'],
35
35
  'c' => ['d'],
36
36
  'd' => []
37
- ]
37
+ })
38
38
  ```
39
39
 
40
40
  Graphs can also be built by individually adding edges and vertices.
@@ -46,6 +46,40 @@ graph.add_vertex('b')
46
46
  graph.add_edge('a','b')
47
47
  ```
48
48
 
49
+ ### Weighted Graphs
50
+
51
+ Weighted graphs have an additional property: each edge must specify a numerical weight.
52
+
53
+ To construct a weighted graph, you must pass in the vertex and edge information as well as the weights:
54
+
55
+ ```
56
+ WeightedUndirectedGraph.new({
57
+ 'a' => ['b','c'],
58
+ 'b' => ['c', 'd', 'e'],
59
+ 'c' => ['d'],
60
+ 'd' => ['e'],
61
+ 'e' => []
62
+ },
63
+ {
64
+ ['a','b'] => 2,
65
+ ['a','c'] => 4,
66
+ ['b','c'] => 1,
67
+ ['b','d'] => 4,
68
+ ['b','e'] => 7,
69
+ ['c','d'] => 4,
70
+ ['d','e'] => 3
71
+ })
72
+ ```
73
+
74
+ You can also build them by adding vertices and edges.
75
+ ```
76
+ graph = WeightedUndirectedGraph.new
77
+ graph.add_vertex('a')
78
+ graph.add_vertex('b')
79
+ graph.add_edge('a','b',3)
80
+ ```
81
+ Now the edge 'a-b' will have a weight of 3.
82
+
49
83
  ## Testing
50
84
 
51
85
  To run the test suite simply execute:
@@ -3,7 +3,7 @@ class DirectedGraph < Graph
3
3
  if edge_exists?(first_vertex, second_vertex)
4
4
  raise ArgumentError, "This edge already exists"
5
5
  elsif vertex_exists?(first_vertex) && vertex_exists?(second_vertex)
6
- self[first_vertex] << second_vertex
6
+ @representation[first_vertex] << second_vertex
7
7
  else
8
8
  raise ArgumentError, "One of the vertices referenced does not exist in the graph"
9
9
  end
@@ -11,7 +11,7 @@ class DirectedGraph < Graph
11
11
 
12
12
  def remove_edge(first_vertex, second_vertex)
13
13
  if edge_exists?(first_vertex, second_vertex)
14
- self[first_vertex].delete(second_vertex)
14
+ @representation[first_vertex].delete(second_vertex)
15
15
  else
16
16
  raise ArgumentError, "That edge does not exist in the graph"
17
17
  end
@@ -19,7 +19,7 @@ class DirectedGraph < Graph
19
19
 
20
20
  def neighbors_of_vertex(name)
21
21
  if vertex_exists?(name)
22
- self[name]
22
+ @representation[name]
23
23
  else
24
24
  raise ArgumentError, "That vertex does not exist in the graph"
25
25
  end
@@ -53,9 +53,9 @@ class DirectedGraph < Graph
53
53
 
54
54
  def reachable_by_two_path(start)
55
55
  if vertex_exists?(start)
56
- reached_vertices = self[start]
56
+ reached_vertices = @representation[start]
57
57
  reached_vertices.each do |vertex|
58
- reached_vertices += self[vertex]
58
+ reached_vertices += @representation[vertex]
59
59
  end
60
60
  reached_vertices.uniq
61
61
  else
@@ -1,13 +1,17 @@
1
1
  # this class should not be invoked directly
2
- class Graph < Hash
2
+ class Graph
3
+ def initialize(hash = {})
4
+ @representation = hash
5
+ end
6
+
3
7
  def vertices
4
- keys
8
+ @representation.keys
5
9
  end
6
10
 
7
11
  def edges
8
12
  [].tap do |edge_constructor|
9
13
  vertices.each do |vertex|
10
- self[vertex].each do |neighbor|
14
+ @representation[vertex].each do |neighbor|
11
15
  edge_constructor << [vertex, neighbor]
12
16
  end
13
17
  end
@@ -16,18 +20,26 @@ class Graph < Hash
16
20
 
17
21
  def add_vertex(name)
18
22
  unless vertex_exists?(name)
19
- self[name] = []
23
+ @representation[name] = []
20
24
  else
21
25
  raise ArgumentError, "Vertex already exists"
22
26
  end
23
27
  end
24
28
 
29
+ def add_vertices(*names)
30
+ if (names & vertices).count == 0
31
+ names.each { |name| add_vertex(name) }
32
+ else
33
+ raise ArgumentError, "One or more of the given vertices already exists"
34
+ end
35
+ end
36
+
25
37
  def remove_vertex(name)
26
38
  if vertex_exists?(name)
27
39
  edges.each do |edge|
28
40
  remove_edge(edge.first, edge.last) if edge.include?(name)
29
41
  end
30
- self.delete(name)
42
+ @representation.delete(name)
31
43
  else
32
44
  raise ArgumentError, "That vertex does not exist in the graph"
33
45
  end
@@ -6,7 +6,7 @@ class UndirectedGraph < Graph
6
6
  raise ArgumentError, "This edge already exists"
7
7
  elsif vertex_exists?(first_vertex) && vertex_exists?(second_vertex)
8
8
  ordered_vertices = order_vertices(first_vertex, second_vertex)
9
- self[ordered_vertices.first] << ordered_vertices.last
9
+ @representation[ordered_vertices.first] << ordered_vertices.last
10
10
  else
11
11
  raise ArgumentError, "One of the vertices referenced does not exist in the graph"
12
12
  end
@@ -15,7 +15,7 @@ class UndirectedGraph < Graph
15
15
  def remove_edge(first_vertex, second_vertex)
16
16
  if edge_exists?(first_vertex, second_vertex)
17
17
  ordered_vertices = order_vertices(first_vertex, second_vertex)
18
- self[ordered_vertices.first].delete(ordered_vertices.last)
18
+ @representation[ordered_vertices.first].delete(ordered_vertices.last)
19
19
  else
20
20
  raise ArgumentError, "That edge does not exist in the graph"
21
21
  end
@@ -1,10 +1,10 @@
1
1
  #this class should not be invoked directly
2
2
  class WeightedGraph < Graph
3
3
 
4
- attr_accessor :weights
4
+ attr_reader :weights
5
5
 
6
- def initialize
7
- super
8
- @weights = {}
6
+ def initialize(hash = {}, weights = {})
7
+ @representation = hash
8
+ @weights = weights
9
9
  end
10
10
  end
@@ -5,8 +5,8 @@ class WeightedUndirectedGraph < WeightedGraph
5
5
  raise ArgumentError, "This edge already exists"
6
6
  elsif vertex_exists?(v) && vertex_exists?(u)
7
7
  ordered_vertices = order_vertices(v, u)
8
- self[ordered_vertices.first] << ordered_vertices.last
9
- weights[ordered_vertices] = w
8
+ @representation[ordered_vertices.first] << ordered_vertices.last
9
+ @weights[ordered_vertices] = w
10
10
  else
11
11
  raise ArgumentError, "One of the vertices referenced does not exist in the graph"
12
12
  end
@@ -15,16 +15,20 @@ class WeightedUndirectedGraph < WeightedGraph
15
15
  def remove_edge(v, u)
16
16
  if edge_exists?(v, u)
17
17
  ordered_vertices = order_vertices(v, u)
18
- self[ordered_vertices.first].delete(ordered_vertices.last)
18
+ @representation[ordered_vertices.first].delete(ordered_vertices.last)
19
19
  remove_weight(v, u)
20
20
  else
21
21
  raise ArgumentError, "That edge does not exist in the graph"
22
22
  end
23
23
  end
24
24
 
25
+ def edge_weight(edge)
26
+ @weights[edge]
27
+ end
28
+
25
29
  def adjust_weight(v, u, w)
26
30
  if edge_exists?(v, u)
27
- weights[[v,u]] = w
31
+ @weights[[v,u]] = w
28
32
  else
29
33
  raise ArgumentError, "That edge does not exist in the graph"
30
34
  end
@@ -54,6 +58,6 @@ class WeightedUndirectedGraph < WeightedGraph
54
58
  end
55
59
 
56
60
  def remove_weight(v, u)
57
- weights.delete(order_vertices(v, u))
61
+ @weights.delete(order_vertices(v, u))
58
62
  end
59
63
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphunk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Hemsley