Program Listing for File yaml.h

Return to documentation for file (interfaces/yaml.h)

#pragma once

#include <yaml-cpp/yaml.h>

#include "lupnt/core/definitions.h"

namespace YAML {
  template <> struct convert<lupnt::Real> {
    static Node encode(const lupnt::Real& rhs) {
      Node node;
      node = static_cast<double>(rhs);
      return node;
    }

    static bool decode(const Node& node, lupnt::Real& rhs) {
      if (!node.IsScalar()) return false;
      rhs = node.as<double>();
      return true;
    }
  };

  template <typename Scalar, int Rows, int Cols> struct convert<Eigen::Matrix<Scalar, Rows, Cols>> {
    static Node encode(const Eigen::Matrix<Scalar, Rows, Cols>& mat) {
      Node node;
      for (int i = 0; i < mat.rows(); ++i) {
        Node row;
        for (int j = 0; j < mat.cols(); ++j) row.push_back(mat(i, j));
        node.push_back(row);
      }
      return node;
    }

    static bool decode(const Node& node, Eigen::Matrix<Scalar, Rows, Cols>& mat) {
      if (!node.IsSequence()) return false;

      // Handle vector, row or column, as a flat sequence.
      constexpr bool is_row_vector = (Rows == 1 && Cols != 1);
      constexpr bool is_col_vector = (Cols == 1 && Rows != 1);
      constexpr bool is_vector = (is_row_vector || is_col_vector);

      if (is_vector) {
        int vec_size = static_cast<int>(node.size());

        if (Rows == 1 && Cols == Eigen::Dynamic) {
          mat.derived().resize(1, vec_size);
        } else if (Cols == 1 && Rows == Eigen::Dynamic) {
          mat.derived().resize(vec_size, 1);
        } else if (Rows == 1 && Cols != Eigen::Dynamic && Cols != vec_size) {
          return false;
        } else if (Cols == 1 && Rows != Eigen::Dynamic && Rows != vec_size) {
          return false;
        }

        for (int i = 0; i < vec_size; ++i) {
          if (is_row_vector) {
            mat(0, i) = node[i].as<Scalar>();
          } else {
            mat(i, 0) = node[i].as<Scalar>();
          }
        }
        return true;
      }

      // Matrix case.
      if (Rows != Eigen::Dynamic && node.size() != static_cast<size_t>(Rows)) {
        return false;
      }

      int n_rows = static_cast<int>(node.size());
      int n_cols = 0;

      if (n_rows > 0) {
        if (!node[0].IsSequence()) return false;
        n_cols = static_cast<int>(node[0].size());
        if (Cols != Eigen::Dynamic && n_cols != Cols) return false;
      }

      if (Rows == Eigen::Dynamic && Cols == Eigen::Dynamic) {
        mat.derived().resize(n_rows, n_cols);
      } else if (Rows == Eigen::Dynamic) {
        mat.derived().resize(n_rows, mat.cols());
      } else if (Cols == Eigen::Dynamic) {
        mat.derived().resize(mat.rows(), n_cols);
      }

      for (int i = 0; i < n_rows; ++i) {
        const Node& row = node[i];
        if (!row.IsSequence()) return false;
        if (Cols != Eigen::Dynamic && static_cast<int>(row.size()) != Cols) return false;

        for (int j = 0; j < static_cast<int>(row.size()); ++j) {
          mat(i, j) = row[j].as<Scalar>();
        }
      }

      return true;
    }
  };
}  // namespace YAML