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.
Files changed (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,463 @@
1
+ """
2
+ #exonware/xwnode/src/exonware/xwnode/strategies/advisor.py
3
+
4
+ Strategy Advisor
5
+
6
+ This module provides the StrategyAdvisor class for intelligent strategy selection,
7
+ performance monitoring, and optimization recommendations in the strategy system.
8
+ """
9
+
10
+ import time
11
+ import threading
12
+ from typing import Dict, List, Optional, Tuple, Any, NamedTuple
13
+ from dataclasses import dataclass
14
+ from collections import defaultdict, deque
15
+ from exonware.xwsystem import get_logger
16
+
17
+ logger = get_logger(__name__)
18
+
19
+ from ..types import NodeMode, EdgeMode, NodeTrait, EdgeTrait, NODE_STRATEGY_METADATA, EDGE_STRATEGY_METADATA
20
+
21
+
22
+ @dataclass
23
+ class StrategyRecommendation:
24
+ """A strategy recommendation with rationale and estimated gain."""
25
+ mode: NodeMode | EdgeMode
26
+ rationale: str
27
+ estimated_gain_percent: float
28
+ confidence: float
29
+ migration_cost: str
30
+ data_loss_risk: bool
31
+
32
+
33
+ @dataclass
34
+ class PerformanceMetrics:
35
+ """Performance metrics for strategy monitoring."""
36
+ operation_count: int = 0
37
+ total_time: float = 0.0
38
+ avg_time: float = 0.0
39
+ min_time: float = float('inf')
40
+ max_time: float = 0.0
41
+ memory_usage: float = 0.0
42
+ last_updated: float = 0.0
43
+
44
+ def update(self, operation_time: float, memory_usage: float = 0.0):
45
+ """Update metrics with new operation data."""
46
+ self.operation_count += 1
47
+ self.total_time += operation_time
48
+ self.avg_time = self.total_time / self.operation_count
49
+ self.min_time = min(self.min_time, operation_time)
50
+ self.max_time = max(self.max_time, operation_time)
51
+ self.memory_usage = memory_usage
52
+ self.last_updated = time.time()
53
+
54
+
55
+ class StrategyAdvisor:
56
+ """
57
+ Intelligent advisor for strategy selection and optimization.
58
+
59
+ This class provides:
60
+ - Performance monitoring and metrics collection
61
+ - Intelligent strategy recommendations
62
+ - Migration cost analysis
63
+ - Heuristic-based mode selection
64
+ """
65
+
66
+ def __init__(self, history_size: int = 1000):
67
+ """Initialize the strategy advisor."""
68
+ self.history_size = history_size
69
+ self._node_metrics: Dict[str, PerformanceMetrics] = defaultdict(PerformanceMetrics)
70
+ self._edge_metrics: Dict[str, PerformanceMetrics] = defaultdict(PerformanceMetrics)
71
+ self._operation_history: deque = deque(maxlen=history_size)
72
+ self._lock = threading.RLock()
73
+
74
+ # Heuristic thresholds
75
+ self._thresholds = {
76
+ 'small_dataset': 100,
77
+ 'medium_dataset': 10000,
78
+ 'large_dataset': 1000000,
79
+ 'sparse_graph': 0.02,
80
+ 'dense_graph': 0.15,
81
+ 'high_churn': 0.1,
82
+ 'write_heavy': 0.7,
83
+ 'lookup_heavy': 0.7,
84
+ 'ordered_heavy': 0.2,
85
+ 'prefix_heavy': 0.1,
86
+ 'priority_heavy': 0.2,
87
+ 'spatial_heavy': 0.1,
88
+ 'temporal_heavy': 0.1,
89
+ }
90
+
91
+ def record_operation(self, strategy_id: str, operation: str,
92
+ duration: float, memory_usage: float = 0.0,
93
+ is_node: bool = True) -> None:
94
+ """
95
+ Record an operation for performance monitoring.
96
+
97
+ Args:
98
+ strategy_id: Unique identifier for the strategy
99
+ operation: Operation name (e.g., 'get', 'set', 'add_edge')
100
+ duration: Operation duration in seconds
101
+ memory_usage: Memory usage in bytes
102
+ is_node: Whether this is a node or edge operation
103
+ """
104
+ with self._lock:
105
+ metrics = self._node_metrics if is_node else self._edge_metrics
106
+ key = f"{strategy_id}:{operation}"
107
+ metrics[key].update(duration, memory_usage)
108
+
109
+ # Record in history
110
+ self._operation_history.append({
111
+ 'timestamp': time.time(),
112
+ 'strategy_id': strategy_id,
113
+ 'operation': operation,
114
+ 'duration': duration,
115
+ 'memory_usage': memory_usage,
116
+ 'is_node': is_node
117
+ })
118
+
119
+ def get_performance_profile(self, strategy_id: str, is_node: bool = True) -> Dict[str, Any]:
120
+ """
121
+ Get performance profile for a strategy.
122
+
123
+ Args:
124
+ strategy_id: Strategy identifier
125
+ is_node: Whether this is a node or edge strategy
126
+
127
+ Returns:
128
+ Performance profile dictionary
129
+ """
130
+ with self._lock:
131
+ metrics = self._node_metrics if is_node else self._edge_metrics
132
+
133
+ profile = {
134
+ 'strategy_id': strategy_id,
135
+ 'is_node': is_node,
136
+ 'operations': {},
137
+ 'overall': {
138
+ 'total_operations': 0,
139
+ 'avg_duration': 0.0,
140
+ 'total_duration': 0.0,
141
+ 'memory_usage': 0.0
142
+ }
143
+ }
144
+
145
+ total_ops = 0
146
+ total_duration = 0.0
147
+ total_memory = 0.0
148
+
149
+ for key, metric in metrics.items():
150
+ if key.startswith(f"{strategy_id}:"):
151
+ operation = key.split(":", 1)[1]
152
+ profile['operations'][operation] = {
153
+ 'count': metric.operation_count,
154
+ 'avg_time': metric.avg_time,
155
+ 'min_time': metric.min_time,
156
+ 'max_time': metric.max_time,
157
+ 'total_time': metric.total_time,
158
+ 'memory_usage': metric.memory_usage,
159
+ 'last_updated': metric.last_updated
160
+ }
161
+
162
+ total_ops += metric.operation_count
163
+ total_duration += metric.total_time
164
+ total_memory = max(total_memory, metric.memory_usage)
165
+
166
+ if total_ops > 0:
167
+ profile['overall']['total_operations'] = total_ops
168
+ profile['overall']['total_duration'] = total_duration
169
+ profile['overall']['avg_duration'] = total_duration / total_ops
170
+ profile['overall']['memory_usage'] = total_memory
171
+
172
+ return profile
173
+
174
+ def suggest_node_strategy(self, data_profile: Dict[str, Any],
175
+ current_mode: Optional[NodeMode] = None) -> StrategyRecommendation:
176
+ """
177
+ Suggest optimal node strategy based on data profile.
178
+
179
+ Args:
180
+ data_profile: Profile of the data and usage patterns
181
+ current_mode: Current strategy mode (if any)
182
+
183
+ Returns:
184
+ Strategy recommendation
185
+ """
186
+ size = data_profile.get('size', 0)
187
+ operations = data_profile.get('operations', {})
188
+ total_ops = sum(operations.values()) if operations else 0
189
+
190
+ # Calculate operation ratios
191
+ if total_ops > 0:
192
+ lookup_ratio = operations.get('get', 0) / total_ops
193
+ insert_ratio = operations.get('set', 0) / total_ops
194
+ ordered_ratio = operations.get('ordered_ops', 0) / total_ops
195
+ range_ratio = operations.get('range_ops', 0) / total_ops
196
+ prefix_ratio = operations.get('prefix_ops', 0) / total_ops
197
+ priority_ratio = operations.get('priority_ops', 0) / total_ops
198
+ else:
199
+ lookup_ratio = insert_ratio = ordered_ratio = range_ratio = prefix_ratio = priority_ratio = 0.0
200
+
201
+ # Decision logic based on heuristics
202
+ if data_profile.get('persistent', False):
203
+ if range_ratio > self._thresholds['ordered_heavy']:
204
+ mode = NodeMode.B_PLUS_TREE
205
+ rationale = f"Persistent data with {range_ratio:.1%} range operations"
206
+ gain = 50.0
207
+ else:
208
+ mode = NodeMode.B_TREE
209
+ rationale = f"Persistent data storage"
210
+ gain = 30.0
211
+
212
+ elif data_profile.get('write_heavy', False) or insert_ratio > self._thresholds['write_heavy']:
213
+ mode = NodeMode.LSM_TREE
214
+ rationale = f"Write-heavy workload ({insert_ratio:.1%} inserts)"
215
+ gain = 80.0
216
+
217
+ elif range_ratio > self._thresholds['ordered_heavy']:
218
+ if data_profile.get('updates', False):
219
+ mode = NodeMode.SEGMENT_TREE
220
+ rationale = f"Range operations with updates ({range_ratio:.1%})"
221
+ gain = 60.0
222
+ else:
223
+ mode = NodeMode.FENWICK_TREE
224
+ rationale = f"Range queries ({range_ratio:.1%})"
225
+ gain = 40.0
226
+
227
+ elif prefix_ratio > self._thresholds['prefix_heavy']:
228
+ if data_profile.get('binary', False):
229
+ mode = NodeMode.PATRICIA
230
+ rationale = f"Binary prefix operations ({prefix_ratio:.1%})"
231
+ gain = 50.0
232
+ else:
233
+ mode = NodeMode.RADIX_TRIE
234
+ rationale = f"String prefix operations ({prefix_ratio:.1%})"
235
+ gain = 40.0
236
+
237
+ elif priority_ratio > self._thresholds['priority_heavy']:
238
+ mode = NodeMode.HEAP
239
+ rationale = f"Priority operations ({priority_ratio:.1%})"
240
+ gain = 30.0
241
+
242
+ elif lookup_ratio > self._thresholds['lookup_heavy']:
243
+ if size > self._thresholds['large_dataset']:
244
+ mode = NodeMode.HASH_MAP
245
+ rationale = f"High lookup ratio ({lookup_ratio:.1%}) with large dataset"
246
+ gain = 70.0
247
+ else:
248
+ mode = NodeMode.ARRAY_LIST
249
+ rationale = f"High lookup ratio ({lookup_ratio:.1%}) with small dataset"
250
+ gain = 20.0
251
+
252
+ elif data_profile.get('connectivity', False):
253
+ mode = NodeMode.UNION_FIND
254
+ rationale = "Connectivity/disjoint set operations"
255
+ gain = 60.0
256
+
257
+ elif data_profile.get('streaming', False):
258
+ if data_profile.get('frequency', False):
259
+ mode = NodeMode.COUNT_MIN_SKETCH
260
+ rationale = "Streaming frequency estimation"
261
+ gain = 90.0
262
+ else:
263
+ mode = NodeMode.HYPERLOGLOG
264
+ rationale = "Streaming cardinality estimation"
265
+ gain = 85.0
266
+
267
+ elif size < self._thresholds['small_dataset']:
268
+ mode = NodeMode.ARRAY_LIST
269
+ rationale = f"Small dataset ({size} items)"
270
+ gain = 15.0
271
+
272
+ elif ordered_ratio > self._thresholds['ordered_heavy']:
273
+ mode = NodeMode.ORDERED_MAP_BALANCED
274
+ rationale = f"Ordered operations ({ordered_ratio:.1%})"
275
+ gain = 25.0
276
+
277
+ else:
278
+ mode = NodeMode.HASH_MAP
279
+ rationale = "General purpose hash map"
280
+ gain = 20.0
281
+
282
+ # Calculate migration cost
283
+ migration_cost = self._calculate_migration_cost(current_mode, mode, is_node=True)
284
+ data_loss_risk = self._assess_data_loss_risk(current_mode, mode, is_node=True)
285
+
286
+ return StrategyRecommendation(
287
+ mode=mode,
288
+ rationale=rationale,
289
+ estimated_gain_percent=gain,
290
+ confidence=0.8,
291
+ migration_cost=migration_cost,
292
+ data_loss_risk=data_loss_risk
293
+ )
294
+
295
+ def suggest_edge_strategy(self, graph_profile: Dict[str, Any],
296
+ current_mode: Optional[EdgeMode] = None) -> StrategyRecommendation:
297
+ """
298
+ Suggest optimal edge strategy based on graph profile.
299
+
300
+ Args:
301
+ graph_profile: Profile of the graph and usage patterns
302
+ current_mode: Current strategy mode (if any)
303
+
304
+ Returns:
305
+ Strategy recommendation
306
+ """
307
+ n = graph_profile.get('vertices', 0)
308
+ m = graph_profile.get('edges', 0)
309
+ density = m / (n * n) if n > 0 else 0
310
+
311
+ # Graph characteristics
312
+ is_spatial = graph_profile.get('spatial', False)
313
+ is_temporal = graph_profile.get('temporal', False)
314
+ is_hyper = graph_profile.get('hyper', False)
315
+ is_undirected = graph_profile.get('undirected', False)
316
+ high_churn = graph_profile.get('high_churn', False)
317
+
318
+ # Decision logic
319
+ if is_hyper:
320
+ mode = EdgeMode.HYPEREDGE_SET
321
+ rationale = "Hypergraph with multi-vertex edges"
322
+ gain = 40.0
323
+
324
+ elif is_temporal:
325
+ mode = EdgeMode.TEMPORAL_EDGESET
326
+ rationale = "Time-aware edge storage"
327
+ gain = 50.0
328
+
329
+ elif is_spatial:
330
+ dims = graph_profile.get('dimensions', 2)
331
+ if dims == 2:
332
+ mode = EdgeMode.QUADTREE
333
+ rationale = "2D spatial partitioning"
334
+ gain = 60.0
335
+ elif dims == 3:
336
+ mode = EdgeMode.OCTREE
337
+ rationale = "3D spatial partitioning"
338
+ gain = 60.0
339
+ else:
340
+ mode = EdgeMode.R_TREE
341
+ rationale = "Spatial indexing for arbitrary dimensions"
342
+ gain = 50.0
343
+
344
+ elif is_undirected:
345
+ mode = EdgeMode.BIDIR_WRAPPER
346
+ rationale = "Undirected graph via bidirectional wrapper"
347
+ gain = 30.0
348
+
349
+ elif high_churn:
350
+ mode = EdgeMode.DYNAMIC_ADJ_LIST
351
+ rationale = "High churn graph with frequent updates"
352
+ gain = 45.0
353
+
354
+ elif density <= self._thresholds['sparse_graph']:
355
+ mode = EdgeMode.CSR
356
+ rationale = f"Sparse graph (density: {density:.3f})"
357
+ gain = 35.0
358
+
359
+ elif density <= self._thresholds['dense_graph']:
360
+ mode = EdgeMode.ADJ_LIST
361
+ rationale = f"Medium density graph (density: {density:.3f})"
362
+ gain = 25.0
363
+
364
+ else:
365
+ mode = EdgeMode.BLOCK_ADJ_MATRIX
366
+ rationale = f"Dense graph (density: {density:.3f}) with cache optimization"
367
+ gain = 40.0
368
+
369
+ # Calculate migration cost
370
+ migration_cost = self._calculate_migration_cost(current_mode, mode, is_node=False)
371
+ data_loss_risk = self._assess_data_loss_risk(current_mode, mode, is_node=False)
372
+
373
+ return StrategyRecommendation(
374
+ mode=mode,
375
+ rationale=rationale,
376
+ estimated_gain_percent=gain,
377
+ confidence=0.8,
378
+ migration_cost=migration_cost,
379
+ data_loss_risk=data_loss_risk
380
+ )
381
+
382
+ def _calculate_migration_cost(self, from_mode: Optional[NodeMode | EdgeMode],
383
+ to_mode: NodeMode | EdgeMode, is_node: bool) -> str:
384
+ """Calculate the cost of migrating between strategies."""
385
+ if from_mode is None:
386
+ return "low"
387
+
388
+ # Define migration cost matrix
389
+ if is_node:
390
+ cost_matrix = {
391
+ NodeMode.ARRAY_LIST: {NodeMode.ORDERED_MAP: "medium", NodeMode.HASH_MAP: "medium"},
392
+ NodeMode.ORDERED_MAP: {NodeMode.ORDERED_MAP_BALANCED: "low", NodeMode.B_TREE: "medium"},
393
+ NodeMode.TRIE: {NodeMode.RADIX_TRIE: "low", NodeMode.PATRICIA: "low"},
394
+ NodeMode.BITMAP: {NodeMode.BITSET_DYNAMIC: "low", NodeMode.ROARING_BITMAP: "medium"},
395
+ }
396
+ else:
397
+ cost_matrix = {
398
+ EdgeMode.ADJ_LIST: {EdgeMode.DYNAMIC_ADJ_LIST: "low", EdgeMode.CSR: "medium"},
399
+ EdgeMode.ADJ_MATRIX: {EdgeMode.BLOCK_ADJ_MATRIX: "low"},
400
+ EdgeMode.QUADTREE: {EdgeMode.OCTREE: "low", EdgeMode.R_TREE: "medium"},
401
+ }
402
+
403
+ # Check if migration is in cost matrix
404
+ if from_mode in cost_matrix and to_mode in cost_matrix[from_mode]:
405
+ return cost_matrix[from_mode][to_mode]
406
+
407
+ # Default cost based on mode types
408
+ if from_mode == to_mode:
409
+ return "none"
410
+ elif is_node and (from_mode in [NodeMode.ARRAY_LIST, NodeMode.LINKED_LIST] and
411
+ to_mode in [NodeMode.HASH_MAP, NodeMode.ORDERED_MAP]):
412
+ return "medium"
413
+ elif not is_node and (from_mode in [EdgeMode.ADJ_LIST, EdgeMode.ADJ_MATRIX] and
414
+ to_mode in [EdgeMode.CSR, EdgeMode.CSC]):
415
+ return "medium"
416
+ else:
417
+ return "high"
418
+
419
+ def _assess_data_loss_risk(self, from_mode: Optional[NodeMode | EdgeMode],
420
+ to_mode: NodeMode | EdgeMode, is_node: bool) -> bool:
421
+ """Assess risk of data loss during migration."""
422
+ if from_mode is None:
423
+ return False
424
+
425
+ # Define lossy migrations
426
+ if is_node:
427
+ lossy_migrations = [
428
+ (NodeMode.ORDERED_MAP, NodeMode.HASH_MAP), # Order loss
429
+ (NodeMode.TRIE, NodeMode.HASH_MAP), # Prefix structure loss
430
+ (NodeMode.HEAP, NodeMode.HASH_MAP), # Priority order loss
431
+ (NodeMode.BLOOM_FILTER, NodeMode.HASH_MAP), # Probabilistic nature loss
432
+ ]
433
+ else:
434
+ lossy_migrations = [
435
+ (EdgeMode.HYPEREDGE_SET, EdgeMode.ADJ_LIST), # Hyperedge structure loss
436
+ (EdgeMode.TEMPORAL_EDGESET, EdgeMode.ADJ_LIST), # Temporal info loss
437
+ (EdgeMode.BIDIR_WRAPPER, EdgeMode.ADJ_LIST), # Bidirectional info loss
438
+ ]
439
+
440
+ return (from_mode, to_mode) in lossy_migrations
441
+
442
+ def get_advisor_stats(self) -> Dict[str, Any]:
443
+ """Get advisor statistics."""
444
+ with self._lock:
445
+ return {
446
+ 'history_size': len(self._operation_history),
447
+ 'node_metrics_count': len(self._node_metrics),
448
+ 'edge_metrics_count': len(self._edge_metrics),
449
+ 'thresholds': self._thresholds.copy(),
450
+ 'last_operation': self._operation_history[-1] if self._operation_history else None
451
+ }
452
+
453
+
454
+ # Global advisor instance
455
+ _advisor = None
456
+
457
+
458
+ def get_advisor() -> StrategyAdvisor:
459
+ """Get the global strategy advisor instance."""
460
+ global _advisor
461
+ if _advisor is None:
462
+ _advisor = StrategyAdvisor()
463
+ return _advisor
@@ -0,0 +1,32 @@
1
+ """
2
+ Edge Strategies Package
3
+
4
+ This package contains all edge strategy implementations organized by type:
5
+ - Linear edges (sequential connections)
6
+ - Tree edges (hierarchical connections)
7
+ - Graph edges (network connections)
8
+
9
+ Company: eXonware.com
10
+ Author: Eng. Muhammad AlShehri
11
+ Email: connect@exonware.com
12
+ Version: 0.0.1.12
13
+ Generation Date: January 2, 2025
14
+ """
15
+
16
+ from .base import AEdgeStrategy, ALinearEdgeStrategy, ATreeEdgeStrategy, AGraphEdgeStrategy
17
+
18
+ # Graph edge strategies
19
+ from .adj_list import AdjListStrategy
20
+ from .adj_matrix import AdjMatrixStrategy
21
+
22
+ __all__ = [
23
+ # Base classes
24
+ 'AEdgeStrategy',
25
+ 'ALinearEdgeStrategy',
26
+ 'ATreeEdgeStrategy',
27
+ 'AGraphEdgeStrategy',
28
+
29
+ # Graph edge strategies
30
+ 'AdjListStrategy',
31
+ 'AdjMatrixStrategy'
32
+ ]