abstract_graph 1.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +13 -5
  2. data/Rakefile +11 -1
  3. data/lib/abstract_graph.rb +1 -0
  4. data/lib/abstract_graph/composition.rb +1 -1
  5. data/lib/abstract_graph/composition/edge.rb +5 -0
  6. data/lib/abstract_graph/composition/edge/initialize.rb +6 -0
  7. data/lib/abstract_graph/composition/edge/is_coincident.rb +5 -2
  8. data/lib/abstract_graph/composition/unique_name_collection.rb +28 -0
  9. data/lib/abstract_graph/composition/unique_name_collection/add.rb +23 -0
  10. data/lib/abstract_graph/composition/unique_name_collection/delete.rb +20 -0
  11. data/lib/abstract_graph/composition/unique_name_collection/dup.rb +24 -0
  12. data/lib/abstract_graph/composition/unique_name_collection/each.rb +18 -0
  13. data/lib/abstract_graph/composition/unique_name_collection/find.rb +18 -0
  14. data/lib/abstract_graph/composition/unique_name_collection/initialize.rb +22 -0
  15. data/lib/abstract_graph/composition/unique_name_collection/link.rb +42 -0
  16. data/lib/abstract_graph/composition/unique_name_collection/method_missing.rb +18 -0
  17. data/lib/abstract_graph/composition/unique_name_collection/rename.rb +34 -0
  18. data/lib/abstract_graph/composition/unique_name_collection/ticket.rb +18 -0
  19. data/lib/abstract_graph/composition/unique_name_collection/ticket/get.rb +20 -0
  20. data/lib/abstract_graph/composition/unique_name_collection/ticket/initialize.rb +20 -0
  21. data/lib/abstract_graph/composition/unique_name_collection/ticket/set.rb +20 -0
  22. data/lib/abstract_graph/composition/vertex.rb +5 -1
  23. data/lib/abstract_graph/composition/vertex/initialize.rb +6 -0
  24. data/lib/abstract_graph/graph.rb +1 -0
  25. data/lib/abstract_graph/graph/add_edge.rb +9 -8
  26. data/lib/abstract_graph/graph/add_vertex.rb +5 -2
  27. data/lib/abstract_graph/graph/adjacency_list.rb +8 -3
  28. data/lib/abstract_graph/graph/change_edge_name.rb +6 -4
  29. data/lib/abstract_graph/graph/change_vertex_name.rb +5 -3
  30. data/lib/abstract_graph/graph/connected.rb +36 -0
  31. data/lib/abstract_graph/graph/delete_edge.rb +5 -4
  32. data/lib/abstract_graph/graph/delete_vertex.rb +5 -4
  33. data/lib/abstract_graph/graph/dup.rb +8 -3
  34. data/lib/abstract_graph/graph/get_edge_name.rb +7 -4
  35. data/lib/abstract_graph/graph/has_edge.rb +6 -3
  36. data/lib/abstract_graph/graph/has_vertex.rb +6 -3
  37. data/lib/abstract_graph/graph/initialize.rb +5 -1
  38. data/lib/abstract_graph/graph/is_adjacent.rb +9 -7
  39. data/lib/abstract_graph/graph/merge_vertices.rb +16 -14
  40. data/lib/abstract_graph/graph/split_vertex.rb +10 -7
  41. data/lib/abstract_graph/graph/templates/complete_bipartite_graph.rb +7 -5
  42. data/lib/abstract_graph/graph/templates/complete_graph.rb +8 -6
  43. data/lib/abstract_graph/graph/templates/cycle_graph.rb +6 -5
  44. data/lib/abstract_graph/graph/templates/path_graph.rb +6 -4
  45. data/lib/abstract_graph/graph/templates/petersen_graph.rb +8 -2
  46. data/lib/abstract_graph/version.rb +1 -1
  47. data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/add_spec.rb +0 -0
  48. data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/dup_spec.rb +0 -0
  49. data/spec/abstract_graph/composition/unique_name_collection/each_spec.rb +38 -0
  50. data/spec/abstract_graph/composition/unique_name_collection/find_spec.rb +33 -0
  51. data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/initialize_spec.rb +0 -0
  52. data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/link_spec.rb +0 -0
  53. data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/method_missing_spec.rb +4 -15
  54. data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/rename_spec.rb +1 -1
  55. data/spec/abstract_graph/composition/{uniquenamecollection_spec.rb → unique_name_collection_spec.rb} +0 -0
  56. data/spec/abstract_graph/graph/add_edge_spec.rb +1 -1
  57. data/spec/abstract_graph/graph/connected_spec.rb +39 -0
  58. data/tasks/benchmark.rb +47 -0
  59. data/tasks/create_method.rb +64 -0
  60. data/tasks/list_methods.rb +5 -0
  61. metadata +45 -32
  62. data/lib/abstract_graph/composition/uniquenamecollection.rb +0 -22
  63. data/lib/abstract_graph/composition/uniquenamecollection/add.rb +0 -19
  64. data/lib/abstract_graph/composition/uniquenamecollection/dup.rb +0 -20
  65. data/lib/abstract_graph/composition/uniquenamecollection/initialize.rb +0 -14
  66. data/lib/abstract_graph/composition/uniquenamecollection/link.rb +0 -32
  67. data/lib/abstract_graph/composition/uniquenamecollection/method_missing.rb +0 -14
  68. data/lib/abstract_graph/composition/uniquenamecollection/rename.rb +0 -28
  69. data/lib/abstract_graph/composition/vertex/delete.rb +0 -12
  70. data/spec/abstract_graph/composition/vertex/delete_spec.rb +0 -12
