Add flatbuffer Matrix table and library
This makes it easier to pack Eigen matrices into flatbuffers for use in
constants files, AOS messages, etc.
Change-Id: Icd1f5d9d3e57821c2aa21eef03d52e67f80faa69
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/frc971/math/flatbuffers_matrix_test.cc b/frc971/math/flatbuffers_matrix_test.cc
new file mode 100644
index 0000000..2807309
--- /dev/null
+++ b/frc971/math/flatbuffers_matrix_test.cc
@@ -0,0 +1,90 @@
+#include "frc971/math/flatbuffers_matrix.h"
+
+#include "gtest/gtest.h"
+
+#include "aos/json_to_flatbuffer.h"
+
+namespace frc971::testing {
+
+class FlatbuffersMatrixTest : public ::testing::Test {
+ protected:
+ template <int Rows, int Cols,
+ fbs::StorageOrder StorageOrder = fbs::StorageOrder::ColMajor>
+ tl::expected<typename EigenMatrix<Rows, Cols, StorageOrder>::type,
+ ConversionFailure>
+ ToEigen(std::string_view json) {
+ return frc971::ToEigen<Rows, Cols, StorageOrder>(
+ aos::FlatbufferDetachedBuffer<fbs::Matrix>(
+ aos::JsonToFlatbuffer<fbs::Matrix>(json))
+ .message());
+ }
+};
+
+TEST_F(FlatbuffersMatrixTest, ReadWriteMatrix) {
+ const Eigen::Matrix<double, 3, 4> expected{
+ {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};
+ aos::fbs::Builder<fbs::MatrixStatic> builder;
+ ASSERT_TRUE(FromEigen(expected, builder.get()));
+ EXPECT_EQ(
+ "{ \"rows\": 3, \"cols\": 4, \"storage_order\": \"ColMajor\", \"data\": "
+ "[ 0.0, 4.0, 8.0, 1.0, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0 ] }",
+ aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
+
+ const Eigen::Matrix<double, 3, 4> result =
+ ToEigenOrDie<3, 4>(builder->AsFlatbuffer());
+ EXPECT_EQ(expected, result);
+}
+
+TEST_F(FlatbuffersMatrixTest, ReadWriteMatrixRowMajor) {
+ const Eigen::Matrix<double, 3, 4, Eigen::StorageOptions::RowMajor> expected{
+ {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};
+ aos::fbs::Builder<fbs::MatrixStatic> builder;
+ ASSERT_TRUE(FromEigen(expected, builder.get()));
+ EXPECT_EQ(
+ "{ \"rows\": 3, \"cols\": 4, \"storage_order\": \"RowMajor\", \"data\": "
+ "[ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 ] }",
+ aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
+
+ const Eigen::Matrix<double, 3, 4, Eigen::StorageOptions::RowMajor> result =
+ ToEigenOrDie<3, 4, fbs::StorageOrder::RowMajor>(builder->AsFlatbuffer());
+ EXPECT_EQ(expected, result);
+}
+
+class FlatbuffersMatrixParamTest
+ : public FlatbuffersMatrixTest,
+ public ::testing::WithParamInterface<
+ std::tuple<std::string, ConversionFailure>> {};
+TEST_P(FlatbuffersMatrixParamTest, ConversionFailures) {
+ auto result = this->ToEigen<3, 4>(std::get<0>(GetParam()));
+ EXPECT_FALSE(result.has_value());
+ EXPECT_EQ(std::get<1>(GetParam()), result.error());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ConversionFailureTests, FlatbuffersMatrixParamTest,
+ ::testing::Values(
+ std::make_tuple("{}", ConversionFailure{fbs::MatrixField::kRows,
+ fbs::FieldError::kMissing}),
+ std::make_tuple(R"json({"rows": 3})json",
+ ConversionFailure{fbs::MatrixField::kCols,
+ fbs::FieldError::kMissing}),
+ std::make_tuple(R"json({"rows": 3, "cols": 4})json",
+ ConversionFailure{fbs::MatrixField::kData,
+ fbs::FieldError::kMissing}),
+ std::make_tuple(
+ R"json({"rows": 1, "cols": 4, "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]})json",
+ ConversionFailure{fbs::MatrixField::kRows,
+ fbs::FieldError::kInconsistentWithTemplate}),
+ std::make_tuple(
+ R"json({"rows": 3, "cols": 7, "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]})json",
+ ConversionFailure{fbs::MatrixField::kCols,
+ fbs::FieldError::kInconsistentWithTemplate}),
+ std::make_tuple(R"json({"rows": 3, "cols": 4, "data": []})json",
+ ConversionFailure{
+ fbs::MatrixField::kData,
+ fbs::FieldError::kInconsistentWithTemplate}),
+ std::make_tuple(
+ R"json({"rows": 3, "cols": 4, "storage_order": "RowMajor", "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]})json",
+ ConversionFailure{fbs::MatrixField::kStorageOrder,
+ fbs::FieldError::kInconsistentWithTemplate})));
+} // namespace frc971::testing