Skip to content

Commit ce0643b

Browse files
authored
Adding backend to pydatastructs APIs (#435)
In addition to the above, * Removed some of the unused imports * Made doc strings consistent
1 parent 64bb29b commit ce0643b

23 files changed

+630
-121
lines changed

pydatastructs/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
__version__ = "1.0.1-dev"
2-
31
from .linear_data_structures import *
42
from .trees import *
53
from .miscellaneous_data_structures import *
64
from .utils import *
75
from .graphs import *
86
from .strings import *
7+
8+
__version__ = "1.0.1-dev"

pydatastructs/graphs/adjacency_list.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from pydatastructs.graphs.graph import Graph
2-
from pydatastructs.linear_data_structures import DynamicOneDimensionalArray
3-
from pydatastructs.utils.misc_util import GraphEdge
2+
from pydatastructs.utils.misc_util import (
3+
GraphEdge, Backend, raise_if_backend_is_not_python)
44

55
__all__ = [
66
'AdjacencyList'
@@ -15,7 +15,9 @@ class AdjacencyList(Graph):
1515
1616
pydatastructs.graphs.graph.Graph
1717
"""
18-
def __new__(cls, *vertices):
18+
def __new__(cls, *vertices, **kwargs):
19+
raise_if_backend_is_not_python(
20+
cls, kwargs.get('backend', Backend.PYTHON))
1921
obj = object.__new__(cls)
2022
for vertex in vertices:
2123
obj.__setattr__(vertex.name, vertex)

pydatastructs/graphs/adjacency_matrix.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from pydatastructs.graphs.graph import Graph
2-
from pydatastructs.linear_data_structures import OneDimensionalArray
3-
from pydatastructs.utils.misc_util import AdjacencyMatrixGraphNode, GraphEdge
2+
from pydatastructs.utils.misc_util import (
3+
GraphEdge, raise_if_backend_is_not_python,
4+
Backend)
45

56
__all__ = [
67
'AdjacencyMatrix'
@@ -15,7 +16,9 @@ class AdjacencyMatrix(Graph):
1516
1617
pydatastructs.graphs.graph.Graph
1718
"""
18-
def __new__(cls, *vertices):
19+
def __new__(cls, *vertices, **kwargs):
20+
raise_if_backend_is_not_python(
21+
cls, kwargs.get('backend', Backend.PYTHON))
1922
obj = object.__new__(cls)
2023
obj.vertices = [vertex.name for vertex in vertices]
2124
for vertex in vertices:

pydatastructs/graphs/algorithms.py

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"""
55
from collections import deque
66
from concurrent.futures import ThreadPoolExecutor
7-
from pydatastructs.utils import GraphEdge
8-
from pydatastructs.utils.misc_util import _comp
7+
from pydatastructs.utils.misc_util import (
8+
_comp, raise_if_backend_is_not_python, Backend)
99
from pydatastructs.miscellaneous_data_structures import (
1010
DisjointSetForest, PriorityQueue)
1111
from pydatastructs.graphs.graph import Graph
@@ -51,6 +51,10 @@ def breadth_first_search(
5151
current node and the node next to current node.
5252
The rest of the arguments are optional and you can
5353
provide your own stuff there.
54+
backend: pydatastructs.Backend
55+
The backend to be used.
56+
Optional, by default, the best available
57+
backend is used.
5458
5559
Note
5660
====
@@ -75,6 +79,8 @@ def breadth_first_search(
7579
>>> G.add_edge(V2.name, V3.name)
7680
>>> breadth_first_search(G, V1.name, f, V3.name)
7781
"""
82+
raise_if_backend_is_not_python(
83+
breadth_first_search, kwargs.get('backend', Backend.PYTHON))
7884
import pydatastructs.graphs.algorithms as algorithms
7985
func = "_breadth_first_search_" + graph._impl
8086
if not hasattr(algorithms, func):
@@ -133,6 +139,10 @@ def breadth_first_search_parallel(
133139
current node and the node next to current node.
134140
The rest of the arguments are optional and you can
135141
provide your own stuff there.
142+
backend: pydatastructs.Backend
143+
The backend to be used.
144+
Optional, by default, the best available
145+
backend is used.
136146
137147
Note
138148
====
@@ -157,6 +167,8 @@ def breadth_first_search_parallel(
157167
>>> G.add_edge(V2.name, V3.name)
158168
>>> breadth_first_search_parallel(G, V1.name, 3, f, V3.name)
159169
"""
170+
raise_if_backend_is_not_python(
171+
breadth_first_search_parallel, kwargs.get('backend', Backend.PYTHON))
160172
import pydatastructs.graphs.algorithms as algorithms
161173
func = "_breadth_first_search_parallel_" + graph._impl
162174
if not hasattr(algorithms, func):
@@ -256,7 +268,7 @@ def _minimum_spanning_tree_prim_adjacency_list(graph):
256268
e[w] = vw
257269
return mst
258270

259-
def minimum_spanning_tree(graph, algorithm):
271+
def minimum_spanning_tree(graph, algorithm, **kwargs):
260272
"""
261273
Computes a minimum spanning tree for the given
262274
graph and algorithm.
@@ -276,6 +288,10 @@ def minimum_spanning_tree(graph, algorithm):
276288
'kruskal' -> Kruskal's algorithm as given in [1].
277289
278290
'prim' -> Prim's algorithm as given in [2].
291+
backend: pydatastructs.Backend
292+
The backend to be used.
293+
Optional, by default, the best available
294+
backend is used.
279295
280296
Returns
281297
=======
@@ -312,6 +328,8 @@ def minimum_spanning_tree(graph, algorithm):
312328
should be used only for such graphs. Using with other
313329
types of graphs may lead to unwanted results.
314330
"""
331+
raise_if_backend_is_not_python(
332+
minimum_spanning_tree, kwargs.get('backend', Backend.PYTHON))
315333
import pydatastructs.graphs.algorithms as algorithms
316334
func = "_minimum_spanning_tree_" + algorithm + "_" + graph._impl
317335
if not hasattr(algorithms, func):
@@ -390,7 +408,7 @@ def _minimum_spanning_tree_parallel_prim_adjacency_list(graph, num_threads):
390408

391409
return mst
392410

393-
def minimum_spanning_tree_parallel(graph, algorithm, num_threads):
411+
def minimum_spanning_tree_parallel(graph, algorithm, num_threads, **kwargs):
394412
"""
395413
Computes a minimum spanning tree for the given
396414
graph and algorithm using the given number of threads.
@@ -412,6 +430,10 @@ def minimum_spanning_tree_parallel(graph, algorithm, num_threads):
412430
'prim' -> Prim's algorithm as given in [2].
413431
num_threads: int
414432
The number of threads to be used.
433+
backend: pydatastructs.Backend
434+
The backend to be used.
435+
Optional, by default, the best available
436+
backend is used.
415437
416438
Returns
417439
=======
@@ -448,6 +470,8 @@ def minimum_spanning_tree_parallel(graph, algorithm, num_threads):
448470
should be used only for such graphs. Using with other
449471
types of graphs will lead to unwanted results.
450472
"""
473+
raise_if_backend_is_not_python(
474+
minimum_spanning_tree_parallel, kwargs.get('backend', Backend.PYTHON))
451475
import pydatastructs.graphs.algorithms as algorithms
452476
func = "_minimum_spanning_tree_parallel_" + algorithm + "_" + graph._impl
453477
if not hasattr(algorithms, func):
@@ -505,7 +529,7 @@ def _strongly_connected_components_kosaraju_adjacency_list(graph):
505529
_strongly_connected_components_kosaraju_adjacency_matrix = \
506530
_strongly_connected_components_kosaraju_adjacency_list
507531

508-
def strongly_connected_components(graph, algorithm):
532+
def strongly_connected_components(graph, algorithm, **kwargs):
509533
"""
510534
Computes strongly connected components for the given
511535
graph and algorithm.
@@ -523,6 +547,10 @@ def strongly_connected_components(graph, algorithm):
523547
supported,
524548
525549
'kosaraju' -> Kosaraju's algorithm as given in [1].
550+
backend: pydatastructs.Backend
551+
The backend to be used.
552+
Optional, by default, the best available
553+
backend is used.
526554
527555
Returns
528556
=======
@@ -550,6 +578,8 @@ def strongly_connected_components(graph, algorithm):
550578
.. [1] https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
551579
552580
"""
581+
raise_if_backend_is_not_python(
582+
strongly_connected_components, kwargs.get('backend', Backend.PYTHON))
553583
import pydatastructs.graphs.algorithms as algorithms
554584
func = "_strongly_connected_components_" + algorithm + "_" + graph._impl
555585
if not hasattr(algorithms, func):
@@ -583,6 +613,10 @@ def depth_first_search(
583613
current node and the node next to current node.
584614
The rest of the arguments are optional and you can
585615
provide your own stuff there.
616+
backend: pydatastructs.Backend
617+
The backend to be used.
618+
Optional, by default, the best available
619+
backend is used.
586620
587621
Note
588622
====
@@ -612,6 +646,8 @@ def depth_first_search(
612646
613647
.. [1] https://en.wikipedia.org/wiki/Depth-first_search
614648
"""
649+
raise_if_backend_is_not_python(
650+
depth_first_search, kwargs.get('backend', Backend.PYTHON))
615651
import pydatastructs.graphs.algorithms as algorithms
616652
func = "_depth_first_search_" + graph._impl
617653
if not hasattr(algorithms, func):
@@ -646,7 +682,8 @@ def _depth_first_search_adjacency_list(
646682
_depth_first_search_adjacency_matrix = _depth_first_search_adjacency_list
647683

648684
def shortest_paths(graph: Graph, algorithm: str,
649-
source: str, target: str="") -> tuple:
685+
source: str, target: str="",
686+
**kwargs) -> tuple:
650687
"""
651688
Finds shortest paths in the given graph from a given source.
652689
@@ -668,6 +705,10 @@ def shortest_paths(graph: Graph, algorithm: str,
668705
The name of the target node.
669706
Optional, by default, all pair shortest paths
670707
are returned.
708+
backend: pydatastructs.Backend
709+
The backend to be used.
710+
Optional, by default, the best available
711+
backend is used.
671712
672713
Returns
673714
=======
@@ -701,6 +742,8 @@ def shortest_paths(graph: Graph, algorithm: str,
701742
.. [1] https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
702743
.. [2] https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
703744
"""
745+
raise_if_backend_is_not_python(
746+
shortest_paths, kwargs.get('backend', Backend.PYTHON))
704747
import pydatastructs.graphs.algorithms as algorithms
705748
func = "_" + algorithm + "_" + graph._impl
706749
if not hasattr(algorithms, func):
@@ -767,7 +810,8 @@ def _dijkstra_adjacency_list(graph: Graph, start: str, target: str):
767810

768811
_dijkstra_adjacency_matrix = _dijkstra_adjacency_list
769812

770-
def all_pair_shortest_paths(graph: Graph, algorithm: str) -> tuple:
813+
def all_pair_shortest_paths(graph: Graph, algorithm: str,
814+
**kwargs) -> tuple:
771815
"""
772816
Finds shortest paths between all pairs of vertices in the given graph.
773817
@@ -781,6 +825,10 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str) -> tuple:
781825
are implemented,
782826
783827
'floyd_warshall' -> Floyd Warshall algorithm as given in [1].
828+
backend: pydatastructs.Backend
829+
The backend to be used.
830+
Optional, by default, the best available
831+
backend is used.
784832
785833
Returns
786834
=======
@@ -810,6 +858,8 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str) -> tuple:
810858
811859
.. [1] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
812860
"""
861+
raise_if_backend_is_not_python(
862+
all_pair_shortest_paths, kwargs.get('backend', Backend.PYTHON))
813863
import pydatastructs.graphs.algorithms as algorithms
814864
func = "_" + algorithm + "_" + graph._impl
815865
if not hasattr(algorithms, func):
@@ -849,7 +899,8 @@ def _floyd_warshall_adjacency_list(graph: Graph):
849899

850900
_floyd_warshall_adjacency_matrix = _floyd_warshall_adjacency_list
851901

852-
def topological_sort(graph: Graph, algorithm: str) -> list:
902+
def topological_sort(graph: Graph, algorithm: str,
903+
**kwargs) -> list:
853904
"""
854905
Performs topological sort on the given graph using given algorithm.
855906
@@ -863,6 +914,10 @@ def topological_sort(graph: Graph, algorithm: str) -> list:
863914
Currently, following are supported,
864915
865916
'kahn' -> Kahn's algorithm as given in [1].
917+
backend: pydatastructs.Backend
918+
The backend to be used.
919+
Optional, by default, the best available
920+
backend is used.
866921
867922
Returns
868923
=======
@@ -886,6 +941,8 @@ def topological_sort(graph: Graph, algorithm: str) -> list:
886941
887942
.. [1] https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
888943
"""
944+
raise_if_backend_is_not_python(
945+
topological_sort, kwargs.get('backend', Backend.PYTHON))
889946
import pydatastructs.graphs.algorithms as algorithms
890947
func = "_" + algorithm + "_" + graph._impl
891948
if not hasattr(algorithms, func):
@@ -920,7 +977,8 @@ def _kahn_adjacency_list(graph: Graph) -> list:
920977
raise ValueError("Graph is not acyclic.")
921978
return L
922979

923-
def topological_sort_parallel(graph: Graph, algorithm: str, num_threads: int) -> list:
980+
def topological_sort_parallel(graph: Graph, algorithm: str, num_threads: int,
981+
**kwargs) -> list:
924982
"""
925983
Performs topological sort on the given graph using given algorithm using
926984
given number of threads.
@@ -937,6 +995,10 @@ def topological_sort_parallel(graph: Graph, algorithm: str, num_threads: int) ->
937995
'kahn' -> Kahn's algorithm as given in [1].
938996
num_threads: int
939997
The maximum number of threads to be used.
998+
backend: pydatastructs.Backend
999+
The backend to be used.
1000+
Optional, by default, the best available
1001+
backend is used.
9401002
9411003
Returns
9421004
=======
@@ -960,6 +1022,8 @@ def topological_sort_parallel(graph: Graph, algorithm: str, num_threads: int) ->
9601022
9611023
.. [1] https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
9621024
"""
1025+
raise_if_backend_is_not_python(
1026+
topological_sort_parallel, kwargs.get('backend', Backend.PYTHON))
9631027
import pydatastructs.graphs.algorithms as algorithms
9641028
func = "_" + algorithm + "_" + graph._impl + '_parallel'
9651029
if not hasattr(algorithms, func):

pydatastructs/graphs/graph.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
from pydatastructs.utils.misc_util import Backend, raise_if_backend_is_not_python
3+
24
__all__ = [
35
'Graph'
46
]
@@ -24,6 +26,10 @@ class Graph(object):
2426
vertices: GraphNode(s)
2527
For AdjacencyList implementation vertices
2628
can be passed for initializing the graph.
29+
backend: pydatastructs.Backend
30+
The backend to be used.
31+
Optional, by default, the best available
32+
backend is used.
2733
2834
Examples
2935
========
@@ -64,6 +70,8 @@ class Graph(object):
6470
__slots__ = ['_impl']
6571

6672
def __new__(cls, *args, **kwargs):
73+
raise_if_backend_is_not_python(
74+
cls, kwargs.get('backend', Backend.PYTHON))
6775
default_impl = args[0]._impl if args else 'adjacency_list'
6876
implementation = kwargs.get('implementation', default_impl)
6977
if implementation == 'adjacency_list':

0 commit comments

Comments
 (0)