Aikido
yaml_extension.hpp
Go to the documentation of this file.
1 #ifndef AIKIDO_IO_DETAIL_YAMLEIGENEXTENSION_HPP_
2 #define AIKIDO_IO_DETAIL_YAMLEIGENEXTENSION_HPP_
3 
4 #include <sstream>
5 #include <unordered_map>
6 
7 #include <Eigen/Dense>
8 #include <yaml-cpp/yaml.h>
9 
10 #include "aikido/common/memory.hpp"
11 
12 namespace aikido {
13 namespace io {
14 namespace detail {
15 
16 //==============================================================================
17 template <typename MatrixType, bool IsVectorAtCompileTime>
19 {
20  // Nothing defined. This class should be always specialized.
21 
22  // The reason this exists is so we can use template specialization to switch
23  // between serializing vectors and serializing matrices based on the
24  // IsVectorAtCompileTime flag. This is a "nice to have" that lets us generate
25  // [1, 2, 3] instead of the syntactic travesty like [[1], [2] ,[3]] when
26  // serializing an Eigen vector.
27 };
28 
29 //==============================================================================
30 // Specialization for vector type
31 template <typename MatrixType>
32 struct encode_impl<MatrixType, true>
33 {
34  static YAML::Node encode(const MatrixType& matrix)
35  {
36  using Index = typename MatrixType::Index;
37 
38  YAML::Node node;
39  for (Index i = 0; i < matrix.size(); ++i)
40  node.push_back(YAML::Node(matrix[i]));
41 
42  return node;
43  }
44 };
45 
46 //==============================================================================
47 // Specialization for matrix type
48 template <typename MatrixType>
49 struct encode_impl<MatrixType, false>
50 {
51  static YAML::Node encode(const MatrixType& matrix)
52  {
53  using Index = typename MatrixType::Index;
54 
55  YAML::Node node;
56  for (Index r = 0; r < matrix.rows(); ++r)
57  {
58  YAML::Node row(YAML::NodeType::Sequence);
59 
60  for (Index c = 0; c < matrix.cols(); ++c)
61  row.push_back(matrix(r, c));
62 
63  node.push_back(row);
64  }
65 
66  return node;
67  }
68 };
69 
70 inline YAML::Mark getMark(const YAML::Node& node)
71 {
72 #ifdef YAMLCPP_NODE_HAS_MARK
73  return node.Mark();
74 #else
75  DART_UNUSED(node);
76  return YAML::Mark::null_mark();
77 #endif
78  // We need this because Node::Mark() was introduced since yaml-cpp 0.5.3.
79  // By using null_mark(), the error message wouldn't tell the exact location
80  // (i.e., line number and column in the yaml file) where the error occurred.
81 }
82 
83 } // namespace detail
84 } // namespace io
85 } // namespace aikido
86 
87 namespace YAML {
88 
89 //==============================================================================
90 // Specialization for Eigen::Matrix<...>. This enables to use YAML::Node
91 // with std::unordered_map as `Node(Eigen::Matrix3d::Identity())` and
92 // `node.as<Eigen::Matrix3d>()`.
93 template <
94  typename _Scalar,
95  int _Rows,
96  int _Cols,
97  int _Options,
98  int _MaxRows,
99  int _MaxCols>
100 struct convert<
101  Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>>
102 {
103  using MatrixType
104  = Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>;
105  using Index = typename MatrixType::Index;
106 
107  static Node encode(const MatrixType& matrix)
108  {
110  return encode_impl<MatrixType, MatrixType::IsVectorAtCompileTime>::encode(
111  matrix);
112  }
113 
117  static bool decode(const YAML::Node& node, MatrixType& matrix)
118  {
120 
121  if (node.Type() != YAML::NodeType::Sequence)
122  {
123  throw YAML::RepresentationException(
124  getMark(node), "Matrix or vector must be a sequence.");
125  }
126 
127  const Index rows = node.size();
128  if (MatrixType::RowsAtCompileTime != Eigen::Dynamic
129  && rows != MatrixType::RowsAtCompileTime)
130  {
131  std::stringstream ss;
132  ss << "Matrix has incorrect number of rows: expected "
133  << MatrixType::RowsAtCompileTime << "; got " << rows << ".";
134  throw YAML::RepresentationException(getMark(node), ss.str());
135  }
136 
137  if (node.size() > 0 && node[0].Type() == YAML::NodeType::Sequence)
138  {
139  // Matrix case
140 
141  const auto cols = node[0].size();
142 
143  if (MatrixType::ColsAtCompileTime != Eigen::Dynamic
144  && cols != static_cast<std::size_t>(MatrixType::ColsAtCompileTime))
145  {
146  std::stringstream ss;
147  ss << "Matrix has incorrect number of cols: expected "
148  << MatrixType::ColsAtCompileTime << "; got " << cols << ".";
149  throw YAML::RepresentationException(getMark(node), ss.str());
150  }
151 
152  if (cols == 0u)
153  matrix.resize(0, 0);
154  else
155  matrix.resize(rows, cols);
156 
157  for (auto r = 0u; r < node.size(); ++r)
158  {
159  if (node[r].Type() != YAML::NodeType::Sequence)
160  {
161  std::stringstream ss;
162  ss << "Row " << r << " of the matrix must be a sequence.";
163  throw YAML::RepresentationException(getMark(node), ss.str());
164  }
165  else if (node[r].size() != cols)
166  {
167  std::stringstream ss;
168  ss << "Expected row " << r << " to have " << cols << " columns; got "
169  << node[r].size() << ".";
170  throw YAML::RepresentationException(getMark(node), ss.str());
171  }
172 
173  for (auto c = 0u; c < cols; ++c)
174  {
175  if (node[r][c].Type() != YAML::NodeType::Scalar)
176  {
177  std::stringstream ss;
178  ss << "Matrix has a non-scalar element at (" << r << ", " << c
179  << ") component (1-based numbering).";
180  throw YAML::RepresentationException(getMark(node), ss.str());
181  }
182 
183  matrix(r, c) = node[r][c].template as<_Scalar>();
184  }
185  }
186  }
187  else
188  {
189  // Vector case
190 
191  if (MatrixType::ColsAtCompileTime != Eigen::Dynamic
192  && 1 != MatrixType::ColsAtCompileTime)
193  {
194  std::stringstream ss;
195  ss << "Matrix has incorrect number of cols: expected "
196  << MatrixType::ColsAtCompileTime << "; got " << 1 << ".";
197  throw YAML::RepresentationException(getMark(node), ss.str());
198  }
199 
200  matrix.resize(rows, 1);
201  for (Index i = 0; i < rows; ++i)
202  {
203  if (node[i].Type() != YAML::NodeType::Scalar)
204  {
205  std::stringstream ss;
206  ss << "Vector has a non-scalar element at the " << i + 1
207  << "-th component (1-based numbering).";
208  throw YAML::RepresentationException(getMark(node), ss.str());
209  }
210 
211  matrix(i, 0) = node[i].template as<_Scalar>();
212  }
213  }
214 
215  return true;
216  }
217 };
218 
219 //==============================================================================
220 // Specialization for Eigen::Isometry<...>. This enables to use YAML::Node
221 // with std::unordered_map as `Node(Eigen::Isometry3d::Identity())` and
222 // `node.as<Eigen::Isometry3d>()`.
223 template <typename _Scalar, int _Dim, int _Mode, int _Options>
224 struct convert<Eigen::Transform<_Scalar, _Dim, _Mode, _Options>>
225 {
226  using TransformType = Eigen::Transform<_Scalar, _Dim, _Mode, _Options>;
227  using MatrixType = typename TransformType::MatrixType;
228 
229  static Node encode(const TransformType& transform)
230  {
231  return convert<MatrixType>::encode(transform.matrix());
232  }
233 
234  static bool decode(const Node& node, TransformType& transform)
235  {
236  return convert<MatrixType>::decode(node, transform.matrix());
237  }
238 };
239 
240 //==============================================================================
241 // Specialization for std::unordered_map<...>. This enables to use YAML::Node
242 // with std::unordered_map as `Node(std::unorderd_map<...>())` and
243 // `node.as<std::unordered_map<...>>()`.
244 template <
245  typename _Key,
246  typename _Tp,
247  typename _Hash,
248  typename _Pred,
249  typename _Alloc>
250 struct convert<std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>>
251 {
252  using UnorderedMap = std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>;
253 
254  static Node encode(const UnorderedMap& map)
255  {
256  Node node(NodeType::Map);
257 
258  for (const auto& it : map)
259  node.force_insert(it.first, it.second);
260 
261  return node;
262  }
263 
264  static bool decode(const Node& node, UnorderedMap& map)
265  {
266  if (!node.IsMap())
267  return false;
268 
269  map.clear();
270  map.reserve(node.size());
271 
272  for (const auto& it : node)
273  map[it.first.as<_Key>()] = it.second.as<_Tp>();
274 
275  return true;
276  }
277 };
278 
279 } // namespace YAML
280 
281 #endif // AIKIDO_IO_YAMLUTILS_HPP_
YAML::convert< std::unordered_map< _Key, _Tp, _Hash, _Pred, _Alloc > >::UnorderedMap
std::unordered_map< _Key, _Tp, _Hash, _Pred, _Alloc > UnorderedMap
Definition: yaml_extension.hpp:252
YAML::convert< Eigen::Transform< _Scalar, _Dim, _Mode, _Options > >::encode
static Node encode(const TransformType &transform)
Definition: yaml_extension.hpp:229
aikido
Format of serialized trajectory in YAML.
Definition: algorithm.hpp:4
aikido::io::detail::encode_impl< MatrixType, true >::encode
static YAML::Node encode(const MatrixType &matrix)
Definition: yaml_extension.hpp:34
YAML::convert< Eigen::Transform< _Scalar, _Dim, _Mode, _Options > >::TransformType
Eigen::Transform< _Scalar, _Dim, _Mode, _Options > TransformType
Definition: yaml_extension.hpp:226
memory.hpp
YAML::convert< Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > >::encode
static Node encode(const MatrixType &matrix)
Definition: yaml_extension.hpp:107
YAML::convert< std::unordered_map< _Key, _Tp, _Hash, _Pred, _Alloc > >::decode
static bool decode(const Node &node, UnorderedMap &map)
Definition: yaml_extension.hpp:264
YAML
Definition: yaml_extension.hpp:87
aikido::io::detail::getMark
YAML::Mark getMark(const YAML::Node &node)
Definition: yaml_extension.hpp:70
YAML::convert< Eigen::Transform< _Scalar, _Dim, _Mode, _Options > >::MatrixType
typename TransformType::MatrixType MatrixType
Definition: yaml_extension.hpp:227
YAML::convert< Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > >::MatrixType
Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > MatrixType
Definition: yaml_extension.hpp:104
YAML::convert< Eigen::Transform< _Scalar, _Dim, _Mode, _Options > >::decode
static bool decode(const Node &node, TransformType &transform)
Definition: yaml_extension.hpp:234
aikido::io::detail::encode_impl
Definition: yaml_extension.hpp:18
YAML::convert< std::unordered_map< _Key, _Tp, _Hash, _Pred, _Alloc > >::encode
static Node encode(const UnorderedMap &map)
Definition: yaml_extension.hpp:254
aikido::io::detail::encode_impl< MatrixType, false >::encode
static YAML::Node encode(const MatrixType &matrix)
Definition: yaml_extension.hpp:51
YAML::convert< Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > >::Index
typename MatrixType::Index Index
Definition: yaml_extension.hpp:105
YAML::convert< Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > >::decode
static bool decode(const YAML::Node &node, MatrixType &matrix)
Reads a YAML::Node that encodes a vector or a matrix; and stores it into matrix.
Definition: yaml_extension.hpp:117