Skip to content

Commit 34bbf19

Browse files
committed
feat: graph attributes now accessible from Python
1 parent edc4c6a commit 34bbf19

File tree

6 files changed

+335
-68
lines changed

6 files changed

+335
-68
lines changed

src/codegen/internal_lib.py.in

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# fmt: off
22

3-
from ctypes import cdll, c_char_p, c_double, c_int, c_void_p, POINTER
3+
from ctypes import cdll, c_char_p, c_double, c_int, c_size_t, c_void_p, POINTER
44
from ctypes.util import find_library
55
from typing import Any
66

@@ -79,18 +79,30 @@ igraph_vector_view = _lib.igraph_vector_view
7979
igraph_vector_view.restype = POINTER(igraph_vector_t)
8080
igraph_vector_view.argtypes = [POINTER(igraph_vector_t), POINTER(igraph_real_t), igraph_integer_t]
8181

82-
igraph_vector_e = _lib.igraph_vector_e
83-
igraph_vector_e.restype = igraph_real_t
84-
igraph_vector_e.argtypes = [POINTER(igraph_vector_t), igraph_integer_t]
82+
igraph_vector_clear = _lib.igraph_vector_clear
83+
igraph_vector_clear.restype = None
84+
igraph_vector_clear.argtypes = [POINTER(igraph_vector_t)]
8585

86-
igraph_vector_e_ptr = _lib.igraph_vector_e_ptr
87-
igraph_vector_e_ptr.restype = POINTER(igraph_real_t)
88-
igraph_vector_e_ptr.argtypes = [POINTER(igraph_vector_t), igraph_integer_t]
86+
igraph_vector_get = _lib.igraph_vector_get
87+
igraph_vector_get.restype = igraph_real_t
88+
igraph_vector_get.argtypes = [POINTER(igraph_vector_t), igraph_integer_t]
89+
90+
igraph_vector_get_ptr = _lib.igraph_vector_get_ptr
91+
igraph_vector_get_ptr.restype = POINTER(igraph_real_t)
92+
igraph_vector_get_ptr.argtypes = [POINTER(igraph_vector_t), igraph_integer_t]
8993

9094
igraph_vector_push_back = _lib.igraph_vector_push_back
9195
igraph_vector_push_back.restype = handle_igraph_error_t
9296
igraph_vector_push_back.argtypes = [POINTER(igraph_vector_t), igraph_real_t]
9397

98+
igraph_vector_resize = _lib.igraph_vector_resize
99+
igraph_vector_resize.restype = handle_igraph_error_t
100+
igraph_vector_resize.argtypes = [POINTER(igraph_vector_t), igraph_integer_t]
101+
102+
igraph_vector_set = _lib.igraph_vector_set
103+
igraph_vector_set.restype = None
104+
igraph_vector_set.argtypes = [POINTER(igraph_vector_t), igraph_integer_t, igraph_real_t]
105+
94106
igraph_vector_size = _lib.igraph_vector_size
95107
igraph_vector_size.restype = igraph_integer_t
96108
igraph_vector_size.argtypes = [POINTER(igraph_vector_t)]
@@ -113,18 +125,30 @@ igraph_vector_int_view = _lib.igraph_vector_int_view
113125
igraph_vector_int_view.restype = POINTER(igraph_vector_int_t)
114126
igraph_vector_int_view.argtypes = [POINTER(igraph_vector_int_t), POINTER(igraph_integer_t), igraph_integer_t]
115127

116-
igraph_vector_int_e = _lib.igraph_vector_int_e
117-
igraph_vector_int_e.restype = igraph_integer_t
118-
igraph_vector_int_e.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t]
128+
igraph_vector_int_clear = _lib.igraph_vector_int_clear
129+
igraph_vector_int_clear.restype = None
130+
igraph_vector_int_clear.argtypes = [POINTER(igraph_vector_int_t)]
119131

120-
igraph_vector_int_e_ptr = _lib.igraph_vector_int_e_ptr
121-
igraph_vector_int_e_ptr.restype = POINTER(igraph_integer_t)
122-
igraph_vector_int_e_ptr.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t]
132+
igraph_vector_int_get = _lib.igraph_vector_int_get
133+
igraph_vector_int_get.restype = igraph_integer_t
134+
igraph_vector_int_get.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t]
135+
136+
igraph_vector_int_get_ptr = _lib.igraph_vector_int_get_ptr
137+
igraph_vector_int_get_ptr.restype = POINTER(igraph_integer_t)
138+
igraph_vector_int_get_ptr.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t]
123139