@@ -8,6 +8,11 @@ module AbstractGraph
8
8
  attr_reader :name
9
9
  attr_accessor :value
10
10
 
11
+ # d: Set the name of vertex.
12
+ # a: Throw an ArgumentError if the name is not a string
13
+ # t: constant
14
+ # p: name should be string
15
+ # r: The name
11
16
  def name=(name)
12
17
  raise ArgumentError if name.class != String
13
18
  @name = name
@@ -18,4 +23,3 @@ module AbstractGraph
18
23
  end
19
24
 
20
25
  require "abstract_graph/composition/vertex/initialize"
21
- require "abstract_graph/composition/vertex/delete"
@@ -4,6 +4,12 @@ module AbstractGraph
4
4
  module Composition
5
5
  class Vertex
6
6
 
7
+ # d: Create a vertex object with a name.
8
+ # a:
9
+ # t: constant
10
+ # p: name is the name of our vertex, default to "",
11
+ # optional value that can be tracked
12
+ # r: The vertex
7
13
  def initialize (name="", value=nil)
8
14
  @name = name
9
15
  @value = value
@@ -31,3 +31,4 @@ require "abstract_graph/graph/merge_vertices"
31
31
  require "abstract_graph/graph/get_edge_name"
32
32
  require "abstract_graph/graph/templates"
33
33
  require "abstract_graph/graph/split_vertex"
34
+ require "abstract_graph/graph/connected"
@@ -3,14 +3,15 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # add a vertex named s to the graph joining
7
- # the vertices named v1 and v2
8
- # p: String s represents name
9
- # Vertex name v1 and v2 are the two vertices
10
- # r: errors when v1, v2 doesn't exist, loop, or multiple edge
6
+ # d: Add an edge to graph.
7
+ # a: Ensure the two vertices exist, then add the edge and check it's not coincident with any
8
+ # other edge.
9
+ # t: |edges|
10
+ # p: s is name of edge, v1 and v2 are names of the two vertices
11
+ # r: returns the graph itself
11
12
  def add_edge( s, v1, v2 )
12
- v1 = @vertices[v1] or return nil
13
- v2 = @vertices[v2] or return nil
13
+ v1 = @vertices.find(v1) or return nil
14
+ v2 = @vertices.find(v2) or return nil
14
15
 
15
16
  raise Exception.new( "AddEdge: Same vertices passed, #{v1.name}" ) if v1 == v2
16
17
 
@@ -18,7 +19,7 @@ module AbstractGraph
18
19
  edge = Edge.new s, v1, v2
19
20
 
20
21
  # check if it's an multiple edge
21
- @edges.each_value do |e|
22
+ @edges.each do |e|
22
23
  raise Exception.new( "AddEdge: Multiple edge being added between #{v1.name}, #{v2.name}" ) if e.is_coincident? edge
23
24
  end
24
25
 
@@ -3,8 +3,11 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # add a vertex named s to the graph
7
- # p: String s represents the name of the wanted vertex
6
+ # d: Add a vertex to graph.
7
+ # a: Adds the new vertex.
8
+ # t: constant
9
+ # p: s is the name of the vertex
10
+ # r: returns the graph itself
8
11
  def add_vertex( s )
9
12
  # create the vertex
10
13
  vertex = Vertex.new s
