#ifndef AIKIDO_CONSTRAINT_DIFFERENTIABLEINTERSECTION_HPP_
#define AIKIDO_CONSTRAINT_DIFFERENTIABLEINTERSECTION_HPP_

#include <memory>

#include <Eigen/Dense>

#include "aikido/constraint/Differentiable.hpp"
#include "aikido/statespace/StateSpace.hpp"

namespace aikido {
namespace constraint {

/// Contains n constraints that take the same statespace.
/// getValue and getJacobian returns stacked vector and matrix.
class DifferentiableIntersection : public Differentiable
{
public:
  DifferentiableIntersection(
      std::vector<DifferentiablePtr> _constraints,
      statespace::ConstStateSpacePtr _stateSpace);

  // Documentation inherited.
  std::size_t getConstraintDimension() const override;

  // Documentation inherited.
  void getValue(const statespace::StateSpace::State* _s, Eigen::VectorXd& _out)
      const override;

  // Documentation inherited.
  void getJacobian(
      const statespace::StateSpace::State* _s,
      Eigen::MatrixXd& _out) const override;

  // Documentation inherited.
  std::vector<ConstraintType> getConstraintTypes() const override;

  // Documentation inherited.
  statespace::ConstStateSpacePtr getStateSpace() const override;

  // Documentation inherited.
  void getValueAndJacobian(
      const statespace::StateSpace::State* _s,
      Eigen::VectorXd& _val,
      Eigen::MatrixXd& _jac) const override;

private:
  std::vector<DifferentiablePtr> mConstraints;
  statespace::ConstStateSpacePtr mStateSpace;
};

} // namespace constraint
} // namespace aikido

#endif


#ifndef NETKET_IMAGINARY_TIME_PROPAGATION_HPP
#define NETKET_IMAGINARY_TIME_PROPAGATION_HPP

#include <Eigen/Dense>

#include "Dynamics/TimeStepper/abstract_time_stepper.hpp"
#include "Operator/MatrixWrapper/matrix_wrapper.hpp"
#include "Operator/operator.hpp"
#include "Output/json_output_writer.hpp"
#include "Stats/stats.hpp"

namespace netket {

class ImagTimePropagation {
 public:
  class Iterator;

  using StateVector = Eigen::VectorXcd;
  using Stepper = ode::AbstractTimeStepper<StateVector>;
  using Matrix = AbstractMatrixWrapper<>;

  using ObsEntry = std::pair<std::string, std::unique_ptr<Matrix>>;

  ImagTimePropagation(Matrix& matrix, Stepper& stepper, double t0,
                      StateVector initial_state)
      : matrix_(matrix),
        stepper_(stepper),
        t_(t0),
        state_(std::move(initial_state)) {
    ode_system_ = [this](const StateVector& x, StateVector& dxdt,
                         double /*t*/) { dxdt.noalias() = -matrix_.Apply(x); };
  }

  void AddObservable(const AbstractOperator& observable,
                     const std::string& name,
                     const std::string& matrix_type = "Sparse") {
    auto wrapper = CreateMatrixWrapper(observable, matrix_type);
    observables_.emplace_back(name, std::move(wrapper));
  }

  void Advance(double dt) {
    // Propagate the state
    stepper_.Propagate(ode_system_, state_, t_, dt);
    // renormalize the state to prevent unbounded growth of the norm
    state_.normalize();
    ComputeObservables(state_);
    t_ += dt;
  }

  /*void Run(StateVector& initial_state, ) {
    assert(initial_state.size() == Dimension());
    state_ = initial_state;
    for (const auto& step : Iterate(range.t0, )) {
    }
  }*/

  Iterator Iterate(double dt,
                   nonstd::optional<Index> n_iter = nonstd::nullopt) {
    return Iterator(*this, dt, std::move(n_iter));
  }

  void ComputeObservables(const StateVector& state) {
    const auto mean_variance = matrix_.MeanVariance(state);
    obsmanager_.Reset("Energy");
    obsmanager_.Push("Energy", mean_variance[0].real());
    obsmanager_.Reset("EnergyVariance");
    obsmanager_.Push("EnergyVariance", mean_variance[1].real());

    for (const auto& entry : observables_) {
      const auto& name = entry.first;
      const auto& obs = entry.second;
      obsmanager_.Reset(name);

      const auto value = obs->Mean(state).real();
      obsmanager_.Push(name, value);
    }
  }

  const ObsManager& GetObsManager() const { return obsmanager_; }

  double GetTime() const { return t_; }
  void SetTime(double t) { t_ = t; }

  class Iterator {
   public:
    // typedefs required for iterators
    using iterator_category = std::input_iterator_tag;
    using difference_type = Index;
    using value_type = Index;
    using pointer_type = Index*;
    using reference_type = Index&;

   private:
    ImagTimePropagation& driver_;
    nonstd::optional<Index> n_iter_;
    double dt_;

    Index cur_iter_;

   public:
    Iterator(ImagTimePropagation& driver, double dt,
             nonstd::optional<Index> n_iter)
        : driver_(driver), n_iter_(std::move(n_iter)), dt_(dt), cur_iter_(0) {}

    Index operator*() const { return cur_iter_; };
    Iterator& operator++() {
      driver_.Advance(dt_);
      cur_iter_ += 1;
      return *this;
    }

    // TODO(C++17): Replace with comparison to special Sentinel type, since
    // C++17 allows end() to return a different type from begin().
    bool operator!=(const Iterator&) {
      return !n_iter_.has_value() || cur_iter_ < n_iter_.value();
    }
    // pybind11::make_iterator requires operator==
    bool operator==(const Iterator& other) { return !(*this != other); }

    Iterator begin() const { return *this; }
    Iterator end() const { return *this; }
  };

 private:
  Matrix& matrix_;
  Stepper& stepper_;
  ode::OdeSystemFunction<StateVector> ode_system_;

  double t_;
  StateVector state_;

  std::vector<ObsEntry> observables_;
  ObsManager obsmanager_;
};

}  // namespace netket

#endif  // NETKET_IMAGINARY_TIME_PROPAGATION_HPP