124140
igraph_vector_int_push_back = _lib.igraph_vector_int_push_back
125141
igraph_vector_int_push_back.restype = handle_igraph_error_t
126142
igraph_vector_int_push_back.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t]
127143

144+
igraph_vector_int_resize = _lib.igraph_vector_int_resize
145+
igraph_vector_int_resize.restype = handle_igraph_error_t
146+
igraph_vector_int_resize.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t]
147+
148+
igraph_vector_int_set = _lib.igraph_vector_int_set
149+
igraph_vector_int_set.restype = None
150+
igraph_vector_int_set.argtypes = [POINTER(igraph_vector_int_t), igraph_integer_t, igraph_integer_t]
151+
128152
igraph_vector_int_size = _lib.igraph_vector_int_size
129153
igraph_vector_int_size.restype = igraph_integer_t
130154
igraph_vector_int_size.argtypes = [POINTER(igraph_vector_int_t)]
@@ -147,18 +171,30 @@ igraph_vector_bool_view = _lib.igraph_vector_bool_view
147171
igraph_vector_bool_view.restype = POINTER(igraph_vector_bool_t)
148172
igraph_vector_bool_view.argtypes = [POINTER(igraph_vector_bool_t), POINTER(igraph_bool_t), igraph_integer_t]
149173

150-
igraph_vector_bool_e = _lib.igraph_vector_bool_e
151-
igraph_vector_bool_e.restype = igraph_bool_t
152-
igraph_vector_bool_e.argtypes = [POINTER(igraph_vector_bool_t), igraph_integer_t]
174+
igraph_vector_bool_clear = _lib.igraph_vector_bool_clear
175+
igraph_vector_bool_clear.restype = None
176+
igraph_vector_bool_clear.argtypes = [POINTER(igraph_vector_bool_t)]
177+
178+
igraph_vector_bool_get = _lib.igraph_vector_bool_get
179+
igraph_vector_bool_get.restype = igraph_bool_t
180+
igraph_vector_bool_get.argtypes = [POINTER(igraph_vector_bool_t), igraph_integer_t]
153181

154-
igraph_vector_bool_e_ptr = _lib.igraph_vector_bool_e_ptr
155-
igraph_vector_bool_e_ptr.restype = POINTER(igraph_bool_t)
156-
igraph_vector_bool_e_ptr.argtypes = [POINTER(igraph_vector_bool_t), igraph_integer_t]
182+
igraph_vector_bool_get_ptr = _lib.igraph_vector_bool_get_ptr
183+
igraph_vector_bool_get_ptr.restype = POINTER(igraph_bool_t)
184+
igraph_vector_bool_get_ptr.argtypes = [POINTER(igraph_vector_bool_t), igraph_integer_t]
157185

158186
igraph_vector_bool_push_back = _lib.igraph_vector_bool_push_back
159187
igraph_vector_bool_push_back.restype = handle_igraph_error_t
160188
igraph_vector_bool_push_back.argtypes = [POINTER(igraph_vector_bool_t), igraph_bool_t]
161189

190+
igraph_vector_bool_resize = _lib.igraph_vector_bool_resize
191+
igraph_vector_bool_resize.restype = handle_igraph_error_t
192+
igraph_vector_bool_resize.argtypes = [POINTER(igraph_vector_bool_t), igraph_integer_t]
193+
194+
igraph_vector_bool_set = _lib.igraph_vector_bool_set
195+
igraph_vector_bool_set.restype = None
196+
igraph_vector_bool_set.argtypes = [POINTER(igraph_vector_bool_t), igraph_integer_t, igraph_bool_t]
197+
162198
igraph_vector_bool_size = _lib.igraph_vector_bool_size
163199
igraph_vector_bool_size.restype = igraph_integer_t
164200
igraph_vector_bool_size.argtypes = [POINTER(igraph_vector_bool_t)]
@@ -173,14 +209,44 @@ igraph_vector_ptr_destroy = _lib.igraph_vector_ptr_destroy
173209
igraph_vector_ptr_destroy.restype = None
174210
igraph_vector_ptr_destroy.argtypes = [c_void_p]
175211