@@ -3,11 +3,16 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # return the adjacent vertices in of a vertex
7
- # p: String s represents the name of the query vertex
6
+ # d: Return adjacent vertices
7
+ # a: Go through the edges and collect all the vertex names, subtracting our own. Thus, only the
8
+ # 'vertices' tuples that have one vertex left are adjacent since the other vertex got deleted.
9
+ # Then, we can use the remaining array and return it.
10
+ # t: |edges|
11
+ # p: s is the name of vertex
12
+ # r: returns nil if nothing, returns array of adjacent vertices' names
8
13
  def adjacency_list( s )
9
14
  # this collects all the edges at first
10
- result = @edges.collect do |id,e|
15
+ result = @edges.collect do |e|
11
16
  e.vertices.collect do |v|
12
17
  v.name
13
18
  end - [s]
@@ -3,11 +3,13 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # changes an edge name to another valid name
7
- # p: String s represents the current edge we want to rename
8
- # String snew is what we want to rename the edge to
6
+ # d: Change the name of an edge
7
+ # a: Changes the name of an edge by checking existing names and then adding our own
8
+ # t: t(rename), which is |edges + vertex|
9
+ # p: s is current name of edge, snew is requested name of edge
10
+ # r: returns graph if everything goes well, nil if it failed
9
11
  def change_edge_name( s, snew )
10
- return nil if @edges.rename(s, snew).nil?
12
+ return nil unless @edges.rename(s, snew)
11
13
  self
12
14
  end
13
15
 
@@ -3,9 +3,11 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # changes a vertex name to another valid name
7
- # p: String s represents the current vertex we want to rename
8
- # String snew is what we want to rename the vertex to
6
+ # d: Change the name of an vertex
7
+ # a: Changes the name of an vertex by checking existing names and then adding our own
8
+ # t: t(rename), which is |edges + vertex|
9
+ # p: s is current name of vertex, snew is requested name of vertex
10
+ # r: returns graph if everything goes well, nil if it failed
9
11
  def change_vertex_name( s, snew )
10
12
  return nil if @vertices.rename(s, snew).nil?
11
13
  self
@@ -0,0 +1,36 @@
1
+ # required in "abstract_graph/graph"
2
+
3
+ module AbstractGraph
4
+ class Graph
5
+
6
+ # d: Check if graph is connected
7
+ # a: Do a depth first search. So we push the first vertex, and then keep trying to go to adjacent
8
+ # vertices until all of them are seen. In the end, check if the list of seen vertices is the
9
+ # same as the complete vertex list.
10
+ # t: |vertices| * t(adjacency_list) which is |vertices| * |edges|
11
+ # p: none
12
+ # r: returns true if graph is connected, false otherwise
13
+ def connected?
14
+ return true if @vertices.empty?
15
+ seen = []
16
+ toSee = [@vertices.first.name]
17
+
18
+ # go through vertices and if we seen them, don't inspect them
19
+ # essentially does a depth first search
20
+ while !toSee.empty? do
21
+ inspect = toSee.pop
22
+ seen << inspect
23
+
24
+ adjacentVertices = adjacency_list( inspect )
25
+ break if adjacentVertices.nil?
26
+
27
+ # add adjacent vertices if they're not in any of the seen lists
28
+ adjacentVertices.each do |v|
29
+ toSee << v if !seen.include?( v ) && !toSee.include?( v )
30
+ end
31
+ end
32
+ seen.size == @vertices.size
33
+ end
34
+
35
+ end
36
+ end
@@ -3,15 +3,16 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # delete an edge in a replicated graph
7
- # p: String s represents the name of the edge
6
+ # d: Delete an edge.
7
+ # a: Deletes the edge.
8
+ # t: constant
9
+ # p: s is the edge name
10
+ # r: graph itself
8
11
  def delete_edge( s )
9
12
  other = self.dup
10
13
  other.delete_edge! s
11
14
  end
12
15
 
13
- # delete an edge in a current graph
14
- # p: String s represents the name of the edge
15
16
  def delete_edge!( s )
16
17
  @edges.delete s
17
18
  self
@@ -3,15 +3,16 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # delete a vertex in a new graph
7
- # p: String s represents the name of the vertex
6
+ # d: Delete an vertex.
7
+ # a: Deletes the vertex.
8
+ # t: constant
9
+ # p: s is the vertex name
10
+ # r: graph itself
8
11
  def delete_vertex( s )
9
12
  other = self.dup
10
13
  other.delete_vertex! s
11
14
  end
12
15
 
13
- # delete a vertex in a current graph
14
- # p: String s represents the name of the vertex
15
16
  def delete_vertex!( s )
16
17
  @vertices.delete s
17
18
  self
