μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
test_eigen_tensor.py
Go to the documentation of this file.
1import sys
2
3import pytest
4
5np = pytest.importorskip("numpy")
6eigen_tensor = pytest.importorskip("pybind11_tests.eigen_tensor")
7submodules = [eigen_tensor.c_style, eigen_tensor.f_style]
8try:
9 import eigen_tensor_avoid_stl_array as avoid
10
11 submodules += [avoid.c_style, avoid.f_style]
12except ImportError as e:
13 # Ensure config, build, toolchain, etc. issues are not masked here:
14 raise RuntimeError(
15 "import eigen_tensor_avoid_stl_array FAILED, while "
16 "import pybind11_tests.eigen_tensor succeeded. "
17 "Please ensure that "
18 "test_eigen_tensor.cpp & "
19 "eigen_tensor_avoid_stl_array.cpp "
20 "are built together (or both are not built if Eigen is not available)."
21 ) from e
22
23tensor_ref = np.empty((3, 5, 2), dtype=np.int64)
24
25for i in range(tensor_ref.shape[0]):
26 for j in range(tensor_ref.shape[1]):
27 for k in range(tensor_ref.shape[2]):
28 tensor_ref[i, j, k] = i * (5 * 2) + j * 2 + k
29
30indices = (2, 3, 1)
31
32
33@pytest.fixture(autouse=True)
34def cleanup():
35 for module in submodules:
36 module.setup()
37
38 yield
39
40 for module in submodules:
41 assert module.is_ok()
42
43
45 pytest.importorskip("eigen_tensor_avoid_stl_array")
46 assert len(submodules) == 4
47
48
49def assert_equal_tensor_ref(mat, writeable=True, modified=None):
50 assert mat.flags.writeable == writeable
51
52 copy = np.array(tensor_ref)
53 if modified is not None:
54 copy[indices] = modified
55
56 np.testing.assert_array_equal(mat, copy)
57
58
59@pytest.mark.parametrize("m", submodules)
60@pytest.mark.parametrize("member_name", ["member", "member_view"])
61def test_reference_internal(m, member_name):
62 if not hasattr(sys, "getrefcount"):
63 pytest.skip("No reference counting")
64 foo = m.CustomExample()
65 counts = sys.getrefcount(foo)
66 mem = getattr(foo, member_name)
67 assert_equal_tensor_ref(mem, writeable=False)
68 new_counts = sys.getrefcount(foo)
69 assert new_counts == counts + 1
70 assert_equal_tensor_ref(mem, writeable=False)
71 del mem
72 assert sys.getrefcount(foo) == counts
73
74
75assert_equal_funcs = [
76 "copy_tensor",
77 "copy_fixed_tensor",
78 "copy_const_tensor",
79 "move_tensor_copy",
80 "move_fixed_tensor_copy",
81 "take_tensor",
82 "take_fixed_tensor",
83 "reference_tensor",
84 "reference_tensor_v2",
85 "reference_fixed_tensor",
86 "reference_view_of_tensor",
87 "reference_view_of_tensor_v3",
88 "reference_view_of_tensor_v5",
89 "reference_view_of_fixed_tensor",
90]
91
92assert_equal_const_funcs = [
93 "reference_view_of_tensor_v2",
94 "reference_view_of_tensor_v4",
95 "reference_view_of_tensor_v6",
96 "reference_const_tensor",
97 "reference_const_tensor_v2",
98]
99
100
101@pytest.mark.parametrize("m", submodules)
102@pytest.mark.parametrize("func_name", assert_equal_funcs + assert_equal_const_funcs)
104 writeable = func_name in assert_equal_funcs
105 assert_equal_tensor_ref(getattr(m, func_name)(), writeable=writeable)
106
107
108@pytest.mark.parametrize("m", submodules)
110 with pytest.raises(
111 RuntimeError, match="Cannot use reference internal when there is no parent"
112 ):
113 m.reference_tensor_internal()
114
115 with pytest.raises(RuntimeError, match="Cannot move from a constant reference"):
116 m.move_const_tensor()
117
118 with pytest.raises(
119 RuntimeError, match="Cannot take ownership of a const reference"
120 ):
121 m.take_const_tensor()
122
123 with pytest.raises(
124 RuntimeError,
125 match="Invalid return_value_policy for Eigen Map type, must be either reference or reference_internal",
126 ):
127 m.take_view_tensor()
128
129
130@pytest.mark.parametrize("m", submodules)
132 with pytest.raises(
133 TypeError, match=r"^round_trip_tensor\‍(\‍): incompatible function arguments"
134 ):
135 m.round_trip_tensor(np.zeros((2, 3)))
136
137 with pytest.raises(TypeError, match=r"^Cannot cast array data from dtype"):
138 m.round_trip_tensor(np.zeros(dtype=np.str_, shape=(2, 3, 1)))
139
140 with pytest.raises(
141 TypeError,
142 match=r"^round_trip_tensor_noconvert\‍(\‍): incompatible function arguments",
143 ):
144 m.round_trip_tensor_noconvert(tensor_ref)
145
147 m.round_trip_tensor_noconvert(tensor_ref.astype(np.float64))
148 )
149
150 if m.needed_options == "F":
151 bad_options = "C"
152 else:
153 bad_options = "F"
154 # Shape, dtype and the order need to be correct for a TensorMap cast
155 with pytest.raises(
156 TypeError, match=r"^round_trip_view_tensor\‍(\‍): incompatible function arguments"
157 ):
158 m.round_trip_view_tensor(
159 np.zeros((3, 5, 2), dtype=np.float64, order=bad_options)
160 )
161
162 with pytest.raises(
163 TypeError, match=r"^round_trip_view_tensor\‍(\‍): incompatible function arguments"
164 ):
165 m.round_trip_view_tensor(
166 np.zeros((3, 5, 2), dtype=np.float32, order=m.needed_options)
167 )
168
169 with pytest.raises(
170 TypeError, match=r"^round_trip_view_tensor\‍(\‍): incompatible function arguments"
171 ):
172 m.round_trip_view_tensor(
173 np.zeros((3, 5), dtype=np.float64, order=m.needed_options)
174 )
175
176 with pytest.raises(
177 TypeError, match=r"^round_trip_view_tensor\‍(\‍): incompatible function arguments"
178 ):
179 temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
180 m.round_trip_view_tensor(
181 temp[:, ::-1, :],
182 )
183
184 with pytest.raises(
185 TypeError, match=r"^round_trip_view_tensor\‍(\‍): incompatible function arguments"
186 ):
187 temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
188 temp.setflags(write=False)
189 m.round_trip_view_tensor(temp)
190
191
192@pytest.mark.parametrize("m", submodules)
194 a = m.reference_tensor()
195 temp = a[indices]
196 a[indices] = 100
197 assert_equal_tensor_ref(m.copy_const_tensor(), modified=100)
198 a[indices] = temp
199 assert_equal_tensor_ref(m.copy_const_tensor())
200
201 a = m.reference_view_of_tensor()
202 a[indices] = 100
203 assert_equal_tensor_ref(m.copy_const_tensor(), modified=100)
204 a[indices] = temp
205 assert_equal_tensor_ref(m.copy_const_tensor())
206
207
208@pytest.mark.parametrize("m", submodules)
210 assert_equal_tensor_ref(m.round_trip_tensor(tensor_ref))
211
212 with pytest.raises(TypeError, match="^Cannot cast array data from"):
213 assert_equal_tensor_ref(m.round_trip_tensor2(tensor_ref))
214
215 assert_equal_tensor_ref(m.round_trip_tensor2(np.array(tensor_ref, dtype=np.int32)))
216 assert_equal_tensor_ref(m.round_trip_fixed_tensor(tensor_ref))
217 assert_equal_tensor_ref(m.round_trip_aligned_view_tensor(m.reference_tensor()))
218
219 copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options)
220 assert_equal_tensor_ref(m.round_trip_view_tensor(copy))
221 assert_equal_tensor_ref(m.round_trip_view_tensor_ref(copy))
222 assert_equal_tensor_ref(m.round_trip_view_tensor_ptr(copy))
223 copy.setflags(write=False)
224 assert_equal_tensor_ref(m.round_trip_const_view_tensor(copy))
225
226 np.testing.assert_array_equal(
227 tensor_ref[:, ::-1, :], m.round_trip_tensor(tensor_ref[:, ::-1, :])
228 )
229
230 assert m.round_trip_rank_0(np.float64(3.5)) == 3.5
231 assert m.round_trip_rank_0(3.5) == 3.5
232
233 with pytest.raises(
234 TypeError,
235 match=r"^round_trip_rank_0_noconvert\‍(\‍): incompatible function arguments",
236 ):
237 m.round_trip_rank_0_noconvert(np.float64(3.5))
238
239 with pytest.raises(
240 TypeError,
241 match=r"^round_trip_rank_0_noconvert\‍(\‍): incompatible function arguments",
242 ):
243 m.round_trip_rank_0_noconvert(3.5)
244
245 with pytest.raises(
246 TypeError, match=r"^round_trip_rank_0_view\‍(\‍): incompatible function arguments"
247 ):
248 m.round_trip_rank_0_view(np.float64(3.5))
249
250 with pytest.raises(
251 TypeError, match=r"^round_trip_rank_0_view\‍(\‍): incompatible function arguments"
252 ):
253 m.round_trip_rank_0_view(3.5)
254
255
256@pytest.mark.parametrize("m", submodules)
258 # Need to create a copy that matches the type on the C side
259 copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options)
260 a = m.round_trip_view_tensor(copy)
261 temp = a[indices]
262 a[indices] = 100
263 assert_equal_tensor_ref(copy, modified=100)
264 a[indices] = temp
266
267
268@pytest.mark.parametrize("m", submodules)
269def test_doc_string(m, doc):
270 assert (
271 doc(m.copy_tensor) == "copy_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
272 )
273 assert (
274 doc(m.copy_fixed_tensor)
275 == "copy_fixed_tensor() -> numpy.ndarray[numpy.float64[3, 5, 2]]"
276 )
277 assert (
278 doc(m.reference_const_tensor)
279 == "reference_const_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
280 )
281
282 order_flag = f"flags.{m.needed_options.lower()}_contiguous"
283 assert doc(m.round_trip_view_tensor) == (
284 f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])"
285 + f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]"
286 )
287 assert doc(m.round_trip_const_view_tensor) == (
288 f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])"
289 + " -> numpy.ndarray[numpy.float64[?, ?, ?]]"
290 )
object getattr(handle obj, handle name)
Definition: pytypes.h:537
bool hasattr(handle obj, handle name)
Definition: pytypes.h:517
size_t len(handle h)
Get the length of a Python object.
Definition: pytypes.h:2002
def test_references_actually_refer(m)
def test_doc_string(m, doc)
def test_round_trip_references_actually_refer(m)
def test_reference_internal(m, member_name)
def assert_equal_tensor_ref(mat, writeable=True, modified=None)
def test_convert_tensor_to_py(m, func_name)
def test_bad_cpp_to_python_casts(m)
def test_bad_python_to_cpp_casts(m)
Annotation for documentation.
Definition: attr.h:41