/*
 * Copyright (c) 2019 Opticks Team. All Rights Reserved.
 *
 * This file is part of Opticks
 * (see https://bitbucket.org/simoncblyth/opticks).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdio>
#include <cfloat>
#include <algorithm>
#include <vector>
#include <sstream>
#include <iomanip>

#include <boost/algorithm/string/join.hpp>

#ifdef _MSC_VER
// members needs to have dll-interface to be used by clients
#pragma warning( disable : 4251 )
#endif

#include "NGLM.hpp"
#include "GLMPrint.hpp"

void assert_same(const char* msg, const glm::vec4& a, const glm::vec4& b)
{
    for(unsigned int k=0 ; k < 4 ; k++)
    {
        if(a[k] == b[k]) continue ;

        char rep[128];
        snprintf(rep, 128, "GLMPrint.assert_same %s  [%u] %.3f %.3f \n", msg, k, a[k], b[k] );
        //assert(0 && rep );

        printf("%s", rep );
    }

}

void fdump(float* f, unsigned int n, const char* msg)
{
    if(!f) return ;

    printf("%s\n", msg);
    for(unsigned int i=0 ; i < n ; i++)
    {
        if(i%4 == 0) printf("\n");
        printf(" %10.4f ", f[i] );
    }
    printf("\n");
}

void print(const glm::mat4& m, const char* msg)
{
    printf("%s mat4\n", msg);

    for (int j=0; j<4; j++)
    {
        for (int i=0; i<4; i++) printf("%10.3f ",m[i][j]);
        printf("\n");
    }
}

void minmax(glm::mat4& m, float& mn, float& mx)
{
    float* f = glm::value_ptr(m);
    for(unsigned int i=0 ; i < 16 ; i++)
    {
         float v = *(f+i);
         if(v>mx) mx = v ;
         if(v<mn) mn = v ;
         printf(" %2d %f \n", i, v );
    }
}

float absmax(glm::mat4& m)
{
    float mn(FLT_MAX);
    float mx(-FLT_MIN);
    minmax(m, mn, mx);
    return std::max( fabs(mn), fabs(mx));
}

void print(const glm::quat& q, const char* msg)
{
    printf("%15s quat %15.6f : %15.6f %15.6f %15.6f  \n", msg, q.w, q.x, q.y, q.z);
}

void print(const glm::vec2& v, const char* msg)
{
    printf("%15s vec2  %10.3f %10.3f \n", msg, v.x, v.y );
}

void print(const glm::vec4& v, const char* msg)
{
    printf("%15s vec4  %10.3f %10.3f %10.3f %10.3f \n", msg, v.x, v.y, v.z, v.w);
}

void print(const glm::vec4& v0, const char* msg0, const glm::vec4& v1, const char* msg1)
{
    const char* fmt =
"%15s vec4  %10.3f %10.3f %10.3f %10.3f   "
"%15s vec4  %10.3f %10.3f %10.3f %10.3f \n" ;
    printf(fmt,
           msg0, v0.x, v0.y, v0.z, v0.w,
           msg1, v1.x, v1.y, v1.z, v1.w
         );
}

void print(const glm::vec4& v, const char* tmpl, unsigned int incl)
{
    char msg[128];
    snprintf(msg, 128, tmpl, incl);
    printf("%15s vec4  %10.3f %10.3f %10.3f %10.3f \n", msg, v.x, v.y, v.z, v.w);
}

void print(const glm::ivec4& v, const char* msg) // _i
{
    printf("%15s ivec4  %7d %7d %7d %7d \n", msg, v.x, v.y, v.z, v.w);
}

void print(const glm::uvec4& v, const char* msg)  // _u
{
    printf("%15s uvec4  %7u %7u %7u %7u \n", msg, v.x, v.y, v.z, v.w);
}

void print(const glm::vec3& v, const char* msg)
{
    printf("%15s vec3  %10.3f %10.3f %10.3f  \n", msg, v.x, v.y, v.z );
}

void print(float* f, const char* msg, unsigned int n)
{
    printf("%s", msg);
    for(unsigned int i=0 ; i < n ; i++)
    {
        if(i % 4 == 0) printf("\n");
        printf(" %15.3f ", *(f+i)) ;
    }
    printf("\n");
}

void print( const glm::vec4& a, const glm::vec4& b, const glm::vec4& c, const char* msg)
{
    printf("%15s vec4*3 "
      "%10.3f %10.3f %10.3f %10.3f    "
      "%10.3f %10.3f %10.3f %10.3f    "
      "%10.3f %10.3f %10.3f %10.3f    "
      " \n",
       msg,
       a.x, a.y, a.z, a.w,
       b.x, b.y, b.z, b.w,
       c.x, c.y, c.z, c.w
     );
}

void print( const glm::vec3& a, const glm::vec3& b, const glm::vec3& c, const glm::vec3& d, const char* msg)
{
    printf("%15s vec3*4 "
      "%10.3f %10.3f %10.3f     "
      "%10.3f %10.3f %10.3f     "
      "%10.3f %10.3f %10.3f     "
      "%10.3f %10.3f %10.3f     "
      " \n",
       msg,
       a.x, a.y, a.z,
       b.x, b.y, b.z,
       c.x, c.y, c.z,
       d.x, d.y, d.z
     );
}


//          Copyright Rein Halbersma 2014-2021.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50

#include <bitset/compatible/bit_set.hpp>        // bit_set
#include <bitset/compatible/bitset.hpp>         // bitset
#include <bitset/compatible/dynamic_bitset.hpp> // dynamic_bitset
#include <bitset/exhaustive.hpp>                // all_doubleton_set_pairs
#include <bitset/primitives.hpp>                // mem_is_subset_of, mem_is_proper_subset_of
#include <xstd/bit_set.hpp>                     // bit_set
#include <boost/dynamic_bitset.hpp>             // dynamic_bitset
#include <boost/mpl/vector.hpp>                 // vector
#include <boost/test/unit_test.hpp>             // BOOST_AUTO_TEST_SUITE, BOOST_AUTO_TEST_SUITE_END, BOOST_AUTO_TEST_CASE_TEMPLATE
#include <cstdint>                              // uint8_t, uint16_t, uint32_t
#include <bitset>                               // bitset

BOOST_AUTO_TEST_SUITE(Quartic)

using namespace xstd;

using bitset_types = boost::mpl::vector
<       std::bitset< 0>
,       std::bitset< 1>
,       std::bitset<31>
,       std::bitset<32>
,       boost::dynamic_bitset<>
,       bit_set< 0, uint8_t>
,       bit_set< 1, uint8_t>
,       bit_set< 7, uint8_t>
,       bit_set< 8, uint8_t>
,       bit_set< 9, uint8_t>
,       bit_set<15, uint8_t>
,       bit_set<16, uint8_t>
,       bit_set<17, uint8_t>
,       bit_set<24, uint8_t>
>;

BOOST_AUTO_TEST_CASE_TEMPLATE(IsSubsetOf, T, bitset_types)
{
        all_doubleton_set_pairs<T>(mem_is_subset_of());
}

BOOST_AUTO_TEST_CASE_TEMPLATE(IsProperSubsetOf, T, bitset_types)
{
        all_doubleton_set_pairs<T>(mem_is_proper_subset_of());
}

BOOST_AUTO_TEST_SUITE_END()


//---------------------------------------------------------------------------//
// Copyright (c) 2020 Mikhail Komarov <nemo@nil.foundation>
// Copyright (c) 2019 Alexey Moskvin
// Copyright (c) 2020 Ilias Khairullin <ilias@nil.foundation>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//---------------------------------------------------------------------------//

#ifndef BOOST_MULTIPRECISION_MONTGOMERY_PARAMS_HPP
#define BOOST_MULTIPRECISION_MONTGOMERY_PARAMS_HPP

#include <boost/container/vector.hpp>

#include <boost/type_traits/is_integral.hpp>

#include <nil/crypto3/multiprecision/cpp_int.hpp>
#include <nil/crypto3/multiprecision/cpp_int/cpp_int_config.hpp>
#include <nil/crypto3/multiprecision/modular/base_params.hpp>
#include <nil/crypto3/multiprecision/modular/barrett_params.hpp>

#include <type_traits>
#include <tuple>
#include <array>
#include <cstddef>    // std::size_t
#include <limits>
#include <string>

namespace nil {
    namespace crypto3 {
        namespace multiprecision {
            namespace backends {
                /**
                 * Parameters for Montgomery Reduction
                 */
                template<typename Backend>
                class montgomery_params : public base_params<Backend> {
                    typedef number<Backend> number_type;

                protected:
                    template<typename Number>
                    inline void initialize_montgomery_params(const Number& p) {
                        this->initialize_base_params(p);
                        find_const_variables(p);
                    }

                    inline void initialize_montgomery_params(const montgomery_params<Backend>& p) {
                        this->initialize_base_params(p);
                        find_const_variables(p);
                    }

                    limb_type monty_inverse(limb_type a) {
                        if (a % 2 == 0) {
                            throw std::invalid_argument("Monty_inverse only valid for odd integers");
                        }

                        limb_type b = 1;
                        limb_type r = 0;

                        for (size_t i = 0; i != sizeof(limb_type) * CHAR_BIT; ++i) {
                            const limb_type bi = b % 2;
                            r >>= 1;
                            r += bi << (sizeof(limb_type) * CHAR_BIT - 1);

                            b -= a * bi;
                            b >>= 1;
                        }

                        // Now invert in addition space
                        r = (~static_cast<limb_type>(0) - r) + 1;

                        return r;
                    }

                    template<typename T>
                    void find_const_variables(const T& pp) {
                        number_type p = pp;
                        if (p <= 0 || !(p % 2)) {
                            return;
                        }

                        m_p_words = this->m_mod.backend().size();

                        m_p_dash = monty_inverse(this->m_mod.backend().limbs()[0]);

                        number_type r;

                        default_ops::eval_bit_set(r.backend(), m_p_words * sizeof(limb_type) * CHAR_BIT);

                        m_r2 = r * r;
                        barrett_params<Backend> barrettParams(this->m_mod);
                        barrettParams.barret_reduce(m_r2.backend());
                    }

                public:
                    montgomery_params() : base_params<Backend>() {
                    }

                    template<typename Number>
                    explicit montgomery_params(const Number& p) : base_params<Backend>(p) {
                        initialize_montgomery_params(p);
                    }

                    inline const number_type& r2() const {
                        return m_r2;
                    }

                    inline limb_type p_dash() const {
                        return m_p_dash;
                    }

                    inline size_t p_words() const {
                        return m_p_words;
                    }

                    template<class V>
                    montgomery_params& operator=(const V& v) {
                        initialize_montgomery_params(v);
                        return *this;
                    }

                    inline void montgomery_reduce(Backend& result) const {
                        using default_ops::eval_lt;
                        using default_ops::eval_multiply_add;

                        typedef cpp_int_backend<sizeof(limb_type) * CHAR_BIT * 3, sizeof(limb_type) * CHAR_BIT * 3,
                                                unsigned_magnitude, unchecked, void>
                            cpp_three_int_backend;

                        const size_t p_size = m_p_words;
                        const limb_type p_dash = m_p_dash;
                        const size_t z_size = 2 * (p_words() + 1);

                        boost::container::vector<limb_type> z(
                            result.size(), 0);    // container::vector<limb_type, alloc> z(result.size(), 0);
                        for (size_t i = 0; i < result.size(); ++i) {
                            z[i] = result.limbs()[i];
                        }

                        if (result.size() < z_size) {
                            result.resize(z_size, z_size);
                            z.resize(z_size, 0);
                        }

                        cpp_three_int_backend w(z[0]);

                        result.limbs()[0] = w.limbs()[0] * p_dash;

                        eval_multiply_add(w, result.limbs()[0], this->m_mod.backend().limbs()[0]);
                        eval_right_shift(w, sizeof(limb_type) * CHAR_BIT);

                        for (size_t i = 1; i != p_size; ++i) {
                            for (size_t j = 0; j < i; ++j) {
                                eval_multiply_add(w, result.limbs()[j], this->m_mod.backend().limbs()[i - j]);
                            }

                            eval_add(w, z[i]);

                            result.limbs()[i] = w.limbs()[0] * p_dash;

                            eval_multiply_add(w, result.limbs()[i], this->m_mod.backend().limbs()[0]);

                            eval_right_shift(w, sizeof(limb_type) * CHAR_BIT);
                        }

                        for (size_t i = 0; i != p_size; ++i) {
                            for (size_t j = i + 1; j != p_size; ++j) {
                                eval_multiply_add(w, result.limbs()[j], this->m_mod.backend().limbs()[p_size + i - j]);
                            }

                            eval_add(w, z[p_size + i]);

                            result.limbs()[i] = w.limbs()[0];

                            eval_right_shift(w, sizeof(limb_type) * CHAR_BIT);
                        }

                        eval_add(w, z[z_size - 1]);

                        result.limbs()[p_size] = w.limbs()[0];
                        result.limbs()[p_size + 1] = w.limbs()[1];

                        if (result.size() != p_size + 1) {
                            result.resize(p_size + 1, p_size + 1);
                        }
                        result.normalize();
                    }

                protected:
                    number_type m_r2;
                    limb_type m_p_dash;
                    size_t m_p_words;
                };

                // // fixed precision montgomery params type which supports compile-time execution
                // template<unsigned MinBits, cpp_integer_type SignType, cpp_int_check_type Checked>
                // class montgomery_params<cpp_int_backend<MinBits, MinBits, SignType, Checked, void>>
                //     : public base_params<cpp_int_backend<MinBits, MinBits, SignType, Checked, void>>
                // {
                //  protected:
                //    typedef base_params<cpp_int_backend<MinBits, MinBits, SignType, Checked, void>> base_type;
                //    typedef typename base_type::policy_type policy_type;
                //
                //    typedef typename policy_type::internal_limb_type internal_limb_type;
                //    typedef typename policy_type::internal_double_limb_type internal_double_limb_type;
                //    typedef typename policy_type::Backend Backend;
                //    typedef typename policy_type::Backend_padded_limbs Backend_padded_limbs;
                //    typedef typename policy_type::Backend_doubled_limbs Backend_doubled_limbs;
                //    typedef typename policy_type::Backend_doubled_padded_limbs Backend_doubled_padded_limbs;
                //    typedef typename policy_type::number_type number_type;
                //
                //    constexpr static auto limbs_count = policy_type::limbs_count;
                //    constexpr static auto limb_bits = policy_type::limb_bits;
                //
                //    constexpr void initialize_montgomery_params(const number_type& p)
                //    {
                //       this->initialize_base_params(p);
                //       find_const_variables(p);
                //       find_modulus_mask();
                //    }
                //
                //    constexpr internal_limb_type monty_inverse(internal_limb_type a)
                //    {
                //       if (a % 2 == 0)
                //       {
                //          throw std::invalid_argument("Monty_inverse only valid for odd integers");
                //       }
                //
                //       internal_limb_type b = 1;
                //       internal_limb_type r = 0;
                //
                //       for (size_t i = 0; i != limb_bits; ++i)
                //       {
                //          const internal_limb_type bi = b % 2;
                //          r >>= 1;
                //          r += bi << (limb_bits - 1);
                //
                //          b -= a * bi;
                //          b >>= 1;
                //       }
                //
                //       // Now invert in addition space
                //       r = (~static_cast<internal_limb_type>(0) - r) + 1;
                //
                //       return r;
                //    }
                //
                //    constexpr void find_const_variables(const number_type& pp)
                //    {
                //       using padded_dbl_number_type = number<Backend_doubled_padded_limbs>;
                //
                //       number_type p = pp;
                //       if (p <= 0 || !(p % 2))
                //       {
                //          return;
                //       }
                //
                //       m_p_words = this->m_mod.backend().size();
                //
                //       m_p_dash = monty_inverse(this->m_mod.backend().limbs()[0]);
                //
                //       padded_dbl_number_type r;
                //
                //       default_ops::eval_bit_set(r.backend(), m_p_words * limb_bits);
                //
                //       r = r * r;
                //       barrett_params<Backend> barrettParams(this->m_mod);
                //       barrettParams.barret_reduce(r.backend());
                //       m_r2 = static_cast<Backend>(r.backend());
                //    }
                //
                //    constexpr void find_modulus_mask()
                //    {
                //       m_modulus_mask = static_cast<internal_limb_type>(1u);
                //       eval_left_shift(m_modulus_mask, this->m_mod.backend().size() * limb_bits);
                //       eval_subtract(m_modulus_mask, static_cast<internal_limb_type>(1u));
                //    }
                //
                //  public:
                //    constexpr montgomery_params()
                //        : base_type(), m_p_dash(), m_p_words(), m_modulus_mask() {}
                //
                //    constexpr explicit montgomery_params(const number_type& p)
                //        : base_type(p), m_p_dash(), m_p_words(), m_modulus_mask()
                //    {
                //       initialize_montgomery_params(p);
                //    }
                //
                //    constexpr const auto& r2() const { return m_r2; }
                //
                //    constexpr auto p_dash() const { return m_p_dash; }
                //
                //    constexpr auto p_words() const { return m_p_words; }
                //
                //    constexpr const auto& modulus_mask() const { return m_modulus_mask; }
                //
                //    constexpr montgomery_params& operator=(const number_type& p)
                //    {
                //       initialize_montgomery_params(p);
                //       return *this;
                //    }
                //
                //    template<typename BackendT,
                //        typename = typename boost::enable_if<
                //            /// result should fit in the output parameter
                //            max_precision<BackendT>::value >= max_precision<Backend>::value>::type>
                //    constexpr void montgomery_reduce(BackendT& result) const
                //    {
                //       BackendT input(result);
                //       montgomery_reduce(result, input);
                //    }
                //
                //    template<typename Backend1, typename Backend2,
                //        typename = typename boost::enable_if<
                //            /// result should fit in the output parameter
                //            max_precision<Backend1>::value >= max_precision<Backend>::value &&
                //            /// input number should be represented by backend of appropriate size
                //            max_precision<Backend2>::value <= max_precision<Backend_doubled_limbs>::value>::type>
                //    constexpr void montgomery_reduce(Backend1& result, const Backend2& input) const
                //    {
                //       Backend_doubled_padded_limbs accum(input);
                //       Backend_doubled_padded_limbs prod;
                //
                //       for (auto i = 0; i < this->m_mod.backend().size(); ++i)
                //       {
                //          eval_multiply(prod, this->m_mod.backend(), accum.limbs()[i] * p_dash());
                //          eval_left_shift(prod, i * limb_bits);
                //          eval_add(accum, prod);
                //       }
                //
                //       eval_right_shift(accum, this->m_mod.backend().size() * limb_bits);
                //
                //       if (accum.compare(this->m_mod.backend()) >= 0)
                //       {
                //          eval_subtract(accum, this->m_mod.backend());
                //       }
                //       eval_bitwise_and(accum, m_modulus_mask);
                //       result = accum;
                //    }
                //
                //    template<typename Backend1, typename Backend2,
                //        typename = typename boost::enable_if<
                //            /// result should fit in the output parameter
                //            max_precision<Backend1>::value >= max_precision<Backend>::value &&
                //            /// multiplier should fit in input parameter type
                //            max_precision<Backend2>::value >= max_precision<Backend1>::value>::type>
                //    constexpr void montgomery_mul(Backend1& result, const Backend2& y) const
                //    {
                //       Backend2 x(result);
                //       montgomery_mul(result, x, y);
                //    }
                //
                //    template<typename Backend1, typename Backend2,
                //             typename = typename boost::enable_if<
                //                 /// result should fit in the output parameter
                //                 max_precision<Backend1>::value >= max_precision<Backend>::value &&
                //                 /// multipliers should consist of the same number of limbs as modulus
                //                 max_precision<Backend2>::value >= max_precision<Backend>::value>::type>
                //    constexpr void montgomery_mul(Backend1& result, const Backend2& x, const Backend2& y) const
                //    {
                //       using default_ops::eval_lt;
                //
                //       /// input parameters should be lesser than modulus
                //       BOOST_ASSERT(eval_lt(x, this->m_mod.backend()) && eval_lt(y, this->m_mod.backend()));
                //
                //       Backend_padded_limbs A(internal_limb_type(0u));
                //
                //       for (auto i = 0; i < this->m_mod.backend().size(); i++)
                //       {
                //          internal_limb_type u_i = (A.limbs()[0] + get_limb_value(x, i) * get_limb_value(y, 0)) *
                //          p_dash();
                //
                //          // A += x[i] * y + u_i * m followed by a 1 limb-shift to the right
                //          internal_limb_type k = 0;
                //          internal_limb_type k2 = 0;
                //
                //          internal_double_limb_type z = static_cast<internal_double_limb_type>(get_limb_value(y, 0)) *
                //                                        static_cast<internal_double_limb_type>(get_limb_value(x, i)) +
                //                                        A.limbs()[0] + k;
                //          // TODO: maybe error here in static_cast<internal_limb_type>(z) if internal_double_limb_type
                //          is nil::crypto3::multiprecision::number internal_double_limb_type z2 =
                //          static_cast<internal_double_limb_type>(get_limb_value(this->m_mod.backend(), 0)) *
                //                                         static_cast<internal_double_limb_type>(u_i) +
                //                                         static_cast<internal_limb_type>(z) + k2;
                //          k = z >> std::numeric_limits<internal_limb_type>::digits;
                //          k2 = z2 >> std::numeric_limits<internal_limb_type>::digits;
                //
                //          for (auto j = 1; j < this->m_mod.backend().size(); ++j)
                //          {
                //             internal_double_limb_type t = static_cast<internal_double_limb_type>(get_limb_value(y,
                //             j)) *
                //                                           static_cast<internal_double_limb_type>(get_limb_value(x,
                //                                           i)) + A.limbs()[j] + k;
                //             // TODO: maybe error here in static_cast<internal_limb_type>(t) if
                //             internal_double_limb_type is nil::crypto3::multiprecision::number
                //             internal_double_limb_type t2 =
                //             static_cast<internal_double_limb_type>(get_limb_value(this->m_mod.backend(), j)) *
                //                                            static_cast<internal_double_limb_type>(u_i) +
                //                                            static_cast<internal_limb_type>(t) + k2;
                //             A.limbs()[j-1] = t2;
                //             k = t >> std::numeric_limits<internal_limb_type>::digits;
                //             k2 = t2 >> std::numeric_limits<internal_limb_type>::digits;
                //          }
                //          internal_double_limb_type tmp =
                //          static_cast<internal_double_limb_type>(A.limbs()[this->m_mod.backend().size()]) + k + k2;
                //          A.limbs()[this->m_mod.backend().size()-1] = tmp;
                //          A.limbs()[this->m_mod.backend().size()] = tmp >>
                //          std::numeric_limits<internal_limb_type>::digits;
                //       }
                //       A.resize(this->m_mod.backend().size(), 1);
                //
                //       if (A.compare(this->m_mod.backend()) >= 0)
                //       {
                //          eval_subtract(A, this->m_mod.backend());
                //       }
                //       eval_bitwise_and(A, m_modulus_mask);
                //       result = A;
                //    }
                //
                //    // TODO: replace in modular_params - need to refactor modular_adaptor structure
                //    template<typename Backend1, typename Backend2,
                //        typename = typename boost::enable_if<
                //            /// result should fit in the output parameter
                //            max_precision<Backend1>::value >= max_precision<Backend>::value>::type>
                //    constexpr void mont_exp(Backend1& result, const Backend2& exp) const
                //    {
                //       Backend1 a(result);
                //       mont_exp(result, a, exp);
                //    }
                //
                //    // TODO: replace in modular_params - need to refactor modular_adaptor structure
                //    template<typename Backend1, typename Backend2, typename Backend3,
                //             typename = typename boost::enable_if<
                //                 /// result should fit in the output parameter
                //                 max_precision<Backend1>::value >= max_precision<Backend>::value &&
                //                 /// input number should fit modulus
                //                 max_precision<Backend2>::value >= max_precision<Backend>::value>::type>
                //    constexpr void mont_exp(Backend1& result, const Backend2& a, Backend3 exp) const
                //    {
                //       using default_ops::eval_eq;
                //       using default_ops::eval_right_shift;
                //       using default_ops::eval_left_shift;
                //       using default_ops::eval_modulus;
                //
                //       Backend_doubled_limbs tmp(static_cast<internal_limb_type>(1u));
                //       eval_multiply(tmp, r2().backend());
                //       montgomery_reduce(tmp);
                //       Backend R_mod_m(tmp);
                //
                //       Backend base(a);
                //
                //       Backend3 zero(static_cast<internal_limb_type>(0u));
                //       if (eval_eq(exp, zero))
                //       {
                //          result = static_cast<internal_limb_type>(1u);
                //          return;
                //       }
                //       if (eval_eq(this->m_mod.backend(), static_cast<internal_limb_type>(1u)))
                //       {
                //          result = static_cast<internal_limb_type>(0u);
                //          return;
                //       }
                //
                //       while (true)
                //       {
                //          internal_limb_type lsb = exp.limbs()[0] & 1u;
                //          eval_right_shift(exp, static_cast<internal_limb_type>(1u));
                //          if (lsb)
                //          {
                //             montgomery_mul(R_mod_m, base);
                //             if (eval_eq(exp, zero))
                //             {
                //                break;
                //             }
                //          }
                //          montgomery_mul(base, base);
                //       }
                //       result = R_mod_m;
                //    }
                //
                //  protected:
                //    number_type m_r2;
                //    internal_limb_type m_p_dash;
                //    size_t m_p_words;
                //    Backend_padded_limbs m_modulus_mask;
                // };
            }    // namespace backends
        }        // namespace multiprecision
    }            // namespace crypto3
}    // namespace nil