@@ -3,15 +3,20 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # does a deep copy of the graph
6
+ # d: Copies the graph.
7
+ # a: Does a deep copy, but does not dup vertex/edge so modifying them will affect both graphs.
8
+ # Copies vertices then edges.
9
+ # t: |vertices| + |edges|
10
+ # p: none
11
+ # r: returns the copy graph
7
12
  def dup
8
13
  other = self.class.new
9
14
  # cannot call UniqueNameCollection#dup because we'll lose
10
15
  # link data
11
- @vertices.each_value do |v|
16
+ @vertices.each do |v|
12
17
  other.vertices.add v
13
18
  end
14
- @edges.each_value do |e|
19
+ @edges.each do |e|
15
20
  other.edges.add e
16
21
  end
17
22
  other
@@ -3,13 +3,16 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # returns the edge connecting v1 and v2, if there is no
7
- # edge, then it returns nil
8
- # p: String v1, v2 represents the names of the vertices
6
+ # d: Returns the edge name given two vertex names.
7
+ # a: Goes through all the edges and see if any of them have the same vertices as
8
+ # the ones we are requesting.
9
+ # t: |edges|
10
+ # p: the names of the two vertices
11
+ # r: nil if edge if nothing, name of edge(string) if found
9
12
  def get_edge_name( v1, v2 )
10
13
  vertices = [v1, v2].sort!
11
14
 
12
- @edges.each_value do |e|
15
+ @edges.each do |e|
13
16
  eVertices = e.vertices.map do |v|
14
17
  v.name
15
18
  end.sort
@@ -3,10 +3,13 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # returns whether there exists a edge with name string
7
- # p: String s represents name of edge
6
+ # d: Checks if graph has the edge.
7
+ # a: Run find on @edges and existance it.
8
+ # t: constant
9
+ # p: name of edge
10
+ # r: true/false depending if edge with name s exists
8
11
  def has_edge?( s )
9
- @edges.has_key? s || false
12
+ !(@edges.find s).nil?
10
13
  end
11
14
 
12
15
  end
@@ -3,10 +3,13 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # returns whether there exists a vertex with name string
7
- # p: String s represents name of query vertex
6
+ # d: Checks if the graph has the vertex.
7
+ # a: Run find on @vertices and existance it.
8
+ # t: constant
9
+ # p: name of vertex
10
+ # r: true/false depending if vertex with name s exists
8
11
  def has_vertex?( s )
9
- @vertices.has_key? s || false
12
+ !(@vertices.find s).nil?
10
13
  end
11
14
 
12
15
  end
@@ -3,7 +3,11 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # public constructor
6
+ # d: Initializes a graph
7
+ # a: Creates a vertex and edge UNC and links them to share namespace
8
+ # t: constant
9
+ # p:
10
+ # r: new graph
7
11
  def initialize
8
12
 
9
13
  @vertices = UniqueNameCollection.new
@@ -3,17 +3,19 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # returns whether or not v1 and v2 are joined by an edge
7
- # p: String v1, v2 represents the names of the vertices
6
+ # d: Check if two vertices are adjacent.
7
+ # a: Go through the edges and check if any of the edges have the same vertices as the
8
+ # two query vertices
9
+ # t: |edges|
10
+ # p: v1 and v2 are the names of the vertices
11
+ # r: true if the vertices are adjacent, false otherwise
8
12
  def is_adjacent?( v1, v2 )
9
13
  vertices = [v1, v2].sort!
10
14
 
