graphunk 0.3.0 → 0.4.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: 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