diff --git a/README.md b/README.md index 09e9b6dc9..803c88b0e 100644 --- a/README.md +++ b/README.md @@ -101,11 +101,11 @@ Keep contributing!! Thanks to these wonderful people ✨✨: - - - + + +
- - - -
+ + + +
diff --git a/pydatastructs/graphs/adjacency_list.py b/pydatastructs/graphs/adjacency_list.py index a06e35533..541ff3a1e 100644 --- a/pydatastructs/graphs/adjacency_list.py +++ b/pydatastructs/graphs/adjacency_list.py @@ -26,8 +26,8 @@ def __new__(cls, *vertices): @classmethod def methods(self): return ['is_adjacent', 'neighbors', - 'add_vertex', 'remove_vertex', 'add_edge', - 'get_edge', 'remove_edge', '__new__'] + 'add_vertex', 'remove_vertex', 'add_edge', + 'get_edge', 'remove_edge', '__new__'] def is_adjacent(self, node1, node2): node1 = self.__getattribute__(node1) @@ -52,8 +52,21 @@ def remove_vertex(self, name): node_obj.adjacent.remove(name) def add_edge(self, source, target, cost=None): + source, target = str(source), str(target) + error_msg = ("Vertex %s is not present in the graph." + "Call Graph.add_vertex to add a new" + "vertex. Graph.add_edge is only responsible" + "for adding edges and it will not add new" + "vertices on its own. This is done to maintain" + "clear separation between the functionality of" + "these two methods.") + if not hasattr(self, source): + raise ValueError(error_msg % (source)) + if not hasattr(self, target): + raise ValueError(error_msg % (target)) + source, target = self.__getattribute__(source), \ - self.__getattribute__(target) + self.__getattribute__(target) source.add_adjacent_node(target.name) if cost is not None: self.edge_weights[source.name + "_" + target.name] = \ diff --git a/pydatastructs/graphs/adjacency_matrix.py b/pydatastructs/graphs/adjacency_matrix.py index a75efabdf..64a39494c 100644 --- a/pydatastructs/graphs/adjacency_matrix.py +++ b/pydatastructs/graphs/adjacency_matrix.py @@ -57,6 +57,18 @@ def remove_vertex(self, node): def add_edge(self, source, target, cost=None): source, target = str(source), str(target) + error_msg = ("Vertex %s is not present in the graph." + "Call Graph.add_vertex to add a new" + "vertex. Graph.add_edge is only responsible" + "for adding edges and it will not add new" + "vertices on its own. This is done to maintain" + "clear separation between the functionality of" + "these two methods.") + if source not in self.matrix: + raise ValueError(error_msg % (source)) + if target not in self.matrix: + raise ValueError(error_msg % (target)) + self.matrix[source][target] = True if cost is not None: self.edge_weights[source + "_" + target] = \ diff --git a/pydatastructs/graphs/graph.py b/pydatastructs/graphs/graph.py index f19fc8e97..0c1b195a8 100644 --- a/pydatastructs/graphs/graph.py +++ b/pydatastructs/graphs/graph.py @@ -49,6 +49,16 @@ class Graph(object): ========== .. [1] https://en.wikipedia.org/wiki/Graph_(abstract_data_type) + + Note + ==== + + Make sure to create nodes (AdjacencyListGraphNode or AdjacencyMatrixGraphNode) + and them in your graph using Graph.add_vertex before adding edges whose + end points require either of the nodes that you added. In other words, + Graph.add_edge doesn't add new nodes on its own if the input + nodes are not already present in the Graph. + """ __slots__ = ['_impl'] @@ -89,7 +99,8 @@ def neighbors(self, node): def add_vertex(self, node): """ - Adds the input vertex to the node. + Adds the input vertex to the node, or does nothing + if the input vertex is already in the graph. """ raise NotImplementedError( "This is an abstract method.") @@ -97,7 +108,7 @@ def add_vertex(self, node): def remove_vertex(self, node): """ Removes the input vertex along with all the edges - pointing towards to it. + pointing towards it. """ raise NotImplementedError( "This is an abstract method.") diff --git a/pydatastructs/graphs/tests/test_adjacency_list.py b/pydatastructs/graphs/tests/test_adjacency_list.py index d1635fc83..3dcef8a7a 100644 --- a/pydatastructs/graphs/tests/test_adjacency_list.py +++ b/pydatastructs/graphs/tests/test_adjacency_list.py @@ -1,5 +1,6 @@ from pydatastructs.graphs import Graph from pydatastructs.utils import AdjacencyListGraphNode +from pydatastructs.utils.raises_util import raises def test_adjacency_list(): v_1 = AdjacencyListGraphNode('v_1', 1) @@ -38,3 +39,6 @@ def test_adjacency_list(): g.remove_vertex('v') assert g.is_adjacent('v_2', 'v') is False assert g.is_adjacent('v_3', 'v') is False + + assert raises(ValueError, lambda: g.add_edge('u', 'v')) + assert raises(ValueError, lambda: g.add_edge('v', 'x')) diff --git a/pydatastructs/graphs/tests/test_adjacency_matrix.py b/pydatastructs/graphs/tests/test_adjacency_matrix.py index 3df819611..c0f7b7c06 100644 --- a/pydatastructs/graphs/tests/test_adjacency_matrix.py +++ b/pydatastructs/graphs/tests/test_adjacency_matrix.py @@ -1,5 +1,6 @@ from pydatastructs.graphs import Graph from pydatastructs.utils import AdjacencyMatrixGraphNode +from pydatastructs.utils.raises_util import raises def test_AdjacencyMatrix(): v_0 = AdjacencyMatrixGraphNode(0, 0) @@ -25,3 +26,6 @@ def test_AdjacencyMatrix(): assert neighbors == [v_1] g.remove_edge(0, 1) assert g.is_adjacent(0, 1) is False + + assert raises(ValueError, lambda: g.add_edge('u', 'v')) + assert raises(ValueError, lambda: g.add_edge('v', 'x')) diff --git a/pydatastructs/linear_data_structures/arrays.py b/pydatastructs/linear_data_structures/arrays.py index 32fa0ee42..e4bc24223 100644 --- a/pydatastructs/linear_data_structures/arrays.py +++ b/pydatastructs/linear_data_structures/arrays.py @@ -15,7 +15,8 @@ def __str__(self) -> str: class OneDimensionalArray(Array): ''' - Represents one dimensional arrays. + Represents one dimensional static arrays of + fixed size. Parameters ========== @@ -269,7 +270,8 @@ class DynamicArray(Array): class DynamicOneDimensionalArray(DynamicArray, OneDimensionalArray): """ - Represents dynamic one dimensional arrays. + Represents resizable and dynamic one + dimensional arrays. Parameters ==========