11
- ( @edges.each_value.find do |e|
12
- vertices == e.vertices.map do |v|
13
- v.name
14
- end.sort
15
+ # note find is overridden on uniqueNameCollection
16
+ ( @edges.each.find do |e|
17
+ vertices == e.vertices.map(&:name).sort
15
18
  end && true ) || false
16
-
17
19
  end
18
20
 
19
21
  end
@@ -3,17 +3,20 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # returns a replicated graph where the vertices with names
7
- # v1 and v2 merge together to a vertex named vmerged and
8
- # the edges that were adjacent to v1 and v2 are now
9
- # adjacent to vmerged
6
+ # d: Merges vertices together so that any edges are connected to merged vertex
7
+ # a: First create a list of all edges within the vertices, they will be deleted.
8
+ # Next create a list of edges to create which will be connected to the final
9
+ # vertex. This is done by finding the remaining edges connected to the vertices.
10
+ # Finally, delete the vertices, add the new vertex, and add the edges.
11
+ # t: |vertices| * |edges|
10
12
  # p: (Array, String)
11
- # array is the string names of vertices to merge together
12
- # string is the name of the final vertex
13
+ # array is the string names of vertices to merge together
14
+ # string is the name of the final vertex
13
15
  # (String, String, String)
14
- # first two strings are the vertices to merge together
15
- # last string is the name of the merged vertex
16
- # e: the edges prioritize v1 to v2 if there are any conflicts
16
+ # first two strings are the vertices to merge together
17
+ # last string is the name of the merged vertex
18
+ # r: the graph itself
19
+ # *: the edges prioritize v1 to v2 if there are any conflicts
17
20
  def merge_vertices( *args )
18
21
  other = self.dup
19
22
  other.merge_vertices!( *args )
@@ -21,7 +24,6 @@ module AbstractGraph
21
24
 
22
25
  # same as before except operates on the current graph
23
26
  def merge_vertices!( *args )
24
-
25
27
  # create a list of vertices we want to merge
26
28
  mergeV = []
27
29
  if args[0].class == Array
@@ -36,7 +38,7 @@ module AbstractGraph
36
38
  # do not need to go through the array of vertices
37
39
  edgesInBetween << get_edge_name( args[0], args[1] )
38
40
  else
39
- edgesInBetween = @edges.values.collect do |e|
41
+ edgesInBetween = @edges.collect do |e|
40
42
  e.name if ( e.vertices.map do |v|
41
43
  v.name
42
44
  end & mergeV ).count == 2
@@ -51,15 +53,15 @@ module AbstractGraph
51
53
  # get the list of connections we want vmerged to be merged with
52
54
  finalConnections = {}
53
55
  mergeV.reverse.each do |vCheck|
54
- @edges.each do |name, e|
56
+ @edges.each do |e|
55
57
  [0,1].each do |edgeVId|
56
58
 
57
59
  # check if the edge contains our vertex
58
60
  if e.vertices[edgeVId].name == vCheck
59
61
  otherVertex = e.vertices[(edgeVId+1)%2].name
60
62
  # track the vertex with the edge name
61
- finalConnections[otherVertex] = name
62
- delete_edge! name
63
+ finalConnections[otherVertex] = e.name
64
+ delete_edge! e.name
63
65
  end
64
66
 
65
67
  end
@@ -3,10 +3,13 @@
3
3
  module AbstractGraph
4
4
  class Graph
5
5
 
6
- # returns a replicated graph where all the vertices are the same but one
7
- # gets split and all it's adjacent vertices are now connected to two replaced vertices
8
- # p: String s the name of the vertex that will be split into vertexName-1 and vertexName-2
9
- # all adjacent edges will also be split and adjacent to the correct vertex
6
+ # d: Split a vertex into two and assign adjacent to each of the vertices.
7
+ # a: Gathers a list of adjacent vertices by going through the edges, then
8
+ # deletes the vertex and all the adjacent edges. Then goes back, creates
9
+ # two vertices, and recreates all the adjacent edges.
10
+ # t: |edges|
11
+ # p: name of vertex to split
12
+ # r: graph itself
10
13
  def split_vertex( s )
11
14
  other = self.dup
12
15
  other.split_vertex!( s )
@@ -15,10 +18,10 @@ module AbstractGraph
15
18
 
16
19
  # same as before except operates on the current graph
17
20
  def split_vertex!( s )
18
- adjacentVertices = @edges.dup.keep_if do |id, e|
21
+ adjacentVertices = @edges.dup.keep_if do |e|
19
22
  e.vertices.collect(&:name).include? s
20
- end.collect do |id, e|
21
- [id, ( e.vertices.collect(&:name) - [s] )[0] ]
23
+ end.collect do |e|
24
+ [ e.name, ( e.vertices.collect(&:name) - [s] )[0] ]
22
25
  end
23
26
 
24
27
  delete_vertex! s
@@ -4,11 +4,13 @@ module AbstractGraph
4
4
  class Graph
5
5
  class << self
6
6
 
7
- # create a connected graph with two sets of vertices where
8
- # the two sets only have vertices adjacent to the other set
9
- # p: the number of vertices in the two sets. the first set has
10
- # n vertices from 2**(0..n-1) and the second set has m
11
- # vertices from 2**(n**m+n-1)
7
+ # d: Create a complete bipartite graph K(n,m).
8
+ # a: It first adds the vertices, then adds the edges. The vertices are named "v(2^i)" from
9
+ # the first set being i=2^0..n-1, and the second set i=2^n..m+n-1. The edges are sums "e(i)"
10
+ # where i=sum of two vertices
11
+ # t: n * m * t(add_edge) + max(n,m) * t(add_vertex)
12
+ # p: n is the number of vertices in the first set, m is number of vertices in second set
13
+ # r: a complete bipartite graph
12
14
  def complete_bipartite_graph n, m
13
15
  result = new
14
16