#endif


/*
    Copyright 2013 Adobe
    Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************************/

#ifndef SUDOKU_HPP
#define SUDOKU_HPP

/****************************************************************************************************/

#include <adobe/config.hpp>

#include <boost/array.hpp>
#include <boost/function.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_adaptor.hpp>

#include <string>
#include <stdexcept>

/****************************************************************************************************/

namespace bfs = boost::filesystem;

/****************************************************************************************************/

namespace sudoku {

/****************************************************************************************************/

template <typename Iterator>
int get_box(Iterator i) {
#if 0
    switch (i.row())
    {
        case 0: case 1: case 2:
        switch (i.col())
        {
            case 0: case 1: case 2: return 0;
            case 3: case 4: case 5: return 1;
            case 6: case 7: case 8: return 2;
        }

        case 3: case 4: case 5:
        switch (i.col())
        {
            case 0: case 1: case 2: return 3;
            case 3: case 4: case 5: return 4;
            case 6: case 7: case 8: return 5;
        }

        case 6: case 7: case 8:
        switch (i.col())
        {
            case 0: case 1: case 2: return 6;
            case 3: case 4: case 5: return 7;
            case 6: case 7: case 8: return 8;
        }
    }

    throw std::runtime_error("get_box");
#else
    return (i.row() / 3) * 3 + (i.col() / 3);
#endif
}

/****************************************************************************************************/

template <typename Iterator>
class row_iterator_adaptor
    : public boost::iterator_adaptor<row_iterator_adaptor<Iterator>, Iterator> {
public:
    typedef typename boost::iterator_adaptor<row_iterator_adaptor<Iterator>, Iterator>::reference
    reference;

    row_iterator_adaptor() {}

    row_iterator_adaptor(Iterator iterator) : row_iterator_adaptor::iterator_adaptor_(iterator) {}

    template <class U>
    row_iterator_adaptor(const row_iterator_adaptor<U>& iterator)
        : row_iterator_adaptor::iterator_adaptor_(iterator.base()) {}

    int col() const { return this->base_reference().col_m; }
    int row() const { return this->base_reference().row_m; }

    const char* traversal_subject_type() const { return "Row"; }
    std::size_t traversal_subject_identifier() const { return row() + 1; }

private:
    friend class boost::iterator_core_access;

    void increment() { this->base_reference().inc_col(); }
    void decrement() { this->base_reference().dec_col(); }
    reference dereference() const { return *this->base(); }
};

/****************************************************************************************************/

template <typename Iterator>
class col_iterator_adaptor
    : public boost::iterator_adaptor<col_iterator_adaptor<Iterator>, Iterator> {
public:
    typedef typename boost::iterator_adaptor<col_iterator_adaptor<Iterator>, Iterator>::reference
    reference;

    col_iterator_adaptor() {}

    col_iterator_adaptor(Iterator iterator) : col_iterator_adaptor::iterator_adaptor_(iterator) {}

    template <class U>
    col_iterator_adaptor(const col_iterator_adaptor<U>& iterator)
        : col_iterator_adaptor::iterator_adaptor_(iterator.base()) {}

    int col() const { return this->base_reference().col_m; }
    int row() const { return this->base_reference().row_m; }

    const char* traversal_subject_type() const { return "Col"; }
    std::size_t traversal_subject_identifier() const { return col() + 1; }

private:
    friend class boost::iterator_core_access;

    void increment() { this->base_reference().inc_row(); }
    void decrement() { this->base_reference().dec_row(); }
    reference dereference() const { return *this->base(); }
};

/****************************************************************************************************/

template <typename Iterator>
class box_iterator_adaptor
    : public boost::iterator_adaptor<box_iterator_adaptor<Iterator>, Iterator> {
public:
    typedef typename boost::iterator_adaptor<box_iterator_adaptor<Iterator>, Iterator>::reference
    reference;

    box_iterator_adaptor() {}

    box_iterator_adaptor(Iterator iterator) : box_iterator_adaptor::iterator_adaptor_(iterator) {}

    template <class U>
    box_iterator_adaptor(const box_iterator_adaptor<U>& iterator)
        : box_iterator_adaptor::iterator_adaptor_(iterator.base()) {}

    int col() const { return this->base_reference().col_m; }
    int row() const { return this->base_reference().row_m; }

    const char* traversal_subject_type() const { return "Box"; }
    std::size_t traversal_subject_identifier() const { return get_box(*this) + 1; }

private:
    friend class boost::iterator_core_access;

    void increment() {
        if (++(this->base_reference().col_m) % 3 == 0) {
            this->base_reference().col_m -= 3;
            this->base_reference().inc_row();
        }
    }

    void decrement() {
        if ((this->base_reference().col_m)-- % 3 == 0) {
            this->base_reference().col_m += 3;
            this->base_reference().dec_row();
        }
    }

    reference dereference() const { return *this->base(); }
};

/****************************************************************************************************/

#if 0
#pragma mark -
#endif

/****************************************************************************************************/

class possibility_set_t {
public:
    typedef boost::array<bool, 9> set_t;
    typedef set_t::iterator iterator;
    typedef set_t::const_iterator const_iterator;

