def __new__(cls, comp, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) obj.items = BinaryHeap() obj.items._comp = comp return obj
def __new__(cls, elements=None, heap_property="min", d=4, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) obj = Heap.__new__(cls) obj.heap_property = heap_property obj.d = d if heap_property == "min": obj._comp = lambda key_parent, key_child: key_parent <= key_child elif heap_property == "max": obj._comp = lambda key_parent, key_child: key_parent >= key_child else: raise ValueError("%s is invalid heap property" % (heap_property)) if elements is None: elements = DynamicOneDimensionalArray(TreeNode, 0) elif _check_type(elements, (list, tuple)): elements = DynamicOneDimensionalArray(TreeNode, len(elements), elements) elif _check_type(elements, Array): elements = DynamicOneDimensionalArray(TreeNode, len(elements), elements._data) else: raise ValueError( f'Expected a list/tuple/Array of TreeNode got {type(elements)}' ) obj.heap = elements obj._last_pos_filled = obj.heap._last_pos_filled obj._build() return obj
def __new__(cls, comp, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) obj.items = SinglyLinkedList() obj.comp = comp return obj
def strongly_connected_components(graph, algorithm, **kwargs): """ Computes strongly connected components for the given graph and algorithm. Parameters ========== graph: Graph The graph whose minimum spanning tree has to be computed. algorithm: str The algorithm which should be used for computing strongly connected components. Currently the following algorithms are supported, 'kosaraju' -> Kosaraju's algorithm as given in [1]. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= components: list Python list with each element as set of vertices. Examples ======== >>> from pydatastructs import Graph, AdjacencyListGraphNode >>> from pydatastructs import strongly_connected_components >>> v1, v2, v3 = [AdjacencyListGraphNode(i) for i in range(3)] >>> g = Graph(v1, v2, v3) >>> g.add_edge(v1.name, v2.name) >>> g.add_edge(v2.name, v3.name) >>> g.add_edge(v3.name, v1.name) >>> scc = strongly_connected_components(g, 'kosaraju') >>> scc == [{'2', '0', '1'}] True References ========== .. [1] https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm """ raise_if_backend_is_not_python( strongly_connected_components, kwargs.get('backend', Backend.PYTHON)) import pydatastructs.graphs.algorithms as algorithms func = "_strongly_connected_components_" + algorithm + "_" + graph._impl if not hasattr(algorithms, func): raise NotImplementedError( "Currently %s algoithm for %s implementation of graphs " "isn't implemented for finding strongly connected components." %(algorithm, graph._impl)) return getattr(algorithms, func)(graph)
def is_ordered(array, **kwargs): """ Checks whether the given array is ordered or not. Parameters ========== array: OneDimensionalArray The array which is to be checked for having specified ordering among its elements. start: int The starting index of the portion of the array under consideration. Optional, by default 0 end: int The ending index of the portion of the array under consideration. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for specifying the desired ordering. Optional, by default, less than or equal to is used for comparing two values. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= True if the specified ordering is present from start to end (inclusive) otherwise False. Examples ======== >>> from pydatastructs import OneDimensionalArray, is_ordered >>> arr = OneDimensionalArray(int, [1, 2, 3, 4]) >>> is_ordered(arr) True >>> arr1 = OneDimensionalArray(int, [1, 2, 3]) >>> is_ordered(arr1, start=0, end=1, comp=lambda u, v: u > v) False """ raise_if_backend_is_not_python(is_ordered, kwargs.get('backend', Backend.PYTHON)) lower = kwargs.get('start', 0) upper = kwargs.get('end', len(array) - 1) comp = kwargs.get("comp", lambda u, v: u <= v) for i in range(lower + 1, upper + 1): if array[i] is None or array[i - 1] is None: continue if comp(array[i], array[i - 1]): return False return True
def __new__(cls, **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) obj = LinkedList.__new__(cls) obj.head = None obj.tail = None obj.size = 0 return obj
def __new__(cls, array, func, **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) sparse_table = SparseTable(array, func) obj.bounds = (0, len(array)) obj.sparse_table = sparse_table return obj
def __new__(cls, *vertices, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) for vertex in vertices: obj.__setattr__(vertex.name, vertex) obj.vertices = [vertex.name for vertex in vertices] obj.edge_weights = {} return obj
def __new__(cls, **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) obj.head, obj.tail = None, None obj._num_nodes = 0 obj._levels = 0 obj._add_level() return obj
def all_pair_shortest_paths(graph: Graph, algorithm: str, **kwargs) -> tuple: """ Finds shortest paths between all pairs of vertices in the given graph. Parameters ========== graph: Graph The graph under consideration. algorithm: str The algorithm to be used. Currently, the following algorithms are implemented, 'floyd_warshall' -> Floyd Warshall algorithm as given in [1]. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= (distances, predecessors): (dict, dict) Examples ======== >>> from pydatastructs import Graph, AdjacencyListGraphNode >>> from pydatastructs import all_pair_shortest_paths >>> V1 = AdjacencyListGraphNode("V1") >>> V2 = AdjacencyListGraphNode("V2") >>> V3 = AdjacencyListGraphNode("V3") >>> G = Graph(V1, V2, V3) >>> G.add_edge('V2', 'V3', 10) >>> G.add_edge('V1', 'V2', 11) >>> G.add_edge('V3', 'V1', 5) >>> dist, _ = all_pair_shortest_paths(G, 'floyd_warshall') >>> dist['V1']['V3'] 21 >>> dist['V3']['V1'] 5 References ========== .. [1] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm """ raise_if_backend_is_not_python( all_pair_shortest_paths, kwargs.get('backend', Backend.PYTHON)) import pydatastructs.graphs.algorithms as algorithms func = "_" + algorithm + "_" + graph._impl if not hasattr(algorithms, func): raise NotImplementedError( "Currently %s algorithm isn't implemented for " "finding shortest paths in graphs."%(algorithm)) return getattr(algorithms, func)(graph)
def linear_search(array, value, **kwargs): """ Implements linear search algorithm. Parameters ========== array: OneDimensionalArray The array which is to be searched. value: The value which is to be searched inside the array. start: int The starting index of the portion which is to be searched. Optional, by default 0 end: int The ending index of the portion which is to be searched. Optional, by default the index of the last position filled. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= output: int The index of value if found. If not found, returns None. Examples ======== >>> from pydatastructs import OneDimensionalArray, linear_search >>> arr = OneDimensionalArray(int,[3, 2, 1]) >>> linear_search(arr, 2) 1 References ========== .. [1] https://en.wikipedia.org/wiki/Linear_search """ raise_if_backend_is_not_python(linear_search, kwargs.get('backend', Backend.PYTHON)) start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) for i in range(start, end + 1): if array[i] == value: return i return None
def __new__(cls, items=None, dtype=NoneType, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if items is None: items = DynamicOneDimensionalArray(dtype, 0) else: items = DynamicOneDimensionalArray(dtype, items) obj = object.__new__(cls) obj.items = items return obj
def __new__(cls, implementation='array', **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if implementation == 'array': return ArrayStack(kwargs.get('items', None), kwargs.get('dtype', int)) if implementation == 'linked_list': return LinkedListStack(kwargs.get('items', None)) raise NotImplementedError("%s hasn't been implemented yet." % (implementation))
def topological_sort_parallel(graph: Graph, algorithm: str, num_threads: int, **kwargs) -> list: """ Performs topological sort on the given graph using given algorithm using given number of threads. Parameters ========== graph: Graph The graph under consideration. algorithm: str The algorithm to be used. Currently, following are supported, 'kahn' -> Kahn's algorithm as given in [1]. num_threads: int The maximum number of threads to be used. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= list The list of topologically sorted vertices. Examples ======== >>> from pydatastructs import Graph, AdjacencyListGraphNode, topological_sort_parallel >>> v_1 = AdjacencyListGraphNode('v_1') >>> v_2 = AdjacencyListGraphNode('v_2') >>> graph = Graph(v_1, v_2) >>> graph.add_edge('v_1', 'v_2') >>> topological_sort_parallel(graph, 'kahn', 1) ['v_1', 'v_2'] References ========== .. [1] https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm """ raise_if_backend_is_not_python( topological_sort_parallel, kwargs.get('backend', Backend.PYTHON)) import pydatastructs.graphs.algorithms as algorithms func = "_" + algorithm + "_" + graph._impl + '_parallel' if not hasattr(algorithms, func): raise NotImplementedError( "Currently %s algorithm isn't implemented for " "performing topological sort on %s graphs."%(algorithm, graph._impl)) return getattr(algorithms, func)(graph, num_threads)
def __new__(cls, root_list=None, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if root_list is None: root_list = [] if not all((_check_type(root, BinomialTree)) for root in root_list): raise TypeError("The root_list should contain " "references to objects of BinomialTree.") obj = Heap.__new__(cls) obj.root_list = root_list return obj
def __new__(cls, items=None, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) obj.stack = SinglyLinkedList() if items is None: pass elif type(items) in (list, tuple): for x in items: obj.push(x) else: raise TypeError("Expected type: list/tuple") return obj
def __new__(cls, segs, **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) if any((not isinstance(seg, (tuple, list, set)) or len(seg) != 2) for seg in segs): raise ValueError('%s is invalid set of intervals'%(segs)) for i in range(len(segs)): segs[i] = list(segs[i]) segs[i].sort() obj.segments = list(segs) obj.tree, obj.root_idx, obj.cache = [], None, False return obj
def __new__(cls, implementation='binary_heap', **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) comp = kwargs.get("comp", lambda u, v: u < v) if implementation == 'linked_list': return LinkedListPriorityQueue(comp) elif implementation == 'binary_heap': return BinaryHeapPriorityQueue(comp) elif implementation == 'binomial_heap': return BinomialHeapPriorityQueue() else: raise NotImplementedError( "%s implementation is not currently supported " "by priority queue.")
def __new__(cls, array, func, data_structure='sparse_table', **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) if len(array) == 0: raise ValueError("Input %s array is empty."%(array)) if data_structure == 'array': return RangeQueryStaticArray(array, func) elif data_structure == 'sparse_table': return RangeQueryStaticSparseTable(array, func) else: raise NotImplementedError( "Currently %s data structure for range " "query without updates isn't implemented yet." % (data_structure))
def __new__(cls, root=None, order=None, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if root is not None and \ not _check_type(root, BinomialTreeNode): raise TypeError("%s i.e., root should be of " "type BinomialTreeNode." % (root)) if order is not None and not _check_type(order, int): raise TypeError("%s i.e., order should be of " "type int." % (order)) obj = object.__new__(cls) if root is not None: root.is_root = True obj.root = root obj.order = order return obj
def __new__(cls, items=None, dtype=NoneType, double_ended=False, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) if items is None: items = DynamicOneDimensionalArray(dtype, 0) else: dtype = type(items[0]) items = DynamicOneDimensionalArray(dtype, items) obj = object.__new__(cls) obj.items, obj._front = items, -1 if items.size == 0: obj._front = -1 obj._rear = -1 else: obj._front = 0 obj._rear = items._num - 1 obj._double_ended = double_ended return obj
def __new__(cls, key=None, root_data=None, comp=None, is_order_statistic=False, max_children=2, **kwargs): raise_if_backend_is_not_python(cls, kwargs.get('backend', Backend.PYTHON)) obj = object.__new__(cls) if key is None and root_data is not None: raise ValueError('Key required.') key = None if root_data is None else key root = MAryTreeNode(key, root_data) root.is_root = True obj.root_idx = 0 obj.max_children = max_children obj.tree, obj.size = ArrayForTrees(MAryTreeNode, [root]), 1 obj.comparator = lambda key1, key2: key1 < key2 \ if comp is None else comp obj.is_order_statistic = is_order_statistic return obj
def __new__(cls, array, func, **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) if len(array) == 0: raise ValueError("Input %s array is empty."%(array)) obj = object.__new__(cls) size = len(array) log_size = int(math.log2(size)) + 1 obj._table = [OneDimensionalArray(int, log_size) for _ in range(size)] obj.func = func for i in range(size): obj._table[i][0] = func((array[i],)) for j in range(1, log_size + 1): for i in range(size - (1 << j) + 1): obj._table[i][j] = func((obj._table[i][j - 1], obj._table[i + (1 << (j - 1))][j - 1])) return obj
def __new__(cls, dtype: type = NoneType, *args, **kwargs): raise_if_backend_is_not_python( cls, kwargs.get('backend', Backend.PYTHON)) if dtype is NoneType: raise ValueError("Data type is not defined.") elif not args: raise ValueError("Too few arguments to create a " "multi dimensional array, pass dimensions.") if len(args) == 1: obj = Array.__new__(cls) obj._dtype = dtype obj._sizes = (args[0], 1) obj._data = [None] * args[0] return obj dimensions = args for dimension in dimensions: if dimension < 1: raise ValueError("Size of dimension cannot be less than 1") n_dimensions = len(dimensions) d_sizes = [] index = 0 while n_dimensions > 1: size = dimensions[index] for i in range(index+1, len(dimensions)): size = size * dimensions[i] d_sizes.append(size) n_dimensions -= 1 index += 1 d_sizes.append(dimensions[index]) d_sizes.append(1) obj = Array.__new__(cls) obj._dtype = dtype obj._sizes = tuple(d_sizes) obj._data = [None] * obj._sizes[1] * dimensions[0] return obj
def quick_sort(array: Array, **kwargs) -> Array: """ Performs quick sort on the given array. Parameters ========== array: Array The array which is to be sorted. start: int The starting index of the portion which is to be sorted. Optional, by default 0 end: int The ending index of the portion which is to be sorted. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for sorting. If the function returns False then only swapping is performed. Optional, by default, less than or equal to is used for comparing two values. pick_pivot_element: lambda/function The function implementing the pivot picking logic for quick sort. Should accept, `low`, `high`, and `array` in this order, where `low` represents the left end of the current partition, `high` represents the right end, and `array` is the original input array to `quick_sort` function. Optional, by default, picks the element at `high` index of the current partition as pivot. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= output: Array The sorted array. Examples ======== >>> from pydatastructs import OneDimensionalArray as ODA, quick_sort >>> arr = ODA(int, [5, 78, 1, 0]) >>> out = quick_sort(arr) >>> str(out) '[0, 1, 5, 78]' >>> arr = ODA(int, [21, 37, 5]) >>> out = quick_sort(arr) >>> str(out) '[5, 21, 37]' References ========== .. [1] https://en.wikipedia.org/wiki/Quicksort """ raise_if_backend_is_not_python(quick_sort, kwargs.get('backend', Backend.PYTHON)) from pydatastructs import Stack comp = kwargs.get("comp", lambda u, v: u <= v) pick_pivot_element = kwargs.get("pick_pivot_element", lambda low, high, array: array[high]) def partition(low, high, pick_pivot_element): i = (low - 1) x = pick_pivot_element(low, high, array) for j in range(low, high): if _comp(array[j], x, comp) is True: i = i + 1 array[i], array[j] = array[j], array[i] array[i + 1], array[high] = array[high], array[i + 1] return (i + 1) lower = kwargs.get('start', 0) upper = kwargs.get('end', len(array) - 1) stack = Stack() stack.push(lower) stack.push(upper) while stack.is_empty is False: high = stack.pop() low = stack.pop() p = partition(low, high, pick_pivot_element) if p - 1 > low: stack.push(low) stack.push(p - 1) if p + 1 < high: stack.push(p + 1) stack.push(high) if _check_type(array, DynamicArray): array._modify(force=True) return array
def longest_common_subsequence(seq1: OneDimensionalArray, seq2: OneDimensionalArray, **kwargs) -> OneDimensionalArray: """ Finds the longest common subsequence between the two given sequences. Parameters ======== seq1: OneDimensionalArray The first sequence. seq2: OneDimensionalArray The second sequence. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= output: OneDimensionalArray The longest common subsequence. Examples ======== >>> from pydatastructs import longest_common_subsequence as LCS, OneDimensionalArray as ODA >>> arr1 = ODA(str, ['A', 'B', 'C', 'D', 'E']) >>> arr2 = ODA(str, ['A', 'B', 'C', 'G' ,'D', 'E', 'F']) >>> lcs = LCS(arr1, arr2) >>> str(lcs) "['A', 'B', 'C', 'D', 'E']" >>> arr1 = ODA(str, ['A', 'P', 'P']) >>> arr2 = ODA(str, ['A', 'p', 'P', 'S', 'P']) >>> lcs = LCS(arr1, arr2) >>> str(lcs) "['A', 'P', 'P']" References ========== .. [1] https://en.wikipedia.org/wiki/Longest_common_subsequence_problem Note ==== The data types of elements across both the sequences should be same and should be comparable. """ raise_if_backend_is_not_python(longest_common_subsequence, kwargs.get('backend', Backend.PYTHON)) row = len(seq1) col = len(seq2) check_mat = {0: [(0, []) for _ in range(col + 1)]} for i in range(1, row + 1): check_mat[i] = [(0, []) for _ in range(col + 1)] for j in range(1, col + 1): if seq1[i - 1] == seq2[j - 1]: temp = check_mat[i - 1][j - 1][1][:] temp.append(seq1[i - 1]) check_mat[i][j] = (check_mat[i - 1][j - 1][0] + 1, temp) else: if check_mat[i - 1][j][0] > check_mat[i][j - 1][0]: check_mat[i][j] = check_mat[i - 1][j] else: check_mat[i][j] = check_mat[i][j - 1] return OneDimensionalArray(seq1._dtype, check_mat[row][col][-1])
def lower_bound(array, value, **kwargs): """ Finds the the index of the first occurence of an element which is not less than the given value according to specified order, in the given OneDimensionalArray using a variation of binary search method. Parameters ========== array: OneDimensionalArray The array in which the lower bound has to be found. start: int The staring index of the portion of the array in which the upper bound of a given value has to be looked for. Optional, by default 0 end: int, optional The ending index of the portion of the array in which the upper bound of a given value has to be looked for. Optional, by default the index of the last position filled. comp: lambda/function The comparator which is to be used for specifying the desired ordering. Optional, by default, less than or equal to is used for comparing two values. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= index: int Index of the lower bound of the given value in the given OneDimensionalArray Examples ======== >>> from pydatastructs import lower_bound, OneDimensionalArray as ODA >>> arr1 = ODA(int, [4, 5, 5, 6, 7]) >>> lb = lower_bound(arr1, 5, end=4, comp=lambda x, y : x < y) >>> lb 1 >>> arr = ODA(int, [7, 6, 5, 5, 4]) >>> lb = lower_bound(arr, 5, start=0, comp=lambda x, y : x > y) >>> lb 2 Note ==== DynamicOneDimensionalArray objects may not work as expected. """ raise_if_backend_is_not_python(lower_bound, kwargs.get('backend', Backend.PYTHON)) start = kwargs.get('start', 0) end = kwargs.get('end', len(array)) comp = kwargs.get('comp', lambda x, y: x < y) index = end inclusive_end = end - 1 if not comp(array[start], value): index = start while start <= inclusive_end: mid = (start + inclusive_end) // 2 if comp(array[mid], value): start = mid + 1 else: index = mid inclusive_end = mid - 1 return index
def minimum_spanning_tree_parallel(graph, algorithm, num_threads, **kwargs): """ Computes a minimum spanning tree for the given graph and algorithm using the given number of threads. Parameters ========== graph: Graph The graph whose minimum spanning tree has to be computed. algorithm: str The algorithm which should be used for computing a minimum spanning tree. Currently the following algorithms are supported, 'kruskal' -> Kruskal's algorithm as given in [1]. 'prim' -> Prim's algorithm as given in [2]. num_threads: int The number of threads to be used. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= mst: Graph A minimum spanning tree using the implementation same as the graph provided in the input. Examples ======== >>> from pydatastructs import Graph, AdjacencyListGraphNode >>> from pydatastructs import minimum_spanning_tree_parallel >>> u = AdjacencyListGraphNode('u') >>> v = AdjacencyListGraphNode('v') >>> G = Graph(u, v) >>> G.add_edge(u.name, v.name, 3) >>> mst = minimum_spanning_tree_parallel(G, 'kruskal', 3) >>> u_n = mst.neighbors(u.name) >>> mst.get_edge(u.name, u_n[0].name).value 3 References ========== .. [1] https://en.wikipedia.org/wiki/Kruskal%27s_algorithm#Parallel_algorithm .. [2] https://en.wikipedia.org/wiki/Prim%27s_algorithm#Parallel_algorithm Note ==== The concept of minimum spanning tree is valid only for connected and undirected graphs. So, this function should be used only for such graphs. Using with other types of graphs will lead to unwanted results. """ raise_if_backend_is_not_python( minimum_spanning_tree_parallel, kwargs.get('backend', Backend.PYTHON)) import pydatastructs.graphs.algorithms as algorithms func = "_minimum_spanning_tree_parallel_" + algorithm + "_" + graph._impl if not hasattr(algorithms, func): raise NotImplementedError( "Currently %s algoithm for %s implementation of graphs " "isn't implemented for finding minimum spanning trees." %(algorithm, graph._impl)) return getattr(algorithms, func)(graph, num_threads)
def shortest_paths(graph: Graph, algorithm: str, source: str, target: str="", **kwargs) -> tuple: """ Finds shortest paths in the given graph from a given source. Parameters ========== graph: Graph The graph under consideration. algorithm: str The algorithm to be used. Currently, the following algorithms are implemented, 'bellman_ford' -> Bellman-Ford algorithm as given in [1]. 'dijkstra' -> Dijkstra algorithm as given in [2]. source: str The name of the source the node. target: str The name of the target node. Optional, by default, all pair shortest paths are returned. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Returns ======= (distances, predecessors): (dict, dict) If target is not provided and algorithm used is 'bellman_ford'/'dijkstra'. (distances[target], predecessors): (float, dict) If target is provided and algorithm used is 'bellman_ford'/'dijkstra'. Examples ======== >>> from pydatastructs import Graph, AdjacencyListGraphNode >>> from pydatastructs import shortest_paths >>> V1 = AdjacencyListGraphNode("V1") >>> V2 = AdjacencyListGraphNode("V2") >>> V3 = AdjacencyListGraphNode("V3") >>> G = Graph(V1, V2, V3) >>> G.add_edge('V2', 'V3', 10) >>> G.add_edge('V1', 'V2', 11) >>> shortest_paths(G, 'bellman_ford', 'V1') ({'V1': 0, 'V2': 11, 'V3': 21}, {'V1': None, 'V2': 'V1', 'V3': 'V2'}) >>> shortest_paths(G, 'dijkstra', 'V1') ({'V2': 11, 'V3': 21, 'V1': 0}, {'V1': None, 'V2': 'V1', 'V3': 'V2'}) References ========== .. [1] https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm .. [2] https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm """ raise_if_backend_is_not_python( shortest_paths, kwargs.get('backend', Backend.PYTHON)) import pydatastructs.graphs.algorithms as algorithms func = "_" + algorithm + "_" + graph._impl if not hasattr(algorithms, func): raise NotImplementedError( "Currently %s algorithm isn't implemented for " "finding shortest paths in graphs."%(algorithm)) return getattr(algorithms, func)(graph, source, target)
def depth_first_search( graph, source_node, operation, *args, **kwargs): """ Implementation of depth first search (DFS) algorithm. Parameters ========== graph: Graph The graph on which DFS is to be performed. source_node: str The name of the source node from where the DFS is to be initiated. operation: function The function which is to be applied on every node when it is visited. The prototype which is to be followed is, `function_name(curr_node, next_node, arg_1, arg_2, . . ., arg_n)`. Here, the first two arguments denote, the current node and the node next to current node. The rest of the arguments are optional and you can provide your own stuff there. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available backend is used. Note ==== You should pass all the arguments which you are going to use in the prototype of your `operation` after passing the operation function. Examples ======== >>> from pydatastructs import Graph, AdjacencyListGraphNode >>> V1 = AdjacencyListGraphNode("V1") >>> V2 = AdjacencyListGraphNode("V2") >>> V3 = AdjacencyListGraphNode("V3") >>> G = Graph(V1, V2, V3) >>> from pydatastructs import depth_first_search >>> def f(curr_node, next_node, dest_node): ... return curr_node != dest_node ... >>> G.add_edge(V1.name, V2.name) >>> G.add_edge(V2.name, V3.name) >>> depth_first_search(G, V1.name, f, V3.name) References ========== .. [1] https://en.wikipedia.org/wiki/Depth-first_search """ raise_if_backend_is_not_python( depth_first_search, kwargs.get('backend', Backend.PYTHON)) import pydatastructs.graphs.algorithms as algorithms func = "_depth_first_search_" + graph._impl if not hasattr(algorithms, func): raise NotImplementedError( "Currently depth first search isn't implemented for " "%s graphs."%(graph._impl)) return getattr(algorithms, func)( graph, source_node, operation, *args, **kwargs)