212+
igraph_vector_ptr_clear = _lib.igraph_vector_ptr_clear
213+
igraph_vector_ptr_clear.restype = None
214+
igraph_vector_ptr_clear.argtypes = [POINTER(igraph_vector_ptr_t)]
215+
176216
igraph_vector_ptr_get = _lib.igraph_vector_ptr_get
177217
igraph_vector_ptr_get.restype = c_void_p
178218
igraph_vector_ptr_get.argtypes = [POINTER(igraph_vector_ptr_t), igraph_integer_t]
179219

220+
igraph_vector_ptr_resize = _lib.igraph_vector_ptr_resize
221+
igraph_vector_ptr_resize.restype = handle_igraph_error_t
222+
igraph_vector_ptr_resize.argtypes = [POINTER(igraph_vector_ptr_t), igraph_integer_t]
223+
180224
igraph_vector_ptr_size = _lib.igraph_vector_ptr_size
181225
igraph_vector_ptr_size.restype = igraph_integer_t
182226
igraph_vector_ptr_size.argtypes = [POINTER(igraph_vector_ptr_t)]
183227

228+
# String vector type
229+
230+
igraph_strvector_clear = _lib.igraph_strvector_clear
231+
igraph_strvector_clear.restype = None
232+
igraph_strvector_clear.argtypes = [POINTER(igraph_strvector_t)]
233+
234+
igraph_strvector_resize = _lib.igraph_strvector_resize
235+
igraph_strvector_resize.restype = handle_igraph_error_t
236+
igraph_strvector_resize.argtypes = [POINTER(igraph_strvector_t), igraph_integer_t]
237+
238+
igraph_strvector_set = _lib.igraph_strvector_set
239+
igraph_strvector_set.restype = handle_igraph_error_t
240+
igraph_strvector_set.argtypes = [POINTER(igraph_strvector_t), igraph_integer_t, c_char_p]
241+
242+
igraph_strvector_set_len = _lib.igraph_strvector_set_len
243+
igraph_strvector_set_len.restype = handle_igraph_error_t
244+
igraph_strvector_set_len.argtypes = [POINTER(igraph_strvector_t), igraph_integer_t, c_char_p, c_size_t]
245+
246+
igraph_strvector_size = _lib.igraph_strvector_size
247+
igraph_strvector_size.restype = igraph_integer_t
248+
igraph_strvector_size.argtypes = [POINTER(igraph_strvector_t)]
249+
184250
# Matrix type
185251

186252
igraph_matrix_init = _lib.igraph_matrix_init

src/igraph_ctypes/_internal/attributes.py

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@
44
py_object,
55
)
66
from dataclasses import dataclass, field
7-
from typing import Any, Callable, Optional
7+
from math import nan
8+
from typing import Any, Callable, MutableMapping, Optional
89

910
from .conversion import igraph_vector_int_t_to_numpy_array_view
10-
from .lib import igraph_error
11+
from .lib import (
12+
igraph_error,
13+
igraph_vector_resize,
14+
igraph_vector_set,
15+
igraph_vector_bool_resize,
16+
igraph_vector_bool_set,
17+
igraph_vector_int_clear,
18+
igraph_strvector_clear,
19+
igraph_strvector_resize,
20+
igraph_strvector_set,
21+
)
1122
from .refcount import incref, decref
1223
from .types import igraph_attribute_table_t, IntArray
1324
from .utils import nop, protect_with
@@ -86,6 +97,14 @@ def copy(
8697
copy_vertex_attributes: bool = True,
8798
copy_edge_attributes: bool = True,
8899
):
100+
"""Creates a shallow copy of the storage area."""
101+
raise NotImplementedError
102+
103+
@abstractmethod
104+
def get_graph_attribute_map(self) -> MutableMapping[str, Any]:
105+
"""Returns a mutable mapping into the storage area that stores the graph
106+
attributes.
107+
"""
89108
raise NotImplementedError
90109

91110

@@ -106,9 +125,6 @@ def add_edges(self, graph, edges: IntArray) -> None:
106125
pass
107126