    explicit possibility_set_t(bool default_to = true) { reset_to(default_to); }

    possibility_set_t(const possibility_set_t& rhs) : set_m(rhs.set_m) {}

    possibility_set_t& operator=(const possibility_set_t& rhs) {
        set_m = rhs.set_m;
        return *this;
    }

    void reset_to(bool value) {
        for (iterator first(set_m.begin()), last(set_m.end()); first != last; ++first)
            *first = value;
    }

    iterator begin() { return set_m.begin(); }
    iterator end() { return set_m.end(); }

    const_iterator begin() const { return set_m.begin(); }
    const_iterator end() const { return set_m.end(); }

    std::size_t size() const { return set_m.size(); }

    std::size_t count_possibilities() const {
        return std::accumulate(set_m.begin(), set_m.end(), 0);
    }
    std::size_t count_impossibilities() const { return 9 - count_possibilities(); }

    bool includes(const possibility_set_t& rhs) const {
        for (const_iterator first1(set_m.begin()), last1(set_m.end()), first2(rhs.set_m.end());
             first1 != last1; ++first1)
            if (*first1 && !*first2)
                return false;

        return true;
    }

    // This is the reason we have a possibility_set_t : off-by-one access

    bool& operator[](std::size_t x) { return set_m[x - 1]; }
    const bool& operator[](std::size_t x) const { return set_m[x - 1]; }

private:
    set_t set_m;
};

/****************************************************************************************************/

inline std::ostream& operator<<(std::ostream& s, const possibility_set_t& x) {
    s << "{";

    std::size_t count(0);

    for (possibility_set_t::const_iterator first(x.begin()), last(x.end()); first != last;
         ++first) {
        ++count;
        if (*first)
            s << " " << count;
    }

    s << " }";

    return s;
}

/****************************************************************************************************/

inline possibility_set_t operator|(const possibility_set_t& x, const possibility_set_t& y) {
    possibility_set_t result(x);

    for (int i(1); i <= 9; ++i)
        result[i] = result[i] || y[i];

    return result;
}

/****************************************************************************************************/

inline possibility_set_t& operator|=(possibility_set_t& x, const possibility_set_t& y) {
    x = x | y;
    return x;
}

/****************************************************************************************************/

inline possibility_set_t operator&(const possibility_set_t& x, const possibility_set_t& y) {
    possibility_set_t result(x);

    for (int i(1); i <= 9; ++i)
        result[i] = result[i] && y[i];

    return result;
}

/****************************************************************************************************/

inline possibility_set_t& operator&=(possibility_set_t& x, const possibility_set_t& y) {
    x = x & y;
    return x;
}

/****************************************************************************************************/

inline possibility_set_t operator-(const possibility_set_t& x, const possibility_set_t& y) {
    possibility_set_t result;

    for (int i(1); i <= 9; ++i)
        result[i] = x[i] & !y[i];

    return result;
}

/****************************************************************************************************/

inline possibility_set_t& operator-=(possibility_set_t& x, const possibility_set_t& y) {
    x = x - y;
    return x;
}

/****************************************************************************************************/

inline possibility_set_t operator+(const possibility_set_t& x, const possibility_set_t& y) {
    return x | y;
}

/****************************************************************************************************/

inline possibility_set_t& operator+=(possibility_set_t& x, const possibility_set_t& y) {
    x = x + y;
    return x;
}

/****************************************************************************************************/

inline bool operator==(const possibility_set_t& x, const possibility_set_t& y) {
    for (int i(1); i <= 9; ++i)
        if (x[i] != y[i])
            return false;

    return true;
}

/****************************************************************************************************/

inline bool operator!=(const possibility_set_t& x, const possibility_set_t& y) { return !(x == y); }

/****************************************************************************************************/

#if 0
#pragma mark -
#endif

/****************************************************************************************************/

class square_t {
public:
    square_t() : value_m(0) {}

