Skip to content

Latest commit

 

History

History
286 lines (231 loc) · 8.39 KB

File metadata and controls

286 lines (231 loc) · 8.39 KB

Eigen::Matrix examples

This example shows how to specialize json_conv_traits for an Eigen matrix class. It defines separate json_conv_traits class templates for the dynamic and fixed sized row/column cases.

#include <jsoncons/json.hpp>
#include <Eigen/Dense>
#include <iostream>
#include <cassert>

namespace jsoncons {
namespace reflect {

// fixed sized row/columns

template <typename Json, typename Scalar, std::size_t RowsAtCompileTime, std::size_t ColsAtCompileTime>
struct json_conv_traits<Json, Eigen::Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime>>
{
    using allocator_type = typename Json::allocator_type;
    using matrix_type = Eigen::Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime>;
    using result_type = conversion_result<matrix_type>;

    static bool is(const Json& jval) noexcept
    {
        if (!jval.is_array() || jval.size() != RowsAtCompileTime)
            return false;

        for (std::size_t i = 0; i < jval.size(); ++i)
        {
            const Json& row = jval[i];
            if (row.size() != ColsAtCompileTime)
            {
                return false;
            }
        }

        return true;
    }

    template <typename Alloc, typename TempAlloc>
    static result_type try_as(const allocator_set<Alloc, TempAlloc>& aset, const Json& jval)
    {
        if (!jval.is_array())
        {
            return result_type{jsoncons::unexpect, conv_errc::not_array};
        }
        if (jval.size() != RowsAtCompileTime)
        {
            return result_type{jsoncons::unexpect, conv_errc::conversion_failed, "Expected " + 
                std::to_string(RowsAtCompileTime) + " rows, found " + std::to_string(jval.size())};
        }

        matrix_type m(RowsAtCompileTime, ColsAtCompileTime);

        for (std::size_t i = 0; i < jval.size(); ++i)
        {
            const Json& row = jval[i];
            if (row.size() != ColsAtCompileTime)
            {
                return result_type{jsoncons::unexpect, conv_errc::conversion_failed, "Expected " + 
                    std::to_string(ColsAtCompileTime) + " columns, found " + std::to_string(row.size())};
            }
            for (std::size_t j = 0; j < row.size(); ++j)
            {
                m(i, j) = row[j].as<Scalar>();
            }
        }

        return result_type{std::move(m)};
    }

    template <typename Alloc, typename TempAlloc>
    static Json to_json(const allocator_set<Alloc, TempAlloc>& aset, const matrix_type& m)
    {
        auto jval = jsoncons::make_obj_using_allocator<Json>(aset.get_allocator(), jsoncons::json_array_arg);
        for (Eigen::Index i = 0; i < m.rows(); ++i)
        {
            auto row = jsoncons::make_obj_using_allocator<Json>(aset.get_allocator(), jsoncons::json_array_arg);
            for (Eigen::Index j = 0; j < m.cols(); ++j)
            {
                row.push_back(m(i, j));
            }
            jval.push_back(std::move(row));
        }

        return jval;
    }
};

// dynamic sized row/columns

template <typename Json, typename Scalar>
struct json_conv_traits<Json, Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>
{
    using allocator_type = typename Json::allocator_type;
    using matrix_type = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
    using result_type = conversion_result<matrix_type>;

    static bool is(const Json& jval) noexcept
    {
        if (!jval.is_array())
            return false;

        std::size_t cols = jval[0].size();

        for (std::size_t i = 0; i < jval.size(); ++i)
        {
            const Json& row = jval[i];
            if (row.size() != cols)
            {
                return false;
            }
        }

        return true;
    }

    template <typename Alloc, typename TempAlloc>
    static result_type try_as(const allocator_set<Alloc, TempAlloc>&, const Json& jval)
    {
        if (!jval.is_array())
        {
            return result_type{jsoncons::unexpect, conv_errc::not_array};
        }
        if (jval.empty() || jval[0].size() == 0)
        {
            return result_type{jsoncons::unexpect, conv_errc::conversion_failed, "Invalid matrix"};
        }

        std::size_t cols = jval[0].size();
        matrix_type m(jval.size(), cols);

        for (std::size_t i = 0; i < jval.size(); ++i)
        {
            const Json& row = jval[i];
            if (row.size() != cols)
            {
                return result_type{jsoncons::unexpect, conv_errc::conversion_failed};
            }
            for (std::size_t j = 0; j < row.size(); ++j)
            {
                m(i, j) = row[j].template as<Scalar>();
            }
        }

        return result_type{std::move(m)};
    }

