diff --git a/src/python/tensor/export_tensor.cpp b/src/python/tensor/export_tensor.cpp index f8bc971f..f22b4364 100644 --- a/src/python/tensor/export_tensor.cpp +++ b/src/python/tensor/export_tensor.cpp @@ -21,9 +21,6 @@ namespace tensorwrapper { -using float_type = double; -using buffer_type = buffer::Contiguous; - template auto make_buffer_info(buffer::Contiguous& buffer) { using size_type = std::size_t; @@ -46,15 +43,39 @@ auto make_buffer_info(buffer::Contiguous& buffer) { strides); } +auto make_tensor(pybind11::buffer b) { + pybind11::buffer_info info = b.request(); + if(info.format != pybind11::format_descriptor::format()) + throw std::runtime_error( + "Incompatible format: expected a double array!"); + + std::vector dims(info.ndim); + for(auto i = 0; i < info.ndim; ++i) { dims[i] = info.shape[i]; } + + parallelzone::runtime::RuntimeView rv = {}; + allocator::Eigen allocator(rv); + shape::Smooth matrix_shape{dims.begin(), dims.end()}; + layout::Physical matrix_layout(matrix_shape); + auto pBuffer = allocator.allocate(matrix_layout); + + auto n_elements = std::accumulate(dims.begin(), dims.end(), 1, + std::multiplies()); + for(auto i = 0; i < n_elements; ++i) + pBuffer->data()[i] = static_cast(info.ptr)[i]; + + return Tensor(matrix_shape, std::move(pBuffer)); +} + void export_tensor(py_module_reference m) { py_class_type(m, "Tensor", pybind11::buffer_protocol()) .def(pybind11::init<>()) + .def(pybind11::init([](pybind11::buffer b) { return make_tensor(b); })) .def("rank", &Tensor::rank) .def(pybind11::self == pybind11::self) .def(pybind11::self != pybind11::self) .def("__str__", [](Tensor& self) { return self.to_string(); }) .def_buffer([](Tensor& t) { - auto pbuffer = dynamic_cast(&t.buffer()); + auto pbuffer = dynamic_cast*>(&t.buffer()); if(pbuffer == nullptr) throw std::runtime_error("Expected buffer to hold doubles"); return make_buffer_info(*pbuffer); diff --git a/tests/python/unit_tests/tensor/test_tensor.py b/tests/python/unit_tests/tensor/test_tensor.py index 0b61be25..a4e17bb6 100644 --- a/tests/python/unit_tests/tensor/test_tensor.py +++ b/tests/python/unit_tests/tensor/test_tensor.py @@ -20,17 +20,30 @@ class TestTensor(unittest.TestCase): - def test_ctor(self): + def test_rank(self): + with self.assertRaises(RuntimeError): + self.defaulted.rank() self.assertEqual(self.scalar.rank(), 0) self.assertEqual(self.vector.rank(), 1) self.assertEqual(self.matrix.rank(), 2) + self.assertEqual(self.scalar_from_cpp.rank(), 0) + self.assertEqual(self.vector_from_cpp.rank(), 1) + self.assertEqual(self.matrix_from_cpp.rank(), 2) + + def test_equality(self): + self.assertTrue(self.scalar == self.scalar_from_cpp) + self.assertTrue(self.vector == self.vector_from_cpp) + self.assertTrue(self.matrix == self.matrix_from_cpp) + + def test_inequality(self): + self.assertTrue(self.defaulted != self.scalar) def test_numpy(self): np_scalar = np.array(self.scalar) np_vector = np.array(self.vector) np_matrix = np.array(self.matrix) - scalar_corr = np.array(42) + scalar_corr = np.array(42.0) vector_corr = np.array([0.0, 1.0, 2.0, 3.0, 4.0]) matrix_corr = np.array([[1.0, 2.0], [3.0, 4.0]]) self.assertFalse((np_scalar - scalar_corr).any()) @@ -38,6 +51,10 @@ def test_numpy(self): self.assertFalse((np_matrix - matrix_corr).any()) def setUp(self): - self.scalar = testing.get_scalar() - self.vector = testing.get_vector() - self.matrix = testing.get_matrix() + self.defaulted = tensorwrapper.Tensor() + self.scalar = tensorwrapper.Tensor(np.array(42.0)) + self.vector = tensorwrapper.Tensor(np.array([0.0, 1.0, 2.0, 3.0, 4.0])) + self.matrix = tensorwrapper.Tensor(np.array([[1.0, 2.0], [3.0, 4.0]])) + self.scalar_from_cpp = testing.get_scalar() + self.vector_from_cpp = testing.get_vector() + self.matrix_from_cpp = testing.get_matrix()