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,227 @@
1
+ """
2
+ Adjacency List Edge Strategy Implementation
3
+
4
+ This module implements the ADJ_LIST strategy for sparse graph representation
5
+ with efficient edge addition and neighbor queries.
6
+ """
7
+
8
+ from typing import Any, Iterator, Dict, List, Set, Optional, Tuple
9
+ from collections import defaultdict
10
+ from .base import AGraphEdgeStrategy
11
+ from ...types import EdgeMode, EdgeTrait
12
+
13
+
14
+ class AdjListStrategy(AGraphEdgeStrategy):
15
+ """
16
+ Adjacency List edge strategy for sparse graph representation.
17
+
18
+ Provides O(1) edge addition and O(degree) neighbor queries,
19
+ ideal for sparse graphs where most vertices have few connections.
20
+ """
21
+
22
+ def __init__(self, traits: EdgeTrait = EdgeTrait.NONE, **options):
23
+ """Initialize the Adjacency List strategy."""
24
+ super().__init__(**options)
25
+ self._mode = EdgeMode.ADJ_LIST
26
+ self._traits = traits
27
+
28
+ self.is_directed = options.get('directed', True)
29
+ self.allow_self_loops = options.get('self_loops', True)
30
+ self.allow_multi_edges = options.get('multi_edges', False)
31
+
32
+ # Core storage: vertex -> list of (neighbor, edge_data)
33
+ self._outgoing: Dict[str, List[Tuple[str, Dict[str, Any]]]] = defaultdict(list)
34
+ self._incoming: Dict[str, List[Tuple[str, Dict[str, Any]]]] = defaultdict(list) if self.is_directed else None
35
+
36
+ # Vertex set for fast membership testing
37
+ self._vertices: Set[str] = set()
38
+
39
+ # Edge properties storage
40
+ self._edge_count = 0
41
+ self._edge_id_counter = 0
42
+
43
+ def get_supported_traits(self) -> EdgeTrait:
44
+ """Get the traits supported by the adjacency list strategy."""
45
+ return (EdgeTrait.SPARSE | EdgeTrait.DIRECTED | EdgeTrait.WEIGHTED | EdgeTrait.MULTI)
46
+
47
+ # ============================================================================
48
+ # CORE EDGE OPERATIONS
49
+ # ============================================================================
50
+
51
+ def add_edge(self, from_node: Any, to_node: Any, **kwargs) -> None:
52
+ """Add an edge between source and target vertices."""
53
+ source = str(from_node)
54
+ target = str(to_node)
55
+
56
+ # Validation
57
+ if not self.allow_self_loops and source == target:
58
+ raise ValueError("Self loops not allowed")
59
+
60
+ if not self.allow_multi_edges and self.has_edge(source, target):
61
+ raise ValueError("Multi edges not allowed")
62
+
63
+ # Add vertices to set
64
+ self._vertices.add(source)
65
+ self._vertices.add(target)
66
+
67
+ # Create edge data
68
+ edge_data = {
69
+ 'weight': kwargs.get('weight', 1.0),
70
+ 'id': f"edge_{self._edge_id_counter}",
71
+ **kwargs
72
+ }
73
+ self._edge_id_counter += 1
74
+
75
+ # Add outgoing edge
76
+ self._outgoing[source].append((target, edge_data))
77
+
78
+ # Add incoming edge if directed
79
+ if self.is_directed and self._incoming is not None:
80
+ self._incoming[target].append((source, edge_data))
81
+ elif not self.is_directed:
82
+ # For undirected, add reverse edge
83
+ self._outgoing[target].append((source, edge_data))
84
+
85
+ self._edge_count += 1
86
+
87
+ def remove_edge(self, from_node: Any, to_node: Any) -> bool:
88
+ """Remove edge between vertices."""
89
+ source = str(from_node)
90
+ target = str(to_node)
91
+
92
+ removed = False
93
+
94
+ # Remove from outgoing
95
+ for i, (neighbor, _) in enumerate(self._outgoing[source]):
96
+ if neighbor == target:
97
+ self._outgoing[source].pop(i)
98
+ removed = True
99
+ break
100
+
101
+ # Remove from incoming if directed
102
+ if self.is_directed and self._incoming is not None:
103
+ for i, (neighbor, _) in enumerate(self._incoming[target]):
104
+ if neighbor == source:
105
+ self._incoming[target].pop(i)
106
+ break
107
+ elif not self.is_directed:
108
+ # For undirected, remove reverse edge
109
+ for i, (neighbor, _) in enumerate(self._outgoing[target]):
110
+ if neighbor == source:
111
+ self._outgoing[target].pop(i)
112
+ break
113
+
114
+ if removed:
115
+ self._edge_count -= 1
116
+
117
+ return removed
118
+
119
+ def has_edge(self, from_node: Any, to_node: Any) -> bool:
120
+ """Check if edge exists."""
121
+ source = str(from_node)
122
+ target = str(to_node)
123
+
124
+ for neighbor, _ in self._outgoing[source]:
125
+ if neighbor == target:
126
+ return True
127
+ return False
128
+
129
+ def get_edge_count(self) -> int:
130
+ """Get total number of edges."""
131
+ return self._edge_count
132
+
133
+ def get_vertex_count(self) -> int:
134
+ """Get total number of vertices."""
135
+ return len(self._vertices)
136
+
137
+ # ============================================================================
138
+ # GRAPH EDGE STRATEGY METHODS
139
+ # ============================================================================
140
+
141
+ def get_neighbors(self, node: Any) -> List[Any]:
142
+ """Get all neighboring nodes."""
143
+ vertex = str(node)
144
+ neighbors = []
145
+ for neighbor, _ in self._outgoing[vertex]:
146
+ neighbors.append(neighbor)
147
+ return neighbors
148
+
149
+ def get_edge_weight(self, from_node: Any, to_node: Any) -> float:
150
+ """Get edge weight."""
151
+ source = str(from_node)
152
+ target = str(to_node)
153
+
154
+ for neighbor, edge_data in self._outgoing[source]:
155
+ if neighbor == target:
156
+ return edge_data.get('weight', 1.0)
157
+ return 0.0
158
+
159
+ def set_edge_weight(self, from_node: Any, to_node: Any, weight: float) -> None:
160
+ """Set edge weight."""
161
+ source = str(from_node)
162
+ target = str(to_node)
163
+
164
+ for neighbor, edge_data in self._outgoing[source]:
165
+ if neighbor == target:
166
+ edge_data['weight'] = weight
167
+ return
168
+ raise ValueError(f"Edge {source} -> {target} not found")
169
+
170
+ def find_shortest_path(self, start: Any, end: Any) -> List[Any]:
171
+ """Find shortest path between nodes."""
172
+ # TODO: Implement BFS/Dijkstra
173
+ return []
174
+
175
+ def find_all_paths(self, start: Any, end: Any) -> List[List[Any]]:
176
+ """Find all paths between nodes."""
177
+ # TODO: Implement DFS
178
+ return []
179
+
180
+ def get_connected_components(self) -> List[List[Any]]:
181
+ """Get all connected components."""
182
+ # TODO: Implement connected components
183
+ return []
184
+
185
+ def is_connected(self, start: Any, end: Any) -> bool:
186
+ """Check if two nodes are connected."""
187
+ # TODO: Implement connectivity check
188
+ return False
189
+
190
+ def get_degree(self, node: Any) -> int:
191
+ """Get degree of node."""
192
+ vertex = str(node)
193
+ return len(self._outgoing[vertex])
194
+
195
+ def is_cyclic(self) -> bool:
196
+ """Check if graph contains cycles."""
197
+ # TODO: Implement cycle detection
198
+ return False
199
+
200
+ # ============================================================================
201
+ # PERFORMANCE CHARACTERISTICS
202
+ # ============================================================================
203
+
204
+ @property
205
+ def backend_info(self) -> Dict[str, Any]:
206
+ """Get backend implementation info."""
207
+ return {
208
+ 'strategy': 'adjacency_list',
209
+ 'backend': 'Dictionary of lists',
210
+ 'complexity': {
211
+ 'add_edge': 'O(1)',
212
+ 'remove_edge': 'O(degree)',
213
+ 'has_edge': 'O(degree)',
214
+ 'get_neighbors': 'O(degree)',
215
+ 'space': 'O(V + E)'
216
+ }
217
+ }
218
+
219
+ @property
220
+ def metrics(self) -> Dict[str, Any]:
221
+ """Get performance metrics."""
222
+ return {
223
+ 'vertices': len(self._vertices),
224
+ 'edges': self._edge_count,
225
+ 'directed': self.is_directed,
226
+ 'density': f"{(self._edge_count / max(1, len(self._vertices) * (len(self._vertices) - 1))) * 100:.1f}%"
227
+ }
@@ -0,0 +1,391 @@
1
+ """
2
+ Adjacency Matrix Edge Strategy Implementation
3
+
4
+ This module implements the ADJ_MATRIX strategy for dense graph representation
5
+ with O(1) edge operations and efficient matrix-based algorithms.
6
+ """
7
+
8
+ from typing import Any, Iterator, Dict, List, Set, Optional, Tuple, Union
9
+ from .base import AGraphEdgeStrategy
10
+ from ...types import EdgeMode, EdgeTrait
11
+
12
+
13
+ class AdjMatrixStrategy(AGraphEdgeStrategy):
14
+ """
15
+ Adjacency Matrix edge strategy for dense graph representation.
16
+
17
+ Provides O(1) edge operations and efficient matrix-based graph algorithms,
18
+ ideal for dense graphs where most vertices are connected.
19
+ """
20
+
21
+ def __init__(self, traits: EdgeTrait = EdgeTrait.NONE, **options):
22
+ """Initialize the Adjacency Matrix strategy."""
23
+ super().__init__(**options)
24
+ self._mode = EdgeMode.ADJ_MATRIX
25
+ self._traits = traits
26
+
27
+ self.is_directed = options.get('directed', True)
28
+ self.initial_capacity = options.get('initial_capacity', 100)
29
+ self.allow_self_loops = options.get('self_loops', True)
30
+ self.default_weight = options.get('default_weight', 1.0)
31
+
32
+ # Core storage: 2D matrix of edge weights/properties
33
+ self._matrix: List[List[Optional[Dict[str, Any]]]] = []
34
+ self._capacity = 0
35
+
36
+ # Vertex management
37
+ self._vertex_to_index: Dict[str, int] = {}
38
+ self._index_to_vertex: Dict[int, str] = {}
39
+ self._vertex_count = 0
40
+ self._edge_count = 0
41
+ self._edge_id_counter = 0
42
+
43
+ # Initialize matrix
44
+ self._resize_matrix(self.initial_capacity)
45
+
46
+ def get_supported_traits(self) -> EdgeTrait:
47
+ """Get the traits supported by the adjacency matrix strategy."""
48
+ return (EdgeTrait.DENSE | EdgeTrait.DIRECTED | EdgeTrait.WEIGHTED | EdgeTrait.CACHE_FRIENDLY)
49
+
50
+ # ============================================================================
51
+ # MATRIX MANAGEMENT
52
+ # ============================================================================
53
+
54
+ def _resize_matrix(self, new_capacity: int) -> None:
55
+ """Resize the adjacency matrix to new capacity."""
56
+ old_capacity = self._capacity
57
+ self._capacity = new_capacity
58
+
59
+ # Create new matrix
60
+ new_matrix = [[None for _ in range(self._capacity)] for _ in range(self._capacity)]
61
+
62
+ # Copy existing data
63
+ for i in range(min(old_capacity, self._capacity)):
64
+ for j in range(min(old_capacity, self._capacity)):
65
+ new_matrix[i][j] = self._matrix[i][j]
66
+
67
+ self._matrix = new_matrix
68
+
69
+ def _get_vertex_index(self, vertex: str) -> int:
70
+ """Get or create index for vertex."""
71
+ if vertex not in self._vertex_to_index:
72
+ if self._vertex_count >= self._capacity:
73
+ self._resize_matrix(self._capacity * 2)
74
+
75
+ index = self._vertex_count
76
+ self._vertex_to_index[vertex] = index
77
+ self._index_to_vertex[index] = vertex
78
+ self._vertex_count += 1
79
+ return index
80
+
81
+ return self._vertex_to_index[vertex]
82
+
83
+ def _get_vertex_by_index(self, index: int) -> Optional[str]:
84
+ """Get vertex by index."""
85
+ return self._index_to_vertex.get(index)
86
+
87
+ # ============================================================================
88
+ # CORE EDGE OPERATIONS
89
+ # ============================================================================
90
+
91
+ def add_edge(self, from_node: Any, to_node: Any, **kwargs) -> None:
92
+ """Add an edge between source and target vertices."""
93
+ source = str(from_node)
94
+ target = str(to_node)
95
+
96
+ # Validation
97
+ if not self.allow_self_loops and source == target:
98
+ raise ValueError("Self loops not allowed")
99
+
100
+ # Get vertex indices
101
+ source_idx = self._get_vertex_index(source)
102
+ target_idx = self._get_vertex_index(target)
103
+
104
+ # Create edge data
105
+ edge_data = {
106
+ 'weight': kwargs.get('weight', self.default_weight),
107
+ 'id': f"edge_{self._edge_id_counter}",
108
+ **kwargs
109
+ }
110
+ self._edge_id_counter += 1
111
+
112
+ # Add edge to matrix
113
+ if self._matrix[source_idx][target_idx] is None:
114
+ self._edge_count += 1
115
+
116
+ self._matrix[source_idx][target_idx] = edge_data
117
+
118
+ # Add reverse edge if undirected
119
+ if not self.is_directed and source != target:
120
+ if self._matrix[target_idx][source_idx] is None:
121
+ self._edge_count += 1
122
+ self._matrix[target_idx][source_idx] = edge_data
123
+
124
+ def remove_edge(self, from_node: Any, to_node: Any) -> bool:
125
+ """Remove edge between vertices."""
126
+ source = str(from_node)
127
+ target = str(to_node)
128
+
129
+ if source not in self._vertex_to_index or target not in self._vertex_to_index:
130
+ return False
131
+
132
+ source_idx = self._vertex_to_index[source]
133
+ target_idx = self._vertex_to_index[target]
134
+
135
+ removed = False
136
+
137
+ # Remove edge from matrix
138
+ if self._matrix[source_idx][target_idx] is not None:
139
+ self._matrix[source_idx][target_idx] = None
140
+ self._edge_count -= 1
141
+ removed = True
142
+
143
+ # Remove reverse edge if undirected
144
+ if not self.is_directed and source != target:
145
+ if self._matrix[target_idx][source_idx] is not None:
146
+ self._matrix[target_idx][source_idx] = None
147
+ self._edge_count -= 1
148
+
149
+ return removed
150
+
151
+ def has_edge(self, from_node: Any, to_node: Any) -> bool:
152
+ """Check if edge exists."""
153
+ source = str(from_node)
154
+ target = str(to_node)
155
+
156
+ if source not in self._vertex_to_index or target not in self._vertex_to_index:
157
+ return False
158
+
159
+ source_idx = self._vertex_to_index[source]
160
+ target_idx = self._vertex_to_index[target]
161
+
162
+ return self._matrix[source_idx][target_idx] is not None
163
+
164
+ def get_edge_count(self) -> int:
165
+ """Get total number of edges."""
166
+ return self._edge_count
167
+
168
+ def get_vertex_count(self) -> int:
169
+ """Get total number of vertices."""
170
+ return self._vertex_count
171
+
172
+ # ============================================================================
173
+ # GRAPH EDGE STRATEGY METHODS
174
+ # ============================================================================
175
+
176
+ def get_neighbors(self, node: Any) -> List[Any]:
177
+ """Get all neighboring nodes."""
178
+ vertex = str(node)
179
+ if vertex not in self._vertex_to_index:
180
+ return []
181
+
182
+ vertex_idx = self._vertex_to_index[vertex]
183
+ neighbors = []
184
+
185
+ for i in range(self._capacity):
186
+ if self._matrix[vertex_idx][i] is not None:
187
+ neighbor = self._index_to_vertex.get(i)
188
+ if neighbor:
189
+ neighbors.append(neighbor)
190
+
191
+ return neighbors
192
+
193
+ def get_edge_weight(self, from_node: Any, to_node: Any) -> float:
194
+ """Get edge weight."""
195
+ source = str(from_node)
196
+ target = str(to_node)
197
+
198
+ if source not in self._vertex_to_index or target not in self._vertex_to_index:
199
+ return 0.0
200
+
201
+ source_idx = self._vertex_to_index[source]
202
+ target_idx = self._vertex_to_index[target]
203
+
204
+ edge_data = self._matrix[source_idx][target_idx]
205
+ return edge_data.get('weight', self.default_weight) if edge_data else 0.0
206
+
207
+ def set_edge_weight(self, from_node: Any, to_node: Any, weight: float) -> None:
208
+ """Set edge weight."""
209
+ source = str(from_node)
210
+ target = str(to_node)
211
+
212
+ if source not in self._vertex_to_index or target not in self._vertex_to_index:
213
+ raise ValueError(f"Edge {source} -> {target} not found")
214
+
215
+ source_idx = self._vertex_to_index[source]
216
+ target_idx = self._vertex_to_index[target]
217
+
218
+ if self._matrix[source_idx][target_idx] is None:
219
+ raise ValueError(f"Edge {source} -> {target} not found")
220
+
221
+ self._matrix[source_idx][target_idx]['weight'] = weight
222
+
223
+ def find_shortest_path(self, start: Any, end: Any) -> List[Any]:
224
+ """Find shortest path between nodes."""
225
+ # TODO: Implement Dijkstra's algorithm
226
+ return []
227
+
228
+ def find_all_paths(self, start: Any, end: Any) -> List[List[Any]]:
229
+ """Find all paths between nodes."""
230
+ # TODO: Implement DFS
231
+ return []
232
+
233
+ def get_connected_components(self) -> List[List[Any]]:
234
+ """Get all connected components."""
235
+ # TODO: Implement connected components
236
+ return []
237
+
238
+ def is_connected(self, start: Any, end: Any) -> bool:
239
+ """Check if two nodes are connected."""
240
+ # TODO: Implement connectivity check
241
+ return False
242
+
243
+ def get_degree(self, node: Any) -> int:
244
+ """Get degree of node."""
245
+ return len(self.get_neighbors(node))
246
+
247
+ def is_cyclic(self) -> bool:
248
+ """Check if graph contains cycles."""
249
+ # TODO: Implement cycle detection
250
+ return False
251
+
252
+ # ============================================================================
253
+ # MATRIX SPECIFIC OPERATIONS
254
+ # ============================================================================
255
+
256
+ def get_matrix(self) -> List[List[Optional[float]]]:
257
+ """Get the adjacency matrix as a 2D list."""
258
+ matrix = []
259
+ for i in range(self._vertex_count):
260
+ row = []
261
+ for j in range(self._vertex_count):
262
+ edge_data = self._matrix[i][j]
263
+ weight = edge_data.get('weight', self.default_weight) if edge_data else 0.0
264
+ row.append(weight)
265
+ matrix.append(row)
266
+ return matrix
267
+
268
+ def get_binary_matrix(self) -> List[List[int]]:
269
+ """Get the binary adjacency matrix."""
270
+ matrix = []
271
+ for i in range(self._vertex_count):
272
+ row = []
273
+ for j in range(self._vertex_count):
274
+ weight = 1 if self._matrix[i][j] is not None else 0
275
+ row.append(weight)
276
+ matrix.append(row)
277
+ return matrix
278
+
279
+ def set_matrix(self, matrix: List[List[Union[float, int, None]]], vertices: List[str]) -> None:
280
+ """Set the adjacency matrix from a 2D list."""
281
+ # Clear existing data
282
+ self.clear()
283
+
284
+ # Set vertices
285
+ for vertex in vertices:
286
+ self._get_vertex_index(vertex)
287
+
288
+ # Set edges
289
+ for i, row in enumerate(matrix):
290
+ for j, weight in enumerate(row):
291
+ if weight is not None and weight != 0:
292
+ source = self._index_to_vertex[i]
293
+ target = self._index_to_vertex[j]
294
+ self.add_edge(source, target, weight=float(weight))
295
+
296
+ def matrix_multiply(self, other: 'xAdjMatrixStrategy') -> 'xAdjMatrixStrategy':
297
+ """Multiply this matrix with another adjacency matrix."""
298
+ # TODO: Implement matrix multiplication
299
+ return self
300
+
301
+ def transpose(self) -> 'xAdjMatrixStrategy':
302
+ """Get the transpose of the adjacency matrix."""
303
+ # TODO: Implement matrix transpose
304
+ return self
305
+
306
+ # ============================================================================
307
+ # ITERATION
308
+ # ============================================================================
309
+
310
+ def edges(self) -> Iterator[tuple[Any, Any, Dict[str, Any]]]:
311
+ """Get all edges in the graph."""
312
+ for i in range(self._vertex_count):
313
+ for j in range(self._vertex_count):
314
+ if self._matrix[i][j] is not None:
315
+ source = self._index_to_vertex[i]
316
+ target = self._index_to_vertex[j]
317
+ yield (source, target, self._matrix[i][j])
318
+
319
+ def vertices(self) -> Iterator[Any]:
320
+ """Get all vertices in the graph."""
321
+ return iter(self._vertex_to_index.keys())
322
+
323
+ # ============================================================================
324
+ # UTILITY METHODS
325
+ # ============================================================================
326
+
327
+ def clear(self) -> None:
328
+ """Clear all edges and vertices."""
329
+ self._matrix = [[None for _ in range(self._capacity)] for _ in range(self._capacity)]
330
+ self._vertex_to_index.clear()
331
+ self._index_to_vertex.clear()
332
+ self._vertex_count = 0
333
+ self._edge_count = 0
334
+ self._edge_id_counter = 0
335
+
336
+ def add_vertex(self, vertex: str) -> None:
337
+ """Add a vertex to the graph."""
338
+ self._get_vertex_index(vertex)
339
+
340
+ def remove_vertex(self, vertex: str) -> bool:
341
+ """Remove a vertex and all its incident edges."""
342
+ if vertex not in self._vertex_to_index:
343
+ return False
344
+
345
+ vertex_idx = self._vertex_to_index[vertex]
346
+
347
+ # Remove all edges incident to this vertex
348
+ for i in range(self._capacity):
349
+ if self._matrix[vertex_idx][i] is not None:
350
+ self._matrix[vertex_idx][i] = None
351
+ self._edge_count -= 1
352
+ if self._matrix[i][vertex_idx] is not None:
353
+ self._matrix[i][vertex_idx] = None
354
+ self._edge_count -= 1
355
+
356
+ # Remove vertex from mappings
357
+ del self._vertex_to_index[vertex]
358
+ del self._index_to_vertex[vertex_idx]
359
+ self._vertex_count -= 1
360
+
361
+ return True
362
+
363
+ # ============================================================================
364
+ # PERFORMANCE CHARACTERISTICS
365
+ # ============================================================================
366
+
367
+ @property
368
+ def backend_info(self) -> Dict[str, Any]:
369
+ """Get backend implementation info."""
370
+ return {
371
+ 'strategy': 'ADJ_MATRIX',
372
+ 'backend': '2D matrix',
373
+ 'complexity': {
374
+ 'add_edge': 'O(1)',
375
+ 'remove_edge': 'O(1)',
376
+ 'has_edge': 'O(1)',
377
+ 'get_neighbors': 'O(V)',
378
+ 'space': 'O(V²)'
379
+ }
380
+ }
381
+
382
+ @property
383
+ def metrics(self) -> Dict[str, Any]:
384
+ """Get performance metrics."""
385
+ return {
386
+ 'vertices': self._vertex_count,
387
+ 'edges': self._edge_count,
388
+ 'capacity': self._capacity,
389
+ 'directed': self.is_directed,
390
+ 'density': f"{(self._edge_count / max(1, self._vertex_count * (self._vertex_count - 1))) * 100:.1f}%"
391
+ }