abstract_graph 1.1.0 → 1.2.1

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.
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