mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-02-23 18:20:47 +08:00
234 lines
7.2 KiB
C++
234 lines
7.2 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)) );
|
|
}
|
|
}
|