pkstruct 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. pkstruct/__init__.py +167 -0
  2. pkstruct/graphs/__init__.py +127 -0
  3. pkstruct/graphs/connectivity.py +157 -0
  4. pkstruct/graphs/directed.py +95 -0
  5. pkstruct/graphs/exceptions.py +63 -0
  6. pkstruct/graphs/graph.py +262 -0
  7. pkstruct/graphs/mst.py +118 -0
  8. pkstruct/graphs/scc.py +138 -0
  9. pkstruct/graphs/shortest_path.py +250 -0
  10. pkstruct/graphs/topo_sort.py +108 -0
  11. pkstruct/graphs/traversal.py +175 -0
  12. pkstruct/graphs/visualization.py +90 -0
  13. pkstruct/graphs/weighted.py +37 -0
  14. pkstruct/linear/__init__.py +95 -0
  15. pkstruct/linear/deques/__init__.py +33 -0
  16. pkstruct/linear/deques/deque.py +194 -0
  17. pkstruct/linear/deques/linked_deque.py +198 -0
  18. pkstruct/linear/exceptions.py +26 -0
  19. pkstruct/linear/linked_lists/__init__.py +5 -0
  20. pkstruct/linear/linked_lists/_base.py +608 -0
  21. pkstruct/linear/linked_lists/circular_linked_list.py +230 -0
  22. pkstruct/linear/linked_lists/doubly_linked_list.py +151 -0
  23. pkstruct/linear/linked_lists/nodes.py +68 -0
  24. pkstruct/linear/linked_lists/singly_linked_list.py +136 -0
  25. pkstruct/linear/queues/__init__.py +44 -0
  26. pkstruct/linear/queues/circular_queue.py +258 -0
  27. pkstruct/linear/queues/linked_queue.py +186 -0
  28. pkstruct/linear/queues/priority_queue.py +202 -0
  29. pkstruct/linear/queues/queue.py +174 -0
  30. pkstruct/linear/stacks/__init__.py +38 -0
  31. pkstruct/linear/stacks/array_stack.py +165 -0
  32. pkstruct/linear/stacks/linked_stack.py +168 -0
  33. pkstruct/linear/stacks/stack.py +158 -0
  34. pkstruct/linear/utils/__init__.py +18 -0
  35. pkstruct/linear/utils/benchmark.py +255 -0
  36. pkstruct/linear/utils/debug_tools.py +239 -0
  37. pkstruct/linear/utils/helpers.py +143 -0
  38. pkstruct/linear/utils/iterators.py +148 -0
  39. pkstruct/linear/visualization/__init__.py +0 -0
  40. pkstruct/linear/visualization/ascii_visualizer.py +114 -0
  41. pkstruct/linear/visualization/linked_list_visualizer.py +126 -0
  42. pkstruct/shared/__init__.py +67 -0
  43. pkstruct/shared/benchmarking/__init__.py +78 -0
  44. pkstruct/shared/debugging/__init__.py +69 -0
  45. pkstruct/shared/exceptions/__init__.py +59 -0
  46. pkstruct/shared/serializers/__init__.py +65 -0
  47. pkstruct/shared/threading/__init__.py +43 -0
  48. pkstruct/shared/validators/__init__.py +98 -0
  49. pkstruct/shared/visualization/__init__.py +21 -0
  50. pkstruct/trees/__init__.py +92 -0
  51. pkstruct/trees/avl.py +321 -0
  52. pkstruct/trees/balancing.py +253 -0
  53. pkstruct/trees/bplus.py +425 -0
  54. pkstruct/trees/bst.py +948 -0
  55. pkstruct/trees/btree.py +504 -0
  56. pkstruct/trees/exceptions.py +96 -0
  57. pkstruct/trees/fenwick_tree.py +312 -0
  58. pkstruct/trees/interval_tree.py +541 -0
  59. pkstruct/trees/node.py +356 -0
  60. pkstruct/trees/red_black.py +710 -0
  61. pkstruct/trees/segment_tree.py +398 -0
  62. pkstruct/trees/traversal.py +456 -0
  63. pkstruct/trees/tree_helpers.py +366 -0
  64. pkstruct/trees/utils/__init__.py +15 -0
  65. pkstruct/trees/utils/complexity_helpers.py +231 -0
  66. pkstruct/trees/visualization/__init__.py +0 -0
  67. pkstruct/trees/visualization/ascii_renderer.py +220 -0
  68. pkstruct/trees/visualization/tree_printer.py +129 -0
  69. pkstruct-0.1.0.dist-info/METADATA +482 -0
  70. pkstruct-0.1.0.dist-info/RECORD +72 -0
  71. pkstruct-0.1.0.dist-info/WHEEL +4 -0
  72. pkstruct-0.1.0.dist-info/licenses/LICENSE +21 -0
