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/35] 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/35] 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/35] [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/35] 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/35] [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/35] 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/35] 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/35] 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/35] [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/35] 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/35] [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/35] 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/35] [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/35] 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/35] [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/35] 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/35] 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/35] 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/35] 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/35] 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/35] 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/35] 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/35] [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/35] 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/35] 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/35] 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/35] [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/35] 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/35] 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/35] [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/35] 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/35] 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/35] 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/35] 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/35] 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