From 0d6985cf109f2108ef6ce17796266ab25fc88bee Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 13:09:06 +0200 Subject: [PATCH 01/48] Implemented KD-Tree Data Structure --- data_structures/kd_tree/__init__.py | 0 data_structures/kd_tree/build_kdtree.py | 19 +++++++++ .../kd_tree/example/example_usage.py | 22 ++++++++++ .../kd_tree/example/hypercube_points.py | 4 ++ data_structures/kd_tree/kd_node.py | 5 +++ .../kd_tree/nearest_neighbour_search.py | 41 +++++++++++++++++++ 6 files changed, 91 insertions(+) create mode 100644 data_structures/kd_tree/__init__.py create mode 100644 data_structures/kd_tree/build_kdtree.py create mode 100644 data_structures/kd_tree/example/example_usage.py create mode 100644 data_structures/kd_tree/example/hypercube_points.py create mode 100644 data_structures/kd_tree/kd_node.py create mode 100644 data_structures/kd_tree/nearest_neighbour_search.py diff --git a/data_structures/kd_tree/__init__.py b/data_structures/kd_tree/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py new file mode 100644 index 000000000000..a1b84b0379a1 --- /dev/null +++ b/data_structures/kd_tree/build_kdtree.py @@ -0,0 +1,19 @@ +from .kd_node import KDNode + +def build_kdtree(points, depth=0): + if not points: + return None + + k = len(points[0]) # dimensionality of the points + axis = depth % k + + # Sort point list and choose median as pivot element + points.sort(key=lambda x: x[axis]) + median_idx = len(points) // 2 + + # Create node and construct subtrees + return KDNode( + point = points[median_idx], + left = build_kdtree(points[:median_idx], depth + 1), + right = build_kdtree(points[median_idx + 1:], depth + 1) + ) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py new file mode 100644 index 000000000000..74bca1aa4470 --- /dev/null +++ b/data_structures/kd_tree/example/example_usage.py @@ -0,0 +1,22 @@ +import numpy as np + +from hypercube_points import hypercube_points +from data_structures.kd_tree.build_kdtree import build_kdtree +from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search + + +num_points = 5000 +cube_size = 10 +num_dimensions = 10 + +points = hypercube_points(num_points, cube_size, num_dimensions) +hypercube_kdtree = build_kdtree(points.tolist()) + +query_point = np.random.rand(num_dimensions).tolist() + +nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search(hypercube_kdtree, query_point) + +print(f"Query point: {query_point}") +print(f"Nearest point: {nearest_point}") +print(f"Distance: {nearest_dist:.4f}") +print(f"Nodes visited: {nodes_visited}") diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py new file mode 100644 index 000000000000..3ce930830919 --- /dev/null +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -0,0 +1,4 @@ +import numpy as np + +def hypercube_points(num_points, hypercube_size, num_dimensions): + return hypercube_size * np.random.rand(num_points, num_dimensions) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py new file mode 100644 index 000000000000..0748cdd65810 --- /dev/null +++ b/data_structures/kd_tree/kd_node.py @@ -0,0 +1,5 @@ +class KDNode: + def __init__(self, point, left = None, right = None): + self.point = point + self.left = left + self.right = right diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py new file mode 100644 index 000000000000..59dff5bebe84 --- /dev/null +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -0,0 +1,41 @@ +def nearest_neighbour_search(root, query_point): + nearest_point = None + nearest_dist = float('inf') + nodes_visited = 0 + + def search(node, depth=0): + nonlocal nearest_point, nearest_dist, nodes_visited + if node is None: + return + + nodes_visited += 1 + + # Calculate the current distance (squared distance) + current_point = node.point + current_dist = sum((qp - cp) ** 2 for qp, cp in zip(query_point, current_point)) + + # Update nearest point if the current node is closer + if nearest_point is None or current_dist < nearest_dist: + nearest_point = current_point + nearest_dist = current_dist + + # Determine which subtree to search first (based on axis and query point) + k = len(query_point) # dimensionality of points + axis = depth % k + + if query_point[axis] <= current_point[axis]: + nearer_subtree = node.left + further_subtree = node.right + else: + nearer_subtree = node.right + further_subtree = node.left + + # Search the nearer subtree first + search(nearer_subtree, depth + 1) + + # If the further subtree has a closer point + if (query_point[axis] - current_point[axis]) ** 2 < nearest_dist: + search(further_subtree, depth + 1) + + search(root, 0) + return nearest_point, nearest_dist, nodes_visited From 6665d23380602b46c6c07e1c8fecc56a5f0b7e92 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 13:16:55 +0200 Subject: [PATCH 02/48] Implemented KD-Tree Data Structure. updated DIRECTORY.md. --- DIRECTORY.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 11de569a2c25..645bcea3d28c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -285,6 +285,12 @@ * Trie * [Radix Tree](data_structures/trie/radix_tree.py) * [Trie](data_structures/trie/trie.py) + * KD Tree + * [KD Tree Node](data_structures/kd_tree/kd_node.py) + * [Build KD Tree](data_structures/kd_tree/build_kdtree.py) + * [Nearest Neighbour Search](data_structures/kd_tree/nearest_neighbour_search.py) + * [Hypercibe Points](data_structures/kd_tree/example/hypercube_points.py) + * [Example Usage](data_structures/kd_tree/example/example_usage.py) ## Digital Image Processing * [Change Brightness](digital_image_processing/change_brightness.py) From 6b3d47e7e485c6029b9ced7dea5eedf1d5ecf449 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:31:38 +0000 Subject: [PATCH 03/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- DIRECTORY.md | 2 +- data_structures/kd_tree/build_kdtree.py | 7 ++++--- data_structures/kd_tree/example/example_usage.py | 4 +++- data_structures/kd_tree/example/hypercube_points.py | 1 + data_structures/kd_tree/kd_node.py | 2 +- data_structures/kd_tree/nearest_neighbour_search.py | 2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 645bcea3d28c..1ca537b991c8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -287,7 +287,7 @@ * [Trie](data_structures/trie/trie.py) * KD Tree * [KD Tree Node](data_structures/kd_tree/kd_node.py) - * [Build KD Tree](data_structures/kd_tree/build_kdtree.py) + * [Build KD Tree](data_structures/kd_tree/build_kdtree.py) * [Nearest Neighbour Search](data_structures/kd_tree/nearest_neighbour_search.py) * [Hypercibe Points](data_structures/kd_tree/example/hypercube_points.py) * [Example Usage](data_structures/kd_tree/example/example_usage.py) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index a1b84b0379a1..71a00df65fcf 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,5 +1,6 @@ from .kd_node import KDNode + def build_kdtree(points, depth=0): if not points: return None @@ -13,7 +14,7 @@ def build_kdtree(points, depth=0): # Create node and construct subtrees return KDNode( - point = points[median_idx], - left = build_kdtree(points[:median_idx], depth + 1), - right = build_kdtree(points[median_idx + 1:], depth + 1) + point=points[median_idx], + left=build_kdtree(points[:median_idx], depth + 1), + right=build_kdtree(points[median_idx + 1 :], depth + 1), ) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 74bca1aa4470..96a2492bbb83 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -14,7 +14,9 @@ query_point = np.random.rand(num_dimensions).tolist() -nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search(hypercube_kdtree, query_point) +nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( + hypercube_kdtree, query_point +) print(f"Query point: {query_point}") print(f"Nearest point: {nearest_point}") diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 3ce930830919..429c3579a380 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,4 +1,5 @@ import numpy as np + def hypercube_points(num_points, hypercube_size, num_dimensions): return hypercube_size * np.random.rand(num_points, num_dimensions) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 0748cdd65810..1fa7431ad6ec 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,5 +1,5 @@ class KDNode: - def __init__(self, point, left = None, right = None): + def __init__(self, point, left=None, right=None): self.point = point self.left = left self.right = right diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index 59dff5bebe84..9e00c9108bb9 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,6 +1,6 @@ def nearest_neighbour_search(root, query_point): nearest_point = None - nearest_dist = float('inf') + nearest_dist = float("inf") nodes_visited = 0 def search(node, depth=0): From 4203cda76113c401429cd48c0338fa170bf24ad8 Mon Sep 17 00:00:00 2001 From: Ramy <126559907+Ramy-Badr-Ahmed@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:02:42 +0200 Subject: [PATCH 04/48] Create __init__.py --- data_structures/kd_tree/example/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 data_structures/kd_tree/example/__init__.py diff --git a/data_structures/kd_tree/example/__init__.py b/data_structures/kd_tree/example/__init__.py new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/data_structures/kd_tree/example/__init__.py @@ -0,0 +1 @@ + From 3222bd3d311befaeb6d7ff93658f0663b0fa2117 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 12:03:11 +0000 Subject: [PATCH 05/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/example/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/data_structures/kd_tree/example/__init__.py b/data_structures/kd_tree/example/__init__.py index 8b137891791f..e69de29bb2d1 100644 --- a/data_structures/kd_tree/example/__init__.py +++ b/data_structures/kd_tree/example/__init__.py @@ -1 +0,0 @@ - From a41ae5bd2848eec9ee71e7df02137a677104b927 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 19:39:39 +0200 Subject: [PATCH 06/48] Replaced legacy `np.random.rand` call with `np.random.Generator` in kd_tree/example_usage.py --- data_structures/kd_tree/example/example_usage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 96a2492bbb83..0ca2019185d8 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -12,7 +12,8 @@ points = hypercube_points(num_points, cube_size, num_dimensions) hypercube_kdtree = build_kdtree(points.tolist()) -query_point = np.random.rand(num_dimensions).tolist() +rng = np.random.default_rng() +query_point = rng.random(num_dimensions).tolist() nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( hypercube_kdtree, query_point From 1668d73a43abd9c6e6ab4f20c93fbbcd5f8600af Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 19:47:09 +0200 Subject: [PATCH 07/48] Replaced legacy `np.random.rand` call with `np.random.Generator` in kd_tree/hypercube_points.py --- data_structures/kd_tree/example/hypercube_points.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 429c3579a380..61b2beb9da85 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -2,4 +2,5 @@ def hypercube_points(num_points, hypercube_size, num_dimensions): - return hypercube_size * np.random.rand(num_points, num_dimensions) + rng = np.random.default_rng() + return hypercube_size * rng.random((num_points, num_dimensions)) From 81d69176858df202c6004dc1295a6ac05e95bcd4 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 20:02:07 +0200 Subject: [PATCH 08/48] added typehints and docstrings --- data_structures/kd_tree/build_kdtree.py | 18 ++++++-- .../kd_tree/example/example_usage.py | 41 ++++++++++++------- .../kd_tree/example/hypercube_points.py | 13 +++++- data_structures/kd_tree/kd_node.py | 21 +++++++++- .../kd_tree/nearest_neighbour_search.py | 30 ++++++++++---- 5 files changed, 95 insertions(+), 28 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 71a00df65fcf..090cef4fdd32 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,20 +1,30 @@ +from typing import List, Optional from .kd_node import KDNode +def build_kdtree(points: List[List[float]], depth: int = 0) -> Optional[KDNode]: + """ + Builds a KD-Tree from a set of k-dimensional points. -def build_kdtree(points, depth=0): + Args: + points (List[List[float]]): A list of k-dimensional points (each point is a list of floats). + depth (int): The current depth in the tree. Used to determine the splitting axis. Defaults to 0. + + Returns: + Optional[KDNode]: The root of the KD-Tree or None if the input list is empty. + """ if not points: return None - k = len(points[0]) # dimensionality of the points + k = len(points[0]) # Dimensionality of the points axis = depth % k # Sort point list and choose median as pivot element - points.sort(key=lambda x: x[axis]) + points.sort(key=lambda point: point[axis]) median_idx = len(points) // 2 # Create node and construct subtrees return KDNode( point=points[median_idx], left=build_kdtree(points[:median_idx], depth + 1), - right=build_kdtree(points[median_idx + 1 :], depth + 1), + right=build_kdtree(points[median_idx + 1:], depth + 1), ) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 0ca2019185d8..d6e01b4ef953 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,25 +1,36 @@ import numpy as np - +from typing import List from hypercube_points import hypercube_points from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search +def main() -> None: + """ + Demonstrates the use of KD-Tree by building it from random points + in a 10-dimensional hypercube and performing a nearest neighbor search. + """ + num_points: int = 5000 + cube_size: int = 10 + num_dimensions: int = 10 -num_points = 5000 -cube_size = 10 -num_dimensions = 10 + # Generate random points within the hypercube + points: np.ndarray = hypercube_points(num_points, cube_size, num_dimensions) + hypercube_kdtree = build_kdtree(points.tolist()) -points = hypercube_points(num_points, cube_size, num_dimensions) -hypercube_kdtree = build_kdtree(points.tolist()) + # Generate a random query point within the same space + rng = np.random.default_rng() + query_point: List[float] = rng.random(num_dimensions).tolist() -rng = np.random.default_rng() -query_point = rng.random(num_dimensions).tolist() + # Perform nearest neighbor search + nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( + hypercube_kdtree, query_point + ) -nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( - hypercube_kdtree, query_point -) + # Print the results + print(f"Query point: {query_point}") + print(f"Nearest point: {nearest_point}") + print(f"Distance: {nearest_dist:.4f}") + print(f"Nodes visited: {nodes_visited}") -print(f"Query point: {query_point}") -print(f"Nearest point: {nearest_point}") -print(f"Distance: {nearest_dist:.4f}") -print(f"Nodes visited: {nodes_visited}") +if __name__ == "__main__": + main() diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 61b2beb9da85..65548bfe259c 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,6 +1,17 @@ import numpy as np +from typing import Union +def hypercube_points(num_points: int, hypercube_size: Union[int, float], num_dimensions: int) -> np.ndarray: + """ + Generates random points uniformly distributed within an n-dimensional hypercube. -def hypercube_points(num_points, hypercube_size, num_dimensions): + Args: + num_points (int): The number of random points to generate. + hypercube_size (Union[int, float]): The size of the hypercube (side length). + num_dimensions (int): The number of dimensions of the hypercube. + + Returns: + np.ndarray: An array of shape (num_points, num_dimensions) with the generated points. + """ rng = np.random.default_rng() return hypercube_size * rng.random((num_points, num_dimensions)) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 1fa7431ad6ec..d05e1f3da1cf 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,5 +1,24 @@ +from typing import List, Optional + class KDNode: - def __init__(self, point, left=None, right=None): + """ + Represents a node in a KD-Tree. + + Attributes: + point (List[float]): The k-dimensional point stored in this node. + left (Optional[KDNode]): The left subtree of this node. + right (Optional[KDNode]): The right subtree of this node. + """ + + def __init__(self, point: List[float], left: Optional['KDNode'] = None, right: Optional['KDNode'] = None) -> None: + """ + Initializes a KDNode with a point and optional left and right children. + + Args: + point (List[float]): The k-dimensional point to be stored in this node. + left (Optional[KDNode]): The left subtree of this node. Defaults to None. + right (Optional[KDNode]): The right subtree of this node. Defaults to None. + """ self.point = point self.left = left self.right = right diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index 9e00c9108bb9..bbb84fdfb098 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,9 +1,25 @@ -def nearest_neighbour_search(root, query_point): - nearest_point = None - nearest_dist = float("inf") - nodes_visited = 0 - - def search(node, depth=0): +from typing import Optional, List, Tuple +from .kd_node import KDNode + +def nearest_neighbour_search(root: Optional[KDNode], query_point: List[float]) -> Tuple[Optional[List[float]], float, int]: + """ + Performs a nearest neighbor search in a KD-Tree for a given query point. + + Args: + root (Optional[KDNode]): The root node of the KD-Tree. + query_point (List[float]): The point for which the nearest neighbor is being searched. + + Returns: + Tuple[Optional[List[float]], float, int]: + - The nearest point found in the KD-Tree to the query point. + - The squared distance to the nearest point. + - The number of nodes visited during the search. + """ + nearest_point: Optional[List[float]] = None + nearest_dist: float = float("inf") + nodes_visited: int = 0 + + def search(node: Optional[KDNode], depth: int = 0) -> None: nonlocal nearest_point, nearest_dist, nodes_visited if node is None: return @@ -12,7 +28,7 @@ def search(node, depth=0): # Calculate the current distance (squared distance) current_point = node.point - current_dist = sum((qp - cp) ** 2 for qp, cp in zip(query_point, current_point)) + current_dist = sum((query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point)) # Update nearest point if the current node is closer if nearest_point is None or current_dist < nearest_dist: From 6cddcbdff7696dc4d5528bc759dc2817543e994d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:02:36 +0000 Subject: [PATCH 09/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/build_kdtree.py | 3 ++- data_structures/kd_tree/example/example_usage.py | 2 ++ data_structures/kd_tree/example/hypercube_points.py | 5 ++++- data_structures/kd_tree/kd_node.py | 8 +++++++- data_structures/kd_tree/nearest_neighbour_search.py | 10 ++++++++-- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 090cef4fdd32..3d053cee832c 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,6 +1,7 @@ from typing import List, Optional from .kd_node import KDNode + def build_kdtree(points: List[List[float]], depth: int = 0) -> Optional[KDNode]: """ Builds a KD-Tree from a set of k-dimensional points. @@ -26,5 +27,5 @@ def build_kdtree(points: List[List[float]], depth: int = 0) -> Optional[KDNode]: return KDNode( point=points[median_idx], left=build_kdtree(points[:median_idx], depth + 1), - right=build_kdtree(points[median_idx + 1:], depth + 1), + right=build_kdtree(points[median_idx + 1 :], depth + 1), ) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index d6e01b4ef953..61264f6a7d83 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -4,6 +4,7 @@ from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search + def main() -> None: """ Demonstrates the use of KD-Tree by building it from random points @@ -32,5 +33,6 @@ def main() -> None: print(f"Distance: {nearest_dist:.4f}") print(f"Nodes visited: {nodes_visited}") + if __name__ == "__main__": main() diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 65548bfe259c..c1541af22026 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,7 +1,10 @@ import numpy as np from typing import Union -def hypercube_points(num_points: int, hypercube_size: Union[int, float], num_dimensions: int) -> np.ndarray: + +def hypercube_points( + num_points: int, hypercube_size: Union[int, float], num_dimensions: int +) -> np.ndarray: """ Generates random points uniformly distributed within an n-dimensional hypercube. diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index d05e1f3da1cf..7a19af9cbf57 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,5 +1,6 @@ from typing import List, Optional + class KDNode: """ Represents a node in a KD-Tree. @@ -10,7 +11,12 @@ class KDNode: right (Optional[KDNode]): The right subtree of this node. """ - def __init__(self, point: List[float], left: Optional['KDNode'] = None, right: Optional['KDNode'] = None) -> None: + def __init__( + self, + point: List[float], + left: Optional["KDNode"] = None, + right: Optional["KDNode"] = None, + ) -> None: """ Initializes a KDNode with a point and optional left and right children. diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index bbb84fdfb098..36a4cdc88a69 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,7 +1,10 @@ from typing import Optional, List, Tuple from .kd_node import KDNode -def nearest_neighbour_search(root: Optional[KDNode], query_point: List[float]) -> Tuple[Optional[List[float]], float, int]: + +def nearest_neighbour_search( + root: Optional[KDNode], query_point: List[float] +) -> Tuple[Optional[List[float]], float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. @@ -28,7 +31,10 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Calculate the current distance (squared distance) current_point = node.point - current_dist = sum((query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point)) + current_dist = sum( + (query_coord - point_coord) ** 2 + for query_coord, point_coord in zip(query_point, current_point) + ) # Update nearest point if the current node is closer if nearest_point is None or current_dist < nearest_dist: From 8b238d1d4d7639d87dea5102459e289d4abb1532 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 20:08:37 +0200 Subject: [PATCH 10/48] docstring for search() --- .../kd_tree/nearest_neighbour_search.py | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index bbb84fdfb098..f0ad2ea5525f 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,7 +1,10 @@ from typing import Optional, List, Tuple from .kd_node import KDNode -def nearest_neighbour_search(root: Optional[KDNode], query_point: List[float]) -> Tuple[Optional[List[float]], float, int]: +def nearest_neighbour_search( + root: Optional[KDNode], + query_point: List[float] +) -> Tuple[Optional[List[float]], float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. @@ -20,6 +23,18 @@ def nearest_neighbour_search(root: Optional[KDNode], query_point: List[float]) - nodes_visited: int = 0 def search(node: Optional[KDNode], depth: int = 0) -> None: + """ + Recursively searches the KD-Tree to find the nearest point to the query point. + + Args: + node (Optional[KDNode]): The current node being examined. + depth (int): The current depth of the tree, which determines the axis to split on. + + Updates: + nearest_point: The closest point found so far in the KD-Tree. + nearest_dist: The squared distance from the query point to the nearest point found. + nodes_visited: The number of nodes visited during the search. + """ nonlocal nearest_point, nearest_dist, nodes_visited if node is None: return @@ -28,7 +43,9 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Calculate the current distance (squared distance) current_point = node.point - current_dist = sum((query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point)) + current_dist = sum( + (query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point) + ) # Update nearest point if the current node is closer if nearest_point is None or current_dist < nearest_dist: @@ -49,7 +66,7 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Search the nearer subtree first search(nearer_subtree, depth + 1) - # If the further subtree has a closer point + # If the further subtree has a closer point, search it if (query_point[axis] - current_point[axis]) ** 2 < nearest_dist: search(further_subtree, depth + 1) From ead2838aafd022db6343551bdbf9080d19f0e826 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:09:36 +0000 Subject: [PATCH 11/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/nearest_neighbour_search.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index f0ad2ea5525f..2d8acbabf0b0 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,9 +1,9 @@ from typing import Optional, List, Tuple from .kd_node import KDNode + def nearest_neighbour_search( - root: Optional[KDNode], - query_point: List[float] + root: Optional[KDNode], query_point: List[float] ) -> Tuple[Optional[List[float]], float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. @@ -44,7 +44,8 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Calculate the current distance (squared distance) current_point = node.point current_dist = sum( - (query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point) + (query_coord - point_coord) ** 2 + for query_coord, point_coord in zip(query_point, current_point) ) # Update nearest point if the current node is closer From 543584cb696e5541b63b084d9864f65e370a58e6 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 20:42:43 +0200 Subject: [PATCH 12/48] Added tests. Updated docstrings/typehints --- data_structures/kd_tree/build_kdtree.py | 17 +++-- .../kd_tree/example/example_usage.py | 6 +- .../kd_tree/example/hypercube_points.py | 14 ++-- data_structures/kd_tree/kd_node.py | 24 +++---- .../kd_tree/nearest_neighbour_search.py | 35 ++++------ data_structures/kd_tree/tests/__init__.py | 0 data_structures/kd_tree/tests/test_kdtree.py | 70 +++++++++++++++++++ 7 files changed, 106 insertions(+), 60 deletions(-) create mode 100644 data_structures/kd_tree/tests/__init__.py create mode 100644 data_structures/kd_tree/tests/test_kdtree.py diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 3d053cee832c..69811b80050c 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,17 +1,16 @@ -from typing import List, Optional +from typing import Optional from .kd_node import KDNode - -def build_kdtree(points: List[List[float]], depth: int = 0) -> Optional[KDNode]: +def build_kdtree(points: list[list[float]], depth: int = 0) -> Optional[KDNode]: """ - Builds a KD-Tree from a set of k-dimensional points. + Builds a KD-Tree from a list of points. Args: - points (List[List[float]]): A list of k-dimensional points (each point is a list of floats). - depth (int): The current depth in the tree. Used to determine the splitting axis. Defaults to 0. + points (list[list[float]]): The list of points to build the KD-Tree from. + depth (int): The current depth in the tree (used to determine axis for splitting). Returns: - Optional[KDNode]: The root of the KD-Tree or None if the input list is empty. + Optional[KDNode]: The root node of the KD-Tree. """ if not points: return None @@ -27,5 +26,5 @@ def build_kdtree(points: List[List[float]], depth: int = 0) -> Optional[KDNode]: return KDNode( point=points[median_idx], left=build_kdtree(points[:median_idx], depth + 1), - right=build_kdtree(points[median_idx + 1 :], depth + 1), - ) + right=build_kdtree(points[median_idx + 1:], depth + 1), + ) \ No newline at end of file diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 61264f6a7d83..37b32c9db36a 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,5 +1,4 @@ import numpy as np -from typing import List from hypercube_points import hypercube_points from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search @@ -11,7 +10,7 @@ def main() -> None: in a 10-dimensional hypercube and performing a nearest neighbor search. """ num_points: int = 5000 - cube_size: int = 10 + cube_size: float = 10.0 # Size of the hypercube (edge length) num_dimensions: int = 10 # Generate random points within the hypercube @@ -20,7 +19,7 @@ def main() -> None: # Generate a random query point within the same space rng = np.random.default_rng() - query_point: List[float] = rng.random(num_dimensions).tolist() + query_point: list[float] = rng.random(num_dimensions).tolist() # Perform nearest neighbor search nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( @@ -33,6 +32,5 @@ def main() -> None: print(f"Distance: {nearest_dist:.4f}") print(f"Nodes visited: {nodes_visited}") - if __name__ == "__main__": main() diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index c1541af22026..7397c4ce6b2e 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,20 +1,16 @@ import numpy as np -from typing import Union - -def hypercube_points( - num_points: int, hypercube_size: Union[int, float], num_dimensions: int -) -> np.ndarray: +def hypercube_points(num_points: int, hypercube_size: float, num_dimensions: int) -> np.ndarray: """ Generates random points uniformly distributed within an n-dimensional hypercube. Args: - num_points (int): The number of random points to generate. - hypercube_size (Union[int, float]): The size of the hypercube (side length). - num_dimensions (int): The number of dimensions of the hypercube. + num_points (int): Number of points to generate. + hypercube_size (float): Size of the hypercube. + num_dimensions (int): Number of dimensions of the hypercube. Returns: - np.ndarray: An array of shape (num_points, num_dimensions) with the generated points. + np.ndarray: An array of shape (num_points, num_dimensions) with generated points. """ rng = np.random.default_rng() return hypercube_size * rng.random((num_points, num_dimensions)) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 7a19af9cbf57..90f1e8e0c334 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,29 +1,23 @@ -from typing import List, Optional - +from typing import Optional class KDNode: """ Represents a node in a KD-Tree. Attributes: - point (List[float]): The k-dimensional point stored in this node. - left (Optional[KDNode]): The left subtree of this node. - right (Optional[KDNode]): The right subtree of this node. + point (list[float]): The point stored in this node. + left (Optional[KDNode]): The left child node. + right (Optional[KDNode]): The right child node. """ - def __init__( - self, - point: List[float], - left: Optional["KDNode"] = None, - right: Optional["KDNode"] = None, - ) -> None: + def __init__(self, point: list[float], left: Optional['KDNode'] = None, right: Optional['KDNode'] = None) -> None: """ - Initializes a KDNode with a point and optional left and right children. + Initializes a KDNode with the given point and child nodes. Args: - point (List[float]): The k-dimensional point to be stored in this node. - left (Optional[KDNode]): The left subtree of this node. Defaults to None. - right (Optional[KDNode]): The right subtree of this node. Defaults to None. + point (list[float]): The point stored in this node. + left (Optional[KDNode]): The left child node. + right (Optional[KDNode]): The right child node. """ self.point = point self.left = left diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index 2d8acbabf0b0..8258b846aca6 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,39 +1,31 @@ -from typing import Optional, List, Tuple -from .kd_node import KDNode +from typing import Optional +from data_structures.kd_tree.kd_node import KDNode - -def nearest_neighbour_search( - root: Optional[KDNode], query_point: List[float] -) -> Tuple[Optional[List[float]], float, int]: +def nearest_neighbour_search(root: Optional[KDNode], query_point: list[float]) -> tuple[Optional[list[float]], float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. Args: root (Optional[KDNode]): The root node of the KD-Tree. - query_point (List[float]): The point for which the nearest neighbor is being searched. + query_point (list[float]): The point for which the nearest neighbor is being searched. Returns: - Tuple[Optional[List[float]], float, int]: + tuple[Optional[list[float]], float, int]: - The nearest point found in the KD-Tree to the query point. - The squared distance to the nearest point. - The number of nodes visited during the search. """ - nearest_point: Optional[List[float]] = None + nearest_point: Optional[list[float]] = None nearest_dist: float = float("inf") nodes_visited: int = 0 def search(node: Optional[KDNode], depth: int = 0) -> None: """ - Recursively searches the KD-Tree to find the nearest point to the query point. + Recursively searches the KD-Tree for the nearest neighbor. Args: - node (Optional[KDNode]): The current node being examined. - depth (int): The current depth of the tree, which determines the axis to split on. - - Updates: - nearest_point: The closest point found so far in the KD-Tree. - nearest_dist: The squared distance from the query point to the nearest point found. - nodes_visited: The number of nodes visited during the search. + node (Optional[KDNode]): The current node in the KD-Tree. + depth (int): The current depth in the tree. """ nonlocal nearest_point, nearest_dist, nodes_visited if node is None: @@ -43,10 +35,7 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Calculate the current distance (squared distance) current_point = node.point - current_dist = sum( - (query_coord - point_coord) ** 2 - for query_coord, point_coord in zip(query_point, current_point) - ) + current_dist = sum((query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point)) # Update nearest point if the current node is closer if nearest_point is None or current_dist < nearest_dist: @@ -54,7 +43,7 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: nearest_dist = current_dist # Determine which subtree to search first (based on axis and query point) - k = len(query_point) # dimensionality of points + k = len(query_point) # Dimensionality of points axis = depth % k if query_point[axis] <= current_point[axis]: @@ -67,7 +56,7 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Search the nearer subtree first search(nearer_subtree, depth + 1) - # If the further subtree has a closer point, search it + # If the further subtree has a closer point if (query_point[axis] - current_point[axis]) ** 2 < nearest_dist: search(further_subtree, depth + 1) diff --git a/data_structures/kd_tree/tests/__init__.py b/data_structures/kd_tree/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py new file mode 100644 index 000000000000..a6cc570c8ec9 --- /dev/null +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -0,0 +1,70 @@ +import unittest +import numpy as np +from data_structures.kd_tree.build_kdtree import build_kdtree +from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search +from data_structures.kd_tree.kd_node import KDNode +from data_structures.kd_tree.example.hypercube_points import hypercube_points + +class TestKDTree(unittest.TestCase): + + def setUp(self): + """ + Set up test data. + """ + self.num_points = 10 + self.cube_size = 10.0 + self.num_dimensions = 2 + self.points = hypercube_points(self.num_points, self.cube_size, self.num_dimensions) + self.kdtree = build_kdtree(self.points.tolist()) + + def test_build_kdtree(self): + """ + Test that KD-Tree is built correctly. + """ + # Check if root is not None + self.assertIsNotNone(self.kdtree) + + # Check if root has correct dimensions + self.assertEqual(len(self.kdtree.point), self.num_dimensions) + + # Check that the tree is balanced to some extent (simplistic check) + self.assertIsInstance(self.kdtree, KDNode) + + def test_nearest_neighbour_search(self): + """ + Test the nearest neighbor search function. + """ + rng = np.random.default_rng() + query_point = rng.random(self.num_dimensions).tolist() + + nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( + self.kdtree, query_point + ) + + # Check that nearest point is not None + self.assertIsNotNone(nearest_point) + + # Check that distance is a non-negative number + self.assertGreaterEqual(nearest_dist, 0) + + # Check that nodes visited is a non-negative integer + self.assertGreaterEqual(nodes_visited, 0) + + def test_edge_cases(self): + """ + Test edge cases such as an empty KD-Tree. + """ + empty_kdtree = build_kdtree([]) + query_point = [0.0] * self.num_dimensions + + nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( + empty_kdtree, query_point + ) + + # With an empty KD-Tree, nearest_point should be None + self.assertIsNone(nearest_point) + self.assertEqual(nearest_dist, float("inf")) + self.assertEqual(nodes_visited, 0) + +if __name__ == '__main__': + unittest.main() From ad31f83a1e89b4620bb59e35ec7311bd92fb36e5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:43:54 +0000 Subject: [PATCH 13/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/build_kdtree.py | 5 +++-- data_structures/kd_tree/example/example_usage.py | 1 + data_structures/kd_tree/example/hypercube_points.py | 5 ++++- data_structures/kd_tree/kd_node.py | 8 +++++++- data_structures/kd_tree/nearest_neighbour_search.py | 10 ++++++++-- data_structures/kd_tree/tests/test_kdtree.py | 9 ++++++--- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 69811b80050c..23ff90dac41f 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,6 +1,7 @@ from typing import Optional from .kd_node import KDNode + def build_kdtree(points: list[list[float]], depth: int = 0) -> Optional[KDNode]: """ Builds a KD-Tree from a list of points. @@ -26,5 +27,5 @@ def build_kdtree(points: list[list[float]], depth: int = 0) -> Optional[KDNode]: return KDNode( point=points[median_idx], left=build_kdtree(points[:median_idx], depth + 1), - right=build_kdtree(points[median_idx + 1:], depth + 1), - ) \ No newline at end of file + right=build_kdtree(points[median_idx + 1 :], depth + 1), + ) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 37b32c9db36a..3dfabda4f81b 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -32,5 +32,6 @@ def main() -> None: print(f"Distance: {nearest_dist:.4f}") print(f"Nodes visited: {nodes_visited}") + if __name__ == "__main__": main() diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 7397c4ce6b2e..ae00a3d8b047 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,6 +1,9 @@ import numpy as np -def hypercube_points(num_points: int, hypercube_size: float, num_dimensions: int) -> np.ndarray: + +def hypercube_points( + num_points: int, hypercube_size: float, num_dimensions: int +) -> np.ndarray: """ Generates random points uniformly distributed within an n-dimensional hypercube. diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 90f1e8e0c334..e14ec39c24c0 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,5 +1,6 @@ from typing import Optional + class KDNode: """ Represents a node in a KD-Tree. @@ -10,7 +11,12 @@ class KDNode: right (Optional[KDNode]): The right child node. """ - def __init__(self, point: list[float], left: Optional['KDNode'] = None, right: Optional['KDNode'] = None) -> None: + def __init__( + self, + point: list[float], + left: Optional["KDNode"] = None, + right: Optional["KDNode"] = None, + ) -> None: """ Initializes a KDNode with the given point and child nodes. diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index 8258b846aca6..eb80638d4923 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,7 +1,10 @@ from typing import Optional from data_structures.kd_tree.kd_node import KDNode -def nearest_neighbour_search(root: Optional[KDNode], query_point: list[float]) -> tuple[Optional[list[float]], float, int]: + +def nearest_neighbour_search( + root: Optional[KDNode], query_point: list[float] +) -> tuple[Optional[list[float]], float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. @@ -35,7 +38,10 @@ def search(node: Optional[KDNode], depth: int = 0) -> None: # Calculate the current distance (squared distance) current_point = node.point - current_dist = sum((query_coord - point_coord) ** 2 for query_coord, point_coord in zip(query_point, current_point)) + current_dist = sum( + (query_coord - point_coord) ** 2 + for query_coord, point_coord in zip(query_point, current_point) + ) # Update nearest point if the current node is closer if nearest_point is None or current_dist < nearest_dist: diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index a6cc570c8ec9..dcf0edec6cfc 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -5,8 +5,8 @@ from data_structures.kd_tree.kd_node import KDNode from data_structures.kd_tree.example.hypercube_points import hypercube_points -class TestKDTree(unittest.TestCase): +class TestKDTree(unittest.TestCase): def setUp(self): """ Set up test data. @@ -14,7 +14,9 @@ def setUp(self): self.num_points = 10 self.cube_size = 10.0 self.num_dimensions = 2 - self.points = hypercube_points(self.num_points, self.cube_size, self.num_dimensions) + self.points = hypercube_points( + self.num_points, self.cube_size, self.num_dimensions + ) self.kdtree = build_kdtree(self.points.tolist()) def test_build_kdtree(self): @@ -66,5 +68,6 @@ def test_edge_cases(self): self.assertEqual(nearest_dist, float("inf")) self.assertEqual(nodes_visited, 0) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() From 1322921f9283782abcdee4bb34f49c2d9ba0da2b Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Wed, 28 Aug 2024 21:24:46 +0200 Subject: [PATCH 14/48] updated tests and used | for type annotations --- data_structures/kd_tree/build_kdtree.py | 17 +-- .../kd_tree/example/example_usage.py | 2 +- .../kd_tree/example/hypercube_points.py | 6 +- data_structures/kd_tree/kd_node.py | 1 - .../kd_tree/nearest_neighbour_search.py | 26 +++-- data_structures/kd_tree/tests/test_kdtree.py | 103 +++++++++--------- 6 files changed, 78 insertions(+), 77 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 23ff90dac41f..1a0a27bb5ced 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,8 +1,8 @@ -from typing import Optional -from .kd_node import KDNode +from data_structures.kd_tree.kd_node import KDNode - -def build_kdtree(points: list[list[float]], depth: int = 0) -> Optional[KDNode]: +def build_kdtree( + points: list[list[float]], depth: int = 0 +) -> KDNode | None: """ Builds a KD-Tree from a list of points. @@ -11,7 +11,7 @@ def build_kdtree(points: list[list[float]], depth: int = 0) -> Optional[KDNode]: depth (int): The current depth in the tree (used to determine axis for splitting). Returns: - Optional[KDNode]: The root node of the KD-Tree. + KDNode | None: The root node of the KD-Tree, or None if no points are provided. """ if not points: return None @@ -24,8 +24,11 @@ def build_kdtree(points: list[list[float]], depth: int = 0) -> Optional[KDNode]: median_idx = len(points) // 2 # Create node and construct subtrees + left_points = points[:median_idx] + right_points = points[median_idx + 1:] + return KDNode( point=points[median_idx], - left=build_kdtree(points[:median_idx], depth + 1), - right=build_kdtree(points[median_idx + 1 :], depth + 1), + left=build_kdtree(left_points, depth + 1), + right=build_kdtree(right_points, depth + 1), ) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 3dfabda4f81b..c0d76405e9d6 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,5 +1,5 @@ import numpy as np -from hypercube_points import hypercube_points +from data_structures.kd_tree.example.hypercube_points import hypercube_points from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index ae00a3d8b047..6e844a836f4e 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,8 +1,7 @@ import numpy as np - def hypercube_points( - num_points: int, hypercube_size: float, num_dimensions: int + num_points: int, hypercube_size: float, num_dimensions: int ) -> np.ndarray: """ Generates random points uniformly distributed within an n-dimensional hypercube. @@ -16,4 +15,5 @@ def hypercube_points( np.ndarray: An array of shape (num_points, num_dimensions) with generated points. """ rng = np.random.default_rng() - return hypercube_size * rng.random((num_points, num_dimensions)) + shape = (num_points, num_dimensions) + return hypercube_size * rng.random(shape) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index e14ec39c24c0..f2b0ff1d2b10 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,6 +1,5 @@ from typing import Optional - class KDNode: """ Represents a node in a KD-Tree. diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index eb80638d4923..1a946c342da1 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,34 +1,36 @@ -from typing import Optional from data_structures.kd_tree.kd_node import KDNode - def nearest_neighbour_search( - root: Optional[KDNode], query_point: list[float] -) -> tuple[Optional[list[float]], float, int]: + root: KDNode | None, + query_point: list[float] +) -> tuple[list[float] | None, float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. Args: - root (Optional[KDNode]): The root node of the KD-Tree. + root (KDNode | None): The root node of the KD-Tree. query_point (list[float]): The point for which the nearest neighbor is being searched. Returns: - tuple[Optional[list[float]], float, int]: - - The nearest point found in the KD-Tree to the query point. + tuple[list[float] | None, float, int]: + - The nearest point found in the KD-Tree to the query point, or None if no point is found. - The squared distance to the nearest point. - The number of nodes visited during the search. """ - nearest_point: Optional[list[float]] = None + nearest_point: list[float] | None = None nearest_dist: float = float("inf") nodes_visited: int = 0 - def search(node: Optional[KDNode], depth: int = 0) -> None: + def search( + node: KDNode | None, + depth: int = 0 + ) -> None: """ - Recursively searches the KD-Tree for the nearest neighbor. + Recursively searches for the nearest neighbor in the KD-Tree. Args: - node (Optional[KDNode]): The current node in the KD-Tree. - depth (int): The current depth in the tree. + node (KDNode | None): The current node in the KD-Tree. + depth (int): The current depth in the KD-Tree. """ nonlocal nearest_point, nearest_dist, nodes_visited if node is None: diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index dcf0edec6cfc..8927afbaa619 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -1,73 +1,70 @@ -import unittest import numpy as np from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search from data_structures.kd_tree.kd_node import KDNode from data_structures.kd_tree.example.hypercube_points import hypercube_points +def test_build_kdtree(): + """ + Test that KD-Tree is built correctly. + """ + num_points = 10 + cube_size = 10.0 + num_dimensions = 2 + points = hypercube_points(num_points, cube_size, num_dimensions) + kdtree = build_kdtree(points.tolist()) -class TestKDTree(unittest.TestCase): - def setUp(self): - """ - Set up test data. - """ - self.num_points = 10 - self.cube_size = 10.0 - self.num_dimensions = 2 - self.points = hypercube_points( - self.num_points, self.cube_size, self.num_dimensions - ) - self.kdtree = build_kdtree(self.points.tolist()) + # Check if root is not None + assert kdtree is not None - def test_build_kdtree(self): - """ - Test that KD-Tree is built correctly. - """ - # Check if root is not None - self.assertIsNotNone(self.kdtree) + # Check if root has correct dimensions + assert len(kdtree.point) == num_dimensions - # Check if root has correct dimensions - self.assertEqual(len(self.kdtree.point), self.num_dimensions) + # Check that the tree is balanced to some extent (simplistic check) + assert isinstance(kdtree, KDNode) - # Check that the tree is balanced to some extent (simplistic check) - self.assertIsInstance(self.kdtree, KDNode) +def test_nearest_neighbour_search(): + """ + Test the nearest neighbor search function. + """ + num_points = 10 + cube_size = 10.0 + num_dimensions = 2 + points = hypercube_points(num_points, cube_size, num_dimensions) + kdtree = build_kdtree(points.tolist()) - def test_nearest_neighbour_search(self): - """ - Test the nearest neighbor search function. - """ - rng = np.random.default_rng() - query_point = rng.random(self.num_dimensions).tolist() + rng = np.random.default_rng() + query_point = rng.random(num_dimensions).tolist() - nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( - self.kdtree, query_point - ) + nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( + kdtree, query_point + ) - # Check that nearest point is not None - self.assertIsNotNone(nearest_point) + # Check that nearest point is not None + assert nearest_point is not None - # Check that distance is a non-negative number - self.assertGreaterEqual(nearest_dist, 0) + # Check that distance is a non-negative number + assert nearest_dist >= 0 - # Check that nodes visited is a non-negative integer - self.assertGreaterEqual(nodes_visited, 0) + # Check that nodes visited is a non-negative integer + assert nodes_visited >= 0 - def test_edge_cases(self): - """ - Test edge cases such as an empty KD-Tree. - """ - empty_kdtree = build_kdtree([]) - query_point = [0.0] * self.num_dimensions +def test_edge_cases(): + """ + Test edge cases such as an empty KD-Tree. + """ + empty_kdtree = build_kdtree([]) + query_point = [0.0] * 2 # Using a default 2D query point - nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( - empty_kdtree, query_point - ) - - # With an empty KD-Tree, nearest_point should be None - self.assertIsNone(nearest_point) - self.assertEqual(nearest_dist, float("inf")) - self.assertEqual(nodes_visited, 0) + nearest_point, nearest_dist, nodes_visited = nearest_neighbour_search( + empty_kdtree, query_point + ) + # With an empty KD-Tree, nearest_point should be None + assert nearest_point is None + assert nearest_dist == float("inf") + assert nodes_visited == 0 if __name__ == "__main__": - unittest.main() + import pytest + pytest.main() From 4608a9f8c2ba3a770d28cbd604987a7e4909123c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:25:51 +0000 Subject: [PATCH 15/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/build_kdtree.py | 7 +++---- data_structures/kd_tree/example/hypercube_points.py | 3 ++- data_structures/kd_tree/kd_node.py | 1 + data_structures/kd_tree/nearest_neighbour_search.py | 9 +++------ data_structures/kd_tree/tests/test_kdtree.py | 5 +++++ 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 1a0a27bb5ced..138ecbf1cd92 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,8 +1,7 @@ from data_structures.kd_tree.kd_node import KDNode -def build_kdtree( - points: list[list[float]], depth: int = 0 -) -> KDNode | None: + +def build_kdtree(points: list[list[float]], depth: int = 0) -> KDNode | None: """ Builds a KD-Tree from a list of points. @@ -25,7 +24,7 @@ def build_kdtree( # Create node and construct subtrees left_points = points[:median_idx] - right_points = points[median_idx + 1:] + right_points = points[median_idx + 1 :] return KDNode( point=points[median_idx], diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 6e844a836f4e..31073e1c8df2 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,7 +1,8 @@ import numpy as np + def hypercube_points( - num_points: int, hypercube_size: float, num_dimensions: int + num_points: int, hypercube_size: float, num_dimensions: int ) -> np.ndarray: """ Generates random points uniformly distributed within an n-dimensional hypercube. diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index f2b0ff1d2b10..e14ec39c24c0 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,5 +1,6 @@ from typing import Optional + class KDNode: """ Represents a node in a KD-Tree. diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index 1a946c342da1..1dd28e3b0119 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,8 +1,8 @@ from data_structures.kd_tree.kd_node import KDNode + def nearest_neighbour_search( - root: KDNode | None, - query_point: list[float] + root: KDNode | None, query_point: list[float] ) -> tuple[list[float] | None, float, int]: """ Performs a nearest neighbor search in a KD-Tree for a given query point. @@ -21,10 +21,7 @@ def nearest_neighbour_search( nearest_dist: float = float("inf") nodes_visited: int = 0 - def search( - node: KDNode | None, - depth: int = 0 - ) -> None: + def search(node: KDNode | None, depth: int = 0) -> None: """ Recursively searches for the nearest neighbor in the KD-Tree. diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index 8927afbaa619..b55d32a30e13 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -4,6 +4,7 @@ from data_structures.kd_tree.kd_node import KDNode from data_structures.kd_tree.example.hypercube_points import hypercube_points + def test_build_kdtree(): """ Test that KD-Tree is built correctly. @@ -23,6 +24,7 @@ def test_build_kdtree(): # Check that the tree is balanced to some extent (simplistic check) assert isinstance(kdtree, KDNode) + def test_nearest_neighbour_search(): """ Test the nearest neighbor search function. @@ -49,6 +51,7 @@ def test_nearest_neighbour_search(): # Check that nodes visited is a non-negative integer assert nodes_visited >= 0 + def test_edge_cases(): """ Test edge cases such as an empty KD-Tree. @@ -65,6 +68,8 @@ def test_edge_cases(): assert nearest_dist == float("inf") assert nodes_visited == 0 + if __name__ == "__main__": import pytest + pytest.main() From 7c1aa7ea9dc290889827da4f0d9d8ae81ccde196 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Thu, 29 Aug 2024 13:07:13 +0200 Subject: [PATCH 16/48] E501 for build_kdtree.py, hypercube_points.py, nearest_neighbour_search.py --- data_structures/kd_tree/build_kdtree.py | 6 ++++-- data_structures/kd_tree/example/hypercube_points.py | 3 ++- data_structures/kd_tree/nearest_neighbour_search.py | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 138ecbf1cd92..7850eb9019f1 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -7,10 +7,12 @@ def build_kdtree(points: list[list[float]], depth: int = 0) -> KDNode | None: Args: points (list[list[float]]): The list of points to build the KD-Tree from. - depth (int): The current depth in the tree (used to determine axis for splitting). + depth (int): The current depth in the tree + (used to determine axis for splitting). Returns: - KDNode | None: The root node of the KD-Tree, or None if no points are provided. + KDNode | None: The root node of the KD-Tree, + or None if no points are provided. """ if not points: return None diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 31073e1c8df2..d7c3937c6a17 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -13,7 +13,8 @@ def hypercube_points( num_dimensions (int): Number of dimensions of the hypercube. Returns: - np.ndarray: An array of shape (num_points, num_dimensions) with generated points. + np.ndarray: An array of shape (num_points, num_dimensions) + with generated points. """ rng = np.random.default_rng() shape = (num_points, num_dimensions) diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index 1dd28e3b0119..b37a811ee19a 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -9,11 +9,13 @@ def nearest_neighbour_search( Args: root (KDNode | None): The root node of the KD-Tree. - query_point (list[float]): The point for which the nearest neighbor is being searched. + query_point (list[float]): The point for which the nearest neighbor + is being searched. Returns: tuple[list[float] | None, float, int]: - - The nearest point found in the KD-Tree to the query point, or None if no point is found. + - The nearest point found in the KD-Tree to the query point, + or None if no point is found. - The squared distance to the nearest point. - The number of nodes visited during the search. """ From ba24e755eb95365097072a655ab9fd8572811b67 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Thu, 29 Aug 2024 13:15:27 +0200 Subject: [PATCH 17/48] I001 for example_usage.py and test_kdtree.py --- data_structures/kd_tree/example/example_usage.py | 2 +- data_structures/kd_tree/tests/test_kdtree.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index c0d76405e9d6..14355ee83d73 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,6 +1,6 @@ import numpy as np -from data_structures.kd_tree.example.hypercube_points import hypercube_points from data_structures.kd_tree.build_kdtree import build_kdtree +from data_structures.kd_tree.example.hypercube_points import hypercube_points from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index b55d32a30e13..feb99102e269 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -1,8 +1,8 @@ import numpy as np from data_structures.kd_tree.build_kdtree import build_kdtree -from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search -from data_structures.kd_tree.kd_node import KDNode from data_structures.kd_tree.example.hypercube_points import hypercube_points +from data_structures.kd_tree.kd_node import KDNode +from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search def test_build_kdtree(): From 05975a34ad0aac93e81fb256efee6a455fb836bd Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Thu, 29 Aug 2024 13:18:39 +0200 Subject: [PATCH 18/48] I001 for example_usage.py and test_kdtree.py --- data_structures/kd_tree/example/example_usage.py | 1 + data_structures/kd_tree/tests/test_kdtree.py | 1 + 2 files changed, 2 insertions(+) diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 14355ee83d73..e270f0cdd245 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,4 +1,5 @@ import numpy as np + from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.example.hypercube_points import hypercube_points from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index feb99102e269..ee3451f222f7 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -1,4 +1,5 @@ import numpy as np + from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.example.hypercube_points import hypercube_points from data_structures.kd_tree.kd_node import KDNode From 31782d1806202d95403b20074df9f3583140a331 Mon Sep 17 00:00:00 2001 From: Ramy <126559907+Ramy-Badr-Ahmed@users.noreply.github.com> Date: Tue, 3 Sep 2024 11:55:45 +0200 Subject: [PATCH 19/48] Update data_structures/kd_tree/build_kdtree.py Co-authored-by: Christian Clauss --- data_structures/kd_tree/build_kdtree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 7850eb9019f1..5fc9a406a791 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -11,7 +11,7 @@ def build_kdtree(points: list[list[float]], depth: int = 0) -> KDNode | None: (used to determine axis for splitting). Returns: - KDNode | None: The root node of the KD-Tree, + The root node of the KD-Tree, or None if no points are provided. """ if not points: From 6a9b3e16cbf1a84a6d00da01bf7a0090c8de7abf Mon Sep 17 00:00:00 2001 From: Ramy <126559907+Ramy-Badr-Ahmed@users.noreply.github.com> Date: Tue, 3 Sep 2024 11:56:09 +0200 Subject: [PATCH 20/48] Update data_structures/kd_tree/example/hypercube_points.py Co-authored-by: Christian Clauss --- data_structures/kd_tree/example/hypercube_points.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index d7c3937c6a17..04d529a2a6a6 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -8,9 +8,9 @@ def hypercube_points( Generates random points uniformly distributed within an n-dimensional hypercube. Args: - num_points (int): Number of points to generate. - hypercube_size (float): Size of the hypercube. - num_dimensions (int): Number of dimensions of the hypercube. + num_points: Number of points to generate. + hypercube_size: Size of the hypercube. + num_dimensions: Number of dimensions of the hypercube. Returns: np.ndarray: An array of shape (num_points, num_dimensions) From 2fd24d400422123ddc7878d613dca34dc58e7a8a Mon Sep 17 00:00:00 2001 From: Ramy <126559907+Ramy-Badr-Ahmed@users.noreply.github.com> Date: Tue, 3 Sep 2024 11:56:57 +0200 Subject: [PATCH 21/48] Update data_structures/kd_tree/example/hypercube_points.py Co-authored-by: Christian Clauss --- data_structures/kd_tree/example/hypercube_points.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 04d529a2a6a6..2d8800ac9338 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -13,7 +13,7 @@ def hypercube_points( num_dimensions: Number of dimensions of the hypercube. Returns: - np.ndarray: An array of shape (num_points, num_dimensions) + An array of shape (num_points, num_dimensions) with generated points. """ rng = np.random.default_rng() From 2cf9d9289657164dd78e8b79ccb0107260444adb Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Tue, 3 Sep 2024 12:40:31 +0200 Subject: [PATCH 22/48] Added new test cases requested in Review. Refactored the test_build_kdtree() to include various checks. --- data_structures/kd_tree/tests/test_kdtree.py | 43 ++++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index ee3451f222f7..516ad46adb2b 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -1,4 +1,5 @@ import numpy as np +import pytest from data_structures.kd_tree.build_kdtree import build_kdtree from data_structures.kd_tree.example.hypercube_points import hypercube_points @@ -6,24 +7,42 @@ from data_structures.kd_tree.nearest_neighbour_search import nearest_neighbour_search -def test_build_kdtree(): +@pytest.mark.parametrize( + "num_points, cube_size, num_dimensions, depth, expected_result", + [ + (0, 10.0, 2, 0, None), # Empty points list + (10, 10.0, 2, 2, KDNode), # Depth = 2, 2D points + (10, 10.0, 3, -2, KDNode), # Depth = -2, 3D points + ], +) +def test_build_kdtree(num_points, cube_size, num_dimensions, depth, expected_result): """ Test that KD-Tree is built correctly. + + Cases: + - Empty points list. + - Positive depth value. + - Negative depth value. """ - num_points = 10 - cube_size = 10.0 - num_dimensions = 2 - points = hypercube_points(num_points, cube_size, num_dimensions) - kdtree = build_kdtree(points.tolist()) + points = hypercube_points(num_points, cube_size, num_dimensions).tolist() \ + if num_points > 0 \ + else [] + + kdtree = build_kdtree(points, depth = depth) - # Check if root is not None - assert kdtree is not None + if expected_result is None: + # Empty points list case + assert kdtree is None, f"Expected None for empty points list, got {kdtree}" + else: + # Check if root node is not None + assert kdtree is not None, "Expected a KDNode, got None" - # Check if root has correct dimensions - assert len(kdtree.point) == num_dimensions + # Check if root has correct dimensions + assert len(kdtree.point) == num_dimensions, \ + f"Expected point dimension {num_dimensions}, got {len(kdtree.point)}" - # Check that the tree is balanced to some extent (simplistic check) - assert isinstance(kdtree, KDNode) + # Check that the tree is balanced to some extent (simplistic check) + assert isinstance(kdtree, KDNode), f"Expected KDNode instance, got {type(kdtree)}" def test_nearest_neighbour_search(): From a3803ee251ae13fc55f4e37d18f49f4afc32b762 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 10:41:47 +0000 Subject: [PATCH 23/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/tests/test_kdtree.py | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index 516ad46adb2b..36ed791121f9 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -10,8 +10,8 @@ @pytest.mark.parametrize( "num_points, cube_size, num_dimensions, depth, expected_result", [ - (0, 10.0, 2, 0, None), # Empty points list - (10, 10.0, 2, 2, KDNode), # Depth = 2, 2D points + (0, 10.0, 2, 0, None), # Empty points list + (10, 10.0, 2, 2, KDNode), # Depth = 2, 2D points (10, 10.0, 3, -2, KDNode), # Depth = -2, 3D points ], ) @@ -24,11 +24,13 @@ def test_build_kdtree(num_points, cube_size, num_dimensions, depth, expected_res - Positive depth value. - Negative depth value. """ - points = hypercube_points(num_points, cube_size, num_dimensions).tolist() \ - if num_points > 0 \ + points = ( + hypercube_points(num_points, cube_size, num_dimensions).tolist() + if num_points > 0 else [] + ) - kdtree = build_kdtree(points, depth = depth) + kdtree = build_kdtree(points, depth=depth) if expected_result is None: # Empty points list case @@ -38,11 +40,14 @@ def test_build_kdtree(num_points, cube_size, num_dimensions, depth, expected_res assert kdtree is not None, "Expected a KDNode, got None" # Check if root has correct dimensions - assert len(kdtree.point) == num_dimensions, \ - f"Expected point dimension {num_dimensions}, got {len(kdtree.point)}" + assert ( + len(kdtree.point) == num_dimensions + ), f"Expected point dimension {num_dimensions}, got {len(kdtree.point)}" # Check that the tree is balanced to some extent (simplistic check) - assert isinstance(kdtree, KDNode), f"Expected KDNode instance, got {type(kdtree)}" + assert isinstance( + kdtree, KDNode + ), f"Expected KDNode instance, got {type(kdtree)}" def test_nearest_neighbour_search(): From f1f5862c836c1a440fdcc331a4d2386c3880c70e Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Tue, 3 Sep 2024 12:46:30 +0200 Subject: [PATCH 24/48] Considered ruff errors --- data_structures/kd_tree/tests/test_kdtree.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index 516ad46adb2b..b53bc2496bef 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -8,7 +8,7 @@ @pytest.mark.parametrize( - "num_points, cube_size, num_dimensions, depth, expected_result", + ("num_points", "cube_size", "num_dimensions", "depth", "expected_result"), [ (0, 10.0, 2, 0, None), # Empty points list (10, 10.0, 2, 2, KDNode), # Depth = 2, 2D points @@ -42,7 +42,8 @@ def test_build_kdtree(num_points, cube_size, num_dimensions, depth, expected_res f"Expected point dimension {num_dimensions}, got {len(kdtree.point)}" # Check that the tree is balanced to some extent (simplistic check) - assert isinstance(kdtree, KDNode), f"Expected KDNode instance, got {type(kdtree)}" + assert isinstance(kdtree, KDNode), \ + f"Expected KDNode instance, got {type(kdtree)}" def test_nearest_neighbour_search(): From 5c07a1a4851654e1030786cb619873c6e1492800 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Tue, 3 Sep 2024 12:49:32 +0200 Subject: [PATCH 25/48] Considered ruff errors --- data_structures/kd_tree/tests/test_kdtree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index 36ed791121f9..81f2cc990074 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -8,7 +8,7 @@ @pytest.mark.parametrize( - "num_points, cube_size, num_dimensions, depth, expected_result", + ("num_points", "cube_size", "num_dimensions", "depth", "expected_result"), [ (0, 10.0, 2, 0, None), # Empty points list (10, 10.0, 2, 2, KDNode), # Depth = 2, 2D points From 3c09ac1dd793f3ee43003427e1475d5f303b6a22 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 3 Sep 2024 13:58:34 +0200 Subject: [PATCH 26/48] Apply suggestions from code review --- data_structures/kd_tree/build_kdtree.py | 4 ++-- data_structures/kd_tree/kd_node.py | 13 +++++-------- data_structures/kd_tree/nearest_neighbour_search.py | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 5fc9a406a791..c5b800a2c992 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -6,8 +6,8 @@ def build_kdtree(points: list[list[float]], depth: int = 0) -> KDNode | None: Builds a KD-Tree from a list of points. Args: - points (list[list[float]]): The list of points to build the KD-Tree from. - depth (int): The current depth in the tree + points: The list of points to build the KD-Tree from. + depth: The current depth in the tree (used to determine axis for splitting). Returns: diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index e14ec39c24c0..276773ee595c 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,21 +1,18 @@ -from typing import Optional - - class KDNode: """ Represents a node in a KD-Tree. Attributes: - point (list[float]): The point stored in this node. - left (Optional[KDNode]): The left child node. - right (Optional[KDNode]): The right child node. + point: The point stored in this node. + left: The left child node. + right: The right child node. """ def __init__( self, point: list[float], - left: Optional["KDNode"] = None, - right: Optional["KDNode"] = None, + left: KDNode | None = None, + right: KDNode | None = None, ) -> None: """ Initializes a KDNode with the given point and child nodes. diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index b37a811ee19a..d9727736f21c 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -28,8 +28,8 @@ def search(node: KDNode | None, depth: int = 0) -> None: Recursively searches for the nearest neighbor in the KD-Tree. Args: - node (KDNode | None): The current node in the KD-Tree. - depth (int): The current depth in the KD-Tree. + node: The current node in the KD-Tree. + depth: The current depth in the KD-Tree. """ nonlocal nearest_point, nearest_dist, nodes_visited if node is None: From bab43e75d3fc2eadc9d0c68e86069da504d4a721 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 11:58:57 +0000 Subject: [PATCH 27/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/kd_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 276773ee595c..11e21c34efe0 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -12,7 +12,7 @@ def __init__( self, point: list[float], left: KDNode | None = None, - right: KDNode | None = None, + right: KDNode | None = None, ) -> None: """ Initializes a KDNode with the given point and child nodes. From a10ff1507ae14b505d5f8516a43b4d7f040a8695 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 3 Sep 2024 14:00:37 +0200 Subject: [PATCH 28/48] Update kd_node.py --- data_structures/kd_tree/kd_node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 11e21c34efe0..c76e77fdf3bf 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -11,8 +11,8 @@ class KDNode: def __init__( self, point: list[float], - left: KDNode | None = None, - right: KDNode | None = None, + left: "KDNode" | None = None, + right: "KDNode" | None = None, ) -> None: """ Initializes a KDNode with the given point and child nodes. From d77a2859bb7bcf58098d350a56f35ca138541625 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Tue, 3 Sep 2024 14:29:51 +0200 Subject: [PATCH 29/48] imported annotations from __future__ --- data_structures/kd_tree/kd_node.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index c76e77fdf3bf..0bd8cfee6855 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,3 +1,6 @@ +from __future__ import annotations + + class KDNode: """ Represents a node in a KD-Tree. @@ -11,8 +14,8 @@ class KDNode: def __init__( self, point: list[float], - left: "KDNode" | None = None, - right: "KDNode" | None = None, + left: KDNode | None = None, + right: KDNode | None = None, ) -> None: """ Initializes a KDNode with the given point and child nodes. From 042680694e9d181a6c401aefdcb8696074d00401 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:30:25 +0000 Subject: [PATCH 30/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/kd_tree/kd_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index 0bd8cfee6855..e1011027938d 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -14,7 +14,7 @@ class KDNode: def __init__( self, point: list[float], - left: KDNode | None = None, + left: KDNode | None = None, right: KDNode | None = None, ) -> None: """ From 9c4cbd475311e6ace73e565162a374cd78549b75 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 20:54:08 +0200 Subject: [PATCH 31/48] Implementation of the suffix tree data structure --- data_structures/suffix_tree/__init__.py | 0 .../suffix_tree/build_suffix_tree.py | 58 +++++++++++++++++++ .../suffix_tree/example/__init__.py | 0 .../suffix_tree/example/example_usage.py | 29 ++++++++++ .../suffix_tree/suffix_tree_node.py | 26 +++++++++ data_structures/suffix_tree/tests/__init__.py | 0 .../suffix_tree/tests/test_suffix_tree.py | 42 ++++++++++++++ 7 files changed, 155 insertions(+) create mode 100644 data_structures/suffix_tree/__init__.py create mode 100644 data_structures/suffix_tree/build_suffix_tree.py create mode 100644 data_structures/suffix_tree/example/__init__.py create mode 100644 data_structures/suffix_tree/example/example_usage.py create mode 100644 data_structures/suffix_tree/suffix_tree_node.py create mode 100644 data_structures/suffix_tree/tests/__init__.py create mode 100644 data_structures/suffix_tree/tests/test_suffix_tree.py diff --git a/data_structures/suffix_tree/__init__.py b/data_structures/suffix_tree/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/data_structures/suffix_tree/build_suffix_tree.py b/data_structures/suffix_tree/build_suffix_tree.py new file mode 100644 index 000000000000..1044b7f0a768 --- /dev/null +++ b/data_structures/suffix_tree/build_suffix_tree.py @@ -0,0 +1,58 @@ +from data_structures.suffix_tree.suffix_tree_node import SuffixTreeNode + + +class SuffixTree: + def __init__(self, text: str) -> None: + """ + Initializes the suffix tree with the given text. + + Args: + text (str): The text for which the suffix tree is to be built. + """ + self.text: str = text + self.root: SuffixTreeNode = SuffixTreeNode() + self.build_suffix_tree() + + def build_suffix_tree(self) -> None: + """ + Builds the suffix tree for the given text by adding all suffixes. + """ + text = self.text + n = len(text) + for i in range(n): + suffix = text[i:] + self._add_suffix(suffix, i) + + def _add_suffix(self, suffix: str, index: int) -> None: + """ + Adds a suffix to the suffix tree. + + Args: + suffix (str): The suffix to add. + index (int): The starting index of the suffix in the original text. + """ + node = self.root + for char in suffix: + if char not in node.children: + node.children[char] = SuffixTreeNode() + node = node.children[char] + node.is_end_of_string = True + node.start = index + node.end = index + len(suffix) - 1 + + def search(self, pattern: str) -> bool: + """ + Searches for a pattern in the suffix tree. + + Args: + pattern (str): The pattern to search for. + + Returns: + bool: True if the pattern is found, False otherwise. + """ + node = self.root + for char in pattern: + if char not in node.children: + return False + node = node.children[char] + return True diff --git a/data_structures/suffix_tree/example/__init__.py b/data_structures/suffix_tree/example/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/data_structures/suffix_tree/example/example_usage.py b/data_structures/suffix_tree/example/example_usage.py new file mode 100644 index 000000000000..c2563cd59f05 --- /dev/null +++ b/data_structures/suffix_tree/example/example_usage.py @@ -0,0 +1,29 @@ +from data_structures.suffix_tree.build_suffix_tree import SuffixTree + + +def main() -> None: + """ + Demonstrate the usage of the SuffixTree class. + + - Initializes a SuffixTree with a predefined text. + - Defines a list of patterns to search for within the suffix tree. + - Searches for each pattern in the suffix tree. + + Patterns tested: + - "ana" (found) --> True + - "ban" (found) --> True + - "na" (found) --> True + - "xyz" (not found) --> False + - "mon" (found) --> True + """ + text = "monkey banana" + suffix_tree = SuffixTree(text) + + patterns = ["ana", "ban", "na", "xyz", "mon"] + for pattern in patterns: + found = suffix_tree.search(pattern) + print(f"Pattern '{pattern}' found: {found}") + + +if __name__ == "__main__": + main() diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py new file mode 100644 index 000000000000..b845280e4cc8 --- /dev/null +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -0,0 +1,26 @@ +from __future__ import annotations +from typing import Dict, Optional + + +class SuffixTreeNode: + def __init__(self, + children: Dict[str, 'SuffixTreeNode'] = None, + is_end_of_string: bool = False, + start: int | None = None, + end: int | None = None, + suffix_link: SuffixTreeNode | None = None) -> None: + """ + Initializes a suffix tree node. + + Parameters: + children (Dict[str, SuffixTreeNode], optional): The children of this node. Defaults to an empty dictionary. + is_end_of_string (bool, optional): Indicates if this node represents the end of a string. Defaults to False. + start (int | None, optional): The start index of the suffix in the text. Defaults to None. + end (int | None, optional): The end index of the suffix in the text. Defaults to None. + suffix_link (SuffixTreeNode | None, optional): Link to another suffix tree node. Defaults to None. + """ + self.children = children or {} + self.is_end_of_string = is_end_of_string + self.start = start + self.end = end + self.suffix_link = suffix_link diff --git a/data_structures/suffix_tree/tests/__init__.py b/data_structures/suffix_tree/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py new file mode 100644 index 000000000000..fe8a73551ff9 --- /dev/null +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -0,0 +1,42 @@ +import unittest +from data_structures.suffix_tree.build_suffix_tree import SuffixTree + + +class TestSuffixTree(unittest.TestCase): + def setUp(self) -> None: + """Set up the initial conditions for each test.""" + self.text = "banana" + self.suffix_tree = SuffixTree(self.text) + + def test_search_existing_patterns(self): + """Test searching for patterns that exist in the suffix tree.""" + patterns = ["ana", "ban", "na"] + for pattern in patterns: + with self.subTest(pattern = pattern): + self.assertTrue(self.suffix_tree.search(pattern), f"Pattern '{pattern}' should be found.") + + def test_search_non_existing_patterns(self): + """Test searching for patterns that do not exist in the suffix tree.""" + patterns = ["xyz", "apple", "cat"] + for pattern in patterns: + with self.subTest(pattern = pattern): + self.assertFalse(self.suffix_tree.search(pattern), f"Pattern '{pattern}' should not be found.") + + def test_search_empty_pattern(self): + """Test searching for an empty pattern.""" + self.assertTrue(self.suffix_tree.search(""), "An empty pattern should be found.") + + def test_search_full_text(self): + """Test searching for the full text.""" + self.assertTrue(self.suffix_tree.search(self.text), "The full text should be found in the suffix tree.") + + def test_search_substrings(self): + """Test searching for substrings of the full text.""" + substrings = ["ban", "ana", "a", "na"] + for substring in substrings: + with self.subTest(substring = substring): + self.assertTrue(self.suffix_tree.search(substring), f"Substring '{substring}' should be found.") + + +if __name__ == "__main__": + unittest.main() From 95ae328460789adc7b7946a11eebb4b7ced28964 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 21:00:46 +0200 Subject: [PATCH 32/48] Adding data to DIRECTORY.md --- DIRECTORY.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 1ca537b991c8..fd71075f97b9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -289,8 +289,12 @@ * [KD Tree Node](data_structures/kd_tree/kd_node.py) * [Build KD Tree](data_structures/kd_tree/build_kdtree.py) * [Nearest Neighbour Search](data_structures/kd_tree/nearest_neighbour_search.py) - * [Hypercibe Points](data_structures/kd_tree/example/hypercube_points.py) + * [Hypercube Points](data_structures/kd_tree/example/hypercube_points.py) * [Example Usage](data_structures/kd_tree/example/example_usage.py) + * Suffix Tree + * [Suffix Tree Node](data_structures/suffix_tree/suffix_tree_node.py) + * [Build Suffix Tree](data_structures/suffix_tree/build_suffix_tree.py) + * [Example Usage](data_structures/suffix_tree/example/example_usage.py) ## Digital Image Processing * [Change Brightness](digital_image_processing/change_brightness.py) From 1454bb22bb9c28ba7a7c989ce4aaa0c67582518e Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 21:23:33 +0200 Subject: [PATCH 33/48] Minor file renaming --- data_structures/suffix_tree/example/example_usage.py | 2 +- .../suffix_tree/{build_suffix_tree.py => suffix_tree.py} | 0 data_structures/suffix_tree/tests/test_suffix_tree.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename data_structures/suffix_tree/{build_suffix_tree.py => suffix_tree.py} (100%) diff --git a/data_structures/suffix_tree/example/example_usage.py b/data_structures/suffix_tree/example/example_usage.py index c2563cd59f05..d097cb6e33f3 100644 --- a/data_structures/suffix_tree/example/example_usage.py +++ b/data_structures/suffix_tree/example/example_usage.py @@ -1,4 +1,4 @@ -from data_structures.suffix_tree.build_suffix_tree import SuffixTree +from data_structures.suffix_tree.suffix_tree import SuffixTree def main() -> None: diff --git a/data_structures/suffix_tree/build_suffix_tree.py b/data_structures/suffix_tree/suffix_tree.py similarity index 100% rename from data_structures/suffix_tree/build_suffix_tree.py rename to data_structures/suffix_tree/suffix_tree.py diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index fe8a73551ff9..cef147a3d41c 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -1,5 +1,5 @@ import unittest -from data_structures.suffix_tree.build_suffix_tree import SuffixTree +from data_structures.suffix_tree.suffix_tree import SuffixTree class TestSuffixTree(unittest.TestCase): From a2b3a8677da1f1f40b574306ff25b631f4f74fb9 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 21:36:05 +0200 Subject: [PATCH 34/48] minor correction --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index fd71075f97b9..4554ab669506 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -289,7 +289,7 @@ * [KD Tree Node](data_structures/kd_tree/kd_node.py) * [Build KD Tree](data_structures/kd_tree/build_kdtree.py) * [Nearest Neighbour Search](data_structures/kd_tree/nearest_neighbour_search.py) - * [Hypercube Points](data_structures/kd_tree/example/hypercube_points.py) + * [Hypercibe Points](data_structures/kd_tree/example/hypercube_points.py) * [Example Usage](data_structures/kd_tree/example/example_usage.py) * Suffix Tree * [Suffix Tree Node](data_structures/suffix_tree/suffix_tree_node.py) From 51832af53fa56b3075c7b30826abeeadf359edf4 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 21:54:06 +0200 Subject: [PATCH 35/48] renaming in DIRECTORY.md --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 4554ab669506..272b55510d46 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -293,7 +293,7 @@ * [Example Usage](data_structures/kd_tree/example/example_usage.py) * Suffix Tree * [Suffix Tree Node](data_structures/suffix_tree/suffix_tree_node.py) - * [Build Suffix Tree](data_structures/suffix_tree/build_suffix_tree.py) + * [Suffix Tree](data_structures/suffix_tree/suffix_tree.py) * [Example Usage](data_structures/suffix_tree/example/example_usage.py) ## Digital Image Processing From 6b5bddcedfc4c5a4fe6d7e73d4817290d7ac0067 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:06:03 +0000 Subject: [PATCH 36/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../suffix_tree/suffix_tree_node.py | 14 +++++---- .../suffix_tree/tests/test_suffix_tree.py | 30 ++++++++++++++----- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index b845280e4cc8..3a67daec6d36 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -3,12 +3,14 @@ class SuffixTreeNode: - def __init__(self, - children: Dict[str, 'SuffixTreeNode'] = None, - is_end_of_string: bool = False, - start: int | None = None, - end: int | None = None, - suffix_link: SuffixTreeNode | None = None) -> None: + def __init__( + self, + children: Dict[str, "SuffixTreeNode"] = None, + is_end_of_string: bool = False, + start: int | None = None, + end: int | None = None, + suffix_link: SuffixTreeNode | None = None, + ) -> None: """ Initializes a suffix tree node. diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index cef147a3d41c..aa65c6b39e4a 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -12,30 +12,44 @@ def test_search_existing_patterns(self): """Test searching for patterns that exist in the suffix tree.""" patterns = ["ana", "ban", "na"] for pattern in patterns: - with self.subTest(pattern = pattern): - self.assertTrue(self.suffix_tree.search(pattern), f"Pattern '{pattern}' should be found.") + with self.subTest(pattern=pattern): + self.assertTrue( + self.suffix_tree.search(pattern), + f"Pattern '{pattern}' should be found.", + ) def test_search_non_existing_patterns(self): """Test searching for patterns that do not exist in the suffix tree.""" patterns = ["xyz", "apple", "cat"] for pattern in patterns: - with self.subTest(pattern = pattern): - self.assertFalse(self.suffix_tree.search(pattern), f"Pattern '{pattern}' should not be found.") + with self.subTest(pattern=pattern): + self.assertFalse( + self.suffix_tree.search(pattern), + f"Pattern '{pattern}' should not be found.", + ) def test_search_empty_pattern(self): """Test searching for an empty pattern.""" - self.assertTrue(self.suffix_tree.search(""), "An empty pattern should be found.") + self.assertTrue( + self.suffix_tree.search(""), "An empty pattern should be found." + ) def test_search_full_text(self): """Test searching for the full text.""" - self.assertTrue(self.suffix_tree.search(self.text), "The full text should be found in the suffix tree.") + self.assertTrue( + self.suffix_tree.search(self.text), + "The full text should be found in the suffix tree.", + ) def test_search_substrings(self): """Test searching for substrings of the full text.""" substrings = ["ban", "ana", "a", "na"] for substring in substrings: - with self.subTest(substring = substring): - self.assertTrue(self.suffix_tree.search(substring), f"Substring '{substring}' should be found.") + with self.subTest(substring=substring): + self.assertTrue( + self.suffix_tree.search(substring), + f"Substring '{substring}' should be found.", + ) if __name__ == "__main__": From 79f40ea94739aa636bb5517750123a1341ed89c2 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 22:32:24 +0200 Subject: [PATCH 37/48] Considering ruff part-1 --- .../suffix_tree/suffix_tree_node.py | 14 +++---- .../suffix_tree/tests/test_suffix_tree.py | 38 ++++++------------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index 3a67daec6d36..f20d77afcd07 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -1,11 +1,10 @@ from __future__ import annotations -from typing import Dict, Optional class SuffixTreeNode: def __init__( self, - children: Dict[str, "SuffixTreeNode"] = None, + children: dict[str, "SuffixTreeNode"] = None, is_end_of_string: bool = False, start: int | None = None, end: int | None = None, @@ -15,11 +14,12 @@ def __init__( Initializes a suffix tree node. Parameters: - children (Dict[str, SuffixTreeNode], optional): The children of this node. Defaults to an empty dictionary. - is_end_of_string (bool, optional): Indicates if this node represents the end of a string. Defaults to False. - start (int | None, optional): The start index of the suffix in the text. Defaults to None. - end (int | None, optional): The end index of the suffix in the text. Defaults to None. - suffix_link (SuffixTreeNode | None, optional): Link to another suffix tree node. Defaults to None. + children (Dict[str, SuffixTreeNode]|None): The children of this node. + is_end_of_string (bool): Indicates if this node represents + the end of a string. + start (int|None): The start index of the suffix in the text. + end (int|None): The end index of the suffix in the text. + suffix_link (SuffixTreeNode|None): Link to another suffix tree node. """ self.children = children or {} self.is_end_of_string = is_end_of_string diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index aa65c6b39e4a..08438a273491 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -8,48 +8,34 @@ def setUp(self) -> None: self.text = "banana" self.suffix_tree = SuffixTree(self.text) - def test_search_existing_patterns(self): + def test_search_existing_patterns(self) -> None: """Test searching for patterns that exist in the suffix tree.""" patterns = ["ana", "ban", "na"] for pattern in patterns: - with self.subTest(pattern=pattern): - self.assertTrue( - self.suffix_tree.search(pattern), - f"Pattern '{pattern}' should be found.", - ) + with self.subTest(pattern = pattern): + assert self.suffix_tree.search(pattern), f"Pattern '{pattern}' should be found." - def test_search_non_existing_patterns(self): + def test_search_non_existing_patterns(self) -> None: """Test searching for patterns that do not exist in the suffix tree.""" patterns = ["xyz", "apple", "cat"] for pattern in patterns: - with self.subTest(pattern=pattern): - self.assertFalse( - self.suffix_tree.search(pattern), - f"Pattern '{pattern}' should not be found.", - ) + with self.subTest(pattern = pattern): + assert not self.suffix_tree.search(pattern), f"Pattern '{pattern}' should not be found." - def test_search_empty_pattern(self): + def test_search_empty_pattern(self) -> None: """Test searching for an empty pattern.""" - self.assertTrue( - self.suffix_tree.search(""), "An empty pattern should be found." - ) + assert self.suffix_tree.search(""), "An empty pattern should be found." - def test_search_full_text(self): + def test_search_full_text(self) -> None: """Test searching for the full text.""" - self.assertTrue( - self.suffix_tree.search(self.text), - "The full text should be found in the suffix tree.", - ) + assert self.suffix_tree.search(self.text), "The full text should be found in the suffix tree." - def test_search_substrings(self): + def test_search_substrings(self) -> None: """Test searching for substrings of the full text.""" substrings = ["ban", "ana", "a", "na"] for substring in substrings: with self.subTest(substring=substring): - self.assertTrue( - self.suffix_tree.search(substring), - f"Substring '{substring}' should be found.", - ) + assert self.suffix_tree.search(substring), f"Substring '{substring}' should be found." if __name__ == "__main__": From bac6962182c2c28f17e94edb5878d8f9a8aed79f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:32:52 +0000 Subject: [PATCH 38/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../suffix_tree/tests/test_suffix_tree.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index 08438a273491..8c88eed3a8ba 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -12,15 +12,19 @@ def test_search_existing_patterns(self) -> None: """Test searching for patterns that exist in the suffix tree.""" patterns = ["ana", "ban", "na"] for pattern in patterns: - with self.subTest(pattern = pattern): - assert self.suffix_tree.search(pattern), f"Pattern '{pattern}' should be found." + with self.subTest(pattern=pattern): + assert self.suffix_tree.search( + pattern + ), f"Pattern '{pattern}' should be found." def test_search_non_existing_patterns(self) -> None: """Test searching for patterns that do not exist in the suffix tree.""" patterns = ["xyz", "apple", "cat"] for pattern in patterns: - with self.subTest(pattern = pattern): - assert not self.suffix_tree.search(pattern), f"Pattern '{pattern}' should not be found." + with self.subTest(pattern=pattern): + assert not self.suffix_tree.search( + pattern + ), f"Pattern '{pattern}' should not be found." def test_search_empty_pattern(self) -> None: """Test searching for an empty pattern.""" @@ -28,14 +32,18 @@ def test_search_empty_pattern(self) -> None: def test_search_full_text(self) -> None: """Test searching for the full text.""" - assert self.suffix_tree.search(self.text), "The full text should be found in the suffix tree." + assert self.suffix_tree.search( + self.text + ), "The full text should be found in the suffix tree." def test_search_substrings(self) -> None: """Test searching for substrings of the full text.""" substrings = ["ban", "ana", "a", "na"] for substring in substrings: with self.subTest(substring=substring): - assert self.suffix_tree.search(substring), f"Substring '{substring}' should be found." + assert self.suffix_tree.search( + substring + ), f"Substring '{substring}' should be found." if __name__ == "__main__": From 87909da36b8890e1c0a8433d135ddaf16650e8a0 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 22:40:59 +0200 Subject: [PATCH 39/48] Considering ruff part-2 --- .../suffix_tree/suffix_tree_node.py | 10 ++++----- .../suffix_tree/tests/test_suffix_tree.py | 21 +++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index f20d77afcd07..bf67db21f892 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -4,7 +4,7 @@ class SuffixTreeNode: def __init__( self, - children: dict[str, "SuffixTreeNode"] = None, + children: dict[str, SuffixTreeNode] = None, is_end_of_string: bool = False, start: int | None = None, end: int | None = None, @@ -14,12 +14,12 @@ def __init__( Initializes a suffix tree node. Parameters: - children (Dict[str, SuffixTreeNode]|None): The children of this node. + children (dict[str, SuffixTreeNode] | None): The children of this node. is_end_of_string (bool): Indicates if this node represents the end of a string. - start (int|None): The start index of the suffix in the text. - end (int|None): The end index of the suffix in the text. - suffix_link (SuffixTreeNode|None): Link to another suffix tree node. + start (int | None): The start index of the suffix in the text. + end (int | None): The end index of the suffix in the text. + suffix_link (SuffixTreeNode | None): Link to another suffix tree node. """ self.children = children or {} self.is_end_of_string = is_end_of_string diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index 08438a273491..0de817153b55 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -1,4 +1,5 @@ import unittest + from data_structures.suffix_tree.suffix_tree import SuffixTree @@ -12,15 +13,19 @@ def test_search_existing_patterns(self) -> None: """Test searching for patterns that exist in the suffix tree.""" patterns = ["ana", "ban", "na"] for pattern in patterns: - with self.subTest(pattern = pattern): - assert self.suffix_tree.search(pattern), f"Pattern '{pattern}' should be found." + with ((self.subTest(pattern = pattern))): + assert self.suffix_tree.search(pattern), ( + f"Pattern '{pattern}' should be found." + ) def test_search_non_existing_patterns(self) -> None: """Test searching for patterns that do not exist in the suffix tree.""" patterns = ["xyz", "apple", "cat"] for pattern in patterns: with self.subTest(pattern = pattern): - assert not self.suffix_tree.search(pattern), f"Pattern '{pattern}' should not be found." + assert not self.suffix_tree.search(pattern), ( + f"Pattern '{pattern}' should not be found." + ) def test_search_empty_pattern(self) -> None: """Test searching for an empty pattern.""" @@ -28,14 +33,18 @@ def test_search_empty_pattern(self) -> None: def test_search_full_text(self) -> None: """Test searching for the full text.""" - assert self.suffix_tree.search(self.text), "The full text should be found in the suffix tree." + assert self.suffix_tree.search(self.text), ( + "The full text should be found in the suffix tree." + ) def test_search_substrings(self) -> None: """Test searching for substrings of the full text.""" substrings = ["ban", "ana", "a", "na"] for substring in substrings: - with self.subTest(substring=substring): - assert self.suffix_tree.search(substring), f"Substring '{substring}' should be found." + with self.subTest(substring = substring): + assert self.suffix_tree.search(substring), ( + f"Substring '{substring}' should be found." + ) if __name__ == "__main__": From 288a4f0eb8f53d148c815c4674dff789ec4bbe88 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:42:47 +0000 Subject: [PATCH 40/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../suffix_tree/tests/test_suffix_tree.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index 0de817153b55..43f7d208a954 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -13,19 +13,19 @@ def test_search_existing_patterns(self) -> None: """Test searching for patterns that exist in the suffix tree.""" patterns = ["ana", "ban", "na"] for pattern in patterns: - with ((self.subTest(pattern = pattern))): - assert self.suffix_tree.search(pattern), ( - f"Pattern '{pattern}' should be found." - ) + with self.subTest(pattern=pattern): + assert self.suffix_tree.search( + pattern + ), f"Pattern '{pattern}' should be found." def test_search_non_existing_patterns(self) -> None: """Test searching for patterns that do not exist in the suffix tree.""" patterns = ["xyz", "apple", "cat"] for pattern in patterns: - with self.subTest(pattern = pattern): - assert not self.suffix_tree.search(pattern), ( - f"Pattern '{pattern}' should not be found." - ) + with self.subTest(pattern=pattern): + assert not self.suffix_tree.search( + pattern + ), f"Pattern '{pattern}' should not be found." def test_search_empty_pattern(self) -> None: """Test searching for an empty pattern.""" @@ -33,18 +33,18 @@ def test_search_empty_pattern(self) -> None: def test_search_full_text(self) -> None: """Test searching for the full text.""" - assert self.suffix_tree.search(self.text), ( - "The full text should be found in the suffix tree." - ) + assert self.suffix_tree.search( + self.text + ), "The full text should be found in the suffix tree." def test_search_substrings(self) -> None: """Test searching for substrings of the full text.""" substrings = ["ban", "ana", "a", "na"] for substring in substrings: - with self.subTest(substring = substring): - assert self.suffix_tree.search(substring), ( - f"Substring '{substring}' should be found." - ) + with self.subTest(substring=substring): + assert self.suffix_tree.search( + substring + ), f"Substring '{substring}' should be found." if __name__ == "__main__": From 93e910d91c5a7ab133aa889b5d74005cdf0b114e Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 22:46:44 +0200 Subject: [PATCH 41/48] Considering ruff part-3 --- .../suffix_tree/suffix_tree_node.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index bf67db21f892..4c77500fd2ca 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -1,25 +1,25 @@ -from __future__ import annotations +from typing import Dict, Optional class SuffixTreeNode: def __init__( - self, - children: dict[str, SuffixTreeNode] = None, - is_end_of_string: bool = False, - start: int | None = None, - end: int | None = None, - suffix_link: SuffixTreeNode | None = None, + self, + children: Optional[Dict[str, 'SuffixTreeNode']] = None, + is_end_of_string: bool = False, + start: Optional[int] = None, + end: Optional[int] = None, + suffix_link: Optional['SuffixTreeNode'] = None, ) -> None: """ Initializes a suffix tree node. Parameters: - children (dict[str, SuffixTreeNode] | None): The children of this node. + children (Optional[Dict[str, SuffixTreeNode]]): The children of this node. is_end_of_string (bool): Indicates if this node represents the end of a string. - start (int | None): The start index of the suffix in the text. - end (int | None): The end index of the suffix in the text. - suffix_link (SuffixTreeNode | None): Link to another suffix tree node. + start (Optional[int]): The start index of the suffix in the text. + end (Optional[int]): The end index of the suffix in the text. + suffix_link (Optional[SuffixTreeNode]): Link to another suffix tree node. """ self.children = children or {} self.is_end_of_string = is_end_of_string From e375de7a1eb5ef1bcb749732461151abfd7f5c9e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:47:07 +0000 Subject: [PATCH 42/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/suffix_tree/suffix_tree_node.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index 4c77500fd2ca..5671880d4fbe 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -3,12 +3,12 @@ class SuffixTreeNode: def __init__( - self, - children: Optional[Dict[str, 'SuffixTreeNode']] = None, - is_end_of_string: bool = False, - start: Optional[int] = None, - end: Optional[int] = None, - suffix_link: Optional['SuffixTreeNode'] = None, + self, + children: Optional[Dict[str, "SuffixTreeNode"]] = None, + is_end_of_string: bool = False, + start: Optional[int] = None, + end: Optional[int] = None, + suffix_link: Optional["SuffixTreeNode"] = None, ) -> None: """ Initializes a suffix tree node. From 52ba6d21436fccc428f7123e4f1865136479cc0d Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 22:50:31 +0200 Subject: [PATCH 43/48] Considering ruff part-4 --- .../suffix_tree/suffix_tree_node.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index 5671880d4fbe..80700d5b6e0d 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -1,25 +1,25 @@ -from typing import Dict, Optional +from __future__ import annotations class SuffixTreeNode: def __init__( - self, - children: Optional[Dict[str, "SuffixTreeNode"]] = None, - is_end_of_string: bool = False, - start: Optional[int] = None, - end: Optional[int] = None, - suffix_link: Optional["SuffixTreeNode"] = None, + self, + children: dict[str, SuffixTreeNode] = None, + is_end_of_string: bool = False, + start: int | None = None, + end: int | None = None, + suffix_link: SuffixTreeNode | None = None, ) -> None: """ Initializes a suffix tree node. Parameters: - children (Optional[Dict[str, SuffixTreeNode]]): The children of this node. + children (dict[str, SuffixTreeNode] | None): The children of this node. is_end_of_string (bool): Indicates if this node represents the end of a string. - start (Optional[int]): The start index of the suffix in the text. - end (Optional[int]): The end index of the suffix in the text. - suffix_link (Optional[SuffixTreeNode]): Link to another suffix tree node. + start (int | None): The start index of the suffix in the text. + end (int | None): The end index of the suffix in the text. + suffix_link (SuffixTreeNode | None): Link to another suffix tree node. """ self.children = children or {} self.is_end_of_string = is_end_of_string From 531252edb691af07c25100b6c95e57810acf4ab1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:50:55 +0000 Subject: [PATCH 44/48] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/suffix_tree/suffix_tree_node.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index 80700d5b6e0d..bf67db21f892 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -3,12 +3,12 @@ class SuffixTreeNode: def __init__( - self, - children: dict[str, SuffixTreeNode] = None, - is_end_of_string: bool = False, - start: int | None = None, - end: int | None = None, - suffix_link: SuffixTreeNode | None = None, + self, + children: dict[str, SuffixTreeNode] = None, + is_end_of_string: bool = False, + start: int | None = None, + end: int | None = None, + suffix_link: SuffixTreeNode | None = None, ) -> None: """ Initializes a suffix tree node. From 7479d2d5bc345c190ca0682aa6f86eec26777676 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 7 Sep 2024 22:53:13 +0200 Subject: [PATCH 45/48] Considering ruff part-5 --- data_structures/suffix_tree/suffix_tree_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index bf67db21f892..b56e6d71a599 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -4,7 +4,7 @@ class SuffixTreeNode: def __init__( self, - children: dict[str, SuffixTreeNode] = None, + children: dict[str, SuffixTreeNode] | None = None, is_end_of_string: bool = False, start: int | None = None, end: int | None = None, From d8eb924747770b3bbdcfbf23b325a2887c15bf3d Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 28 Sep 2024 14:53:32 +0200 Subject: [PATCH 46/48] Implemented Suffix Tree Data Structure. Added some comments to my files in #11532, #11554. --- data_structures/kd_tree/build_kdtree.py | 6 ++++++ data_structures/kd_tree/example/example_usage.py | 6 ++++++ data_structures/kd_tree/example/hypercube_points.py | 6 ++++++ data_structures/kd_tree/kd_node.py | 6 ++++++ data_structures/kd_tree/nearest_neighbour_search.py | 6 ++++++ data_structures/kd_tree/tests/test_kdtree.py | 6 ++++++ data_structures/suffix_tree/example/example_usage.py | 6 ++++++ data_structures/suffix_tree/suffix_tree.py | 6 ++++++ data_structures/suffix_tree/suffix_tree_node.py | 6 ++++++ data_structures/suffix_tree/tests/test_suffix_tree.py | 6 ++++++ 10 files changed, 60 insertions(+) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index c5b800a2c992..05e6548df184 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# https://github.com/TheAlgorithms/Python/pull/11532 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + from data_structures.kd_tree.kd_node import KDNode diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index e270f0cdd245..852c43836310 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# https://github.com/TheAlgorithms/Python/pull/11532 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + import numpy as np from data_structures.kd_tree.build_kdtree import build_kdtree diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 2d8800ac9338..8d063a46167d 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# https://github.com/TheAlgorithms/Python/pull/11532 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + import numpy as np diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index e1011027938d..ca9eb3d102d0 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# https://github.com/TheAlgorithms/Python/pull/11532 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + from __future__ import annotations diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index d9727736f21c..a28c9b7d4a9a 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# https://github.com/TheAlgorithms/Python/pull/11532 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + from data_structures.kd_tree.kd_node import KDNode diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index 81f2cc990074..72a5a45be1f0 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# https://github.com/TheAlgorithms/Python/pull/11532 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + import numpy as np import pytest diff --git a/data_structures/suffix_tree/example/example_usage.py b/data_structures/suffix_tree/example/example_usage.py index d097cb6e33f3..404e70dd0e16 100644 --- a/data_structures/suffix_tree/example/example_usage.py +++ b/data_structures/suffix_tree/example/example_usage.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# https://github.com/TheAlgorithms/Python/pull/11554 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + from data_structures.suffix_tree.suffix_tree import SuffixTree diff --git a/data_structures/suffix_tree/suffix_tree.py b/data_structures/suffix_tree/suffix_tree.py index 1044b7f0a768..95066770dca1 100644 --- a/data_structures/suffix_tree/suffix_tree.py +++ b/data_structures/suffix_tree/suffix_tree.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# https://github.com/TheAlgorithms/Python/pull/11554 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + from data_structures.suffix_tree.suffix_tree_node import SuffixTreeNode diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index b56e6d71a599..583511cc3537 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# https://github.com/TheAlgorithms/Python/pull/11554 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + from __future__ import annotations diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index 43f7d208a954..09ac0e727f48 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -1,3 +1,9 @@ +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# https://github.com/TheAlgorithms/Python/pull/11554 +# +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Thank you! + import unittest from data_structures.suffix_tree.suffix_tree import SuffixTree From 666bb6ffd92105ace0fac8610f7a7af88d1b412f Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 28 Sep 2024 12:54:12 +0000 Subject: [PATCH 47/48] updating DIRECTORY.md --- DIRECTORY.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 272b55510d46..955001e2aa23 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -243,6 +243,15 @@ * [Min Heap](data_structures/heap/min_heap.py) * [Randomized Heap](data_structures/heap/randomized_heap.py) * [Skew Heap](data_structures/heap/skew_heap.py) + * Kd Tree + * [Build Kdtree](data_structures/kd_tree/build_kdtree.py) + * Example + * [Example Usage](data_structures/kd_tree/example/example_usage.py) + * [Hypercube Points](data_structures/kd_tree/example/hypercube_points.py) + * [Kd Node](data_structures/kd_tree/kd_node.py) + * [Nearest Neighbour Search](data_structures/kd_tree/nearest_neighbour_search.py) + * Tests + * [Test Kdtree](data_structures/kd_tree/tests/test_kdtree.py) * Linked List * [Circular Linked List](data_structures/linked_list/circular_linked_list.py) * [Deque Doubly](data_structures/linked_list/deque_doubly.py) @@ -282,19 +291,16 @@ * [Stack With Doubly Linked List](data_structures/stacks/stack_with_doubly_linked_list.py) * [Stack With Singly Linked List](data_structures/stacks/stack_with_singly_linked_list.py) * [Stock Span Problem](data_structures/stacks/stock_span_problem.py) + * Suffix Tree + * Example + * [Example Usage](data_structures/suffix_tree/example/example_usage.py) + * [Suffix Tree](data_structures/suffix_tree/suffix_tree.py) + * [Suffix Tree Node](data_structures/suffix_tree/suffix_tree_node.py) + * Tests + * [Test Suffix Tree](data_structures/suffix_tree/tests/test_suffix_tree.py) * Trie * [Radix Tree](data_structures/trie/radix_tree.py) * [Trie](data_structures/trie/trie.py) - * KD Tree - * [KD Tree Node](data_structures/kd_tree/kd_node.py) - * [Build KD Tree](data_structures/kd_tree/build_kdtree.py) - * [Nearest Neighbour Search](data_structures/kd_tree/nearest_neighbour_search.py) - * [Hypercibe Points](data_structures/kd_tree/example/hypercube_points.py) - * [Example Usage](data_structures/kd_tree/example/example_usage.py) - * Suffix Tree - * [Suffix Tree Node](data_structures/suffix_tree/suffix_tree_node.py) - * [Suffix Tree](data_structures/suffix_tree/suffix_tree.py) - * [Example Usage](data_structures/suffix_tree/example/example_usage.py) ## Digital Image Processing * [Change Brightness](digital_image_processing/change_brightness.py) From 3a6c8a3ef5c35dc9ad318acd9e2e86ff60b8ac95 Mon Sep 17 00:00:00 2001 From: Ramy-Badr-Ahmed Date: Sat, 28 Sep 2024 15:01:52 +0200 Subject: [PATCH 48/48] Implemented Suffix Tree Data Structure. Added some comments to my files in #11532, #11554. --- data_structures/kd_tree/build_kdtree.py | 6 ++++-- data_structures/kd_tree/example/example_usage.py | 6 ++++-- data_structures/kd_tree/example/hypercube_points.py | 6 ++++-- data_structures/kd_tree/kd_node.py | 6 ++++-- data_structures/kd_tree/nearest_neighbour_search.py | 6 ++++-- data_structures/kd_tree/tests/test_kdtree.py | 6 ++++-- data_structures/suffix_tree/example/example_usage.py | 6 ++++-- data_structures/suffix_tree/suffix_tree.py | 6 ++++-- data_structures/suffix_tree/suffix_tree_node.py | 6 ++++-- data_structures/suffix_tree/tests/test_suffix_tree.py | 6 ++++-- 10 files changed, 40 insertions(+), 20 deletions(-) diff --git a/data_structures/kd_tree/build_kdtree.py b/data_structures/kd_tree/build_kdtree.py index 05e6548df184..074a5dac4d42 100644 --- a/data_structures/kd_tree/build_kdtree.py +++ b/data_structures/kd_tree/build_kdtree.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11532 # https://github.com/TheAlgorithms/Python/pull/11532 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! from data_structures.kd_tree.kd_node import KDNode diff --git a/data_structures/kd_tree/example/example_usage.py b/data_structures/kd_tree/example/example_usage.py index 852c43836310..892c3b8c4a2a 100644 --- a/data_structures/kd_tree/example/example_usage.py +++ b/data_structures/kd_tree/example/example_usage.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11532 # https://github.com/TheAlgorithms/Python/pull/11532 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! import numpy as np diff --git a/data_structures/kd_tree/example/hypercube_points.py b/data_structures/kd_tree/example/hypercube_points.py index 8d063a46167d..66744856e6d5 100644 --- a/data_structures/kd_tree/example/hypercube_points.py +++ b/data_structures/kd_tree/example/hypercube_points.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11532 # https://github.com/TheAlgorithms/Python/pull/11532 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! import numpy as np diff --git a/data_structures/kd_tree/kd_node.py b/data_structures/kd_tree/kd_node.py index ca9eb3d102d0..5a22ef609077 100644 --- a/data_structures/kd_tree/kd_node.py +++ b/data_structures/kd_tree/kd_node.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11532 # https://github.com/TheAlgorithms/Python/pull/11532 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! from __future__ import annotations diff --git a/data_structures/kd_tree/nearest_neighbour_search.py b/data_structures/kd_tree/nearest_neighbour_search.py index a28c9b7d4a9a..8104944c08f0 100644 --- a/data_structures/kd_tree/nearest_neighbour_search.py +++ b/data_structures/kd_tree/nearest_neighbour_search.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11532 # https://github.com/TheAlgorithms/Python/pull/11532 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! from data_structures.kd_tree.kd_node import KDNode diff --git a/data_structures/kd_tree/tests/test_kdtree.py b/data_structures/kd_tree/tests/test_kdtree.py index 72a5a45be1f0..dce5e4f34ff4 100644 --- a/data_structures/kd_tree/tests/test_kdtree.py +++ b/data_structures/kd_tree/tests/test_kdtree.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11532 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11532 # https://github.com/TheAlgorithms/Python/pull/11532 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! import numpy as np diff --git a/data_structures/suffix_tree/example/example_usage.py b/data_structures/suffix_tree/example/example_usage.py index 404e70dd0e16..724ac57e8bfb 100644 --- a/data_structures/suffix_tree/example/example_usage.py +++ b/data_structures/suffix_tree/example/example_usage.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11554 # https://github.com/TheAlgorithms/Python/pull/11554 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! from data_structures.suffix_tree.suffix_tree import SuffixTree diff --git a/data_structures/suffix_tree/suffix_tree.py b/data_structures/suffix_tree/suffix_tree.py index 95066770dca1..ad54fb0ba009 100644 --- a/data_structures/suffix_tree/suffix_tree.py +++ b/data_structures/suffix_tree/suffix_tree.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11554 # https://github.com/TheAlgorithms/Python/pull/11554 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! from data_structures.suffix_tree.suffix_tree_node import SuffixTreeNode diff --git a/data_structures/suffix_tree/suffix_tree_node.py b/data_structures/suffix_tree/suffix_tree_node.py index 583511cc3537..e5b628645063 100644 --- a/data_structures/suffix_tree/suffix_tree_node.py +++ b/data_structures/suffix_tree/suffix_tree_node.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11554 # https://github.com/TheAlgorithms/Python/pull/11554 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! from __future__ import annotations diff --git a/data_structures/suffix_tree/tests/test_suffix_tree.py b/data_structures/suffix_tree/tests/test_suffix_tree.py index 09ac0e727f48..45c6790ac48a 100644 --- a/data_structures/suffix_tree/tests/test_suffix_tree.py +++ b/data_structures/suffix_tree/tests/test_suffix_tree.py @@ -1,7 +1,9 @@ -# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #11554 +# Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) +# in Pull Request: #11554 # https://github.com/TheAlgorithms/Python/pull/11554 # -# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file. +# Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request +# addressing bugs/corrections to this file. # Thank you! import unittest