exonware-xwnode 0.0.1.12__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.
- exonware/__init__.py +14 -0
- exonware/xwnode/__init__.py +127 -0
- exonware/xwnode/base.py +676 -0
- exonware/xwnode/config.py +178 -0
- exonware/xwnode/contracts.py +730 -0
- exonware/xwnode/errors.py +503 -0
- exonware/xwnode/facade.py +460 -0
- exonware/xwnode/strategies/__init__.py +158 -0
- exonware/xwnode/strategies/advisor.py +463 -0
- exonware/xwnode/strategies/edges/__init__.py +32 -0
- exonware/xwnode/strategies/edges/adj_list.py +227 -0
- exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
- exonware/xwnode/strategies/edges/base.py +169 -0
- exonware/xwnode/strategies/flyweight.py +328 -0
- exonware/xwnode/strategies/impls/__init__.py +13 -0
- exonware/xwnode/strategies/impls/_base_edge.py +403 -0
- exonware/xwnode/strategies/impls/_base_node.py +307 -0
- exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
- exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
- exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
- exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
- exonware/xwnode/strategies/impls/edge_coo.py +533 -0
- exonware/xwnode/strategies/impls/edge_csc.py +447 -0
- exonware/xwnode/strategies/impls/edge_csr.py +492 -0
- exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
- exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
- exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
- exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
- exonware/xwnode/strategies/impls/edge_octree.py +574 -0
- exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
- exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
- exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
- exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
- exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
- exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
- exonware/xwnode/strategies/manager.py +775 -0
- exonware/xwnode/strategies/metrics.py +538 -0
- exonware/xwnode/strategies/migration.py +432 -0
- exonware/xwnode/strategies/nodes/__init__.py +50 -0
- exonware/xwnode/strategies/nodes/_base_node.py +307 -0
- exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
- exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
- exonware/xwnode/strategies/nodes/array_list.py +209 -0
- exonware/xwnode/strategies/nodes/base.py +247 -0
- exonware/xwnode/strategies/nodes/deque.py +200 -0
- exonware/xwnode/strategies/nodes/hash_map.py +135 -0
- exonware/xwnode/strategies/nodes/heap.py +307 -0
- exonware/xwnode/strategies/nodes/linked_list.py +232 -0
- exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
- exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
- exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
- exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
- exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
- exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
- exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
- exonware/xwnode/strategies/nodes/node_btree.py +357 -0
- exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
- exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
- exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
- exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
- exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
- exonware/xwnode/strategies/nodes/node_heap.py +191 -0
- exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
- exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
- exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
- exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
- exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
- exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
- exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
- exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
- exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
- exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
- exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
- exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
- exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
- exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
- exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
- exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
- exonware/xwnode/strategies/nodes/node_treap.py +387 -0
- exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
- exonware/xwnode/strategies/nodes/node_trie.py +252 -0
- exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
- exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
- exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
- exonware/xwnode/strategies/nodes/queue.py +161 -0
- exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
- exonware/xwnode/strategies/nodes/stack.py +152 -0
- exonware/xwnode/strategies/nodes/trie.py +274 -0
- exonware/xwnode/strategies/nodes/union_find.py +283 -0
- exonware/xwnode/strategies/pattern_detector.py +603 -0
- exonware/xwnode/strategies/performance_monitor.py +487 -0
- exonware/xwnode/strategies/queries/__init__.py +24 -0
- exonware/xwnode/strategies/queries/base.py +236 -0
- exonware/xwnode/strategies/queries/cql.py +201 -0
- exonware/xwnode/strategies/queries/cypher.py +181 -0
- exonware/xwnode/strategies/queries/datalog.py +70 -0
- exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
- exonware/xwnode/strategies/queries/eql.py +70 -0
- exonware/xwnode/strategies/queries/flux.py +70 -0
- exonware/xwnode/strategies/queries/gql.py +70 -0
- exonware/xwnode/strategies/queries/graphql.py +240 -0
- exonware/xwnode/strategies/queries/gremlin.py +181 -0
- exonware/xwnode/strategies/queries/hiveql.py +214 -0
- exonware/xwnode/strategies/queries/hql.py +70 -0
- exonware/xwnode/strategies/queries/jmespath.py +219 -0
- exonware/xwnode/strategies/queries/jq.py +66 -0
- exonware/xwnode/strategies/queries/json_query.py +66 -0
- exonware/xwnode/strategies/queries/jsoniq.py +248 -0
- exonware/xwnode/strategies/queries/kql.py +70 -0
- exonware/xwnode/strategies/queries/linq.py +238 -0
- exonware/xwnode/strategies/queries/logql.py +70 -0
- exonware/xwnode/strategies/queries/mql.py +68 -0
- exonware/xwnode/strategies/queries/n1ql.py +210 -0
- exonware/xwnode/strategies/queries/partiql.py +70 -0
- exonware/xwnode/strategies/queries/pig.py +215 -0
- exonware/xwnode/strategies/queries/promql.py +70 -0
- exonware/xwnode/strategies/queries/sparql.py +220 -0
- exonware/xwnode/strategies/queries/sql.py +275 -0
- exonware/xwnode/strategies/queries/xml_query.py +66 -0
- exonware/xwnode/strategies/queries/xpath.py +223 -0
- exonware/xwnode/strategies/queries/xquery.py +258 -0
- exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
- exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
- exonware/xwnode/strategies/registry.py +604 -0
- exonware/xwnode/strategies/simple.py +273 -0
- exonware/xwnode/strategies/utils.py +532 -0
- exonware/xwnode/types.py +912 -0
- exonware/xwnode/version.py +78 -0
- exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
- exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
- exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
- exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
"""
|
2
|
+
Trie Node Strategy Implementation
|
3
|
+
|
4
|
+
This module implements the TRIE strategy for efficient string prefix operations.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Any, Iterator, Dict, List, Optional
|
8
|
+
from .base import ANodeTreeStrategy
|
9
|
+
from ...types import NodeMode, NodeTrait
|
10
|
+
|
11
|
+
|
12
|
+
class TrieNode:
|
13
|
+
"""Node in the trie structure."""
|
14
|
+
|
15
|
+
def __init__(self):
|
16
|
+
self.children: Dict[str, 'TrieNode'] = {}
|
17
|
+
self.is_end_of_word = False
|
18
|
+
self.value: Any = None
|
19
|
+
|
20
|
+
|
21
|
+
class xTrieStrategy(ANodeTreeStrategy):
|
22
|
+
"""
|
23
|
+
Trie node strategy for efficient string prefix operations.
|
24
|
+
|
25
|
+
Optimized for prefix matching, autocomplete, and string searching.
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
29
|
+
"""Initialize the trie strategy."""
|
30
|
+
super().__init__(data=None, **options)
|
31
|
+
self._mode = NodeMode.TRIE
|
32
|
+
self._traits = traits
|
33
|
+
self._root = TrieNode()
|
34
|
+
self._size = 0
|
35
|
+
|
36
|
+
def get_supported_traits(self) -> NodeTrait:
|
37
|
+
"""Get the traits supported by the trie strategy."""
|
38
|
+
return (NodeTrait.ORDERED | NodeTrait.HIERARCHICAL | NodeTrait.INDEXED)
|
39
|
+
|
40
|
+
# ============================================================================
|
41
|
+
# CORE OPERATIONS
|
42
|
+
# ============================================================================
|
43
|
+
|
44
|
+
def insert(self, key: Any, value: Any) -> None:
|
45
|
+
"""Store a key-value pair (key should be string-like)."""
|
46
|
+
word = str(key)
|
47
|
+
node = self._root
|
48
|
+
|
49
|
+
# Traverse/create path
|
50
|
+
for char in word:
|
51
|
+
if char not in node.children:
|
52
|
+
node.children[char] = TrieNode()
|
53
|
+
node = node.children[char]
|
54
|
+
|
55
|
+
# Mark end of word and store value
|
56
|
+
if not node.is_end_of_word:
|
57
|
+
self._size += 1
|
58
|
+
node.is_end_of_word = True
|
59
|
+
node.value = value
|
60
|
+
|
61
|
+
def find(self, key: Any) -> Any:
|
62
|
+
"""Retrieve a value by key."""
|
63
|
+
word = str(key)
|
64
|
+
node = self._root
|
65
|
+
|
66
|
+
# Traverse path
|
67
|
+
for char in word:
|
68
|
+
if char not in node.children:
|
69
|
+
return None
|
70
|
+
node = node.children[char]
|
71
|
+
|
72
|
+
return node.value if node.is_end_of_word else None
|
73
|
+
|
74
|
+
def delete(self, key: Any) -> bool:
|
75
|
+
"""Remove a key-value pair."""
|
76
|
+
word = str(key)
|
77
|
+
return self._delete_helper(self._root, word, 0)
|
78
|
+
|
79
|
+
def _delete_helper(self, node: TrieNode, word: str, index: int) -> bool:
|
80
|
+
"""Helper method for deletion."""
|
81
|
+
if index == len(word):
|
82
|
+
if node.is_end_of_word:
|
83
|
+
node.is_end_of_word = False
|
84
|
+
node.value = None
|
85
|
+
self._size -= 1
|
86
|
+
return True
|
87
|
+
return False
|
88
|
+
|
89
|
+
char = word[index]
|
90
|
+
if char not in node.children:
|
91
|
+
return False
|
92
|
+
|
93
|
+
deleted = self._delete_helper(node.children[char], word, index + 1)
|
94
|
+
|
95
|
+
# Clean up empty nodes
|
96
|
+
if deleted and not node.children[char].children and not node.children[char].is_end_of_word:
|
97
|
+
del node.children[char]
|
98
|
+
|
99
|
+
return deleted
|
100
|
+
|
101
|
+
def size(self) -> int:
|
102
|
+
"""Get the number of items."""
|
103
|
+
return self._size
|
104
|
+
|
105
|
+
def is_empty(self) -> bool:
|
106
|
+
"""Check if the structure is empty."""
|
107
|
+
return self._size == 0
|
108
|
+
|
109
|
+
def to_native(self) -> Dict[str, Any]:
|
110
|
+
"""Convert to native Python dictionary."""
|
111
|
+
result = {}
|
112
|
+
self._collect_words(self._root, "", result)
|
113
|
+
return result
|
114
|
+
|
115
|
+
def _collect_words(self, node: TrieNode, prefix: str, result: Dict[str, Any]) -> None:
|
116
|
+
"""Collect all words from trie."""
|
117
|
+
if node.is_end_of_word:
|
118
|
+
result[prefix] = node.value
|
119
|
+
|
120
|
+
for char, child in node.children.items():
|
121
|
+
self._collect_words(child, prefix + char, result)
|
122
|
+
|
123
|
+
# ============================================================================
|
124
|
+
# TREE STRATEGY METHODS
|
125
|
+
# ============================================================================
|
126
|
+
|
127
|
+
def traverse(self, order: str = 'inorder') -> List[Any]:
|
128
|
+
"""Traverse tree in specified order."""
|
129
|
+
result = []
|
130
|
+
self._collect_words(self._root, "", result)
|
131
|
+
return list(result.values())
|
132
|
+
|
133
|
+
def get_min(self) -> Any:
|
134
|
+
"""Get minimum key."""
|
135
|
+
# Find leftmost word
|
136
|
+
node = self._root
|
137
|
+
word = ""
|
138
|
+
while node.children:
|
139
|
+
char = min(node.children.keys())
|
140
|
+
word += char
|
141
|
+
node = node.children[char]
|
142
|
+
return word if node.is_end_of_word else None
|
143
|
+
|
144
|
+
def get_max(self) -> Any:
|
145
|
+
"""Get maximum key."""
|
146
|
+
# Find rightmost word
|
147
|
+
node = self._root
|
148
|
+
word = ""
|
149
|
+
while node.children:
|
150
|
+
char = max(node.children.keys())
|
151
|
+
word += char
|
152
|
+
node = node.children[char]
|
153
|
+
return word if node.is_end_of_word else None
|
154
|
+
|
155
|
+
# ============================================================================
|
156
|
+
# AUTO-3 Phase 2 methods
|
157
|
+
# ============================================================================
|
158
|
+
|
159
|
+
def as_trie(self):
|
160
|
+
"""Provide Trie behavioral view."""
|
161
|
+
return self
|
162
|
+
|
163
|
+
def as_heap(self):
|
164
|
+
"""Provide Heap behavioral view."""
|
165
|
+
# TODO: Implement Heap view
|
166
|
+
return self
|
167
|
+
|
168
|
+
def as_skip_list(self):
|
169
|
+
"""Provide SkipList behavioral view."""
|
170
|
+
# TODO: Implement SkipList view
|
171
|
+
return self
|
172
|
+
|
173
|
+
# ============================================================================
|
174
|
+
# TRIE SPECIFIC OPERATIONS
|
175
|
+
# ============================================================================
|
176
|
+
|
177
|
+
def prefix_search(self, prefix: str) -> List[str]:
|
178
|
+
"""Find all keys with given prefix."""
|
179
|
+
node = self._root
|
180
|
+
|
181
|
+
# Navigate to prefix
|
182
|
+
for char in prefix:
|
183
|
+
if char not in node.children:
|
184
|
+
return []
|
185
|
+
node = node.children[char]
|
186
|
+
|
187
|
+
# Collect all words with this prefix
|
188
|
+
result = []
|
189
|
+
self._collect_words(node, prefix, result)
|
190
|
+
return list(result.keys())
|
191
|
+
|
192
|
+
def longest_common_prefix(self) -> str:
|
193
|
+
"""Find longest common prefix of all keys."""
|
194
|
+
if not self._root.children:
|
195
|
+
return ""
|
196
|
+
|
197
|
+
prefix = ""
|
198
|
+
node = self._root
|
199
|
+
|
200
|
+
while len(node.children) == 1 and not node.is_end_of_word:
|
201
|
+
char = list(node.children.keys())[0]
|
202
|
+
prefix += char
|
203
|
+
node = node.children[char]
|
204
|
+
|
205
|
+
return prefix
|
206
|
+
|
207
|
+
def keys_with_prefix(self, prefix: str) -> List[str]:
|
208
|
+
"""Get all keys with given prefix."""
|
209
|
+
return self.prefix_search(prefix)
|
210
|
+
|
211
|
+
def keys_with_suffix(self, suffix: str) -> List[str]:
|
212
|
+
"""Get all keys with given suffix."""
|
213
|
+
# TODO: Implement suffix search
|
214
|
+
return []
|
215
|
+
|
216
|
+
# ============================================================================
|
217
|
+
# ITERATION
|
218
|
+
# ============================================================================
|
219
|
+
|
220
|
+
def keys(self) -> Iterator[str]:
|
221
|
+
"""Get all keys."""
|
222
|
+
result = {}
|
223
|
+
self._collect_words(self._root, "", result)
|
224
|
+
return iter(result.keys())
|
225
|
+
|
226
|
+
def values(self) -> Iterator[Any]:
|
227
|
+
"""Get all values."""
|
228
|
+
result = {}
|
229
|
+
self._collect_words(self._root, "", result)
|
230
|
+
return iter(result.values())
|
231
|
+
|
232
|
+
def items(self) -> Iterator[tuple[str, Any]]:
|
233
|
+
"""Get all key-value pairs."""
|
234
|
+
result = {}
|
235
|
+
self._collect_words(self._root, "", result)
|
236
|
+
return iter(result.items())
|
237
|
+
|
238
|
+
# ============================================================================
|
239
|
+
# PERFORMANCE CHARACTERISTICS
|
240
|
+
# ============================================================================
|
241
|
+
|
242
|
+
@property
|
243
|
+
def backend_info(self) -> Dict[str, Any]:
|
244
|
+
"""Get backend implementation info."""
|
245
|
+
return {
|
246
|
+
'strategy': 'TRIE',
|
247
|
+
'backend': 'Trie tree',
|
248
|
+
'complexity': {
|
249
|
+
'insert': 'O(m)',
|
250
|
+
'search': 'O(m)',
|
251
|
+
'delete': 'O(m)',
|
252
|
+
'prefix_search': 'O(m + k)',
|
253
|
+
'space': 'O(ALPHABET_SIZE * N * M)'
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
@property
|
258
|
+
def metrics(self) -> Dict[str, Any]:
|
259
|
+
"""Get performance metrics."""
|
260
|
+
return {
|
261
|
+
'size': self._size,
|
262
|
+
'memory_usage': f"{self._size * 32} bytes (estimated)",
|
263
|
+
'height': self._get_height()
|
264
|
+
}
|
265
|
+
|
266
|
+
def _get_height(self) -> int:
|
267
|
+
"""Get height of trie."""
|
268
|
+
return self._height_helper(self._root)
|
269
|
+
|
270
|
+
def _height_helper(self, node: TrieNode) -> int:
|
271
|
+
"""Helper for height calculation."""
|
272
|
+
if not node.children:
|
273
|
+
return 0
|
274
|
+
return 1 + max(self._height_helper(child) for child in node.children.values())
|
@@ -0,0 +1,283 @@
|
|
1
|
+
"""
|
2
|
+
Union-Find Node Strategy Implementation
|
3
|
+
|
4
|
+
This module implements the UNION_FIND strategy for efficient set operations.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Any, Iterator, Dict, List, Set
|
8
|
+
from .base import ANodeGraphStrategy
|
9
|
+
from ...types import NodeMode, NodeTrait
|
10
|
+
|
11
|
+
|
12
|
+
class UnionFind:
|
13
|
+
"""Union-Find data structure."""
|
14
|
+
|
15
|
+
def __init__(self):
|
16
|
+
self.parent: Dict[str, str] = {}
|
17
|
+
self.rank: Dict[str, int] = {}
|
18
|
+
self.values: Dict[str, Any] = {}
|
19
|
+
|
20
|
+
def make_set(self, x: str, value: Any = None) -> None:
|
21
|
+
"""Make a new set containing x."""
|
22
|
+
if x not in self.parent:
|
23
|
+
self.parent[x] = x
|
24
|
+
self.rank[x] = 0
|
25
|
+
self.values[x] = value
|
26
|
+
|
27
|
+
def find(self, x: str) -> str:
|
28
|
+
"""Find the root of the set containing x."""
|
29
|
+
if x not in self.parent:
|
30
|
+
return x
|
31
|
+
|
32
|
+
if self.parent[x] != x:
|
33
|
+
self.parent[x] = self.find(self.parent[x]) # Path compression
|
34
|
+
return self.parent[x]
|
35
|
+
|
36
|
+
def union(self, x: str, y: str) -> bool:
|
37
|
+
"""Union the sets containing x and y."""
|
38
|
+
root_x = self.find(x)
|
39
|
+
root_y = self.find(y)
|
40
|
+
|
41
|
+
if root_x == root_y:
|
42
|
+
return False # Already in same set
|
43
|
+
|
44
|
+
# Union by rank
|
45
|
+
if self.rank[root_x] < self.rank[root_y]:
|
46
|
+
self.parent[root_x] = root_y
|
47
|
+
elif self.rank[root_x] > self.rank[root_y]:
|
48
|
+
self.parent[root_y] = root_x
|
49
|
+
else:
|
50
|
+
self.parent[root_y] = root_x
|
51
|
+
self.rank[root_x] += 1
|
52
|
+
|
53
|
+
return True
|
54
|
+
|
55
|
+
def connected(self, x: str, y: str) -> bool:
|
56
|
+
"""Check if x and y are in the same set."""
|
57
|
+
return self.find(x) == self.find(y)
|
58
|
+
|
59
|
+
def get_set_members(self, x: str) -> Set[str]:
|
60
|
+
"""Get all members of the set containing x."""
|
61
|
+
root = self.find(x)
|
62
|
+
return {member for member in self.parent.keys() if self.find(member) == root}
|
63
|
+
|
64
|
+
def get_all_sets(self) -> List[Set[str]]:
|
65
|
+
"""Get all disjoint sets."""
|
66
|
+
roots = set(self.find(x) for x in self.parent.keys())
|
67
|
+
return [self.get_set_members(root) for root in roots]
|
68
|
+
|
69
|
+
def get_set_count(self) -> int:
|
70
|
+
"""Get the number of disjoint sets."""
|
71
|
+
roots = set(self.find(x) for x in self.parent.keys())
|
72
|
+
return len(roots)
|
73
|
+
|
74
|
+
def get_set_size(self, x: str) -> int:
|
75
|
+
"""Get the size of the set containing x."""
|
76
|
+
return len(self.get_set_members(x))
|
77
|
+
|
78
|
+
|
79
|
+
class xUnionFindStrategy(ANodeGraphStrategy):
|
80
|
+
"""
|
81
|
+
Union-Find node strategy for efficient set operations.
|
82
|
+
|
83
|
+
Optimized for union, find, and connected operations on disjoint sets.
|
84
|
+
"""
|
85
|
+
|
86
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
87
|
+
"""Initialize the union-find strategy."""
|
88
|
+
super().__init__(data=None, **options)
|
89
|
+
self._mode = NodeMode.UNION_FIND
|
90
|
+
self._traits = traits
|
91
|
+
self._union_find = UnionFind()
|
92
|
+
self._size = 0
|
93
|
+
|
94
|
+
def get_supported_traits(self) -> NodeTrait:
|
95
|
+
"""Get the traits supported by the union-find strategy."""
|
96
|
+
return (NodeTrait.SET_OPERATIONS | NodeTrait.HIERARCHICAL)
|
97
|
+
|
98
|
+
# ============================================================================
|
99
|
+
# CORE OPERATIONS
|
100
|
+
# ============================================================================
|
101
|
+
|
102
|
+
def insert(self, key: Any, value: Any) -> None:
|
103
|
+
"""Store a key-value pair (creates a new set)."""
|
104
|
+
str_key = str(key)
|
105
|
+
if str_key not in self._union_find.parent:
|
106
|
+
self._size += 1
|
107
|
+
self._union_find.make_set(str_key, value)
|
108
|
+
|
109
|
+
def find(self, key: Any) -> Any:
|
110
|
+
"""Find the root of the set containing key."""
|
111
|
+
str_key = str(key)
|
112
|
+
root = self._union_find.find(str_key)
|
113
|
+
return self._union_find.values.get(root)
|
114
|
+
|
115
|
+
def delete(self, key: Any) -> bool:
|
116
|
+
"""Delete a key (not supported in union-find)."""
|
117
|
+
# Union-Find doesn't support deletion efficiently
|
118
|
+
return False
|
119
|
+
|
120
|
+
def size(self) -> int:
|
121
|
+
"""Get the number of elements."""
|
122
|
+
return self._size
|
123
|
+
|
124
|
+
def is_empty(self) -> bool:
|
125
|
+
"""Check if the structure is empty."""
|
126
|
+
return self._size == 0
|
127
|
+
|
128
|
+
def to_native(self) -> Dict[str, Any]:
|
129
|
+
"""Convert to native Python dictionary."""
|
130
|
+
return self._union_find.values.copy()
|
131
|
+
|
132
|
+
# ============================================================================
|
133
|
+
# GRAPH STRATEGY METHODS
|
134
|
+
# ============================================================================
|
135
|
+
|
136
|
+
def add_edge(self, from_node: Any, to_node: Any, weight: float = 1.0) -> None:
|
137
|
+
"""Add edge between nodes (union operation)."""
|
138
|
+
str_from = str(from_node)
|
139
|
+
str_to = str(to_node)
|
140
|
+
|
141
|
+
# Make sure both nodes exist
|
142
|
+
if str_from not in self._union_find.parent:
|
143
|
+
self._union_find.make_set(str_from)
|
144
|
+
self._size += 1
|
145
|
+
if str_to not in self._union_find.parent:
|
146
|
+
self._union_find.make_set(str_to)
|
147
|
+
self._size += 1
|
148
|
+
|
149
|
+
# Union the sets
|
150
|
+
self._union_find.union(str_from, str_to)
|
151
|
+
|
152
|
+
def remove_edge(self, from_node: Any, to_node: Any) -> bool:
|
153
|
+
"""Remove edge between nodes (not supported in union-find)."""
|
154
|
+
# Union-Find doesn't support edge removal efficiently
|
155
|
+
return False
|
156
|
+
|
157
|
+
def has_edge(self, from_node: Any, to_node: Any) -> bool:
|
158
|
+
"""Check if edge exists (connected operation)."""
|
159
|
+
str_from = str(from_node)
|
160
|
+
str_to = str(to_node)
|
161
|
+
|
162
|
+
if str_from not in self._union_find.parent or str_to not in self._union_find.parent:
|
163
|
+
return False
|
164
|
+
|
165
|
+
return self._union_find.connected(str_from, str_to)
|
166
|
+
|
167
|
+
def find_path(self, start: Any, end: Any) -> List[Any]:
|
168
|
+
"""Find path between nodes."""
|
169
|
+
if self.has_edge(start, end):
|
170
|
+
return [start, end]
|
171
|
+
return []
|
172
|
+
|
173
|
+
def get_neighbors(self, node: Any) -> List[Any]:
|
174
|
+
"""Get neighboring nodes (all nodes in same set)."""
|
175
|
+
str_node = str(node)
|
176
|
+
if str_node not in self._union_find.parent:
|
177
|
+
return []
|
178
|
+
|
179
|
+
members = self._union_find.get_set_members(str_node)
|
180
|
+
return [member for member in members if member != str_node]
|
181
|
+
|
182
|
+
def get_edge_weight(self, from_node: Any, to_node: Any) -> float:
|
183
|
+
"""Get edge weight (always 1.0 for union-find)."""
|
184
|
+
return 1.0 if self.has_edge(from_node, to_node) else 0.0
|
185
|
+
|
186
|
+
# ============================================================================
|
187
|
+
# AUTO-3 Phase 3&4 methods
|
188
|
+
# ============================================================================
|
189
|
+
|
190
|
+
def as_union_find(self):
|
191
|
+
"""Provide Union-Find behavioral view."""
|
192
|
+
return self
|
193
|
+
|
194
|
+
def as_neural_graph(self):
|
195
|
+
"""Provide Neural Graph behavioral view."""
|
196
|
+
# TODO: Implement Neural Graph view
|
197
|
+
return self
|
198
|
+
|
199
|
+
def as_flow_network(self):
|
200
|
+
"""Provide Flow Network behavioral view."""
|
201
|
+
# TODO: Implement Flow Network view
|
202
|
+
return self
|
203
|
+
|
204
|
+
# ============================================================================
|
205
|
+
# UNION-FIND SPECIFIC OPERATIONS
|
206
|
+
# ============================================================================
|
207
|
+
|
208
|
+
def make_set(self, element: str, value: Any = None) -> None:
|
209
|
+
"""Make a new set containing element."""
|
210
|
+
if element not in self._union_find.parent:
|
211
|
+
self._size += 1
|
212
|
+
self._union_find.make_set(element, value)
|
213
|
+
|
214
|
+
def find_root(self, element: str) -> str:
|
215
|
+
"""Find the root of the set containing element."""
|
216
|
+
return self._union_find.find(element)
|
217
|
+
|
218
|
+
def union_sets(self, element1: str, element2: str) -> bool:
|
219
|
+
"""Union the sets containing element1 and element2."""
|
220
|
+
return self._union_find.union(element1, element2)
|
221
|
+
|
222
|
+
def connected(self, element1: str, element2: str) -> bool:
|
223
|
+
"""Check if element1 and element2 are in the same set."""
|
224
|
+
return self._union_find.connected(element1, element2)
|
225
|
+
|
226
|
+
def get_set_members(self, element: str) -> Set[str]:
|
227
|
+
"""Get all members of the set containing element."""
|
228
|
+
return self._union_find.get_set_members(element)
|
229
|
+
|
230
|
+
def get_all_sets(self) -> List[Set[str]]:
|
231
|
+
"""Get all disjoint sets."""
|
232
|
+
return self._union_find.get_all_sets()
|
233
|
+
|
234
|
+
def get_set_count(self) -> int:
|
235
|
+
"""Get the number of disjoint sets."""
|
236
|
+
return self._union_find.get_set_count()
|
237
|
+
|
238
|
+
def get_set_size(self, element: str) -> int:
|
239
|
+
"""Get the size of the set containing element."""
|
240
|
+
return self._union_find.get_set_size(element)
|
241
|
+
|
242
|
+
# ============================================================================
|
243
|
+
# ITERATION
|
244
|
+
# ============================================================================
|
245
|
+
|
246
|
+
def keys(self) -> Iterator[str]:
|
247
|
+
"""Get all elements."""
|
248
|
+
return iter(self._union_find.parent.keys())
|
249
|
+
|
250
|
+
def values(self) -> Iterator[Any]:
|
251
|
+
"""Get all values."""
|
252
|
+
return iter(self._union_find.values.values())
|
253
|
+
|
254
|
+
def items(self) -> Iterator[tuple[str, Any]]:
|
255
|
+
"""Get all element-value pairs."""
|
256
|
+
return iter(self._union_find.values.items())
|
257
|
+
|
258
|
+
# ============================================================================
|
259
|
+
# PERFORMANCE CHARACTERISTICS
|
260
|
+
# ============================================================================
|
261
|
+
|
262
|
+
@property
|
263
|
+
def backend_info(self) -> Dict[str, Any]:
|
264
|
+
"""Get backend implementation info."""
|
265
|
+
return {
|
266
|
+
'strategy': 'UNION_FIND',
|
267
|
+
'backend': 'Union-Find with path compression',
|
268
|
+
'complexity': {
|
269
|
+
'make_set': 'O(1)',
|
270
|
+
'find': 'O(α(n))',
|
271
|
+
'union': 'O(α(n))',
|
272
|
+
'connected': 'O(α(n))'
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
@property
|
277
|
+
def metrics(self) -> Dict[str, Any]:
|
278
|
+
"""Get performance metrics."""
|
279
|
+
return {
|
280
|
+
'elements': self._size,
|
281
|
+
'sets': self._union_find.get_set_count(),
|
282
|
+
'memory_usage': f"{self._size * 32} bytes (estimated)"
|
283
|
+
}
|