    template <typename Alloc, typename TempAlloc>
    static Json to_json(const allocator_set<Alloc, TempAlloc>& aset, const matrix_type& m)
    {
        auto jval = jsoncons::make_obj_using_allocator<Json>(aset.get_allocator(), jsoncons::json_array_arg);
        for (Eigen::Index i = 0; i < m.rows(); ++i)
        {
            auto row = jsoncons::make_obj_using_allocator<Json>(aset.get_allocator(), jsoncons::json_array_arg);
            for (Eigen::Index j = 0; j < m.cols(); ++j)
            {
                row.push_back(m(i, j));
            }
            jval.push_back(std::move(row));
        }

        return jval;
    }
};

} // namespace reflect
} // namespace jsoncons

Fixed size matrix example

using matrix_type = Eigen::Matrix<double, 3, 4>;

// Don't use auto here! (Random returns proxy)
matrix_type m1 = matrix_type::Random(3, 4);
std::cout << "(1) " << '\n' << m1 << "\n\n";

std::string buffer;
auto options = jsoncons::json_options{}.array_array_line_splits(jsoncons::line_split_kind::same_line);

auto wresult = jsoncons::try_encode_json_pretty(m1, buffer, options);
assert(wresult);

std::cout << "(2) " << '\n' << buffer << "\n\n";

auto rresult = jsoncons::try_decode_json<matrix_type>(buffer);
assert(rresult);
auto& m2(*rresult);
assert(m1 == m2);

// This should fail
auto r3by3 = jsoncons::try_decode_json<Eigen::Matrix<double, 3, 3>>(buffer);
if (!r3by3)
{
    std::cout << "(3) " << r3by3.error().message() << "\n\n";
}

auto jresult = jsoncons::try_decode_json<jsoncons::json>(buffer);
assert(jresult);
auto j1(*jresult);

auto mresult = j1.try_as<matrix_type>();
assert(mresult);
auto& m3(*mresult);
assert(m1 == m3);

jsoncons::json j2{m1};
assert(j1 == j2);

Output:

(1)
 -0.997497   0.617481  -0.299417    0.49321
  0.127171   0.170019   0.791925  -0.651784
 -0.613392 -0.0402539    0.64568   0.717887

(2)
[
    [-0.9974974822229682, 0.6174810022278512, -0.2994170964690085, 0.4932096316415906],
    [0.12717062898648024, 0.1700186162907804, 0.7919248023926511, -0.651783806878872],
    [-0.6133915219580676, -0.04025391399884026, 0.6456801049836727, 0.717886898403882]
]

(3) Expected 3 columns, found 4: Unable to convert into the provided type at line 1 and column 2

Dynamic matrix example

using matrix_type = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;

// Don't use auto here! (Random returns proxy)
matrix_type m1 = matrix_type::Random(3, 4);
std::cout << "(1) " << '\n' << m1 << "\n\n";

std::string buffer;
auto options = jsoncons::json_options{}.array_array_line_splits(jsoncons::line_split_kind::same_line);

auto wresult = jsoncons::try_encode_json_pretty(m1, buffer, options);
assert(wresult);

std::cout << "(2) " << '\n' << buffer << "\n\n";

auto rresult = jsoncons::try_decode_json<matrix_type>(buffer);
assert(rresult);
auto& m2(*rresult);

assert(m1 == m2);

auto jresult = jsoncons::try_decode_json<jsoncons::json>(buffer);
assert(jresult);
auto j1(*jresult);

auto mresult = j1.try_as<matrix_type>();
assert(mresult);
auto& m3(*mresult);
assert(m1 == m3);

jsoncons::json j2{m1};
assert(j1 == j2);

Output:

(1)
 -0.997497   0.617481  -0.299417    0.49321
  0.127171   0.170019   0.791925  -0.651784
 -0.613392 -0.0402539    0.64568   0.717887

(2)
[
    [-0.9974974822229682, 0.6174810022278512, -0.2994170964690085, 0.4932096316415906],
    [0.12717062898648024, 0.1700186162907804, 0.7919248023926511, -0.651783806878872],
    [-0.6133915219580676, -0.04025391399884026, 0.6456801049836727, 0.717886898403882]
]

See also

allocator_set
decode_json, try_decode_json
encode_json, encode_json_pretty, try_encode_json, try_encode_json_pretty
basic_json