    square_t(const square_t& rhs) : value_m(rhs.value_m), possibilities_m(rhs.possibilities_m) {}

    square_t& operator=(const square_t& rhs) {
        value_m = rhs.value_m;
        possibilities_m = rhs.possibilities_m;
        return *this;
    }

    int value_m;
    possibility_set_t possibilities_m;
};

/****************************************************************************************************/

#if 0
#pragma mark -
#endif

/****************************************************************************************************/

class sudoku_t {
public:
    square_t& square(int row, int col) { return grid_m[col * 9 + row]; }
    const square_t& square(int row, int col) const { return grid_m[col * 9 + row]; }

    std::string name_m;

    template <class Value>
    class iter_base
        : public boost::iterator_facade<iter_base<Value>, Value, std::bidirectional_iterator_tag> {
    public:
        iter_base() : row_m(0), col_m(0), g_m(0) {}

        explicit iter_base(Value* p, int row = 0, int col = 0) : row_m(row), col_m(col), g_m(p) {}

        void inc_row() { ++row_m; }
        void dec_row() { --row_m; }

        void inc_col() { ++col_m; }
        void dec_col() { --col_m; }

        int col() { return col_m; }
        int row() { return row_m; }

        int row_m;
        int col_m;

    private:
        friend class boost::iterator_core_access;

        void increment() {
            if (++col_m == 9) {
                col_m = 0;
                ++row_m;
            }
        }

        void decrement() {
            if (col_m-- == 0) {
                col_m = 8;
                --row_m;
            }
        }

        bool equal(iter_base const& other) const {
            return this->row_m == other.row_m && this->col_m == other.col_m;
        }

        Value& dereference() const { return g_m[col_m * 9 + row_m]; }

    private:
        Value* g_m; // always refers to square (0, 0) in the puzzle
    };

    typedef iter_base<square_t> iterator;
    typedef iter_base<const square_t> const_iterator;

    iterator at(int row, int col) { return iterator(&grid_m[0], row, col); }
    const_iterator at(int row, int col) const { return const_iterator(&grid_m[0], row, col); }

    iterator begin() { return at(0, 0); }
    iterator end() { return at(9, 0); }

    const_iterator begin() const { return at(0, 0); }
    const_iterator end() const { return at(9, 0); }

    // REVISIT (fbrereto) : What is to be done about the differing
    //                      end() iterator points between the types?
    //                      end().base() doesn't return the same result
    //                      for the different types; does it matter?

    typedef row_iterator_adaptor<iterator> row_iterator;
    typedef row_iterator_adaptor<const_iterator> const_row_iterator;

    row_iterator row_begin(int row) { return at(row, 0); }
    row_iterator row_end(int row) { return at(row, 9); }

    const_row_iterator row_begin(int row) const { return at(row, 0); }
    const_row_iterator row_end(int row) const { return at(row, 9); }

    typedef col_iterator_adaptor<iterator> col_iterator;
    typedef col_iterator_adaptor<const_iterator> const_col_iterator;

    col_iterator col_begin(int col) { return at(0, col); }
    col_iterator col_end(int col) { return at(9, col); }

    const_col_iterator col_begin(int col) const { return at(0, col); }
    const_col_iterator col_end(int col) const { return at(9, col); }

    typedef box_iterator_adaptor<iterator> box_iterator;
    typedef box_iterator_adaptor<const_iterator> const_box_iterator;

    box_iterator box_begin(int box) {
        std::pair<int, int> c(box_begin_coord(box));
        return at(c.first, c.second);
    }
    box_iterator box_end(int box) {
        std::pair<int, int> c(box_end_coord(box));
        return at(c.first, c.second);
    }

    const_box_iterator box_begin(int box) const {
        std::pair<int, int> c(box_begin_coord(box));
        return at(c.first, c.second);
    }
    const_box_iterator box_end(int box) const {
        std::pair<int, int> c(box_end_coord(box));
        return at(c.first, c.second);
    }

private:
    static std::pair<int, int> box_begin_coord(int box) {
        switch (box) {
        case 0:
            return std::make_pair(0, 0);
        case 1:
            return std::make_pair(0, 3);
        case 2:
            return std::make_pair(0, 6);
        case 3:
            return std::make_pair(3, 0);
        case 4:
            return std::make_pair(3, 3);
        case 5:
            return std::make_pair(3, 6);
        case 6:
            return std::make_pair(6, 0);
        case 7:
            return std::make_pair(6, 3);
        case 8:
            return std::make_pair(6, 6);
        default:
            throw std::runtime_error("box_begin_coord");
        }
    }

    static std::pair<int, int> box_end_coord(int box) {
        switch (box) {
        case 0:
            return std::make_pair(3, 0);
        case 1:
            return std::make_pair(3, 3);
        case 2:
            return std::make_pair(3, 6);
        case 3:
            return std::make_pair(6, 0);
        case 4:
            return std::make_pair(6, 3);
        case 5:
            return std::make_pair(6, 6);
        case 6:
            return std::make_pair(9, 0);
        case 7:
            return std::make_pair(9, 3);
        case 8:
            return std::make_pair(9, 6);
        default:
            throw std::runtime_error("box_end_coord");
        }
    }

    square_t grid_m[81];
};

/****************************************************************************************************/

std::ostream& operator<<(std::ostream& s, const sudoku_t& x) {
    sudoku_t::const_iterator first(x.begin());
    sudoku_t::const_iterator last(x.end());
    int col_count(0);
    int row_count(0);
    const char* hr("------+-------+------");

    for (; first != last; ++first) {
        if (first->value_m)
            s << first->value_m;
        else
            s << '.';

        ++col_count;

        if (col_count % 9 == 0) {
            ++row_count;

            if (row_count == 3 || row_count == 6)
                s << std::endl << hr;

            s << std::endl;
        } else if (col_count % 3 == 0)
            s << " | ";
        else
            s << ' ';
    }

    return s;
}

/****************************************************************************************************/

} // namespace sudoku

/****************************************************************************************************/

#endif

/****************************************************************************************************/


#include "MimicMap.h"
#include <iostream>
#include <random>
#include <unordered_map>
#include <map>
#include <boost/timer/timer.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/unordered_map.hpp>

template<typename T>
T random_key(T from, T to) {
  static std::mt19937_64 rng(0xdeadbeaf);
  std::uniform_int_distribution<T> dist(from, to);
  return static_cast<T>(dist(rng));
}