pkstruct/__init__.py ADDED
@@ -0,0 +1,167 @@
1
+ """
2
+ pkstruct - Production-grade modular data structures toolkit for Python.
3
+
4
+ This package provides industrial-strength implementations of fundamental
5
+ data structures with thread safety, serialization, visualization, and
6
+ comprehensive algorithmic helpers.
7
+
8
+ Modules
9
+ -------
10
+ graphs
11
+ Graph, DirectedGraph, WeightedGraph, traversal, shortest path, MST, SCC
12
+ trees
13
+ BinarySearchTree, AVLTree, RedBlackTree, BTree, BPlusTree,
14
+ SegmentTree, FenwickTree, IntervalTree
15
+ linear
16
+ SinglyLinkedList, DoublyLinkedList, CircularLinkedList
17
+ shared
18
+ Infrastructure components (exceptions, validators, serializers, etc.)
19
+
20
+ Example
21
+ -------
22
+ >>> from pkstruct import BinarySearchTree
23
+ >>> bst = BinarySearchTree()
24
+ >>> bst.insert(10)
25
+ >>> bst.insert(5)
26
+ >>> bst.insert(15)
27
+ >>> list(bst)
28
+ [5, 10, 15]
29
+ """
30
+
31
+ from pkstruct.graphs import (
32
+ Graph,
33
+ DirectedGraph,
34
+ WeightedGraph,
35
+ bfs,
36
+ dfs,
37
+ dijkstra,
38
+ bellman_ford,
39
+ floyd_warshall,
40
+ kruskal,
41
+ prim,
42
+ connected_components,
43
+ is_bipartite,
44
+ has_cycle,
45
+ topological_sort_kahn,
46
+ topological_sort_dfs,
47
+ kosaraju,
48
+ tarjan,
49
+ visualize,
50
+ GraphError,
51
+ VertexNotFoundError,
52
+ EdgeNotFoundError,
53
+ InvalidGraphOperationError,
54
+ NegativeCycleError,
55
+ NoPathError,
56
+ )
57
+ from pkstruct.linear import (
58
+ ArrayStack,
59
+ CircularLinkedList,
60
+ CircularQueue,
61
+ ConcurrencyError,
62
+ DoublyLinkedList,
63
+ EmptyStructureError,
64
+ IndexOutOfRangeError,
65
+ InvalidRangeError,
66
+ LinkedDeque,
67
+ LinkedQueue,
68
+ LinkedStack,
69
+ PkstructError,
70
+ PriorityQueue,
71
+ QueueFullError,
72
+ SerializationError,
73
+ SinglyLinkedList,
74
+ ValidationError,
75
+ ValueNotFoundError,
76
+ )
77
+ from pkstruct.trees import (
78
+ AVLTree,
79
+ BinarySearchTree,
80
+ BPlusTree,
81
+ BTree,
82
+ DuplicateKeyError,
83
+ EmptyTreeError,
84
+ FenwickTree,
85
+ IndexOutOfBoundsError,
86
+ IntervalTree,
87
+ InvalidIntervalError,
88
+ InvalidOperationError,
89
+ InvalidOrderError,
90
+ KeyNotFoundError,
91
+ RedBlackTree,
92
+ SegmentTree,
93
+ TreeBalanceError,
94
+ TreeError,
95
+ )
96
+ from pkstruct.trees import (
97
+ SerializationError as TreeSerializationError,
98
+ )
99
+
100
+ __all__ = [
101
+ # Graphs
102
+ "Graph",
103
+ "DirectedGraph",
104
+ "WeightedGraph",
105
+ "bfs",
106
+ "dfs",
107
+ "dijkstra",
108
+ "bellman_ford",
109
+ "floyd_warshall",
110
+ "kruskal",
111
+ "prim",
112
+ "connected_components",
113
+ "is_bipartite",
114
+ "has_cycle",
115
+ "topological_sort_kahn",
116
+ "topological_sort_dfs",
117
+ "kosaraju",
118
+ "tarjan",
119
+ "visualize",
120
+ "GraphError",
121
+ "VertexNotFoundError",
122
+ "EdgeNotFoundError",
123
+ "InvalidGraphOperationError",
124
+ "NegativeCycleError",
125
+ "NoPathError",
126
+ # Linear
127
+ "SinglyLinkedList",
128
+ "DoublyLinkedList",
129
+ "CircularLinkedList",
130
+ "ArrayStack",
131
+ "LinkedStack",
132
+ "LinkedQueue",
133
+ "CircularQueue",
134
+ "PriorityQueue",
135
+ "LinkedDeque",
136
+ "QueueFullError",
137
+ "PkstructError",
138
+ "ValidationError",
139
+ "IndexOutOfRangeError",
140
+ "ValueNotFoundError",
141
+ "EmptyStructureError",
142
+ "SerializationError",
143
+ "ConcurrencyError",
144
+ "InvalidRangeError",
145
+ # Trees
146
+ "BinarySearchTree",
147
+ "AVLTree",
148
+ "RedBlackTree",
149
+ "BTree",
150
+ "BPlusTree",
151
+ "SegmentTree",
152
+ "FenwickTree",
153
+ "IntervalTree",
154
+ "TreeError",
155
+ "KeyNotFoundError",
156
+ "DuplicateKeyError",
157
+ "EmptyTreeError",
158
+ "InvalidOrderError",
159
+ "InvalidOperationError",
160
+ "TreeBalanceError",
161
+ "TreeSerializationError",
162
+ "InvalidIntervalError",
163
+ "IndexOutOfBoundsError",
164
+ ]
165
+
166
+ __version__ = "0.1.0"
167
+ __author__ = "pkstruct contributors"
@@ -0,0 +1,127 @@
1
+ """
2
+ pkstruct.graphs
3
+ ===============
4
+
5
+ Graph data structures module for the pkstruct ecosystem.
6
+
7
+ Provides production-grade implementations of graph representations and
8
+ classic graph algorithms with thread safety and ASCII visualization.
9
+
10
+ Classes
11
+ -------
12
+ Graph
13
+ Adjacency-list based graph supporting directed/undirected and weighted modes.
14
+ DirectedGraph
15
+ Directed graph with in-degree, out-degree, reverse, sources, and sinks.
16
+ WeightedGraph
17
+ Convenience subclass for weighted undirected graphs.
18
+
19
+ Algorithms
20
+ ----------
21
+ Traversal:
22
+ bfs, dfs, bfs_paths, dfs_paths
23
+ Shortest Path:
24
+ dijkstra, bellman_ford, floyd_warshall
25
+ Minimum Spanning Tree:
26
+ kruskal, prim
27
+ Connectivity:
28
+ connected_components, is_connected, is_bipartite, has_cycle, has_cycle_directed
29
+ Topological Sort:
30
+ topological_sort_kahn, topological_sort_dfs
31
+ Strongly Connected Components:
32
+ kosaraju, tarjan
33
+
34
+ Exceptions
35
+ ----------
36
+ GraphError, VertexNotFoundError, EdgeNotFoundError, InvalidGraphOperationError,
37
+ NegativeCycleError, NoPathError
38
+
39
+ Example
40
+ -------
41
+ >>> from pkstruct.graphs import Graph
42
+ >>> g = Graph()
43
+ >>> g.add_edge("A", "B")
44
+ >>> g.add_edge("B", "C")
45
+ >>> g.add_edge("A", "C")
46
+ >>> list(g.get_neighbors("A"))
47
+ ['B', 'C']
48
+ >>> len(g)
49
+ 3
50
+ """
51
+
52
+ from pkstruct.graphs.connectivity import (
53
+ connected_components,
54
+ has_cycle,
55
+ has_cycle_directed,
56
+ is_bipartite,
57
+ is_connected,
58
+ )
59
+ from pkstruct.graphs.directed import DirectedGraph
60
+ from pkstruct.graphs.exceptions import (
61
+ EdgeNotFoundError,
62
+ GraphError,
63
+ InvalidGraphOperationError,
64
+ NegativeCycleError,
65
+ NoPathError,
66
+ VertexNotFoundError,
67
+ )
68
+ from pkstruct.graphs.graph import Graph
69
+ from pkstruct.graphs.mst import kruskal, prim
70
+ from pkstruct.graphs.scc import kosaraju, tarjan
71
+ from pkstruct.graphs.shortest_path import (
72
+ bellman_ford,
73
+ dijkstra,
74
+ floyd_warshall,
75
+ reconstruct_path,
76
+ reconstruct_path_fw,
77
+ )
78
+ from pkstruct.graphs.topo_sort import topological_sort_dfs, topological_sort_kahn
79
+ from pkstruct.graphs.traversal import bfs, bfs_paths, dfs, dfs_paths
80
+ from pkstruct.graphs.visualization import adjacency_matrix, visualize
81
+ from pkstruct.graphs.weighted import WeightedGraph
82
+
83
+ __all__ = [
84
+ # Graph classes
85
+ "Graph",
86
+ "DirectedGraph",
87
+ "WeightedGraph",
88
+ # Traversal
89
+ "bfs",
90
+ "dfs",
91
+ "bfs_paths",
92
+ "dfs_paths",
93
+ # Shortest Path
94
+ "dijkstra",
95
+ "bellman_ford",
96
+ "floyd_warshall",
97
+ "reconstruct_path",
98
+ "reconstruct_path_fw",
99
+ # MST
100
+ "kruskal",
101
+ "prim",
102
+ # Connectivity
103
+ "connected_components",
104
+ "is_connected",
105
+ "is_bipartite",
106
+ "has_cycle",
107
+ "has_cycle_directed",
108
+ # Topological Sort
109
+ "topological_sort_kahn",
110
+ "topological_sort_dfs",
111
+ # SCC
112
+ "kosaraju",
113
+ "tarjan",
114
+ # Visualization
115
+ "visualize",
116
+ "adjacency_matrix",
117
+ # Exceptions
118
+ "GraphError",
119
+ "VertexNotFoundError",
120
+ "EdgeNotFoundError",
121
+ "InvalidGraphOperationError",
122
+ "NegativeCycleError",
123
+ "NoPathError",
124
+ ]
125
+
126
+ __version__ = "0.1.0"
127
+ __author__ = "pkstruct contributors"
@@ -0,0 +1,157 @@
1
+ """
2
+ pkstruct.graphs.connectivity
3
+ ============================
4
+ Graph connectivity algorithms: connected components, bipartite check.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections import deque
10
+ from typing import Any
11
+
12
+ from pkstruct.graphs.graph import Graph
13
+ from pkstruct.graphs.exceptions import VertexNotFoundError
14
+
15
+
16
+ def connected_components(graph: Graph) -> list[list[Any]]:
17
+ """Return all connected components of an undirected graph.
18
+
19
+ Parameters
20
+ ----------
21
+ graph : Graph
22
+ An undirected graph.
23
+
24
+ Returns
25
+ -------
26
+ list[list[Any]]
27
+ List of components, each being a list of vertices.
28
+ """
29
+ visited: set[Any] = set()
30
+ components: list[list[Any]] = []
31
+
32
+ for v in graph:
33
+ if v not in visited:
34
+ component: list[Any] = []
35
+ queue: deque[Any] = deque([v])
36
+ visited.add(v)
37
+ while queue:
38
+ current = queue.popleft()
39
+ component.append(current)
40
+ for neighbor in graph.get_neighbors(current):
41
+ if neighbor not in visited:
42
+ visited.add(neighbor)
43
+ queue.append(neighbor)
44
+ components.append(component)
45
+
46
+ return components
47
+
48
+
49
+ def is_connected(graph: Graph) -> bool:
50
+ """Return *True* if the undirected graph is connected.
51
+
52
+ Parameters
53
+ ----------
54
+ graph : Graph
55
+ An undirected graph.
56
+
57
+ Returns
58
+ -------
59
+ bool
60
+ """
61
+ if graph.is_empty():
62
+ return True
63
+ components = connected_components(graph)
64
+ return len(components) == 1
65
+
66
+
67
+ def is_bipartite(graph: Graph) -> bool:
68
+ """Check if a graph is bipartite using BFS coloring.
69
+
70
+ Parameters
71
+ ----------
72
+ graph : Graph
73
+ An undirected graph.
74
+
75
+ Returns
76
+ -------
77
+ bool
78
+ *True* if the graph is bipartite.
79
+ """
80
+ color: dict[Any, int] = {}
81
+
82
+ for start in graph:
83
+ if start not in color:
84
+ color[start] = 0
85
+ queue: deque[Any] = deque([start])
86
+ while queue:
87
+ v = queue.popleft()
88
+ for neighbor in graph.get_neighbors(v):
89
+ if neighbor not in color:
90
+ color[neighbor] = 1 - color[v]
91
+ queue.append(neighbor)
92
+ elif color[neighbor] == color[v]:
93
+ return False
94
+ return True
95
+
96
+
97
+ def has_cycle(graph: Graph) -> bool:
98
+ """Detect if an undirected graph contains a cycle.
99
+
100
+ Parameters
101
+ ----------
102
+ graph : Graph
103
+ An undirected graph.
104
+
105
+ Returns
106
+ -------
107
+ bool
108
+ """
109
+ visited: set[Any] = set()
110
+
111
+ def _dfs(v: Any, parent: Any | None) -> bool:
112
+ visited.add(v)
113
+ for neighbor in graph.get_neighbors(v):
114
+ if neighbor not in visited:
115
+ if _dfs(neighbor, v):
116
+ return True
117
+ elif neighbor != parent:
118
+ return True
119
+ return False
120
+
121
+ for v in graph:
122
+ if v not in visited:
123
+ if _dfs(v, None):
124
+ return True
125
+ return False
126
+
127
+
128
+ def has_cycle_directed(graph: Graph) -> bool:
129
+ """Detect if a directed graph contains a cycle using DFS coloring.
130
+
131
+ Parameters
132
+ ----------
133
+ graph : Graph
134
+ A directed graph.
135
+
136
+ Returns
137
+ -------
138
+ bool
139
+ """
140
+ WHITE, GRAY, BLACK = 0, 1, 2
141
+ color: dict[Any, int] = {v: WHITE for v in graph}
142
+
143
+ def _dfs(v: Any) -> bool:
144
+ color[v] = GRAY
145
+ for neighbor in graph.get_neighbors(v):
146
+ if color[neighbor] == GRAY:
147
+ return True
148
+ if color[neighbor] == WHITE and _dfs(neighbor):
149
+ return True
150
+ color[v] = BLACK
151
+ return False
152
+
153
+ for v in graph:
154
+ if color[v] == WHITE:
155
+ if _dfs(v):
156
+ return True
157
+ return False
@@ -0,0 +1,95 @@
1
+ """
2
+ pkstruct.graphs.directed
3
+ ========================
4
+ Directed graph implementation with direction-specific operations.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Iterator
10
+ from typing import Any
11
+
12
+ from pkstruct.graphs.exceptions import VertexNotFoundError
13
+ from pkstruct.graphs.graph import Graph
14
+
15
+
16
+ class DirectedGraph(Graph):
17
+ """A directed graph (convenience subclass of ``Graph`` with ``directed=True``).
18
+
19
+ Provides additional methods specific to directed graphs such as
20
+ in-degree, out-degree, transpose, sources, and sinks.
21
+
22
+ Example
23
+ -------
24
+ >>> g = DirectedGraph()
25
+ >>> g.add_edge("A", "B")
26
+ >>> g.add_edge("B", "C")
27
+ >>> g.add_edge("A", "C")
28
+ >>> g.out_degree("A")
29
+ 2
30
+ >>> g.in_degree("C")
31
+ 2
32
+ """
33
+
34
+ def __init__(self) -> None:
35
+ super().__init__(directed=True)
36
+
37
+ def in_degree(self, v: Any) -> int:
38
+ """Return the number of incoming edges to *v*.
39
+
40
+ Raises
41
+ ------
42
+ VertexNotFoundError
43
+ If *v* is not in the graph.
44
+ """
45
+ with self._lock:
46
+ if v not in self._adj:
47
+ raise VertexNotFoundError(v)
48
+ count = 0
49
+ for u in self._adj:
50
+ if v in self._adj[u]:
51
+ count += 1
52
+ return count
53
+
54
+ def out_degree(self, v: Any) -> int:
55
+ """Return the number of outgoing edges from *v*.
56
+
57
+ Raises
58
+ ------
59
+ VertexNotFoundError
60
+ If *v* is not in the graph.
61
+ """
62
+ return self.degree(v)
63
+
64
+ def sources(self) -> list[Any]:
65
+ """Return all vertices with in-degree 0."""
66
+ with self._lock:
67
+ return [v for v in self._adj if self.in_degree(v) == 0]
68
+
69
+ def sinks(self) -> list[Any]:
70
+ """Return all vertices with out-degree 0."""
71
+ with self._lock:
72
+ return [v for v in self._adj if self.out_degree(v) == 0]
73
+
74
+ def reverse(self) -> DirectedGraph:
75
+ """Return the transpose (reverse all edges).
76
+
77
+ Returns
78
+ -------
79
+ DirectedGraph
80
+ A new graph with every edge (u, v) replaced by (v, u).
81
+ """
82
+ with self._lock:
83
+ rev = DirectedGraph()
84
+ for u in self._adj:
85
+ rev.add_vertex(u)
86
+ for u in self._adj:
87
+ for v, w in self._adj[u].items():
88
+ rev.add_edge(v, u, w)
89
+ return rev
90
+
91
+ def __repr__(self) -> str:
92
+ with self._lock:
93
+ vertices = list(self._adj.keys())
94
+ edges = self.get_edges()
95
+ return f"DirectedGraph(vertices={len(vertices)}, edges={len(edges)})"
@@ -0,0 +1,63 @@
1
+ """
2
+ pkstruct.graphs.exceptions
3
+ ==========================
4
+ Custom exception hierarchy for the graphs module.
5
+
6
+ All graph-specific exceptions inherit from :class:`GraphError` so callers
7
+ can catch the entire family with a single ``except GraphError`` clause.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ __all__ = [
13
+ "GraphError",
14
+ "VertexNotFoundError",
15
+ "EdgeNotFoundError",
16
+ "InvalidGraphOperationError",
17
+ "NegativeCycleError",
18
+ "NoPathError",
19
+ ]
20
+
21
+
22
+ class GraphError(Exception):
23
+ """Base exception for all graph-related errors."""
24
+
25
+
26
+ class VertexNotFoundError(GraphError):
27
+ """Raised when a vertex does not exist in the graph."""
28
+
29
+ def __init__(self, vertex: object) -> None:
30
+ super().__init__(f"Vertex not found: {vertex!r}")
31
+ self.vertex = vertex
32
+
33
+
34
+ class EdgeNotFoundError(GraphError):
35
+ """Raised when an edge does not exist in the graph."""
36
+
37
+ def __init__(self, u: object, v: object) -> None:
38
+ super().__init__(f"Edge not found: ({u!r}, {v!r})")
39
+ self.u = u
40
+ self.v = v
41
+
42
+
43
+ class InvalidGraphOperationError(GraphError):
44
+ """Raised when an operation is invalid for the current graph state."""
45
+
46
+ def __init__(self, message: str) -> None:
47
+ super().__init__(message)
48
+
49
+
50
+ class NegativeCycleError(GraphError):
51
+ """Raised when a negative-weight cycle is detected."""
52
+
53
+ def __init__(self, message: str = "Graph contains a negative-weight cycle") -> None:
54
+ super().__init__(message)
55
+
56
+
57
+ class NoPathError(GraphError):
58
+ """Raised when no path exists between two vertices."""
59
+
60
+ def __init__(self, source: object, target: object) -> None:
61
+ super().__init__(f"No path from {source!r} to {target!r}")
62
+ self.source = source
63
+ self.target = target