| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. |
| // |
| // Copyright (C) 2021 The Eigen Team |
| // |
| // This Source Code Form is subject to the terms of the Mozilla |
| // Public License v. 2.0. If a copy of the MPL was not distributed |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #include "main.h" |
| |
| #include <Eigen/Core> |
| #include <Eigen/SparseCore> |
| #include <vector> |
| |
| template <typename T> |
| struct RandomImpl { |
| static auto Create(Eigen::Index rows, Eigen::Index cols) { return T::Random(rows, cols); } |
| }; |
| |
| template <typename Scalar, int Options, typename DenseIndex> |
| struct RandomImpl<Eigen::SparseMatrix<Scalar, Options, DenseIndex>> { |
| using T = Eigen::SparseMatrix<Scalar, Options, DenseIndex>; |
| |
| static auto Create(Eigen::Index rows, Eigen::Index cols) { |
| Eigen::SparseMatrix<Scalar, Options, DenseIndex> M(rows, cols); |
| M.setZero(); |
| double density = 0.1; |
| |
| // Reserve some space along each inner dim. |
| int nnz = static_cast<int>(std::ceil(density * 1.5 * M.innerSize())); |
| M.reserve(Eigen::VectorXi::Constant(M.outerSize(), nnz)); |
| |
| for (int j = 0; j < M.outerSize(); j++) { |
| for (int i = 0; i < M.innerSize(); i++) { |
| bool zero = (Eigen::internal::random<double>(0, 1) > density); |
| if (!zero) { |
| M.insertByOuterInner(j, i) = internal::random<Scalar>(); |
| } |
| } |
| } |
| |
| // 50-50 whether to compress or not. |
| if (Eigen::internal::random<double>(0, 1) >= 0.5) { |
| M.makeCompressed(); |
| } |
| |
| return M; |
| } |
| }; |
| |
| template <typename Scalar, int Options, typename DenseIndex> |
| struct RandomImpl<Eigen::SparseVector<Scalar, Options, DenseIndex>> { |
| using T = Eigen::SparseVector<Scalar, Options, DenseIndex>; |
| |
| static auto Create(Eigen::Index rows, Eigen::Index cols) { |
| Eigen::SparseVector<Scalar, Options, DenseIndex> M(rows, cols); |
| M.setZero(); |
| double density = 0.1; |
| |
| // Reserve some space along each inner dim. |
| int nnz = static_cast<int>(density * 1.5 * M.innerSize()); |
| M.reserve(nnz); |
| |
| for (int i = 0; i < M.innerSize(); i++) { |
| bool zero = (Eigen::internal::random<double>(0, 1) > density); |
| if (!zero) { |
| M.insert(i) = internal::random<Scalar>(); |
| } |
| } |
| |
| return M; |
| } |
| }; |
| |
| struct MyPodType { |
| double x; |
| int y; |
| float z; |
| }; |
| |
| // Plain-old-data serialization. |
| void test_pod_type() { |
| MyPodType initial = {1.3, 17, 1.9f}; |
| MyPodType clone = {-1, -1, -1}; |
| |
| Eigen::Serializer<MyPodType> serializer; |
| |
| // Determine required size. |
| size_t buffer_size = serializer.size(initial); |
| VERIFY_IS_EQUAL(buffer_size, sizeof(MyPodType)); |
| |
| // Serialize. |
| std::vector<uint8_t> buffer(buffer_size); |
| uint8_t* begin = buffer.data(); |
| uint8_t* end = buffer.data() + buffer.size(); |
| uint8_t* dest = serializer.serialize(begin, end, initial); |
| VERIFY(dest != nullptr); |
| VERIFY_IS_EQUAL(dest - begin, buffer_size); |
| |
| // Deserialize. |
| const uint8_t* src = serializer.deserialize(begin, end, clone); |
| VERIFY(src != nullptr); |
| VERIFY_IS_EQUAL(src - begin, buffer_size); |
| VERIFY_IS_EQUAL(clone.x, initial.x); |
| VERIFY_IS_EQUAL(clone.y, initial.y); |
| VERIFY_IS_EQUAL(clone.z, initial.z); |
| |
| // Serialize with bounds checking errors. |
| dest = serializer.serialize(begin, end - 1, initial); |
| VERIFY(dest == nullptr); |
| dest = serializer.serialize(begin, begin, initial); |
| VERIFY(dest == nullptr); |
| dest = serializer.serialize(nullptr, nullptr, initial); |
| VERIFY(dest == nullptr); |
| |
| // Deserialize with bounds checking errors. |
| src = serializer.deserialize(begin, end - 1, clone); |
| VERIFY(src == nullptr); |
| src = serializer.deserialize(begin, begin, clone); |
| VERIFY(src == nullptr); |
| src = serializer.deserialize(nullptr, nullptr, clone); |
| VERIFY(src == nullptr); |
| } |
| |
| // Matrix, Vector, Array |
| template <typename T> |
| void test_eigen_type(const T& type) { |
| const Index rows = type.rows(); |
| const Index cols = type.cols(); |
| |
| const T initial = RandomImpl<T>::Create(rows, cols); |
| |
| // Serialize. |
| Eigen::Serializer<T> serializer; |
| size_t buffer_size = serializer.size(initial); |
| std::vector<uint8_t> buffer(buffer_size); |
| uint8_t* begin = buffer.data(); |
| uint8_t* end = buffer.data() + buffer.size(); |
| uint8_t* dest = serializer.serialize(begin, end, initial); |
| VERIFY(dest != nullptr); |
| VERIFY_IS_EQUAL(dest - begin, buffer_size); |
| |
| // Deserialize. |
| T clone; |
| const uint8_t* src = serializer.deserialize(begin, end, clone); |
| VERIFY(src != nullptr); |
| VERIFY_IS_EQUAL(src - begin, buffer_size); |
| VERIFY_IS_CWISE_EQUAL(clone, initial); |
| |
| // Serialize with bounds checking errors. |
| dest = serializer.serialize(begin, end - 1, initial); |
| VERIFY(dest == nullptr); |
| dest = serializer.serialize(begin, begin, initial); |
| VERIFY(dest == nullptr); |
| dest = serializer.serialize(nullptr, nullptr, initial); |
| VERIFY(dest == nullptr); |
| |
| // Deserialize with bounds checking errors. |
| src = serializer.deserialize(begin, end - 1, clone); |
| VERIFY(src == nullptr); |
| src = serializer.deserialize(begin, begin, clone); |
| VERIFY(src == nullptr); |
| src = serializer.deserialize(nullptr, nullptr, clone); |
| VERIFY(src == nullptr); |
| } |
| |
| // Test a collection of dense types. |
| template <typename T1, typename T2, typename T3> |
| void test_dense_types(const T1& type1, const T2& type2, const T3& type3) { |
| // Make random inputs. |
| const T1 x1 = T1::Random(type1.rows(), type1.cols()); |
| const T2 x2 = T2::Random(type2.rows(), type2.cols()); |
| const T3 x3 = T3::Random(type3.rows(), type3.cols()); |
| |
| // Allocate buffer and serialize. |
| size_t buffer_size = Eigen::serialize_size(x1, x2, x3); |
| std::vector<uint8_t> buffer(buffer_size); |
| uint8_t* begin = buffer.data(); |
| uint8_t* end = buffer.data() + buffer.size(); |
| uint8_t* dest = Eigen::serialize(begin, end, x1, x2, x3); |
| VERIFY(dest != nullptr); |
| |
| // Clone everything. |
| T1 y1; |
| T2 y2; |
| T3 y3; |
| const uint8_t* src = Eigen::deserialize(begin, end, y1, y2, y3); |
| VERIFY(src != nullptr); |
| |
| // Verify they equal. |
| VERIFY_IS_CWISE_EQUAL(y1, x1); |
| VERIFY_IS_CWISE_EQUAL(y2, x2); |
| VERIFY_IS_CWISE_EQUAL(y3, x3); |
| |
| // Serialize everything with bounds checking errors. |
| dest = Eigen::serialize(begin, end - 1, y1, y2, y3); |
| VERIFY(dest == nullptr); |
| dest = Eigen::serialize(begin, begin, y1, y2, y3); |
| VERIFY(dest == nullptr); |
| dest = Eigen::serialize(nullptr, nullptr, y1, y2, y3); |
| VERIFY(dest == nullptr); |
| |
| // Deserialize everything with bounds checking errors. |
| src = Eigen::deserialize(begin, end - 1, y1, y2, y3); |
| VERIFY(src == nullptr); |
| src = Eigen::deserialize(begin, begin, y1, y2, y3); |
| VERIFY(src == nullptr); |
| src = Eigen::deserialize(nullptr, nullptr, y1, y2, y3); |
| VERIFY(src == nullptr); |
| } |
| |
| EIGEN_DECLARE_TEST(serializer) { |
| CALL_SUBTEST(test_pod_type()); |
| |
| for (int i = 0; i < g_repeat; i++) { |
| CALL_SUBTEST(test_eigen_type(Eigen::Array33f())); |
| CALL_SUBTEST(test_eigen_type(Eigen::ArrayXd(10))); |
| CALL_SUBTEST(test_eigen_type(Eigen::Vector3f())); |
| CALL_SUBTEST(test_eigen_type(Eigen::Matrix4d())); |
| CALL_SUBTEST(test_eigen_type(Eigen::MatrixXd(15, 17))); |
| CALL_SUBTEST(test_eigen_type(Eigen::SparseMatrix<float>(13, 12))); |
| CALL_SUBTEST(test_eigen_type(Eigen::SparseVector<float>(17))); |
| |
| CALL_SUBTEST(test_dense_types(Eigen::Array33f(), Eigen::ArrayXd(10), Eigen::MatrixXd(15, 17))); |
| } |
| } |