template<typename M, typename T>
void time_op_random(M& m, T from, T to, int loop) {
  boost::timer::cpu_timer timer;
  for (int i = 0; i < loop; ++i) {
    m[random_key(from, to)] = i;
  }
  std::cout << (static_cast<double>(timer.elapsed().wall) / loop);
}
template<typename M, typename T>
void time_insert_random(M& m, T from, T to, int loop) {
  boost::timer::cpu_timer timer;
  for (int i = 0; i < loop; ++i) {
    const typename M::value_type
      p = std::make_pair(random_key(from, to), i);
    m.insert(p);
  }
  std::cout << (static_cast<double>(timer.elapsed().wall) / loop);
}
template<typename M, typename T>
void time_find_random(M& m, T from, T to, int loop) {
  for (T key = from; key <= to; ++key) {
    const typename M::value_type
      p = std::make_pair(key, key);
    m.insert(p);
  }
  boost::timer::cpu_timer timer;
  for (int i = 0; i < loop; ++i) {
    m.find(random_key(from, to));
  }
  std::cout << (static_cast<double>(timer.elapsed().wall) / loop);
}

std::vector<int>
get_sizes(int min_loop, int max_loop) {
  std::vector<int> counts;
  for(int n = min_loop; n <= max_loop;) {
    counts.push_back(n);
    if (n < 10) {
      ++n;
    } else if (n < 100) {
      n += 10;
    } else if (n < 1000) {
      n += 100;
    } else {
      n += 1000;
    }
  }
  return counts;
}

int main(int argc, char* argv[]) {
  const int from = 0;
  const std::vector<int> sizes = get_sizes(1, 100000);
  const int loop = 1000000;
  {
    std::cerr << "operator[]" << std::endl;
    FILE* fp = freopen("performance_op.dat", "w", stdout);
    std::cout << "# operator[]" << std::endl;
    std::cout << "# MimicMap MimicMap(reserved) unordered_map unordered_map(reserved) flat_map map" << std::endl;
    for (int to : sizes) {
      std::cerr << " " << to << std::endl;
      std::cout << to << " ";
      {
        MimicMap<int, int> m;
        time_op_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        MimicMap<int, int> m;
        m.reserve(from, to);
        time_op_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::unordered_map<int, int> m;
        time_op_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::unordered_map<int, int> m;
        m.reserve(to - from);
        time_op_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        boost::container::flat_map<int, int> m;
        time_op_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::map<int, int> m;
        time_op_random(m, from, to, loop);
      }
      std::cout << std::endl;
    }
    fclose(fp);
    std::cerr << "insert" << std::endl;
    fp = freopen("performance_insert.dat", "w", stdout);
    std::cout << "# insert" << std::endl;
    std::cout << "# MimicMap MimicMap(reserved) unordered_map unordered_map(reserved) flat_map map" << std::endl;
    for (int to : sizes) {
      std::cerr << " " << to << std::endl;
      std::cout << to << " ";
      {
        MimicMap<int, int> m;
        time_insert_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        MimicMap<int, int> m;
        m.reserve(from, to);
        time_insert_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::unordered_map<int, int> m;
        time_insert_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::unordered_map<int, int> m;
        m.reserve(to - from);
        time_insert_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        boost::container::flat_map<int, int> m;
        time_insert_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::map<int, int> m;
        time_insert_random(m, from, to, loop);
      }
      std::cout << std::endl;
    }
    fclose(fp);
    std::cerr << "find" << std::endl;
    fp = freopen("performance_find.dat", "w", stdout);
    std::cout << "# find" << std::endl;
    std::cout << "# MimicMap unordered_map flat_map map" << std::endl;
    for (int to : sizes) {
      std::cerr << " " << to << std::endl;
      std::cout << to << " ";
      {
        MimicMap<int, int> m;
        m.reserve(from, to);
        time_find_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::unordered_map<int, int> m;
        m.reserve(to - from);
        time_find_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        boost::container::flat_map<int, int> m;
        time_find_random(m, from, to, loop);
      }
      std::cout << " ";
      {
        std::map<int, int> m;
        time_find_random(m, from, to, loop);
      }
      std::cout << std::endl;
    }
    fclose(fp);
  }
}


// Author(s): Wieger Wesselink
// Copyright: see the accompanying file COPYING or copy at
// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
/// \file one_point_rewriter_test.cpp
/// \brief Test for PBES rewriters.

#define BOOST_TEST_MODULE find_test
#include <boost/test/included/unit_test_framework.hpp>
#include "mcrl2/data/rewriter.h"
#include "mcrl2/pbes/detail/parse.h"
#include "mcrl2/pbes/rewrite.h"
#include "mcrl2/pbes/rewriters/one_point_rule_rewriter.h"
#include "mcrl2/pbes/rewriters/simplify_rewriter.h"
#include "mcrl2/pbes/txt2pbes.h"
#include "mcrl2/utilities/detail/test_operation.h"

using namespace mcrl2;
using namespace mcrl2::pbes_system;

const std::string VARIABLE_SPECIFICATION =
  "datavar         \n"
  "  b:  Bool;     \n"
  "  b1: Bool;     \n"
  "  b2: Bool;     \n"
  "  b3: Bool;     \n"
  "                \n"
  "  n:  Nat;      \n"
  "  n1: Nat;      \n"
  "  n2: Nat;      \n"
  "  n3: Nat;      \n"
  "                \n"
  "  p:  Pos;      \n"
  "  p1: Pos;      \n"
  "  p2: Pos;      \n"
  "  p3: Pos;      \n"
  "                \n"
  "predvar         \n"
  "  X;            \n"
  "  Y: Nat;       \n"
  "  W: Bool;      \n"
  "  Z: Bool, Nat; \n"
  "  X0;           \n"
  "  X1: Bool;     \n"
  "  X2: Nat, Nat; \n"
  "  X3: Bool, Nat;\n"
  "  X4: Nat, Bool;\n"
  ;

// PBES expression parser
class parser
{
  protected:
    std::string m_var_decl;
    std::string m_data_spec;

  public:
    explicit parser(const std::string& var_decl = VARIABLE_SPECIFICATION, const std::string& data_spec = "")
      : m_var_decl(var_decl),
        m_data_spec(data_spec)
    {}

    pbes_expression operator()(const std::string& expr)
    {
      return pbes_system::parse_pbes_expression(expr, m_var_decl, m_data_spec);
    }
};

void test_one_point_rule_rewriter(const std::string& expr1, const std::string& expr2)
{
  one_point_rule_rewriter R;
  data::data_specification dataspec;
  dataspec.add_context_sort(data::sort_nat::nat()); // TODO: is there a more elegant way to achieve this?
  data::rewriter r(dataspec);
  simplify_data_rewriter<data::rewriter> S(r);
  BOOST_CHECK(utilities::detail::test_operation(
    expr1,
    expr2,
    parser(),
    std::equal_to<pbes_expression>(),
    [&](const pbes_expression& x) { return S(R(x)); },
    "R1",
    S,
    "R2"
  ));
}

BOOST_AUTO_TEST_CASE(one_point_rule_rewriter_test)
{
  std::cout << "<test_one_point_rule_rewriter>" << std::endl;
  test_one_point_rule_rewriter("forall n: Nat. val(n != 3) || val(n == 5)", "val(false)");
  test_one_point_rule_rewriter("exists n: Nat. val(n == 3) && val(n == 5)", "val(false)");
  test_one_point_rule_rewriter("forall c: Bool. forall b: Bool. val(b) => val(b || c)", "val(!false)");
  test_one_point_rule_rewriter("forall d:Nat. val(d == 1) => Y(d)", "Y(1)");
  test_one_point_rule_rewriter("forall m:Nat. exists n:Nat. val(m == n) && Y(n)", "forall m: Nat. Y(m)");
  test_one_point_rule_rewriter("forall m:Nat. exists n:Nat. val(n == m) && Y(n)", "forall m: Nat. Y(m)");
  test_one_point_rule_rewriter("exists m:Nat. forall n:Nat. val(m != n) || Y(n)", "exists m: Nat. Y(m)");
  test_one_point_rule_rewriter("exists m:Nat. forall n:Nat. val(n != m) || Y(n)", "exists m: Nat. Y(m)");
  test_one_point_rule_rewriter("forall p: Bool, q: Bool. val(!(p == q)) || val(!q) || val(!(p == true))", "val(false)");
}

BOOST_AUTO_TEST_CASE(ticket_1388)
{
  std::string text;
  bool normalize = false;
  pbes p;
  one_point_rule_rewriter R;

  text =
    "pbes mu X = exists e: Bool. exists b: Bool, d: Bool. val(b == e) && val(d == b);\n"
    "init X;\n"
    ;
  p = txt2pbes(text, normalize);
  pbes_rewrite(p, R);
  BOOST_CHECK(p.is_closed() && p.is_well_typed());

  text =
    "pbes nu X = forall b,c: Bool. !val(b == false) || !val(c == b);\n"
    "init X;"
    ;
  p = txt2pbes(text, normalize);
  pbes_rewrite(p, R);
  BOOST_CHECK(p.is_closed() && p.is_well_typed());
}


// based on boost example vf2_sub_graph_iso_multi_example.cpp
//
// g++ -std=c++14 vf2_sub_graph_iso_multi_example_patterns.cpp -O0 -g3 -o example.elf

#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
using namespace boost;
using namespace std;

