|
| 1 | +from __future__ import annotations |
| 2 | + |
1 | 3 | from ctypes import pointer |
2 | 4 | from math import nan |
3 | | -from typing import Any, Callable, Optional |
| 5 | +from typing import Any, Callable, Optional, TYPE_CHECKING |
4 | 6 |
|
5 | 7 | from igraph_ctypes._internal.conversion import igraph_vector_int_t_to_numpy_array_view |
| 8 | +from igraph_ctypes._internal.enums import AttributeElementType, AttributeType |
6 | 9 | from igraph_ctypes._internal.lib import ( |
7 | 10 | igraph_error, |
| 11 | + igraph_es_as_vector, |
8 | 12 | igraph_vector_resize, |
9 | 13 | igraph_vector_set, |
10 | 14 | igraph_vector_bool_resize, |
11 | 15 | igraph_vector_bool_set, |
12 | 16 | igraph_vector_int_clear, |
| 17 | + igraph_vector_int_push_back, |
| 18 | + igraph_vector_int_size, |
| 19 | + igraph_vs_as_vector, |
13 | 20 | igraph_strvector_clear, |
14 | 21 | igraph_strvector_resize, |
| 22 | + igraph_strvector_push_back, |
15 | 23 | igraph_strvector_set, |
16 | 24 | ) |
17 | 25 | from igraph_ctypes._internal.types import igraph_attribute_table_t |
|
23 | 31 | detach_storage_from_graph, |
24 | 32 | get_storage_from_graph, |
25 | 33 | ) |
| 34 | +from .utils import python_object_to_igraph_attribute_type |
| 35 | +from .value_list import AttributeValueList |
| 36 | + |
| 37 | +if TYPE_CHECKING: |
| 38 | + from igraph_ctypes._internal.wrappers import _VectorInt |
26 | 39 |
|
27 | 40 | __all__ = ( |
28 | 41 | "AttributeHandlerBase", |
@@ -72,8 +85,13 @@ class AttributeHandler(AttributeHandlerBase): |
72 | 85 | as its storage backend. |
73 | 86 | """ |
74 | 87 |
|
| 88 | + _indices: _VectorInt |
| 89 | + |
75 | 90 | def init(self, graph, attr): |
| 91 | + from igraph_ctypes._internal.wrappers import _VectorInt |
| 92 | + |
76 | 93 | assign_storage_to_graph(graph, DictAttributeStorage()) |
| 94 | + self._indices = _VectorInt.create(0) |
77 | 95 |
|
78 | 96 | def destroy(self, graph) -> None: |
79 | 97 | storage = get_storage_from_graph(graph) |
@@ -132,70 +150,141 @@ def combine_edges(self, graph, to, mapping, combinations): |
132 | 150 | pass |
133 | 151 |
|
134 | 152 | def get_info(self, graph, gnames, gtypes, vnames, vtypes, enames, etypes): |
135 | | - # TODO(ntamas): fill the names and the types |
| 153 | + storage = get_storage_from_graph(graph) |
| 154 | + |
136 | 155 | igraph_strvector_clear(gnames) |
137 | 156 | igraph_vector_int_clear(gtypes) |
| 157 | + for name, value in storage.get_graph_attribute_map().items(): |
| 158 | + igraph_strvector_push_back(gnames, name.encode("utf-8")) |
| 159 | + igraph_vector_int_push_back( |
| 160 | + gtypes, python_object_to_igraph_attribute_type(value) |
| 161 | + ) |
138 | 162 |
|
139 | 163 | igraph_strvector_clear(vnames) |
140 | 164 | igraph_vector_int_clear(vtypes) |
| 165 | + for name, value in storage.get_vertex_attribute_map().items(): |
| 166 | + igraph_strvector_push_back(vnames, name.encode("utf-8")) |
| 167 | + igraph_vector_int_push_back(vtypes, value.type) |
141 | 168 |
|
142 | 169 | igraph_strvector_clear(enames) |
143 | 170 | igraph_vector_int_clear(etypes) |
| 171 | + for name, value in storage.get_edge_attribute_map().items(): |
| 172 | + igraph_strvector_push_back(enames, name.encode("utf-8")) |
| 173 | + igraph_vector_int_push_back(etypes, value.type) |
| 174 | + |
| 175 | + def has_attr(self, graph, type: int, name: bytes) -> bool: |
| 176 | + storage = get_storage_from_graph(graph) |
| 177 | + name_str = name.decode("utf-8") |
| 178 | + |
| 179 | + if type == AttributeElementType.GRAPH: |
| 180 | + map = storage.get_graph_attribute_map() |
| 181 | + elif type == AttributeElementType.VERTEX: |
| 182 | + map = storage.get_vertex_attribute_map() |
| 183 | + elif type == AttributeElementType.EDGE: |
| 184 | + map = storage.get_edge_attribute_map() |
| 185 | + else: |
| 186 | + return False |
144 | 187 |
|
145 | | - def has_attr(self, graph, type, name) -> bool: |
146 | | - return False |
| 188 | + return name_str in map |
147 | 189 |
|
148 | 190 | def get_type(self, graph, type, elemtype, name): |
149 | | - pass |
| 191 | + storage = get_storage_from_graph(graph) |
| 192 | + name_str = name.decode("utf-8") |
150 | 193 |
|
151 | | - def get_numeric_graph_attr(self, graph, name, value): |
152 | | - vec = value.contents |
153 | | - igraph_vector_resize(vec, 1) |
154 | | - igraph_vector_set( |
155 | | - vec, |
156 | | - 0, |
157 | | - self._to_numeric( |
158 | | - get_storage_from_graph(graph).get_graph_attribute_map()[name] |
159 | | - ), |
160 | | - ) |
| 194 | + if type == AttributeElementType.GRAPH: |
| 195 | + map = storage.get_graph_attribute_map() |
| 196 | + if name_str in map: |
| 197 | + return python_object_to_igraph_attribute_type(map[name_str]) |
| 198 | + elif type == AttributeElementType.VERTEX: |
| 199 | + map = storage.get_vertex_attribute_map() |
| 200 | + if name_str in map: |
| 201 | + return map[name_str].type |
| 202 | + elif type == AttributeElementType.EDGE: |
| 203 | + map = storage.get_edge_attribute_map() |
| 204 | + else: |
| 205 | + return AttributeType.UNSPECIFIED |
161 | 206 |
|
162 | | - def get_string_graph_attr(self, graph, name, value): |
163 | | - vec = value.contents |
164 | | - igraph_strvector_resize(vec, 1) |
165 | | - igraph_strvector_set( |
166 | | - vec, |
167 | | - 0, |
168 | | - self._to_bytes( |
169 | | - get_storage_from_graph(graph).get_graph_attribute_map()[name] |
170 | | - ), |
171 | | - ) |
| 207 | + return map[name_str].type if name_str in map else AttributeType.UNSPECIFIED |
172 | 208 |
|
173 | | - def get_bool_graph_attr(self, graph, name, value): |
174 | | - vec = value.contents |
175 | | - igraph_vector_bool_resize(vec, 1) |
176 | | - igraph_vector_bool_set( |
177 | | - vec, |
178 | | - 0, |
179 | | - bool(get_storage_from_graph(graph).get_graph_attribute_map()[name]), |
180 | | - ) |
| 209 | + def get_numeric_graph_attr(self, graph, name: bytes, value): |
| 210 | + map = get_storage_from_graph(graph).get_graph_attribute_map() |
| 211 | + igraph_vector_resize(value, 1) |
| 212 | + igraph_vector_set(value, 0, self._to_numeric(map[name.decode("utf-8")])) |
181 | 213 |
|
182 | | - def get_numeric_vertex_attr(self, graph, name, vs, value): |
183 | | - pass |
| 214 | + def get_string_graph_attr(self, graph, name: bytes, value): |
| 215 | + map = get_storage_from_graph(graph).get_graph_attribute_map() |
| 216 | + igraph_strvector_resize(value, 1) |
| 217 | + igraph_strvector_set(value, 0, self._to_bytes(map[name.decode("utf-8")])) |
184 | 218 |
|
185 | | - def get_string_vertex_attr(self, graph, name, vs, value): |
186 | | - pass |
| 219 | + def get_bool_graph_attr(self, graph, name: bytes, value): |
| 220 | + map = get_storage_from_graph(graph).get_graph_attribute_map() |
| 221 | + igraph_vector_bool_resize(value, 1) |
| 222 | + igraph_vector_bool_set(value, 0, bool(map[name.decode("utf-8")])) |
187 | 223 |
|
188 | | - def get_bool_vertex_attr(self, graph, name, vs, value): |
189 | | - pass |
| 224 | + def get_numeric_vertex_attr(self, graph, name: bytes, vs, value): |
| 225 | + map = get_storage_from_graph(graph).get_vertex_attribute_map() |
190 | 226 |
|
191 | | - def get_numeric_edge_attr(self, graph, name, es, value): |
192 | | - pass |
| 227 | + igraph_vs_as_vector(graph, vs, self._indices) |
| 228 | + values = self._get_values_by_index(map[name.decode("utf-8")], self._indices) |
193 | 229 |
|
194 | | - def get_string_edge_attr(self, graph, name, es, value): |
195 | | - pass |
| 230 | + igraph_vector_resize(value, len(values)) |
| 231 | + for i, v in enumerate(values): |
| 232 | + igraph_vector_set(value, i, self._to_numeric(v)) |
196 | 233 |
|
197 | | - def get_bool_edge_attr(self, graph, name, es, value): |
198 | | - pass |
| 234 | + def get_string_vertex_attr(self, graph, name: bytes, vs, value): |
| 235 | + map = get_storage_from_graph(graph).get_vertex_attribute_map() |
| 236 | + |
| 237 | + igraph_vs_as_vector(graph, vs, self._indices) |
| 238 | + values = self._get_values_by_index(map[name.decode("utf-8")], self._indices) |
| 239 | + |
| 240 | + igraph_strvector_resize(value, len(values)) |
| 241 | + for i, v in enumerate(values): |
| 242 | + igraph_strvector_set(value, i, self._to_bytes(v)) |
| 243 | + |
| 244 | + def get_bool_vertex_attr(self, graph, name: bytes, vs, value): |
| 245 | + map = get_storage_from_graph(graph).get_vertex_attribute_map() |
| 246 | + |
| 247 | + igraph_vs_as_vector(graph, vs, self._indices) |
| 248 | + values = self._get_values_by_index(map[name.decode("utf-8")], self._indices) |
| 249 | + |
| 250 | + igraph_vector_bool_resize(value, len(values)) |
| 251 | + for i, v in enumerate(values): |
| 252 | + igraph_vector_bool_set(value, i, bool(v)) |
| 253 | + |
| 254 | + def get_numeric_edge_attr(self, graph, name: bytes, es, value): |
| 255 | + map = get_storage_from_graph(graph).get_edge_attribute_map() |
| 256 | + |
| 257 | + igraph_es_as_vector(graph, es, self._indices) |
| 258 | + values = self._get_values_by_index(map[name.decode("utf-8")], self._indices) |
| 259 | + |
| 260 | + igraph_vector_resize(value, len(values)) |
| 261 | + for i, v in enumerate(values): |
| 262 | + igraph_vector_set(value, i, self._to_numeric(v)) |
| 263 | + |
| 264 | + def get_string_edge_attr(self, graph, name: bytes, es, value): |
| 265 | + map = get_storage_from_graph(graph).get_edge_attribute_map() |
| 266 | + |
| 267 | + igraph_es_as_vector(graph, es, self._indices) |
| 268 | + values = self._get_values_by_index(map[name.decode("utf-8")], self._indices) |
| 269 | + |
| 270 | + igraph_strvector_resize(value, len(values)) |
| 271 | + for i, v in enumerate(values): |
| 272 | + igraph_strvector_set(value, i, self._to_bytes(v)) |
| 273 | + |
| 274 | + def get_bool_edge_attr(self, graph, name: bytes, es, value): |
| 275 | + map = get_storage_from_graph(graph).get_edge_attribute_map() |
| 276 | + |
| 277 | + igraph_es_as_vector(graph, es, self._indices) |
| 278 | + values = self._get_values_by_index(map[name.decode("utf-8")], self._indices) |
| 279 | + |
| 280 | + igraph_vector_bool_resize(value, len(values)) |
| 281 | + for i, v in enumerate(values): |
| 282 | + igraph_vector_bool_set(value, i, bool(v)) |
| 283 | + |
| 284 | + @staticmethod |
| 285 | + def _get_values_by_index(values: AttributeValueList, indices: _VectorInt): |
| 286 | + index_array = igraph_vector_int_t_to_numpy_array_view(indices) |
| 287 | + return values[index_array] |
199 | 288 |
|
200 | 289 | @staticmethod |
201 | 290 | def _to_bytes(value: Any) -> bytes: |
|
0 commit comments