Skip to content

Commit 3d081dd

Browse files
committed
feat: added conversion from igraph vectors NumPy array _views_ into the vectors
1 parent c68d71a commit 3d081dd

File tree

3 files changed

+87
-5
lines changed

3 files changed

+87
-5
lines changed

.coveragerc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
[run]
22
omit = src/codegen/*
3+
4+
[report]
5+
exclude_lines =
6+
pragma: no cover
7+
if TYPE_CHECKING:

src/igraph_ctypes/_internal/conversion.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import numpy as np
66

7-
from ctypes import memmove, POINTER
7+
from ctypes import addressof, memmove, POINTER
88
from typing import Any, Iterable, Optional, Sequence, TYPE_CHECKING
99

1010
from .enums import MatrixStorage
@@ -104,8 +104,11 @@
104104
"igraph_vector_bool_t_to_list",
105105
"igraph_vector_int_t_to_list",
106106
"igraph_vector_t_to_numpy_array",
107+
"igraph_vector_t_to_numpy_array_view",
107108
"igraph_vector_bool_t_to_numpy_array",
109+
"igraph_vector_bool_t_to_numpy_array_view",
108110
"igraph_vector_int_t_to_numpy_array",
111+
"igraph_vector_int_t_to_numpy_array_view",
109112
"igraph_vector_int_list_t_to_list_of_numpy_array",
110113
"igraph_vector_list_t_to_list_of_numpy_array",
111114
"iterable_edge_indices_to_igraph_vector_int_t",
@@ -700,6 +703,14 @@ def igraph_vector_t_to_numpy_array(vector: _Vector) -> RealArray:
700703
return result
701704

702705

706+
def igraph_vector_t_to_numpy_array_view(vector: _Vector) -> RealArray:
707+
n = igraph_vector_size(vector)
708+
addr = addressof(igraph_vector_e_ptr(vector, 0).contents)
709+
buf_type = igraph_real_t * n
710+
buf = buf_type.from_address(addr)
711+
return np.frombuffer(buf, dtype=np_type_of_igraph_real_t)
712+
713+
703714
def igraph_vector_bool_t_to_numpy_array(vector: _VectorBool) -> BoolArray:
704715
n = igraph_vector_bool_size(vector)
705716
result = np.zeros(n, dtype=np_type_of_igraph_bool_t)
@@ -708,6 +719,14 @@ def igraph_vector_bool_t_to_numpy_array(vector: _VectorBool) -> BoolArray:
708719
return result
709720

710721

722+
def igraph_vector_bool_t_to_numpy_array_view(vector: _VectorBool) -> BoolArray:
723+
n = igraph_vector_bool_size(vector)
724+
addr = addressof(igraph_vector_bool_e_ptr(vector, 0).contents)
725+
buf_type = igraph_bool_t * n
726+
buf = buf_type.from_address(addr)
727+
return np.frombuffer(buf, dtype=np_type_of_igraph_bool_t)
728+
729+
711730
def igraph_vector_int_t_to_numpy_array(vector: _VectorInt) -> IntArray:
712731
n = igraph_vector_int_size(vector)
713732
result = np.zeros(n, dtype=np_type_of_igraph_integer_t)
@@ -716,6 +735,14 @@ def igraph_vector_int_t_to_numpy_array(vector: _VectorInt) -> IntArray:
716735
return result
717736

718737

738+
def igraph_vector_int_t_to_numpy_array_view(vector: _VectorInt) -> IntArray:
739+
n = igraph_vector_int_size(vector)
740+
addr = addressof(igraph_vector_int_e_ptr(vector, 0).contents)
741+
buf_type = igraph_integer_t * n
742+
buf = buf_type.from_address(addr)
743+
return np.frombuffer(buf, dtype=np_type_of_igraph_integer_t)
744+
745+
719746
def igraph_vector_list_t_to_list_of_numpy_array(
720747
vector_list: _VectorList,
721748
) -> list[RealArray]:

tests/test_conversion.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
igraph_matrix_int_t_to_numpy_array,
1212
igraph_vector_t_to_list,
1313
igraph_vector_t_to_numpy_array,
14+
igraph_vector_t_to_numpy_array_view,
1415
igraph_vector_bool_t_to_list,
1516
igraph_vector_bool_t_to_numpy_array,
17+
igraph_vector_bool_t_to_numpy_array_view,
1618
igraph_vector_int_t_to_list,
1719
igraph_vector_int_t_to_numpy_array,
20+
igraph_vector_int_t_to_numpy_array_view,
1821
igraph_vector_int_list_t_to_list_of_numpy_array,
1922
igraph_vector_list_t_to_list_of_numpy_array,
2023
iterable_of_iterable_to_igraph_vector_list_t,
@@ -94,6 +97,22 @@ def test_bool_vector_roundtrip():
9497
assert (restored_array == expected_array).all()
9598

9699

100+
def test_bool_vector_view_roundtrip():
101+
input = [False, 0, True, False, "", "yes", True]
102+
expected = [bool(x) for x in input]
103+
expected_array = array(expected, dtype=bool)
104+
105+
converted = iterable_to_igraph_vector_bool_t(expected)
106+
assert isinstance(converted, _VectorBool)
107+
108+
restored = igraph_vector_bool_t_to_numpy_array_view(converted)
109+
assert (restored == expected_array).all()
110+
111+
another_restored = igraph_vector_bool_t_to_numpy_array_view(converted)
112+
assert (another_restored == expected_array).all()
113+
assert restored.data == another_restored.data
114+
115+
97116
def test_int_vector_roundtrip():
98117
input = [1, 4, 7, 11, 8, 3, 5, 6, 2, -6]
99118
expected = list(input)
@@ -115,6 +134,22 @@ def test_int_vector_roundtrip():
115134
assert (restored_array == expected_array).all()
116135

117136

137+
def test_int_vector_view_roundtrip():
138+
input = [1, 4, 7, 11, 8, 3, 5, 6, 2, -6]
139+
expected = list(input)
140+
expected_array = array(expected)
141+
142+
converted = iterable_to_igraph_vector_int_t(expected)
143+
assert isinstance(converted, _VectorInt)
144+
145+
restored = igraph_vector_int_t_to_numpy_array_view(converted)
146+
assert (restored == expected_array).all()
147+
148+
another_restored = igraph_vector_int_t_to_numpy_array_view(converted)
149+
assert (another_restored == expected_array).all()
150+
assert restored.data == another_restored.data
151+
152+
118153
def test_real_vector_roundtrip():
119154
input = [1.23, 4.567, 8.91011, -12.3456]
120155
expected = list(input)
@@ -136,6 +171,22 @@ def test_real_vector_roundtrip():
136171
assert (restored_array == expected_array).all()
137172

138173

174+
def test_real_vector_view_roundtrip():
175+
input = [1.23, 4.567, 8.91011, -12.3456]
176+
expected = list(input)
177+
expected_array = array(expected)
178+
179+
converted = iterable_to_igraph_vector_t(expected)
180+
assert isinstance(converted, _Vector)
181+
182+
restored = igraph_vector_t_to_numpy_array_view(converted)
183+
assert (restored == expected_array).all()
184+
185+
another_restored = igraph_vector_t_to_numpy_array_view(converted)
186+
assert (another_restored == expected_array).all()
187+
assert restored.data == another_restored.data
188+
189+
139190
def test_int_matrix_roundtrip():
140191
input = [
141192
[0, 1, 2, 3, 4],
@@ -196,7 +247,7 @@ def test_int_vector_list_roundtrip():
196247
restored_items = igraph_vector_int_list_t_to_list_of_numpy_array(converted)
197248
assert len(restored_items) == len(input)
198249

199-
for original_item, restored_item in zip(input, restored_items):
250+
for original_item, restored_item in zip(input, restored_items, strict=True):
200251
assert (array(original_item) == restored_item).all()
201252

202253

@@ -214,12 +265,12 @@ def test_vector_list_roundtrip():
214265
restored_items = igraph_vector_list_t_to_list_of_numpy_array(converted)
215266
assert len(restored_items) == len(input)
216267

217-
for original_item, restored_item in zip(input, restored_items):
268+
for original_item, restored_item in zip(input, restored_items, strict=True):
218269
assert (array(original_item) == restored_item).all()
219270

220271

221272
def test_vertex_selector():
222-
g = create_empty_graph(5)._instance
273+
g = create_empty_graph(5)
223274

224275
vs = vertex_selector_to_igraph_vs_t(None, g)
225276
assert vs.unwrap().type == VertexSequenceType.NONE
@@ -246,7 +297,6 @@ def test_vertex_selector():
246297
def test_edge_selector():
247298
g = create_empty_graph(5)
248299
g.add_edges([(0, 1), (1, 2), (2, 4), (4, 0)])
249-
g = g._instance
250300

251301
es = edge_selector_to_igraph_es_t(None, g)
252302
assert es.unwrap().type == EdgeSequenceType.NONE

0 commit comments

Comments
 (0)