108127
def clear(self) -> None:
109-
"""Clears the storage area, removing all attributes from the
110-
attribute dictionaries.
111-
"""
112128
self.graph_attributes.clear()
113129
self.vertex_attributes.clear()
114130
self.edge_attributes.clear()
@@ -119,13 +135,15 @@ def copy(
119135
copy_vertex_attributes: bool = True,
120136
copy_edge_attributes: bool = True,
121137
):
122-
"""Creates a shallow copy of the storage area."""
123138
return self.__class__(
124139
self.graph_attributes.copy() if copy_graph_attributes else {},
125140
self.vertex_attributes.copy() if copy_vertex_attributes else {},
126141
self.edge_attributes.copy() if copy_edge_attributes else {},
127142
)
128143

144+
def get_graph_attribute_map(self) -> MutableMapping[str, Any]:
145+
return self.graph_attributes
146+
129147

130148
def _assign_storage_to_graph(graph, storage: Optional[AttributeStorage] = None) -> None:
131149
"""Assigns an attribute storage object to a graph, taking care of
@@ -223,7 +241,15 @@ def combine_edges(self, graph, to, mapping, combinations):
223241
pass
224242

225243
def get_info(self, graph, gnames, gtypes, vnames, vtypes, enames, etypes):
226-
pass
244+
# TODO(ntamas): fill the names and the types
245+
igraph_strvector_clear(gnames)
246+
igraph_vector_int_clear(gtypes)
247+
248+
igraph_strvector_clear(vnames)
249+
igraph_vector_int_clear(vtypes)
250+
251+
igraph_strvector_clear(enames)
252+
igraph_vector_int_clear(etypes)
227253

228254
def has_attr(self, graph, type, name) -> bool:
229255
return False
@@ -232,21 +258,43 @@ def get_type(self, graph, type, elemtype, name):
232258
pass
233259

234260
def get_numeric_graph_attr(self, graph, name, value):
235-
pass
261+
vec = value.contents
262+
igraph_vector_resize(vec, 1)
263+
igraph_vector_set(
264+
vec,
265+
0,
266+
self._to_numeric(
267+
_get_storage_from_graph(graph).get_graph_attribute_map()[name]
268+
),
269+
)
236270

237271
def get_string_graph_attr(self, graph, name, value):
238-
pass
272+
vec = value.contents
273+
igraph_strvector_resize(vec, 1)
274+
igraph_strvector_set(
275+
vec,
276+
0,
277+
self._to_bytes(
278+
_get_storage_from_graph(graph).get_graph_attribute_map()[name]
279+
),
280+
)
239281

240-
def get_boolean_graph_attr(self, graph, name, value):
241-
pass
282+
def get_bool_graph_attr(self, graph, name, value):
283+
vec = value.contents
284+
igraph_vector_bool_resize(vec, 1)
285+
igraph_vector_bool_set(
286+
vec,
287+
0,
288+
bool(_get_storage_from_graph(graph).get_graph_attribute_map()[name]),
289+
)
242290

243291
def get_numeric_vertex_attr(self, graph, name, vs, value):
244292
pass
245293

246294
def get_string_vertex_attr(self, graph, name, vs, value):
247295
pass
248296

249-
def get_boolean_vertex_attr(self, graph, name, vs, value):
297+
def get_bool_vertex_attr(self, graph, name, vs, value):
250298
pass
251299

252300
def get_numeric_edge_attr(self, graph, name, es, value):
@@ -255,5 +303,27 @@ def get_numeric_edge_attr(self, graph, name, es, value):
255303
def get_string_edge_attr(self, graph, name, es, value):
256304
pass
257305

258-
def get_boolean_edge_attr(self, graph, name, es, value):
306+
def get_bool_edge_attr(self, graph, name, es, value):
259307
pass
308+
309+
@staticmethod
310+
def _to_bytes(value: Any) -> bytes:
311+
"""Converts an arbitrary Python object into a byte-level representation,
312+
assuming UTF-8 encoding for strings. Returns an empty byte string if the
313+
conversion fails.
314+
"""
315+
try:
316+
value_str = str(value)
317+
return value_str.encode("utf-8", errors="replace")
318+
except Exception:
319+
return b""
320+
321+
@staticmethod
322+
def _to_numeric(value: Any) -> float:
323+
"""Converts an arbitrary Python object into a floating-point value,
324+
returning NaN if the conversion fails.
325+
"""
326+
try:
327+
return float(value) # type: ignore
328+
except Exception:
329+
return nan

0 commit comments

Comments
 (0)