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.
- checksums.yaml +13 -5
- data/Rakefile +11 -1
- data/lib/abstract_graph.rb +1 -0
- data/lib/abstract_graph/composition.rb +1 -1
- data/lib/abstract_graph/composition/edge.rb +5 -0
- data/lib/abstract_graph/composition/edge/initialize.rb +6 -0
- data/lib/abstract_graph/composition/edge/is_coincident.rb +5 -2
- data/lib/abstract_graph/composition/unique_name_collection.rb +28 -0
- data/lib/abstract_graph/composition/unique_name_collection/add.rb +23 -0
- data/lib/abstract_graph/composition/unique_name_collection/delete.rb +20 -0
- data/lib/abstract_graph/composition/unique_name_collection/dup.rb +24 -0
- data/lib/abstract_graph/composition/unique_name_collection/each.rb +18 -0
- data/lib/abstract_graph/composition/unique_name_collection/find.rb +18 -0
- data/lib/abstract_graph/composition/unique_name_collection/initialize.rb +22 -0
- data/lib/abstract_graph/composition/unique_name_collection/link.rb +42 -0
- data/lib/abstract_graph/composition/unique_name_collection/method_missing.rb +18 -0
- data/lib/abstract_graph/composition/unique_name_collection/rename.rb +34 -0
- data/lib/abstract_graph/composition/unique_name_collection/ticket.rb +18 -0
- data/lib/abstract_graph/composition/unique_name_collection/ticket/get.rb +20 -0
- data/lib/abstract_graph/composition/unique_name_collection/ticket/initialize.rb +20 -0
- data/lib/abstract_graph/composition/unique_name_collection/ticket/set.rb +20 -0
- data/lib/abstract_graph/composition/vertex.rb +5 -1
- data/lib/abstract_graph/composition/vertex/initialize.rb +6 -0
- data/lib/abstract_graph/graph.rb +1 -0
- data/lib/abstract_graph/graph/add_edge.rb +9 -8
- data/lib/abstract_graph/graph/add_vertex.rb +5 -2
- data/lib/abstract_graph/graph/adjacency_list.rb +8 -3
- data/lib/abstract_graph/graph/change_edge_name.rb +6 -4
- data/lib/abstract_graph/graph/change_vertex_name.rb +5 -3
- data/lib/abstract_graph/graph/connected.rb +36 -0
- data/lib/abstract_graph/graph/delete_edge.rb +5 -4
- data/lib/abstract_graph/graph/delete_vertex.rb +5 -4
- data/lib/abstract_graph/graph/dup.rb +8 -3
- data/lib/abstract_graph/graph/get_edge_name.rb +7 -4
- data/lib/abstract_graph/graph/has_edge.rb +6 -3
- data/lib/abstract_graph/graph/has_vertex.rb +6 -3
- data/lib/abstract_graph/graph/initialize.rb +5 -1
- data/lib/abstract_graph/graph/is_adjacent.rb +9 -7
- data/lib/abstract_graph/graph/merge_vertices.rb +16 -14
- data/lib/abstract_graph/graph/split_vertex.rb +10 -7
- data/lib/abstract_graph/graph/templates/complete_bipartite_graph.rb +7 -5
- data/lib/abstract_graph/graph/templates/complete_graph.rb +8 -6
- data/lib/abstract_graph/graph/templates/cycle_graph.rb +6 -5
- data/lib/abstract_graph/graph/templates/path_graph.rb +6 -4
- data/lib/abstract_graph/graph/templates/petersen_graph.rb +8 -2
- data/lib/abstract_graph/version.rb +1 -1
- data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/add_spec.rb +0 -0
- data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/dup_spec.rb +0 -0
- data/spec/abstract_graph/composition/unique_name_collection/each_spec.rb +38 -0
- data/spec/abstract_graph/composition/unique_name_collection/find_spec.rb +33 -0
- data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/initialize_spec.rb +0 -0
- data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/link_spec.rb +0 -0
- data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/method_missing_spec.rb +4 -15
- data/spec/abstract_graph/composition/{uniquenamecollection → unique_name_collection}/rename_spec.rb +1 -1
- data/spec/abstract_graph/composition/{uniquenamecollection_spec.rb → unique_name_collection_spec.rb} +0 -0
- data/spec/abstract_graph/graph/add_edge_spec.rb +1 -1
- data/spec/abstract_graph/graph/connected_spec.rb +39 -0
- data/tasks/benchmark.rb +47 -0
- data/tasks/create_method.rb +64 -0
- data/tasks/list_methods.rb +5 -0
- metadata +45 -32
- data/lib/abstract_graph/composition/uniquenamecollection.rb +0 -22
- data/lib/abstract_graph/composition/uniquenamecollection/add.rb +0 -19
- data/lib/abstract_graph/composition/uniquenamecollection/dup.rb +0 -20
- data/lib/abstract_graph/composition/uniquenamecollection/initialize.rb +0 -14
- data/lib/abstract_graph/composition/uniquenamecollection/link.rb +0 -32
- data/lib/abstract_graph/composition/uniquenamecollection/method_missing.rb +0 -14
- data/lib/abstract_graph/composition/uniquenamecollection/rename.rb +0 -28
- data/lib/abstract_graph/composition/vertex/delete.rb +0 -12
- 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
|
data/lib/abstract_graph/graph.rb
CHANGED
@@ -3,14 +3,15 @@
|
|
3
3
|
module AbstractGraph
|
4
4
|
class Graph
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
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
|
13
|
-
v2 = @vertices
|
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.
|
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
|
-
#
|
7
|
-
#
|
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
|
-
#
|
7
|
-
#
|
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 |
|
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
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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
|
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
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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
|
-
#
|
7
|
-
#
|
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
|
-
#
|
7
|
-
#
|
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
|
-
#
|
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.
|
16
|
+
@vertices.each do |v|
|
12
17
|
other.vertices.add v
|
13
18
|
end
|
14
|
-
@edges.
|
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
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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.
|
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
|
-
#
|
7
|
-
#
|
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.
|
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
|
-
#
|
7
|
-
#
|
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.
|
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
|
-
#
|
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
|
-
#
|
7
|
-
#
|
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
|
-
|
12
|
-
|
13
|
-
|
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
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
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
|
-
#
|
12
|
-
#
|
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
|
-
#
|
15
|
-
#
|
16
|
-
#
|
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.
|
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 |
|
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
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
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 |
|
21
|
+
adjacentVertices = @edges.dup.keep_if do |e|
|
19
22
|
e.vertices.collect(&:name).include? s
|
20
|
-
end.collect do |
|
21
|
-
[
|
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
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
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
|
|