namespace Graph {

// molecule instance/pattern is a node in the complex graph, edge is a bond
// note: char is replaced with a pointer to MoleculeInstance in the actual implementation
typedef property< vertex_name_t, char, property< vertex_index_t, int > > mt_vertex_property;

// using a vecS graphs => the index maps are implicit.
// we are not using any edge property
typedef adjacency_list< vecS, vecS, bidirectionalS, mt_vertex_property> graph_type;

typedef property_map< graph_type, vertex_name_t >::type vertex_name_map_t;

// Binary function object that returns true if the values for item1
// in property_map1 and item2 in property_map2 are equivalent.
struct property_map_molecule_type_matching {

  property_map_molecule_type_matching(const vertex_name_map_t property_map1, const vertex_name_map_t property_map2) :
    m_property_map1(property_map1),
    m_property_map2(property_map2) { }

  template <typename ItemFirst, typename ItemSecond>
  bool operator()(const ItemFirst item1, const ItemSecond item2) {
    char n1 = get(m_property_map1, item1);
    char n2 = get(m_property_map2, item2);
    cout << "Comparing " << item1 << " " << n1 << " and " << item2 << " " << n2 << "\n";

    return n1 == n2;
  }

private:
  const vertex_name_map_t m_property_map1;
  const vertex_name_map_t m_property_map2;
};

// Returns a property_map_equivalent object that compares the values
// of property_map1 and property_map2.
property_map_molecule_type_matching make_property_map_molecule_type_matching(
    const vertex_name_map_t property_map1,
    const vertex_name_map_t property_map2
) {
  return property_map_molecule_type_matching(property_map1, property_map2);
}

} // namespace Graph

int main()
{
  // Build graph_small
  Graph::graph_type graph_small;

  add_vertex(Graph::mt_vertex_property('b'), graph_small); //0
  add_vertex(Graph::mt_vertex_property('c'), graph_small); //1
  add_vertex(Graph::mt_vertex_property('d'), graph_small); //2

  add_edge(0, 1, graph_small);
  add_edge(1, 2, graph_small);

  // Build graph_large
  Graph::graph_type graph_large;

  add_vertex(Graph::mt_vertex_property('a'), graph_large); //0
  add_vertex(Graph::mt_vertex_property('b'), graph_large); //1
  add_vertex(Graph::mt_vertex_property('c'), graph_large); //2
  add_vertex(Graph::mt_vertex_property('c'), graph_large); //3
  add_vertex(Graph::mt_vertex_property('d'), graph_large); //3

  add_edge(0, 1, graph_large);
  add_edge(1, 2, graph_large);
  add_edge(1, 3, graph_large);
  add_edge(2, 4, graph_large);
  add_edge(3, 4, graph_large);

  // Create callback
  vf2_print_callback< Graph::graph_type, Graph::graph_type > callback(graph_small, graph_large);

  //typedef Graph::property_map_molecule_type_matching< Graph::vertex_name_map_t, Graph::vertex_name_map_t > vertex_comp_t;
  typedef Graph::property_map_molecule_type_matching vertex_comp_t;

  vertex_comp_t vertex_comp = Graph::make_property_map_molecule_type_matching(get(vertex_name, graph_small), get(vertex_name, graph_large));

  // Print out all subgraph isomorphism mappings between graph1 and graph_small.
  // Function vertex_order_by_mult is used to compute the order of
  // vertices of graph1. This is the order in which the vertices are examined
  // during the matching process.
  // might need to use mono

  vf2_subgraph_iso(
      graph_small, graph_large, callback, vertex_order_by_mult(graph_small),
      vertices_equivalent(vertex_comp)
  );

  return 0;
}


#include <boost/hana.hpp>  // boost::hana
namespace hana = boost::hana;

class shape {};
class circle {};
class triangle {};

int main()
{
    using namespace hana::literals;

    constexpr auto tup = hana::make_tuple(
        hana::type_c<shape*>, hana::type_c<circle>, hana::type_c<triangle>);

    constexpr auto no_pointers = hana::remove_if(
        tup, [](auto a) { return hana::traits::is_pointer(a); });

    static_assert(no_pointers == hana::make_tuple(hana::type_c<circle>,
                                                  hana::type_c<triangle>));
    static_assert(
        hana::reverse(no_pointers) ==
        hana::make_tuple(hana::type_c<triangle>, hana::type_c<circle>));
    static_assert(tup[1_c] == hana::type_c<circle>);
}


/*    Copyright (c) 2010-2015, Delft University of Technology
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without modification, are
 *    permitted provided that the following conditions are met:
 *      - Redistributions of source code must retain the above copyright notice, this list of
 *        conditions and the following disclaimer.
 *      - Redistributions in binary form must reproduce the above copyright notice, this list of
 *        conditions and the following disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *      - Neither the name of the Delft University of Technology nor the names of its contributors
 *        may be used to endorse or promote products derived from this software without specific
 *        prior written permission.
 *
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 *    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *    OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110216    K. Kumar          File created.
 *      110217    E. Iorfida        Minor changes made.
 *      110221    K. Kumar          Updated variable-naming to comply with protocol.
 *      110920    K. Kumar          Corrected simple errors outlined by M. Persson.
 *      120215    K. Kumar          Updated to use new propagateKeplerOrbit() function;
 *                                  Boostified unit test; added new unit tests based on ODTBX.
 *      120217    K. Kumar          Updated computeModuloForSignedValues() to computeModulo() from
 *                                  Tudat Core.
 *      120225    K. Kumar          Updated unit test using data from (Melman, 2010) to fix bug in
 *                                  Linux; data is no longer imported from input text file.
 *      120508    K. Kumar          Corrected bug in backwards propagation loop end-condition.
 *      120607    P. Musegaas       Updated unit test to new interface.
 *      120813    P. Musegaas       Updated unit test to new root finding structure.
 *      120823    P. Musegaas       Separated existing unit tests. Added unit test for hyperbolic
 *                                  kepler propagation, with accompanying data from GTOP.
 *      120904    P. Musegaas       Added unit test of a case that failed on the old modulo
 *                                  function in the Kepler propagator. Removed dedicated modulo
 *                                  unit test.
 *      121205    P. Musegaas       Updated code to final version of rootfinders.
 *      150417    D. Dirkx          Made modifications for templated element conversions.
 *
 *    References
 *      Melman, J. Propagate software, J.C.P.Melman@tudelft.nl, 2010.
 *      NASA, Goddard Spaceflight Center. Orbit Determination Toolbox (ODTBX), NASA - GSFC Open
 *          Source Software, http://opensource.gsfc.nasa.gov/projects/ODTBX/, last accessed:
 *          31st January, 2012.
 *      ESA, GTOP Toolbox, http://www.esa.int/gsp/ACT/doc/INF/Code/globopt/GTOPtoolbox.rar.
 *
 *    Notes
 *
 */

#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

#include "Tudat/Astrodynamics/BasicAstrodynamics/keplerPropagator.h"

#include <Eigen/Core>

#include <map>
#include <limits>

#include "Tudat/Astrodynamics/BasicAstrodynamics/stateVectorIndices.h"
#include "Tudat/Astrodynamics/BasicAstrodynamics/orbitalElementConversions.h"
#include "Tudat/Basics/testMacros.h"

#include "Tudat/Mathematics/BasicMathematics/basicMathematicsFunctions.h"
#include "Tudat/Mathematics/BasicMathematics/mathematicalConstants.h"
#include "Tudat/Mathematics/BasicMathematics/linearAlgebraTypes.h"

#include "Tudat/Astrodynamics/BasicAstrodynamics/UnitTests/keplerPropagatorTestData.h"
#include "Tudat/Astrodynamics/BasicAstrodynamics/keplerPropagator.h"
#include "Tudat/InputOutput/basicInputOutput.h"

