228 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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)));
 | |
|   }
 | |
| }
 | 
