test_eigen.py revision 12037
1import pytest 2 3pytestmark = pytest.requires_eigen_and_numpy 4 5with pytest.suppress(ImportError): 6 import numpy as np 7 8 ref = np.array([[ 0., 3, 0, 0, 0, 11], 9 [22, 0, 0, 0, 17, 11], 10 [ 7, 5, 0, 1, 0, 11], 11 [ 0, 0, 0, 0, 0, 11], 12 [ 0, 0, 14, 0, 8, 11]]) 13 14 15def assert_equal_ref(mat): 16 np.testing.assert_array_equal(mat, ref) 17 18 19def assert_sparse_equal_ref(sparse_mat): 20 assert_equal_ref(sparse_mat.todense()) 21 22 23def test_fixed(): 24 from pybind11_tests import fixed_r, fixed_c, fixed_copy_r, fixed_copy_c 25 26 assert_equal_ref(fixed_c()) 27 assert_equal_ref(fixed_r()) 28 assert_equal_ref(fixed_copy_r(fixed_r())) 29 assert_equal_ref(fixed_copy_c(fixed_c())) 30 assert_equal_ref(fixed_copy_r(fixed_c())) 31 assert_equal_ref(fixed_copy_c(fixed_r())) 32 33 34def test_dense(): 35 from pybind11_tests import dense_r, dense_c, dense_copy_r, dense_copy_c 36 37 assert_equal_ref(dense_r()) 38 assert_equal_ref(dense_c()) 39 assert_equal_ref(dense_copy_r(dense_r())) 40 assert_equal_ref(dense_copy_c(dense_c())) 41 assert_equal_ref(dense_copy_r(dense_c())) 42 assert_equal_ref(dense_copy_c(dense_r())) 43 44 45def test_partially_fixed(): 46 from pybind11_tests import (partial_copy_four_rm_r, partial_copy_four_rm_c, 47 partial_copy_four_cm_r, partial_copy_four_cm_c) 48 49 ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) 50 np.testing.assert_array_equal(partial_copy_four_rm_r(ref2), ref2) 51 np.testing.assert_array_equal(partial_copy_four_rm_c(ref2), ref2) 52 np.testing.assert_array_equal(partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]]) 53 np.testing.assert_array_equal(partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :]) 54 np.testing.assert_array_equal(partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]) 55 np.testing.assert_array_equal( 56 partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) 57 58 np.testing.assert_array_equal(partial_copy_four_cm_r(ref2), ref2) 59 np.testing.assert_array_equal(partial_copy_four_cm_c(ref2), ref2) 60 np.testing.assert_array_equal(partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]]) 61 np.testing.assert_array_equal(partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :]) 62 np.testing.assert_array_equal(partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]) 63 np.testing.assert_array_equal( 64 partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) 65 66 67def test_mutator_descriptors(): 68 from pybind11_tests import fixed_mutator_r, fixed_mutator_c, fixed_mutator_a 69 zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major 70 zc = zr.reshape(6, 5).transpose() # column-major 71 72 fixed_mutator_r(zr) 73 fixed_mutator_c(zc) 74 fixed_mutator_a(zr) 75 fixed_mutator_a(zc) 76 with pytest.raises(TypeError) as excinfo: 77 fixed_mutator_r(zc) 78 assert ('(numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> arg0: None' 79 in str(excinfo.value)) 80 with pytest.raises(TypeError) as excinfo: 81 fixed_mutator_c(zr) 82 assert ('(numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> arg0: None' 83 in str(excinfo.value)) 84 with pytest.raises(TypeError) as excinfo: 85 fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32')) 86 assert ('(numpy.ndarray[float32[5, 6], flags.writeable]) -> arg0: None' 87 in str(excinfo.value)) 88 zr.flags.writeable = False 89 with pytest.raises(TypeError): 90 fixed_mutator_r(zr) 91 with pytest.raises(TypeError): 92 fixed_mutator_a(zr) 93 94 95def test_cpp_casting(): 96 from pybind11_tests import (cpp_copy, cpp_ref_c, cpp_ref_r, cpp_ref_any, 97 fixed_r, fixed_c, get_cm_ref, get_rm_ref, ReturnTester) 98 assert cpp_copy(fixed_r()) == 22. 99 assert cpp_copy(fixed_c()) == 22. 100 z = np.array([[5., 6], [7, 8]]) 101 assert cpp_copy(z) == 7. 102 assert cpp_copy(get_cm_ref()) == 21. 103 assert cpp_copy(get_rm_ref()) == 21. 104 assert cpp_ref_c(get_cm_ref()) == 21. 105 assert cpp_ref_r(get_rm_ref()) == 21. 106 with pytest.raises(RuntimeError) as excinfo: 107 # Can't reference fixed_c: it contains floats, cpp_ref_any wants doubles 108 cpp_ref_any(fixed_c()) 109 assert 'Unable to cast Python instance' in str(excinfo.value) 110 with pytest.raises(RuntimeError) as excinfo: 111 # Can't reference fixed_r: it contains floats, cpp_ref_any wants doubles 112 cpp_ref_any(fixed_r()) 113 assert 'Unable to cast Python instance' in str(excinfo.value) 114 assert cpp_ref_any(ReturnTester.create()) == 1. 115 116 assert cpp_ref_any(get_cm_ref()) == 21. 117 assert cpp_ref_any(get_cm_ref()) == 21. 118 119 120def test_pass_readonly_array(): 121 from pybind11_tests import fixed_copy_r, fixed_r, fixed_r_const 122 z = np.full((5, 6), 42.0) 123 z.flags.writeable = False 124 np.testing.assert_array_equal(z, fixed_copy_r(z)) 125 np.testing.assert_array_equal(fixed_r_const(), fixed_r()) 126 assert not fixed_r_const().flags.writeable 127 np.testing.assert_array_equal(fixed_copy_r(fixed_r_const()), fixed_r_const()) 128 129 130def test_nonunit_stride_from_python(): 131 from pybind11_tests import ( 132 double_row, double_col, double_complex, double_mat_cm, double_mat_rm, 133 double_threec, double_threer) 134 135 counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) 136 second_row = counting_mat[1, :] 137 second_col = counting_mat[:, 1] 138 np.testing.assert_array_equal(double_row(second_row), 2.0 * second_row) 139 np.testing.assert_array_equal(double_col(second_row), 2.0 * second_row) 140 np.testing.assert_array_equal(double_complex(second_row), 2.0 * second_row) 141 np.testing.assert_array_equal(double_row(second_col), 2.0 * second_col) 142 np.testing.assert_array_equal(double_col(second_col), 2.0 * second_col) 143 np.testing.assert_array_equal(double_complex(second_col), 2.0 * second_col) 144 145 counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) 146 slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] 147 for slice_idx, ref_mat in enumerate(slices): 148 np.testing.assert_array_equal(double_mat_cm(ref_mat), 2.0 * ref_mat) 149 np.testing.assert_array_equal(double_mat_rm(ref_mat), 2.0 * ref_mat) 150 151 # Mutator: 152 double_threer(second_row) 153 double_threec(second_col) 154 np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]]) 155 156 157def test_nonunit_stride_to_python(): 158 from pybind11_tests import diagonal, diagonal_1, diagonal_n, block 159 160 assert np.all(diagonal(ref) == ref.diagonal()) 161 assert np.all(diagonal_1(ref) == ref.diagonal(1)) 162 for i in range(-5, 7): 163 assert np.all(diagonal_n(ref, i) == ref.diagonal(i)), "diagonal_n({})".format(i) 164 165 assert np.all(block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]) 166 assert np.all(block(ref, 1, 4, 4, 2) == ref[1:, 4:]) 167 assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:]) 168 169 170def test_eigen_ref_to_python(): 171 from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4 172 173 chols = [cholesky1, cholesky2, cholesky3, cholesky4] 174 for i, chol in enumerate(chols, start=1): 175 mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]])) 176 assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i) 177 178 179def assign_both(a1, a2, r, c, v): 180 a1[r, c] = v 181 a2[r, c] = v 182 183 184def array_copy_but_one(a, r, c, v): 185 z = np.array(a, copy=True) 186 z[r, c] = v 187 return z 188 189 190def test_eigen_return_references(): 191 """Tests various ways of returning references and non-referencing copies""" 192 from pybind11_tests import ReturnTester 193 master = np.ones((10, 10)) 194 a = ReturnTester() 195 a_get1 = a.get() 196 assert not a_get1.flags.owndata and a_get1.flags.writeable 197 assign_both(a_get1, master, 3, 3, 5) 198 a_get2 = a.get_ptr() 199 assert not a_get2.flags.owndata and a_get2.flags.writeable 200 assign_both(a_get1, master, 2, 3, 6) 201 202 a_view1 = a.view() 203 assert not a_view1.flags.owndata and not a_view1.flags.writeable 204 with pytest.raises(ValueError): 205 a_view1[2, 3] = 4 206 a_view2 = a.view_ptr() 207 assert not a_view2.flags.owndata and not a_view2.flags.writeable 208 with pytest.raises(ValueError): 209 a_view2[2, 3] = 4 210 211 a_copy1 = a.copy_get() 212 assert a_copy1.flags.owndata and a_copy1.flags.writeable 213 np.testing.assert_array_equal(a_copy1, master) 214 a_copy1[7, 7] = -44 # Shouldn't affect anything else 215 c1want = array_copy_but_one(master, 7, 7, -44) 216 a_copy2 = a.copy_view() 217 assert a_copy2.flags.owndata and a_copy2.flags.writeable 218 np.testing.assert_array_equal(a_copy2, master) 219 a_copy2[4, 4] = -22 # Shouldn't affect anything else 220 c2want = array_copy_but_one(master, 4, 4, -22) 221 222 a_ref1 = a.ref() 223 assert not a_ref1.flags.owndata and a_ref1.flags.writeable 224 assign_both(a_ref1, master, 1, 1, 15) 225 a_ref2 = a.ref_const() 226 assert not a_ref2.flags.owndata and not a_ref2.flags.writeable 227 with pytest.raises(ValueError): 228 a_ref2[5, 5] = 33 229 a_ref3 = a.ref_safe() 230 assert not a_ref3.flags.owndata and a_ref3.flags.writeable 231 assign_both(a_ref3, master, 0, 7, 99) 232 a_ref4 = a.ref_const_safe() 233 assert not a_ref4.flags.owndata and not a_ref4.flags.writeable 234 with pytest.raises(ValueError): 235 a_ref4[7, 0] = 987654321 236 237 a_copy3 = a.copy_ref() 238 assert a_copy3.flags.owndata and a_copy3.flags.writeable 239 np.testing.assert_array_equal(a_copy3, master) 240 a_copy3[8, 1] = 11 241 c3want = array_copy_but_one(master, 8, 1, 11) 242 a_copy4 = a.copy_ref_const() 243 assert a_copy4.flags.owndata and a_copy4.flags.writeable 244 np.testing.assert_array_equal(a_copy4, master) 245 a_copy4[8, 4] = 88 246 c4want = array_copy_but_one(master, 8, 4, 88) 247 248 a_block1 = a.block(3, 3, 2, 2) 249 assert not a_block1.flags.owndata and a_block1.flags.writeable 250 a_block1[0, 0] = 55 251 master[3, 3] = 55 252 a_block2 = a.block_safe(2, 2, 3, 2) 253 assert not a_block2.flags.owndata and a_block2.flags.writeable 254 a_block2[2, 1] = -123 255 master[4, 3] = -123 256 a_block3 = a.block_const(6, 7, 4, 3) 257 assert not a_block3.flags.owndata and not a_block3.flags.writeable 258 with pytest.raises(ValueError): 259 a_block3[2, 2] = -44444 260 261 a_copy5 = a.copy_block(2, 2, 2, 3) 262 assert a_copy5.flags.owndata and a_copy5.flags.writeable 263 np.testing.assert_array_equal(a_copy5, master[2:4, 2:5]) 264 a_copy5[1, 1] = 777 265 c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777) 266 267 a_corn1 = a.corners() 268 assert not a_corn1.flags.owndata and a_corn1.flags.writeable 269 a_corn1 *= 50 270 a_corn1[1, 1] = 999 271 master[0, 0] = 50 272 master[0, 9] = 50 273 master[9, 0] = 50 274 master[9, 9] = 999 275 a_corn2 = a.corners_const() 276 assert not a_corn2.flags.owndata and not a_corn2.flags.writeable 277 with pytest.raises(ValueError): 278 a_corn2[1, 0] = 51 279 280 # All of the changes made all the way along should be visible everywhere 281 # now (except for the copies, of course) 282 np.testing.assert_array_equal(a_get1, master) 283 np.testing.assert_array_equal(a_get2, master) 284 np.testing.assert_array_equal(a_view1, master) 285 np.testing.assert_array_equal(a_view2, master) 286 np.testing.assert_array_equal(a_ref1, master) 287 np.testing.assert_array_equal(a_ref2, master) 288 np.testing.assert_array_equal(a_ref3, master) 289 np.testing.assert_array_equal(a_ref4, master) 290 np.testing.assert_array_equal(a_block1, master[3:5, 3:5]) 291 np.testing.assert_array_equal(a_block2, master[2:5, 2:4]) 292 np.testing.assert_array_equal(a_block3, master[6:10, 7:10]) 293 np.testing.assert_array_equal(a_corn1, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) 294 np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) 295 296 np.testing.assert_array_equal(a_copy1, c1want) 297 np.testing.assert_array_equal(a_copy2, c2want) 298 np.testing.assert_array_equal(a_copy3, c3want) 299 np.testing.assert_array_equal(a_copy4, c4want) 300 np.testing.assert_array_equal(a_copy5, c5want) 301 302 303def assert_keeps_alive(cl, method, *args): 304 from pybind11_tests import ConstructorStats 305 cstats = ConstructorStats.get(cl) 306 start_with = cstats.alive() 307 a = cl() 308 assert cstats.alive() == start_with + 1 309 z = method(a, *args) 310 assert cstats.alive() == start_with + 1 311 del a 312 # Here's the keep alive in action: 313 assert cstats.alive() == start_with + 1 314 del z 315 # Keep alive should have expired: 316 assert cstats.alive() == start_with 317 318 319def test_eigen_keepalive(): 320 from pybind11_tests import ReturnTester, ConstructorStats 321 a = ReturnTester() 322 323 cstats = ConstructorStats.get(ReturnTester) 324 assert cstats.alive() == 1 325 unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)] 326 copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(), 327 a.copy_block(4, 3, 2, 1)] 328 del a 329 assert cstats.alive() == 0 330 del unsafe 331 del copies 332 333 for meth in [ReturnTester.get, ReturnTester.get_ptr, ReturnTester.view, 334 ReturnTester.view_ptr, ReturnTester.ref_safe, ReturnTester.ref_const_safe, 335 ReturnTester.corners, ReturnTester.corners_const]: 336 assert_keeps_alive(ReturnTester, meth) 337 338 for meth in [ReturnTester.block_safe, ReturnTester.block_const]: 339 assert_keeps_alive(ReturnTester, meth, 4, 3, 2, 1) 340 341 342def test_eigen_ref_mutators(): 343 """Tests whether Eigen can mutate numpy values""" 344 from pybind11_tests import add_rm, add_cm, add_any, add1, add2 345 orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]]) 346 zr = np.array(orig) 347 zc = np.array(orig, order='F') 348 add_rm(zr, 1, 0, 100) 349 assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]])) 350 add_cm(zc, 1, 0, 200) 351 assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]])) 352 353 add_any(zr, 1, 0, 20) 354 assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]])) 355 add_any(zc, 1, 0, 10) 356 assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]])) 357 358 # Can't reference a col-major array with a row-major Ref, and vice versa: 359 with pytest.raises(TypeError): 360 add_rm(zc, 1, 0, 1) 361 with pytest.raises(TypeError): 362 add_cm(zr, 1, 0, 1) 363 364 # Overloads: 365 add1(zr, 1, 0, -100) 366 add2(zr, 1, 0, -20) 367 assert np.all(zr == orig) 368 add1(zc, 1, 0, -200) 369 add2(zc, 1, 0, -10) 370 assert np.all(zc == orig) 371 372 # a non-contiguous slice (this won't work on either the row- or 373 # column-contiguous refs, but should work for the any) 374 cornersr = zr[0::2, 0::2] 375 cornersc = zc[0::2, 0::2] 376 377 assert np.all(cornersr == np.array([[1., 3], [7, 9]])) 378 assert np.all(cornersc == np.array([[1., 3], [7, 9]])) 379 380 with pytest.raises(TypeError): 381 add_rm(cornersr, 0, 1, 25) 382 with pytest.raises(TypeError): 383 add_cm(cornersr, 0, 1, 25) 384 with pytest.raises(TypeError): 385 add_rm(cornersc, 0, 1, 25) 386 with pytest.raises(TypeError): 387 add_cm(cornersc, 0, 1, 25) 388 add_any(cornersr, 0, 1, 25) 389 add_any(cornersc, 0, 1, 44) 390 assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]])) 391 assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]])) 392 393 # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method: 394 zro = zr[0:4, 0:4] 395 zro.flags.writeable = False 396 with pytest.raises(TypeError): 397 add_rm(zro, 0, 0, 0) 398 with pytest.raises(TypeError): 399 add_any(zro, 0, 0, 0) 400 with pytest.raises(TypeError): 401 add1(zro, 0, 0, 0) 402 with pytest.raises(TypeError): 403 add2(zro, 0, 0, 0) 404 405 # integer array shouldn't be passable to a double-matrix-accepting mutating func: 406 zi = np.array([[1, 2], [3, 4]]) 407 with pytest.raises(TypeError): 408 add_rm(zi) 409 410 411def test_numpy_ref_mutators(): 412 """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)""" 413 from pybind11_tests import ( 414 get_cm_ref, get_cm_const_ref, get_rm_ref, get_rm_const_ref, reset_refs) 415 reset_refs() # In case another test already changed it 416 417 zc = get_cm_ref() 418 zcro = get_cm_const_ref() 419 zr = get_rm_ref() 420 zrro = get_rm_const_ref() 421 422 assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4 423 424 assert not zc.flags.owndata and zc.flags.writeable 425 assert not zr.flags.owndata and zr.flags.writeable 426 assert not zcro.flags.owndata and not zcro.flags.writeable 427 assert not zrro.flags.owndata and not zrro.flags.writeable 428 429 zc[1, 2] = 99 430 expect = np.array([[11., 12, 13], [21, 22, 99], [31, 32, 33]]) 431 # We should have just changed zc, of course, but also zcro and the original eigen matrix 432 assert np.all(zc == expect) 433 assert np.all(zcro == expect) 434 assert np.all(get_cm_ref() == expect) 435 436 zr[1, 2] = 99 437 assert np.all(zr == expect) 438 assert np.all(zrro == expect) 439 assert np.all(get_rm_ref() == expect) 440 441 # Make sure the readonly ones are numpy-readonly: 442 with pytest.raises(ValueError): 443 zcro[1, 2] = 6 444 with pytest.raises(ValueError): 445 zrro[1, 2] = 6 446 447 # We should be able to explicitly copy like this (and since we're copying, 448 # the const should drop away) 449 y1 = np.array(get_cm_const_ref()) 450 451 assert y1.flags.owndata and y1.flags.writeable 452 # We should get copies of the eigen data, which was modified above: 453 assert y1[1, 2] == 99 454 y1[1, 2] += 12 455 assert y1[1, 2] == 111 456 assert zc[1, 2] == 99 # Make sure we aren't referencing the original 457 458 459def test_both_ref_mutators(): 460 """Tests a complex chain of nested eigen/numpy references""" 461 from pybind11_tests import ( 462 incr_matrix, get_cm_ref, incr_matrix_any, even_cols, even_rows, reset_refs) 463 reset_refs() # In case another test already changed it 464 465 z = get_cm_ref() # numpy -> eigen 466 z[0, 2] -= 3 467 z2 = incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen 468 z2[1, 1] += 6 469 z3 = incr_matrix(z, 2) # (numpy -> eigen)^3 470 z3[2, 2] += -5 471 z4 = incr_matrix(z, 3) # (numpy -> eigen)^4 472 z4[1, 1] -= 1 473 z5 = incr_matrix(z, 4) # (numpy -> eigen)^5 474 z5[0, 0] = 0 475 assert np.all(z == z2) 476 assert np.all(z == z3) 477 assert np.all(z == z4) 478 assert np.all(z == z5) 479 expect = np.array([[0., 22, 20], [31, 37, 33], [41, 42, 38]]) 480 assert np.all(z == expect) 481 482 y = np.array(range(100), dtype='float64').reshape(10, 10) 483 y2 = incr_matrix_any(y, 10) # np -> eigen -> np 484 y3 = incr_matrix_any(y2[0::2, 0::2], -33) # np -> eigen -> np slice -> np -> eigen -> np 485 y4 = even_rows(y3) # numpy -> eigen slice -> (... y3) 486 y5 = even_cols(y4) # numpy -> eigen slice -> (... y4) 487 y6 = incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5) 488 489 # Apply same mutations using just numpy: 490 yexpect = np.array(range(100), dtype='float64').reshape(10, 10) 491 yexpect += 10 492 yexpect[0::2, 0::2] -= 33 493 yexpect[0::4, 0::4] += 1000 494 assert np.all(y6 == yexpect[0::4, 0::4]) 495 assert np.all(y5 == yexpect[0::4, 0::4]) 496 assert np.all(y4 == yexpect[0::4, 0::2]) 497 assert np.all(y3 == yexpect[0::2, 0::2]) 498 assert np.all(y2 == yexpect) 499 assert np.all(y == yexpect) 500 501 502def test_nocopy_wrapper(): 503 from pybind11_tests import get_elem, get_elem_nocopy, get_elem_rm_nocopy 504 # get_elem requires a column-contiguous matrix reference, but should be 505 # callable with other types of matrix (via copying): 506 int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F') 507 dbl_matrix_colmajor = np.array(int_matrix_colmajor, dtype='double', order='F', copy=True) 508 int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True) 509 dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True) 510 511 # All should be callable via get_elem: 512 assert get_elem(int_matrix_colmajor) == 8 513 assert get_elem(dbl_matrix_colmajor) == 8 514 assert get_elem(int_matrix_rowmajor) == 8 515 assert get_elem(dbl_matrix_rowmajor) == 8 516 517 # All but the second should fail with get_elem_nocopy: 518 with pytest.raises(TypeError) as excinfo: 519 get_elem_nocopy(int_matrix_colmajor) 520 assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and 521 ', flags.f_contiguous' in str(excinfo.value)) 522 assert get_elem_nocopy(dbl_matrix_colmajor) == 8 523 with pytest.raises(TypeError) as excinfo: 524 get_elem_nocopy(int_matrix_rowmajor) 525 assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and 526 ', flags.f_contiguous' in str(excinfo.value)) 527 with pytest.raises(TypeError) as excinfo: 528 get_elem_nocopy(dbl_matrix_rowmajor) 529 assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and 530 ', flags.f_contiguous' in str(excinfo.value)) 531 532 # For the row-major test, we take a long matrix in row-major, so only the third is allowed: 533 with pytest.raises(TypeError) as excinfo: 534 get_elem_rm_nocopy(int_matrix_colmajor) 535 assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and 536 ', flags.c_contiguous' in str(excinfo.value)) 537 with pytest.raises(TypeError) as excinfo: 538 get_elem_rm_nocopy(dbl_matrix_colmajor) 539 assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and 540 ', flags.c_contiguous' in str(excinfo.value)) 541 assert get_elem_rm_nocopy(int_matrix_rowmajor) == 8 542 with pytest.raises(TypeError) as excinfo: 543 get_elem_rm_nocopy(dbl_matrix_rowmajor) 544 assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and 545 ', flags.c_contiguous' in str(excinfo.value)) 546 547 548def test_special_matrix_objects(): 549 from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower 550 551 assert np.all(incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7])) 552 553 asymm = np.array([[ 1., 2, 3, 4], 554 [ 5, 6, 7, 8], 555 [ 9, 10, 11, 12], 556 [13, 14, 15, 16]]) 557 symm_lower = np.array(asymm) 558 symm_upper = np.array(asymm) 559 for i in range(4): 560 for j in range(i + 1, 4): 561 symm_lower[i, j] = symm_lower[j, i] 562 symm_upper[j, i] = symm_upper[i, j] 563 564 assert np.all(symmetric_lower(asymm) == symm_lower) 565 assert np.all(symmetric_upper(asymm) == symm_upper) 566 567 568def test_dense_signature(doc): 569 from pybind11_tests import double_col, double_row, double_complex, double_mat_rm 570 571 assert doc(double_col) == """ 572 double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]] 573 """ 574 assert doc(double_row) == """ 575 double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]] 576 """ 577 assert doc(double_complex) == """ 578 double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]] 579 """ 580 assert doc(double_mat_rm) == """ 581 double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]] 582 """ 583 584 585@pytest.requires_eigen_and_scipy 586def test_sparse(): 587 from pybind11_tests import sparse_r, sparse_c, sparse_copy_r, sparse_copy_c 588 589 assert_sparse_equal_ref(sparse_r()) 590 assert_sparse_equal_ref(sparse_c()) 591 assert_sparse_equal_ref(sparse_copy_r(sparse_r())) 592 assert_sparse_equal_ref(sparse_copy_c(sparse_c())) 593 assert_sparse_equal_ref(sparse_copy_r(sparse_c())) 594 assert_sparse_equal_ref(sparse_copy_c(sparse_r())) 595 596 597@pytest.requires_eigen_and_scipy 598def test_sparse_signature(doc): 599 from pybind11_tests import sparse_copy_r, sparse_copy_c 600 601 assert doc(sparse_copy_r) == """ 602 sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32] 603 """ # noqa: E501 line too long 604 assert doc(sparse_copy_c) == """ 605 sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32] 606 """ # noqa: E501 line too long 607 608 609def test_issue738(): 610 from pybind11_tests import iss738_f1, iss738_f2 611 612 assert np.all(iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) 613 assert np.all(iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) 614 615 assert np.all(iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) 616 assert np.all(iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) 617 618 619def test_custom_operator_new(): 620 """Using Eigen types as member variables requires a class-specific 621 operator new with proper alignment""" 622 from pybind11_tests import CustomOperatorNew 623 624 o = CustomOperatorNew() 625 np.testing.assert_allclose(o.a, 0.0) 626 np.testing.assert_allclose(o.b.diagonal(), 1.0) 627