namespace tudat
{
namespace unit_tests
{

using namespace orbital_element_conversions;

//! Test 1: Comparison of propagateKeplerOrbit() output with benchmark data from (Melman, 2010).
BOOST_AUTO_TEST_CASE( testPropagateKeplerOrbit_Eccentric_Melman )
{
    // Load benchmark data.
    // This data originates from J. Melman and is generated by the software package Propagate.

    // Create propagation history map for benchmark data to be stored in.
    PropagationHistory benchmarkKeplerPropagationHistory = getMelmanBenchmarkData( );

    // Propagate to final state in Keplerian elements.
    basic_mathematics::Vector6d computedFinalStateInKeplerianElements
            = propagateKeplerOrbit(
                benchmarkKeplerPropagationHistory.begin( )->second,
                benchmarkKeplerPropagationHistory.rbegin( )->first -
                benchmarkKeplerPropagationHistory.begin( )->first,
                getMelmanEarthGravitationalParameter( ) );

    // Check that computed results match expected results.
    BOOST_CHECK_CLOSE_FRACTION(
                benchmarkKeplerPropagationHistory.rbegin( )->second( 5 ),
                basic_mathematics::computeModulo( computedFinalStateInKeplerianElements( 5 ),
                                                  2.0 * mathematical_constants::PI ), 1.0e-8 );
}

//! Test 2: Comparison of kepprop2b() test output from (GSFC, 2012) using modulo option.
BOOST_AUTO_TEST_CASE( testPropagateKeplerOrbit_Eccentric_kepprop2b_modulo )
{
    // Create expected propagation history.
    PropagationHistory expectedPropagationHistory = getODTBXBenchmarkData( );

    // Set Earth gravitational parameter [m^3 s^-2].
    const double earthGravitationalParameter = 398600.4415e9;

    // Set time step for ODTBX benchmark data.
    const double timeStep = 8640.0;

    // Compute propagation history.
    PropagationHistory computedPropagationHistory;
    computedPropagationHistory[ 0.0 ] = expectedPropagationHistory[ 0.0 ];

    for ( unsigned int i = 1; i < expectedPropagationHistory.size( ); i++ )
    {
        computedPropagationHistory[ static_cast< double >( i ) * timeStep ]
                = propagateKeplerOrbit(
                    computedPropagationHistory[ static_cast< double >( i - 1 ) * timeStep ],
                    timeStep, earthGravitationalParameter  );

        computedPropagationHistory[ static_cast< double >( i ) * timeStep ]( 5 )
                = basic_mathematics::computeModulo(
                    computedPropagationHistory[ static_cast< double >( i ) * timeStep ]( 5 ),
                    2.0 * mathematical_constants::PI );

        // Check that computed results match expected results.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                    computedPropagationHistory[ static_cast< double >( i ) * timeStep ],
                    expectedPropagationHistory[ static_cast< double >( i ) * timeStep ],
                    1.0e-13 );
    }
}

//! Test 3: Comparison of kepprop2b() test output from (GSFC, 2012), propagating backwards.
BOOST_AUTO_TEST_CASE( testPropagateKeplerOrbit_Eccentric_kepprop2b_backwards )
{
    // Create expected propagation history.
    PropagationHistory expectedPropagationHistory = getODTBXBenchmarkData( );

    // Set Earth gravitational parameter [m^3 s^-2].
    const double earthGravitationalParameter = 398600.4415e9;

    // Set time step for ODTBX benchmark data.
    const double timeStep = 8640.0;

    // Compute propagation history.
    PropagationHistory computedPropagationHistory;
    computedPropagationHistory[ 10.0 * 8640.0 ] = expectedPropagationHistory[ 10.0 * 8640.0 ];

    for ( int i = expectedPropagationHistory.size( ) - 2; i >= 0; i-- )
    {
        computedPropagationHistory[ static_cast< double >( i ) * timeStep ]
                = propagateKeplerOrbit(
                    computedPropagationHistory[ static_cast< double >( i + 1 ) * timeStep ],
                    -timeStep, earthGravitationalParameter );

        computedPropagationHistory[ static_cast< double >( i ) * timeStep ]( 5 )
                = basic_mathematics::computeModulo(
                    computedPropagationHistory[ static_cast< double >( i ) * timeStep ]( 5 ),
                    2.0 * mathematical_constants::PI );

        // Check that computed results match expected results.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                    computedPropagationHistory[ static_cast< double >( i ) * timeStep ],
                    expectedPropagationHistory[ static_cast< double >( i ) * timeStep ],
                    1.0e-13 );
    }
}

//! Test 4: Comparison of hyperbolic kepler propagation with that of GTOP.
BOOST_AUTO_TEST_CASE( testPropagateKeplerOrbit_hyperbolic_GTOP )
{
    // Load the expected propagation history.
    PropagationHistory expectedPropagationHistory = getGTOPBenchmarkData( );

    // Set the time step for the GTOP benchmark data to 100 days.
    const double timeStep = 86400.0 * 100.0;

    // Compute propagation history.
    PropagationHistory computedPropagationHistory;
    computedPropagationHistory[ 0.0 ] = expectedPropagationHistory[ 0.0 ];

    for ( unsigned int i = 1; i < expectedPropagationHistory.size( ); i++ )
    {
        // Compute next entry.
        computedPropagationHistory[ static_cast< double >( i ) * timeStep ] =
                propagateKeplerOrbit(
                    computedPropagationHistory[ static_cast< double >( i - 1 ) * timeStep ],
                    timeStep, getGTOPGravitationalParameter( ) );

        // Check that computed results match expected results.
        BOOST_CHECK_CLOSE_FRACTION(
                    computedPropagationHistory[ static_cast< double >( i ) * timeStep ]( 5 ),
                    expectedPropagationHistory[ static_cast< double >( i ) * timeStep ]( 5 ),
                    1.0e-15 );
    }
}

//! Test 5: Unit test that failed on versions that caused the old modulo function to crash.
BOOST_AUTO_TEST_CASE( testPropagateKeplerOrbit_FunctionFailingOnOldModuloFunction )
{
    // Set expected true anomaly.
    const double expectedTrueAnomaly = -3.1245538487052089;

    // Set the propagation time.
    const double propagationTime = 8651869.8944624383;

    // Set the gravitational parameter (of the Sun).
    const double gravitationalParameter = 1.32712428e20;

    // Set initial Keplerian elements.
    basic_mathematics::Vector6d keplerElements;
    keplerElements << 56618890355.593132, 0.99961601437304082, 1.0238269559089248,
            3.1526292818328812, 1.5807574453453865, 3.1478950321924795;

    // Propagate Keplerian elements.
    keplerElements = propagateKeplerOrbit(
                keplerElements, propagationTime, gravitationalParameter );

    // Check that computed results match expected results.
    BOOST_CHECK_CLOSE_FRACTION( keplerElements( trueAnomalyIndex ),
                                expectedTrueAnomaly,
                                1.0e-15 );
}

//! Test 6. Propagation test using ODTBX test Kepler elements.
BOOST_AUTO_TEST_CASE( testMeanAnomalyAgainstMeanMotion )
{
    std::vector< double > doubleErrors;
    // Test using double parameters.
    {
        double gravitationalParameter = 398600.4415e9;
        basic_mathematics::Vector6d initialStateInKeplerianElements;

        initialStateInKeplerianElements << 42165.3431351313e3, 0.26248354351331, 0.30281462522101,
                4.71463172847351, 4.85569272927819, 2.37248926702153;
        double timeStep = 600.0;
        double meanMotion = std::sqrt( gravitationalParameter /
                                       std::pow( initialStateInKeplerianElements( 0 ), 3.0 ) );

        double initialMeanAnomaly = convertEccentricAnomalyToMeanAnomaly(
                    convertTrueAnomalyToEccentricAnomaly(
                        initialStateInKeplerianElements( 5 ), initialStateInKeplerianElements( 1 ) ),
                    initialStateInKeplerianElements( 1 ) );

        double propagationTime, propagatedMeanAnomaly;

        basic_mathematics::Vector6d propagatedKeplerElements;

        for( int i = -25; i < 26; i++ )
        {
            propagationTime = static_cast< double >( i ) * timeStep;
            propagatedKeplerElements = propagateKeplerOrbit(
                        initialStateInKeplerianElements, propagationTime, gravitationalParameter );
            propagatedMeanAnomaly = convertEccentricAnomalyToMeanAnomaly(
                        convertTrueAnomalyToEccentricAnomaly(
                            propagatedKeplerElements( 5 ), initialStateInKeplerianElements( 1 ) ),
                        initialStateInKeplerianElements( 1 ) );
            doubleErrors.push_back( meanMotion * propagationTime - ( propagatedMeanAnomaly - initialMeanAnomaly ) );
        }
    }

    std::vector< double > longDoubleErrors;
    // Test using long double parameters.
    {
        long double gravitationalParameter = 398600.4415e9L;
        Eigen::Matrix< long double, 6, 1 > initialStateInKeplerianElements;

        initialStateInKeplerianElements << 42165.3431351313e3L, 0.26248354351331L, 0.30281462522101L,
                4.71463172847351L, 4.85569272927819L, 2.37248926702153L;
        long double timeStep = 600.0L;
        long double meanMotion = std::sqrt( gravitationalParameter /
                                            ( initialStateInKeplerianElements( 0 ) *
                                              initialStateInKeplerianElements( 0 ) *
                                              initialStateInKeplerianElements( 0 ) ) );

        long double initialMeanAnomaly = convertEccentricAnomalyToMeanAnomaly< long double >(
                    convertTrueAnomalyToEccentricAnomaly< long double >(
                        initialStateInKeplerianElements( 5 ), initialStateInKeplerianElements( 1 ) ),
                    initialStateInKeplerianElements( 1 ) );

        long double propagationTime, propagatedMeanAnomaly;

        Eigen::Matrix< long double, 6, 1 > propagatedKeplerElements;

        for( int i = -25; i < 26; i++ )
        {
            propagationTime = static_cast< long double >( i ) * timeStep;

            propagatedKeplerElements = propagateKeplerOrbit< long double >(
                        initialStateInKeplerianElements, propagationTime, gravitationalParameter );
            propagatedMeanAnomaly = convertEccentricAnomalyToMeanAnomaly< long double >(
                        convertTrueAnomalyToEccentricAnomaly< long double >(
                            propagatedKeplerElements( 5 ), initialStateInKeplerianElements( 1 ) ),
                        initialStateInKeplerianElements( 1 ) );

            longDoubleErrors.push_back( static_cast< double >(
                                            meanMotion * propagationTime -
                                            ( propagatedMeanAnomaly - initialMeanAnomaly ) ) );
        }
    }

    for( unsigned int i = 0; i < doubleErrors.size( ); i++ )
    {
        if( std::fabs( doubleErrors.at( i ) ) > 0.0 )
        {
            BOOST_CHECK_SMALL(
                        static_cast< double >( std::fabs( longDoubleErrors.at( i ) / doubleErrors.at( i ) ) ),
                        static_cast< double >( 5.0 * std::numeric_limits< long double >::epsilon( ) /
                        std::numeric_limits< double >::epsilon( ) ) );
        }
        else
        {
            BOOST_CHECK_SMALL( static_cast< double >( longDoubleErrors.at( i ) ),
                               static_cast< double >( 5.0 * std::numeric_limits< long double >::epsilon( ) ) );
        }
    }
}
} // namespace unit_tests
} // namespace tudat