#ifdef STAN_OPENCL
#include <stan/math/prim.hpp>
#include <stan/math/opencl/opencl.hpp>
#include <test/unit/math/expect_near_rel.hpp>
#include <test/unit/util.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <gtest/gtest.h>
#include <algorithm>

TEST(MathMatrixCL, mdivide_left_tri_low_cl_exception) {
  stan::math::matrix_d m1(2, 3);
  m1 << 1, 2, 3, 4, 5, 6;
  stan::math::matrix_cl<double> m2(m1, stan::math::matrix_cl_view::Lower);
  stan::math::matrix_cl<double> m3(2, 3);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m2), std::invalid_argument);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m2, m2), std::invalid_argument);
  m2.view(stan::math::matrix_cl_view::Upper);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m2), std::invalid_argument);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m2, m2), std::invalid_argument);

  stan::math::matrix_d m4(3, 3);
  m4 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
  stan::math::matrix_cl<double> m5(m1, stan::math::matrix_cl_view::Entire);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m5), std::invalid_argument);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m5, m5), std::invalid_argument);
  m5.view(stan::math::matrix_cl_view::Diagonal);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m5), std::invalid_argument);
  EXPECT_THROW(stan::math::mdivide_left_tri_low(m5, m5), std::invalid_argument);
}

void mdivide_left_tri_low_Ab_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    m1(i, i) = 10000.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = 0.0;
    }
    m1(i, 0) = stan::math::uniform_rng(-5, 5, rng);
  }
  // force the CPU version for comparison
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = size * 2;
  stan::math::matrix_d m1_cpu = stan::math::mdivide_left_tri_low(m1, m1);

  stan::math::matrix_cl<double> m0_cl(m1, stan::math::matrix_cl_view::Lower);
  stan::math::matrix_d m1_cl = stan::math::from_matrix_cl(
      stan::math::mdivide_left_tri_low(m0_cl, m0_cl));
  double max_error = 0;
  for (int i = 0; i < m1_cpu.size(); i++) {
    stan::test::expect_near_rel("mdivide_left_tri_low (OpenCL)", m1_cpu(i),
                                m1_cl(i));
  }
}

void mdivide_left_tri_low_A_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    m1(i, i) = 10000.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = 0.0;
    }
  }
  stan::math::matrix_d m1_cpu(size, size);
  stan::math::matrix_d m1_cl(size, size);
  // force the CPU version for comparison
  stan::math::opencl_context.tuning_opts().tri_inverse_size_worth_transfer
      = size * 2;
  m1_cpu = stan::math::mdivide_left_tri_low(m1);

  stan::math::matrix_cl<double> m1_A_cl(m1, stan::math::matrix_cl_view::Lower);
  m1_cl = stan::math::from_matrix_cl(stan::math::mdivide_left_tri_low(m1_A_cl));
  double max_error = 0;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j <= i; j++) {
      stan::test::expect_near_rel("mdivide_left_tri_low (OpenCL)", m1_cpu(i, j),
                                  m1_cl(i, j));
    }
  }
}

TEST(MathMatrixCL, mdivide_left_tri_low_test_cl_small) {
  mdivide_left_tri_low_Ab_test(3);
  mdivide_left_tri_low_A_test(3);
}

TEST(MathMatrixCL, mdivide_left_tri_low_test_cl_1under_block_size) {
  mdivide_left_tri_low_Ab_test(31);
  mdivide_left_tri_low_A_test(31);
}

TEST(MathMatrixCL, mdivide_left_tri_low_test_cl_1over_block_size) {
  mdivide_left_tri_low_Ab_test(33);
  mdivide_left_tri_low_A_test(33);
}

TEST(MathMatrixCL, mdivide_left_tri_low_test_cl_big_power_of_2) {
  mdivide_left_tri_low_Ab_test(512);
  mdivide_left_tri_low_A_test(512);
}

TEST(MathMatrixCL, mdivide_left_tri_low_test_cl_big_non_power_of_2) {
  mdivide_left_tri_low_Ab_test(700);
  mdivide_left_tri_low_A_test(700);
}

TEST(MathMatrixCL, mdivide_left_tri_low_test_cl_very_big_non_power_of_2) {
  mdivide_left_tri_low_Ab_test(1500);
  mdivide_left_tri_low_A_test(1500);
}
#endif


// Copyright (C) 2014-2016 Vicente J. Botet Escriba
//
//  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)

// <experimental/applicative.hpp>
// <experimental/optional.hpp>

#include <boost/detail/lightweight_test.hpp>
#include <experimental/applicative.hpp>
#include <experimental/optional.hpp>

int twice(int i) {
  return 2*i;
}

int main()
{
#if __cplusplus >= 201402L

  namespace stde = std::experimental;

  static_assert(stde::is_nullable_v<stde::optional<int>>, "ERROR");
  static_assert(stde::is_type_constructible_v<stde::optional<int>>, "ERROR");
  static_assert(stde::is_applicative<stde::optional<stde::_t>>::value, "ERROR");

  {
    stde::optional<int> x = stde::none<stde::optional>();
    stde::optional<int(*)(int)> f = stde::none<stde::optional>();
    stde::optional<int> y = stde::applicative::ap(f, x);
    BOOST_TEST(! stde::has_value(y));
  }
  {
    stde::optional<int> x = stde::make<stde::optional>(1);
    stde::optional<int(*)(int)> f = stde::none<stde::optional>();
    stde::optional<int> y = stde::applicative::ap(f, x);
    BOOST_TEST(! stde::has_value(y));
  }
  {
    stde::optional<int> x = stde::none<stde::optional>();
    stde::optional<int(*)(int)> f = stde::make<stde::optional>(twice);
    stde::optional<int> y = stde::applicative::ap(f, x);
    BOOST_TEST(! stde::has_value(y));
  }
  {
    int v=1;
    stde::optional<int> x = stde::make<stde::optional>(v);
    stde::optional<int(*)(int)> f = stde::make<stde::optional>(twice);
    stde::optional<int> y = stde::applicative::ap(f, x);
    (void)y;
    BOOST_TEST(stde::value_or_error::has_value(y));
    //BOOST_TEST(stde::deref(y) == 2);
    BOOST_TEST(stde::value_or_error::deref(y) == 2);
    BOOST_TEST(*y == 2);
  }
#endif

  return ::boost::report_errors();
}


/*
 * 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)
 *
 * Copyright (c) 2020 Andrey Semashev
 */
/*!
 * \file   bit_operation_tools.hpp
 *
 * This file contains bit operation tools
 */

#ifndef BOOST_ATOMIC_BIT_OPERATION_TOOLS_HPP_INCLUDED_
#define BOOST_ATOMIC_BIT_OPERATION_TOOLS_HPP_INCLUDED_

#include <boost/predef/architecture/x86.h>

#if BOOST_ARCH_X86

#include <boost/atomic/detail/config.hpp>
#include <boost/atomic/detail/header.hpp>

#if defined(_MSC_VER)
extern "C" unsigned char _BitScanForward(unsigned long* index, unsigned long x);
#if defined(BOOST_MSVC)
#pragma intrinsic(_BitScanForward)
#endif
#endif

namespace boost {
namespace atomics {
namespace detail {

//! Counts trailing zero bits
BOOST_FORCEINLINE unsigned int count_trailing_zeros(unsigned int x)
{
#if defined(__GNUC__)
    return __builtin_ctz(x);
#elif defined(_MSC_VER)
    unsigned long index;
    _BitScanForward(&index, x);
    return static_cast< unsigned int >(index);
#else
    unsigned int index = 0u;
    if ((x & 0xFFFF) == 0u)
    {
        x >>= 16;
        index += 16u;
    }
    if ((x & 0xFF) == 0u)
    {
        x >>= 8;
        index += 8u;
    }
    if ((x & 0xF) == 0u)
    {
        x >>= 4;
        index += 4u;
    }
    if ((x & 0x3) == 0u)
    {
        x >>= 2;
        index += 2u;
    }
    if ((x & 0x1) == 0u)
    {
        index += 1u;
    }
    return index;
#endif
}

} // namespace detail
} // namespace atomics
} // namespace boost

#include <boost/atomic/detail/footer.hpp>

#endif // BOOST_ARCH_X86

#endif // BOOST_ATOMIC_BIT_OPERATION_TOOLS_HPP_INCLUDED_


/**
 * Copyright (c) 2013 Jonan Cruz-Martin
 *
 * Distributed under the terms of the MIT license, see the accompanying
 * file COPYING or http://opensource.org/licenses/MIT.
 *
 * @file
 * @brief Class definitions for domains of lines.
 */

#ifndef DOMAINS_LINEAR_HPP
#define DOMAINS_LINEAR_HPP

#include "types.hpp"
#include "../points/cartesian.hpp"
#include "../points/cylindrical.hpp"
#include "../points/polar.hpp"
#include "../points/spherical.hpp"

#include "../vertices/linear.hpp"
#include "../cells/linear.hpp"

#include <boost/python.hpp>
using namespace boost::python;

/**
 * Domain of lines in the cartesian 1D space.
 *
 * @since 0.1.0
 */
class LinearCartesian1D_Domain {
	/**
	 * ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCartesian1D_Domain_t    domain;
public:
	LinearCartesian1D_Domain() {};

	/**
	 * Return the number of vertices contained in the domain.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_vertices();

	/**
	 * Create a new vertex in the domain based on the given point.
	 *
	 * @param point Point that represents the vertex. The point object will be copied.
	 *
	 * @since 0.1.0
	 */
	void make_vertex(PointCartesian1D point);

	/**
	 * Return the vertex identified by the given index.
	 *
	 * @param index Numerical vertex ID as assigned by ViennaGrid on vertex creation.
	 *
	 * @since 0.1.0
	 */
	LinearCartesian1D_Vertex get_vertex(unsigned int index);

	/**
	 * Return a Python list containing all the vertices of the domain.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_vertices();

	/**
	 * Return the number of cells contained in the segment.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_cells();

	/**
	 * Create a new cell in the segment.
	 *
	 * @param vertex1
	 * @param vertex2
	 *
	 * @return The newly created cell.
	 *
	 * @since 0.1.0
	 */
	LinearCartesian1D_Cell make_cell(LinearCartesian1D_Vertex vertex1, LinearCartesian1D_Vertex vertex2);

	/**
	 * Return a Python list containing all the cells contained in the segment.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_cells();

	/**
	 * Get a reference to the ViennaGrid domain object.
	 *
	 * @return Reference to the ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCartesian1D_Domain_t & get_domain();
};

//////////////////////////
// Linear, cartesian 2D //
//////////////////////////

/**
 * Domain of lines in the cartesian 2D space.
 *
 * @since 0.1.0
 */
class LinearCartesian2D_Domain {
	/**
	 * ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCartesian2D_Domain_t    domain;
public:
	LinearCartesian2D_Domain() {};

	/**
	 * Return the number of vertices contained in the domain.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_vertices();

	/**
	 * Create a new vertex in the domain based on the given point.
	 *
	 * @param point Point that represents the vertex. The point object will be copied.
	 *
	 * @since 0.1.0
	 */
	void make_vertex(PointCartesian2D point);

	/**
	 * Return the vertex identified by the given index.
	 *
	 * @param index Numerical vertex ID as assigned by ViennaGrid on vertex creation.
	 *
	 * @since 0.1.0
	 */
	LinearCartesian2D_Vertex get_vertex(unsigned int index);

	/**
	 * Return a Python list containing all the vertices of the domain.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_vertices();

	/**
	 * Return the number of cells contained in the segment.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_cells();

	/**
	 * Create a new cell in the segment.
	 *
	 * @param vertex1
	 * @param vertex2
	 *
	 * @return The newly created cell.
	 *
	 * @since 0.1.0
	 */
	LinearCartesian2D_Cell make_cell(LinearCartesian2D_Vertex vertex1, LinearCartesian2D_Vertex vertex2);

	/**
	 * Return a Python list containing all the cells contained in the segment.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_cells();

	/**
	 * Get a reference to the ViennaGrid domain object.
	 *
	 * @return Reference to the ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCartesian2D_Domain_t & get_domain();
};

//////////////////////////
// Linear, cartesian 3D //
//////////////////////////

/**
 * Domain of lines in the cartesian 3D space.
 *
 * @since 0.1.0
 */
class LinearCartesian3D_Domain {
	/**
	 * ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCartesian3D_Domain_t    domain;
public:
	LinearCartesian3D_Domain() {};

	/**
	 * Return the number of vertices contained in the domain.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_vertices();

	/**
	 * Create a new vertex in the domain based on the given point.
	 *
	 * @param point Point that represents the vertex. The point object will be copied.
	 *
	 * @since 0.1.0
	 */
	void make_vertex(PointCartesian3D point);

	/**
	 * Return the vertex identified by the given index.
	 *
	 * @param index Numerical vertex ID as assigned by ViennaGrid on vertex creation.
	 *
	 * @since 0.1.0
	 */
	LinearCartesian3D_Vertex get_vertex(unsigned int index);

	/**
	 * Return a Python list containing all the vertices of the domain.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_vertices();

	/**
	 * Return the number of cells contained in the segment.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_cells();

	/**
	 * Create a new cell in the segment.
	 *
	 * @param vertex1
	 * @param vertex2
	 *
	 * @return The newly created cell.
	 *
	 * @since 0.1.0
	 */
	LinearCartesian3D_Cell make_cell(LinearCartesian3D_Vertex vertex1, LinearCartesian3D_Vertex vertex2);

	/**
	 * Return a Python list containing all the cells contained in the segment.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_cells();

	/**
	 * Get a reference to the ViennaGrid domain object.
	 *
	 * @return Reference to the ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCartesian3D_Domain_t & get_domain();
};

//////////////////////////////
// Linear, cylindrical (3D) //
//////////////////////////////

/**
 * Domain of lines in the cylindrical space.
 *
 * @since 0.1.0
 */
class LinearCylindrical3D_Domain {
	/**
	 * ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCylindrical3D_Domain_t    domain;
public:
	LinearCylindrical3D_Domain() {};

	/**
	 * Return the number of vertices contained in the domain.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_vertices();

	/**
	 * Create a new vertex in the domain based on the given point.
	 *
	 * @param point Point that represents the vertex. The point object will be copied.
	 *
	 * @since 0.1.0
	 */
	void make_vertex(PointCylindrical3D point);

	/**
	 * Return the vertex identified by the given index.
	 *
	 * @param index Numerical vertex ID as assigned by ViennaGrid on vertex creation.
	 *
	 * @since 0.1.0
	 */
	LinearCylindrical3D_Vertex get_vertex(unsigned int index);

	/**
	 * Return a Python list containing all the vertices of the domain.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_vertices();

	/**
	 * Return the number of cells contained in the segment.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_cells();

	/**
	 * Create a new cell in the segment.
	 *
	 * @param vertex1
	 * @param vertex2
	 *
	 * @return The newly created cell.
	 *
	 * @since 0.1.0
	 */
	LinearCylindrical3D_Cell make_cell(LinearCylindrical3D_Vertex vertex1, LinearCylindrical3D_Vertex vertex2);

	/**
	 * Return a Python list containing all the cells contained in the segment.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_cells();

	/**
	 * Get a reference to the ViennaGrid domain object.
	 *
	 * @return Reference to the ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearCylindrical3D_Domain_t & get_domain();
};

////////////////////////
// Linear, polar (2D) //
////////////////////////

/**
 * Domain of lines in the polar space.
 *
 * @since 0.1.0
 */
class LinearPolar2D_Domain {
	/**
	 * ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearPolar2D_Domain_t    domain;
public:
	LinearPolar2D_Domain() {};

	/**
	 * Return the number of vertices contained in the domain.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_vertices();

	/**
	 * Create a new vertex in the domain based on the given point.
	 *
	 * @param point Point that represents the vertex. The point object will be copied.
	 *
	 * @since 0.1.0
	 */
	void make_vertex(PointPolar2D point);

	/**
	 * Return the vertex identified by the given index.
	 *
	 * @param index Numerical vertex ID as assigned by ViennaGrid on vertex creation.
	 *
	 * @since 0.1.0
	 */
	LinearPolar2D_Vertex get_vertex(unsigned int index);

	/**
	 * Return a Python list containing all the vertices of the domain.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_vertices();

	/**
	 * Return the number of cells contained in the segment.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_cells();

	/**
	 * Create a new cell in the segment.
	 *
	 * @param vertex1
	 * @param vertex2
	 *
	 * @return The newly created cell.
	 *
	 * @since 0.1.0
	 */
	LinearPolar2D_Cell make_cell(LinearPolar2D_Vertex vertex1, LinearPolar2D_Vertex vertex2);

	/**
	 * Return a Python list containing all the cells contained in the segment.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_cells();

	/**
	 * Get a reference to the ViennaGrid domain object.
	 *
	 * @return Reference to the ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearPolar2D_Domain_t & get_domain();
};

////////////////////////////
// Linear, spherical (3D) //
////////////////////////////

/**
 * Domain of lines in the spherical space.
 *
 * @since 0.1.0
 */
class LinearSpherical3D_Domain {
	/**
	 * ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearSpherical3D_Domain_t    domain;
public:
	LinearSpherical3D_Domain() {};

	/**
	 * Return the number of vertices contained in the domain.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_vertices();

	/**
	 * Create a new vertex in the domain based on the given point.
	 *
	 * @param point Point that represents the vertex. The point object will be copied.
	 *
	 * @since 0.1.0
	 */
	void make_vertex(PointSpherical3D point);

	/**
	 * Return the vertex identified by the given index.
	 *
	 * @param index Numerical vertex ID as assigned by ViennaGrid on vertex creation.
	 *
	 * @since 0.1.0
	 */
	LinearSpherical3D_Vertex get_vertex(unsigned int index);

	/**
	 * Return a Python list containing all the vertices of the domain.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_vertices();

	/**
	 * Return the number of cells contained in the segment.
	 *
	 * @return unsigned integer
	 *
	 * @since 0.1.0
	 */
	unsigned int num_cells();

	/**
	 * Create a new cell in the segment.
	 *
	 * @param vertex1
	 * @param vertex2
	 *
	 * @return The newly created cell.
	 *
	 * @since 0.1.0
	 */
	LinearSpherical3D_Cell make_cell(LinearSpherical3D_Vertex vertex1, LinearSpherical3D_Vertex vertex2);

	/**
	 * Return a Python list containing all the cells contained in the segment.
	 *
	 * @return Python list
	 *
	 * @since 0.1.0
	 */
	list get_cells();

	/**
	 * Get a reference to the ViennaGrid domain object.
	 *
	 * @return Reference to the ViennaGrid domain object.
	 * @since 0.1.0
	 */
	LinearSpherical3D_Domain_t & get_domain();
};

#endif


/*-----------------------------------------------------------------------------+
Copyright (c) 2008-2009: Joachim Faulhaber
+------------------------------------------------------------------------------+
   Distributed under the Boost Software License, Version 1.0.
      (See accompanying file LICENCE.txt or copy at
           http://www.boost.org/LICENSE_1_0.txt)
+-----------------------------------------------------------------------------*/
#ifndef BOOST_ICL_INTERVAL_SUBSET_COMPARER_HPP_JOFA_090827
#define BOOST_ICL_INTERVAL_SUBSET_COMPARER_HPP_JOFA_090827

#include <boost/icl/type_traits/is_map.hpp>
#include <boost/icl/detail/notate.hpp>
#include <boost/icl/detail/relation_state.hpp>
#include <boost/icl/type_traits/identity_element.hpp>
#include <boost/icl/type_traits/is_concept_equivalent.hpp>
#include <boost/icl/type_traits/is_interval_container.hpp>
#include <boost/icl/type_traits/is_set.hpp>
#include <boost/icl/concept/interval_set_value.hpp>

namespace boost{namespace icl
{

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#endif

namespace Interval_Set
{

//------------------------------------------------------------------------------
template<class LeftT, class RightT>
struct settic_codomain_compare
{
    static int apply(typename LeftT::const_iterator& left_, typename RightT::const_iterator& right_)
    {
        return inclusion_compare( icl::co_value<LeftT>(left_),
                                 icl::co_value<RightT>(right_));
    }
};

template<class LeftT, class RightT>
struct atomic_codomain_compare
{
    static int apply(typename LeftT::const_iterator& left_, typename RightT::const_iterator& right_)
    {
        if(icl::co_value<LeftT>(left_) == icl::co_value<RightT>(right_))
            return inclusion::equal;
        else
            return inclusion::unrelated;
    }
};

template<class LeftT, class RightT>
struct empty_codomain_compare
{
    static int apply(typename LeftT::const_iterator&, typename RightT::const_iterator)
    {
        return inclusion::equal;
    }
};

template<class LeftT, class RightT>
struct map_codomain_compare
{
    static int apply(typename LeftT::const_iterator& left_, typename RightT::const_iterator& right_)
    {
        using namespace boost::mpl;
        typedef typename LeftT::codomain_type  LeftCodomainT;
        typedef typename RightT::codomain_type RightCodomainT;

        return
            if_<
                bool_<is_concept_equivalent<is_set,LeftCodomainT,
                                                   RightCodomainT>::value>,
                settic_codomain_compare<LeftT,RightT>,
                atomic_codomain_compare<LeftT,RightT>
            >
            ::type::apply(left_, right_);
    }
};

//------------------------------------------------------------------------------
template<class LeftT, class RightT>
class subset_comparer
{
private:
    subset_comparer& operator = (const subset_comparer&);
public:
    typedef typename LeftT::const_iterator  LeftIterT;
    typedef typename RightT::const_iterator RightIterT;

    BOOST_STATIC_CONSTANT(bool,
        _compare_codomain = (mpl::and_<is_map<LeftT>, is_map<RightT> >::value));

    subset_comparer(const LeftT&      left,
                    const RightT&     right,
                    const LeftIterT&  left_end,
                    const RightIterT& right_end)
        : _left(left), _right(right),
          _left_end(left_end), _right_end(right_end), _result(equal)
    {}

    enum{nextboth, nextleft, nextright, stop};

    enum
    {
        unrelated  = inclusion::unrelated,
        subset     = inclusion::subset,     // left is_subset_of   right
        superset   = inclusion::superset,   // left is_superset_of right
        equal      = inclusion::equal       // equal = subset | superset
    };

    int result()const{ return _result; }

    int co_compare(LeftIterT& left, RightIterT& right)
    {
        using namespace boost::mpl;

        return
            if_<
                bool_<is_concept_equivalent<is_interval_map,LeftT,RightT>::value>,
                map_codomain_compare<LeftT,RightT>,
                empty_codomain_compare<LeftT,RightT>
            >
            ::type::apply(left,right);
    }

    int restrict_result(int state) { return _result &= state; }

    int proceed(LeftIterT& left, RightIterT& right)
    {
        if(upper_less(key_value<LeftT>(left), key_value<RightT>(right)))
        {   // left  ..)
            // right .....)
            _prior_left = left;
            ++left;
            return nextleft;
        }
        else if(upper_less(key_value<RightT>(right), key_value<LeftT>(left)))
        {   // left  .....)
            // right ..)
            _prior_right = right;
            ++right;
            return nextright;
        }
        else//key_value<LeftT>(left).upper_equal(key_value<RightT>(right))
        {   // left  ..)
            // right ..)
            ++left;
            ++right;
            return nextboth;
        }
    }

    int next_both(LeftIterT& left, RightIterT& right)
    {
        if(left == _left_end && right == _right_end)
            return stop;
        else if(left == _left_end)
        {   // left: ....end    left could be subset
            // right:....[..
            restrict_result(subset);
            return stop;
        }
        else if(right == _right_end)
        {   // left: ....[..    left could be superset
            // right:....end
            restrict_result(superset);
            return stop;
        }
        else if(exclusive_less(key_value<LeftT>(left), key_value<RightT>(right)))
        {   // left: [..) . . .[---)      left could be superset
            // right:           [..)....  if [---) exists
            restrict_result(superset);
            if(unrelated == _result)
                return stop;
            else
            {
                LeftIterT joint_ = _left.lower_bound(key_value<RightT>(right));
                if(joint_ == _left.end())
                {
                    _result = unrelated;
                    return stop;
                }
                else
                {
                    left = joint_;
                    return nextboth;
                }
            }
        }
        else if(exclusive_less(key_value<RightT>(right), key_value<LeftT>(left)))
        {   // left:             [..  left could be subset
            // right:....) . . .[---) if [---) exists
            restrict_result(subset);
            if(unrelated == _result)
                return stop;
            else
            {
                RightIterT joint_ = _right.lower_bound(key_value<LeftT>(left));
                if(joint_ == _right.end())
                {
                    _result = unrelated;
                    return stop;
                }
                else
                {
                    right = joint_;
                    return nextboth;
                }
            }
        }

        // left and right have intervals with nonempty intersection:
        if(_compare_codomain)
            if(unrelated == restrict_result(co_compare(left,right)))
                return stop;

        // examine left borders only. Right borders are checked in proceed
        if(lower_less(key_value<LeftT>(left), key_value<RightT>(right)))
        {   // left: ....[...     left could be superset
            // right:....   [..
            if(unrelated == restrict_result(superset))
                return stop;
        }
        else if(lower_less(key_value<RightT>(right), key_value<LeftT>(left)))
        {   // left: ....   [..   left can be subset
            // right:....[...
            if(unrelated == restrict_result(subset))
                return stop;
        }
        //else key_value<LeftT>(right).lower_equal(key_value<RightT>(left))
            // left: ....[..   both can be equal
            // right:....[..
            // nothing to do: proceed

        return proceed(left, right);
    }

    int next_left(LeftIterT& left, RightIterT& right)
    {
        if(left == _left_end)
        {   // left: ..)end    left could be subset
            // right:......)
            restrict_result(subset);
            return stop;
        }
        else if(!touches(key_value<LeftT>(_prior_left), key_value<LeftT>(left)))
        {   // left: ..)   [..
            // right:.........)
            if(lower_less(key_value<RightT>(right), key_value<LeftT>(left)))
            {   //   ..)   [..   left could be subset
                //   ..........)
                if(unrelated == restrict_result(subset))
                    return stop;
            }
            //else   ..)   [...
            //          [..
            if(_compare_codomain && intersects(key_value<LeftT>(left),key_value<RightT>(right)) )
                if(unrelated == restrict_result(co_compare(left,right)))
                    return stop;
        }
        else
        {   // left: ..)[..  left could be subset
            // right:.......)
            if(_compare_codomain && intersects(key_value<LeftT>(left), key_value<RightT>(right)) )
                if(unrelated == restrict_result(co_compare(left,right)))
                    return stop;
        }

        return proceed(left, right);
    }

    int next_right(LeftIterT& left, RightIterT& right)
    {
        if(right == _right_end)
        {   // left: ......)    left could be superset
            // right:..)end
            restrict_result(superset);
            return stop;
        }
        else if(!touches(key_value<RightT>(_prior_right), key_value<RightT>(right)))
        {   // left: .........)
            // right:..)   [..
            if(lower_less(key_value<LeftT>(left), key_value<RightT>(right)))
            {   //       [....)  left could be superset
                //   ..)   [..
                if(unrelated == restrict_result(superset))
                    return stop;
            }
            //else       [....)
            //   ..)   [..
            if(_compare_codomain && intersects(key_value<LeftT>(left), key_value<RightT>(right)) )
                if(unrelated == restrict_result(co_compare(left,right)))
                    return stop;
        }
        else
        {
            if(_compare_codomain && intersects(key_value<LeftT>(left), key_value<RightT>(right)) )
                if(unrelated == restrict_result(co_compare(left,right)))
                    return stop;
        }

        return proceed(left, right);
    }

private:
    const LeftT&  _left;
    const RightT& _right;
    LeftIterT     _left_end;
    RightIterT    _right_end;
    LeftIterT     _prior_left;
    RightIterT    _prior_right;
    int           _result;
};

//------------------------------------------------------------------------------
// Subset/superset comparison on ranges of two interval container
//------------------------------------------------------------------------------
template<class LeftT, class RightT>
int subset_compare
(
    const LeftT& left,   //sub
    const RightT& right, //super
    typename LeftT::const_iterator  left_begin,
    typename LeftT::const_iterator  left_end,
    typename RightT::const_iterator right_begin,
    typename RightT::const_iterator right_end
)
{
    typedef subset_comparer<LeftT,RightT> Step;
    Step step(left, right, left_end, right_end);

    typename LeftT::const_iterator  left_  = left_begin;
    typename RightT::const_iterator right_ = right_begin;

    int state = Step::nextboth;
    while(state != Step::stop)
    {
        switch(state){
        case Step::nextboth:    state = step.next_both(left_, right_);  break;
        case Step::nextleft:    state = step.next_left(left_, right_);  break;
        case Step::nextright:   state = step.next_right(left_, right_); break;
        }
    }
    return step.result();
}

} // namespace Interval_Set

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

}} // namespace icl boost

#endif


#include <cstdlib>
#include <boost/hana/assert.hpp>

#include <gem/gem.hpp>

using namespace gem;
using namespace boost::hana;

auto main(void) -> int
{
    {

        Dimension d {2_u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            Dimension<unsigned int, 2, 2, 2>>::value);
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            Dimension<unsigned int, 2, 4, 0>>::value);
    }

    {
        Dimension d {2};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            Dimension<unsigned int, 2, 2, 2>>::value);
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            Dimension<unsigned int, 2, 4, 0>>::value);
    }

    {
        Dimension d {2_u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            unsigned int>::value);
    }

    {
        Dimension d {2_c};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            unsigned int>::value);
    }

    {
        Dimension d {2};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            unsigned int>::value);
    }

    {
        Dimension d {2_u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<unsigned int,
            decltype(d)>::value);
    }

    {
        Dimension d {2_c};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<unsigned int,
            decltype(d)>::value);
    }

    {
        Dimension d {2};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<unsigned int,
            decltype(d)>::value);
    }

    {
        Dimension d {2};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            unsigned int>::value);
    }

    {
        Dimension d {2u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            unsigned int>::value);
    }

    {
        Dimension d {2_u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            integral_constant<unsigned int, 2>>::value);
    }

    {
        Dimension d {2_c};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            integral_constant<unsigned int, 2>>::value);
    }

    {
        Dimension d {2};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            integral_constant<unsigned int, 2>>::value);
    }

    {
        Dimension d {2u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<decltype(d),
            integral_constant<unsigned int, 2>>::value);
    }

    {
        Dimension d {2_u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<
            integral_constant<unsigned int, 2>,
            decltype(d)>::value);
    }

    {
        Dimension d {2_c};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<
            integral_constant<unsigned int, 2>,
            decltype(d)>::value);
    }

    {
        Dimension d {2};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<
            integral_constant<unsigned int, 2>,
            decltype(d)>::value);
    }

    {
        Dimension d {2u};
        BOOST_HANA_CONSTEXPR_CHECK(has_common<
            integral_constant<unsigned int, 2>,
            decltype(d)>::value);
    }

    return EXIT_SUCCESS;
}


// #define DEBUG_DEVELOP 1

#ifndef INCLUDED_STDDEFX
#include "stddefx.h"
#define INCLUDED_STDDEFX
#endif

#ifndef INCLUDED_CALC_DYNAMICWAVE
#include "calc_dynamicwave.h"
#define INCLUDED_CALC_DYNAMICWAVE
#endif

// Library headers.
#ifndef INCLUDED_BOOST_FORMAT
#include <boost/format.hpp>
#define INCLUDED_BOOST_FORMAT
#endif
// PCRaster library headers.
#ifndef INCLUDED_COM_CSFCELL
#include "com_csfcell.h"
#define INCLUDED_COM_CSFCELL
#endif
#ifndef INCLUDED_COM_MVOP
#include "com_mvop.h"
#define INCLUDED_COM_MVOP
#endif
#ifndef INCLUDED_APPARGS
#include "appargs.h"      // appDynamicWaveRoughness
#define INCLUDED_APPARGS
#endif

// Module headers.
#ifndef INCLUDED_CALC_VFIELD
#include "calc_vfield.h"
#define INCLUDED_CALC_VFIELD
#endif
#ifndef INCLUDED_CALC_SCOPEDLDDGRAPH
#include "calc_scopedlddgraph.h"
#define INCLUDED_CALC_SCOPEDLDDGRAPH
#endif
#ifndef INCLUDED_CALC_LOOKUPTABLE
#include "calc_lookuptable.h"
#define INCLUDED_CALC_LOOKUPTABLE
#endif
#ifndef INCLUDED_CALC_EXECARGUMENTS
#include "calc_execarguments.h"
#define INCLUDED_CALC_EXECARGUMENTS
#endif
#ifndef INCLUDED_CALC_FIELD
#include "calc_field.h"
#define INCLUDED_CALC_FIELD
#endif
#ifndef INCLUDED_CALC_NONSPATIAL
#include "calc_nonspatial.h"
#define INCLUDED_CALC_NONSPATIAL
#endif
#ifndef INCLUDED_CALC_DOMAINERROR
#include "calc_domainerror.h"
#define INCLUDED_CALC_DOMAINERROR
#endif
#ifndef INCLUDED_CALC_DOWNSTREAMVISITOR
#include "calc_downstreamvisitor.h"
#define INCLUDED_CALC_DOWNSTREAMVISITOR
#endif
#ifndef INCLUDED_CALC_TIMESLICEVISITOR
#include "calc_TimeSliceVisitor.h"
#define INCLUDED_CALC_TIMESLICEVISITOR
#endif

/*!
  \file
  This file contains the implementation of the DynamicWave class.
*/

//------------------------------------------------------------------------------

namespace calc {

static   std::string prefix;

DynamicWave     dynamicWave;
KinematicWave   kinematicWave; // kinwavestate, kinwaveflux
Kinematic       builtIn_kinematic;
// Muskingum       builtIn_muskingumtimestep;
Muskingum       builtIn_muskingum;
LookupState     builtIn_lookupstate;
LookupPotential builtIn_lookuppotential;

//! call setPrefixSort on ctor
class DynamicWaveExecArguments : public ExecArguments {
  public:
    DynamicWaveExecArguments(
      const Operator& op,
      RunTimeEnv *rte,
      size_t nrActualArgs):
       ExecArguments(op,rte,nrActualArgs)
    {
      const LookupTable *tab=
        dynamic_cast<const LookupTable *>(firstNonFieldInput());
      PRECOND(tab);
      ((LookupTable *)tab)->setPrefixStableSort(1);
    }
};

//! Accumulation through a directed graph, like LddGraph
class DWVisitor : public TimeSliceVisitor, public DynamicWaveTable
{
private:
   DWVisitor &          operator=           (DWVisitor  const& rhs);
                   DWVisitor                (DWVisitor  const& rhs);

   CurrentSliceInfo       d_csi;

   //! _state
   double*                d_state;

   //! _flux
   double*                d_flux;

   const  LookupTable&    d_tab;

   const VField<INT4 >&   d_profileId;
   const float*           d_inflow;
   const VField<REAL4>&   d_bottomLevel;
   const VField<REAL4>&   d_roughness;
   const VField<REAL4>&   d_segmentLength;
   const VField<UINT1>&   d_constantState;

   //! set to 0 at start visit per Pit
   std::vector<double>    d_fluxTS;

   typedef double (* QDyn)(double Roughness, double Aact, double Sf, double R);
   const QDyn             d_qDyn;
   static  double qDynChezy(double,double,double,double);
   static  double qDynManning(double,double,double,double);

   void initVertexBeforeSlice(size_t v);
   void visitEdge        (size_t up, size_t down);
   void finishVertex     (size_t v);

   double dwPotential    (size_t v) const;
   double dwFlux         (size_t up,size_t down) const;
   double dwLookup       (size_t v,double  fromVal,
                          LookupColumns fromCol,
                          LookupColumns toCol) const;

public:
                    DWVisitor           (double* state, double* flux,
                                           const  LookupTable& tab,
                                           const  VField<INT4>&  profileId,
                                           const  LddGraph& lg,
                                           const  float*          inflow,
                                           const  VField<float>&  bottomLevel,
                                           const  VField<float>&  roughness,
                                           const  VField<float>&  segmentLength,
                                           const  VField<INT4>&   nrTimeSlices,
                                           const  Field&          timestepInSecs,
                                           const  VField<UINT1>&  constantState);

  /* virtual */    ~DWVisitor               ();

  void             initPerCatchmentSlice    (CurrentSliceInfo const& csi);

};

DWVisitor::DWVisitor(double* state, double* flux,
                 const  LookupTable& tab,
                 const  VField<INT4>&  profileId,
                 const  LddGraph& lg,
                 const  float*          inflow,
                 const  VField<float>&  bottomLevel,
                 const  VField<float>&  roughness,
                 const  VField<float>&  segmentLength,
                 const  VField<INT4>&   nrTimeSlices,
                 const  Field&          timestepInSecs,
                 const  VField<UINT1>&  constantState):
  TimeSliceVisitor(lg,nrTimeSlices,timestepInSecs),
  d_state(state),
  d_flux(flux),

  d_tab(tab),
  d_profileId(profileId),
  d_inflow(inflow),
  d_bottomLevel(bottomLevel),
  d_roughness(roughness),
  d_segmentLength(segmentLength),
  d_constantState(constantState),

  d_fluxTS(lg.nrVertices()),
  d_qDyn((appDynamicWaveRoughness==APP_DWR_CHEZY)?qDynChezy : qDynManning)
{
}

DWVisitor::~DWVisitor()
{
}

void DWVisitor::initPerCatchmentSlice(CurrentSliceInfo const& csi)
{
  d_csi = csi;
}

void DWVisitor::initVertexBeforeSlice(size_t v)
{
  d_fluxTS[v]=0;
}

//! identical structure as LddRouting::visitEdge
/*!
 * called for each edge from up to down in downstreamorder
 * calculate transport (flux) from up to down
 *
 * \pre
 *   d_fluxTs[up] is at entrance the sum of up's
 *   upstream fluxes, 0 if up has no upstream cells
 *   finishVertex does that
 */
void DWVisitor::visitEdge(size_t up, size_t down)
{
  // _potential = g(...) FTTB integrated in dwFlux()

  if (d_constantState[up]!=1)
    d_state[up] += d_inflow[up]/d_csi.nrTimeSlices;

  d_fluxTS[up] = std::min<double>(
                   d_state[up],
                   std::max(0.0,dwFlux(up,down))*d_csi.sliceInSecs);
  DEVELOP_PRECOND(d_fluxTS[up] >= 0);

  if (d_constantState[up]!=1)
    d_state[up]-=d_fluxTS[up];
  DEVELOP_PRECOND(d_state[up] >= 0);
  d_flux[up]+=d_fluxTS[up];

  // send calculated flux to down
  d_fluxTS[down]+=d_fluxTS[up];
}

void DWVisitor::finishVertex(size_t v)
{
  // d_fluxTS is now the sum of upstream fluxes
  if (d_constantState[v]!=1)
    d_state[v]+=d_fluxTS[v];
}

double tableLookup(
    const  LookupTable& tab,
    INT4   profileVal,
    float  fromVal,
    DynamicWaveTable::LookupColumns fromCol,
    DynamicWaveTable::LookupColumns toCol)
{
  double result;
  std::vector<float> prefixKey(1,profileVal);
  bool r=tab.interpolate(result, prefixKey,fromVal,fromCol,toCol);
  if (!r) {
     // enum   LookupColumns { profileId=0,H=1,A=2,P=3 };
     PRECOND(DynamicWaveTable::profileId==0);
     PRECOND(DynamicWaveTable::H==1);
     PRECOND(DynamicWaveTable::A==2);
     PRECOND(DynamicWaveTable::P==3);
     const char *names[] = {
       "ProfileId","H","A","P" };

     std::string msg(
      ( boost::format("No match for Key{ProfileId=%1%,%2%=%3%} -> %4%") %
      profileVal % names[fromCol] % fromVal % names[toCol]).str());
     throw DomainError(msg);
  }
  return result;
}

double DWVisitor::dwLookup(
    size_t v,
    double  fromVal,
    LookupColumns fromCol,
    LookupColumns toCol) const
{
  return tableLookup(d_tab,d_profileId[v],(float)fromVal,fromCol,toCol);
}

double DWVisitor::dwPotential(size_t v) const
{
  PRECOND(d_state[v] >= 0);
  double a = d_state[v]/d_segmentLength[v]; // m2
  double h = dwLookup(v,a,A,H);  // m
  return h+d_bottomLevel[v];
}

inline static double sqrtSf(
    double sF)
{
 // FTTB holds if no negative fluxes, sF always >= 0
 DEVELOP_PRECOND(sF >=0);
  if (sF >= 0)
        return std::sqrt(sF);
  return -std::sqrt(-sF);
}

//! calculates Q in m3/sec
double DWVisitor::qDynChezy(
    double Roughness,
    double Aact,
    double Sf,
    double R)
{
  // Roughness is Chezy-coefficient
  return Roughness  * Aact * sqrtSf(Sf)  * std::sqrt(R);
}

//! calculates Q in m3/sec
double DWVisitor::qDynManning(
    double Roughness,
    double Aact,
    double Sf,
    double R)
{
  // Roughness is Manning coefficient
  return sqrtSf(Sf)*Aact*std::pow(R,2.0/3)/Roughness;
}

/*
 * \param v    the upstream cell
 * \param down the downstream cell
 */
double DWVisitor::dwFlux(size_t v, size_t down) const
{
 double pot=dwPotential(v);
 double dsPot=dwPotential(down);
 if (dsPot > pot) {
   // FTTB no negative fluxes, e.g. no water uphill
   return 0.0;
 }
 double h=pot-d_bottomLevel[v]; // water depth in cell
 PRECOND(h>=0);
 double a=dwLookup(v,h,H,A); //  Aact natte oppervlak
 PRECOND(a >= 0);
 double p=dwLookup(v,h,H,P); // wetted perimeter voor de gegeven waterdiepte
 PRECOND(p >= 0);
 double aDivP = (p > 0 ? a/p : 0);
 double sF=(pot-dsPot)/d_segmentLength[v];
 // FTTB holds if no negative fluxes, sF always >= 0
 PRECOND(sF >=0);
 // qDyn is qDynChezy or qDynManning
 double  fluxPerSecond = d_qDyn(d_roughness[v], a, sF, aDivP);
 return fluxPerSecond;
}
} // namespace calc

//------------------------------------------------------------------------------
// DEFINITION OF STATIC DYNAMICWAVE MEMBERS
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// DEFINITION OF DYNAMICWAVE MEMBERS
//------------------------------------------------------------------------------

calc::DynamicWave::DynamicWave()
{
}

/* NOT IMPLEMENTED
//! Copy constructor.
calc::DynamicWave::DynamicWave(DynamicWave const& rhs)

  : Base(rhs)

{
}
*/

calc::DynamicWave::~DynamicWave()
{
}

/* NOT IMPLEMENTED
//! Assignment operator.
calc::DynamicWave& calc::DynamicWave::operator=(DynamicWave const& rhs)
{
  if (this != &rhs) {
  }
  return *this;
}
*/

void calc::DynamicWave::exec(RunTimeEnv* rte,
                             const Operator& op,
                             size_t nrActualInputs) const
{
  DynamicWaveExecArguments a(op,rte,nrActualInputs);
  const LookupTable *tab=
    dynamic_cast<const LookupTable *>(a.firstNonFieldInput());

  enum Args {
   argProfileId=0,
   argLdd=1,
   argOldState=2,
   argInflow=3,
   argBottomLevel=4,
   argRoughness=5,
   argSegmentLength=6,
   argNrTimeSlices=7,
   argTimestepInSecs=8,
   argConstantState=9
  };

  ScopedLddGraph      lg(rte,a[argLdd]);

  // field length, ldd known to be spatial
  size_t fLen=a[argLdd].nrValues();

  BitField mvField(fLen);
  POSTCOND(mvField.none());

  const VField<INT4>      profileId(a[argProfileId],mvField);
  const VField<REAL4>      oldState(a[argOldState],mvField);
  const VField<REAL4>        inflow(a[argInflow],mvField);
  const VField<REAL4>   bottomLevel(a[argBottomLevel],mvField);
  const VField<REAL4>     roughness(a[argRoughness],mvField);
  const VField<REAL4> segmentLength(a[argSegmentLength],mvField);
  const VField<INT4>   nrTimeSlices(a[argNrTimeSlices],mvField);
  const VField<UINT1> constantState(a[argConstantState],mvField);

  PRECOND(!a[argTimestepInSecs].isSpatial());
  float timestepInSecs= a[argTimestepInSecs].src_f()[0];
  if (timestepInSecs <= 0)
    throw DomainError("timestepInSecs must be > 0");

  // check for nonspatial case
  PRECOND(!a[argNrTimeSlices].isSpatial());
  if (a[argNrTimeSlices].src_4()[0] <= 0)
      throw DomainError("nrTimeSlices must be > 0");

  // initialize newStateV with oldState
  std::vector<double> newStateV(fLen);
  lg.current().copyField<double,float>(&(newStateV[0]),oldState);
  // initialize fluxV to 0
  std::vector<double> fluxV(fLen,0.0);

  lg.setMVInput(mvField);

  // m3/channellength/sec  -> m3/Timestep
  std::vector<float> inflowM3perTimestep(fLen);
  lg.current().copyField<float,float>(&(inflowM3perTimestep[0]),inflow);
  for(size_t i=0; i < fLen; ++i)
    inflowM3perTimestep[i] *= timestepInSecs * segmentLength[i];

  DWVisitor  dwv(&(newStateV[0]),&(fluxV[0]),*tab,
                 profileId,
                 lg.current(),
                 &(inflowM3perTimestep[0]),
                 bottomLevel,
                 roughness,
                 segmentLength,
                 nrTimeSlices,
                 a[argTimestepInSecs],
                 constantState);

  dwv.visitPerCachmentSlice();

  a.createResults();
  Field& newState(a.result(0));
  Field&     flux(a.result(1));

  lg.current().copyField<float,double>(newState.dest_f(),&(newStateV[0]));

  // m3/timestep -> m3/sec
  for(size_t i=0; i < fLen; ++i)
    fluxV[i] /= timestepInSecs;
  lg.current().copyField<float,double>(flux.dest_f(),&(fluxV[0]));

  a.pushResults();
}

void calc::LookupState::exec(RunTimeEnv* rte,
                             const Operator& op,
                             size_t nrActualInputs) const
{
  DynamicWaveExecArguments a(op,rte,nrActualInputs);
  const LookupTable *tab=
    dynamic_cast<const LookupTable *>(a.firstNonFieldInput());

  Field& result(a.createResult());

  // 1 if all inputs are nonspatial
  size_t fLen=result.nrValues();

  const VField<INT4>      profileId(a[0],fLen);
  const VField<REAL4>   bottomLevel(a[1],fLen);
  const VField<REAL4> segmentLength(a[2],fLen);
  const VField<REAL4>     potential(a[3],fLen);

  PRECOND(result.cri()==CRI_f);
  float *r=result.dest_f();
  for(size_t i=0;i<fLen;++i) {
    if (com::oneIsMV(profileId[i],bottomLevel[i])|
        com::oneIsMV(segmentLength[i],potential[i]))
      pcr::setMV(r[i]);
    else {
      float h=potential[i]-bottomLevel[i];
      double a=tableLookup(*tab,profileId[i],h,
          DynamicWaveTable::H, DynamicWaveTable::A);
      r[i]=(float)(a*segmentLength[i]);
    }
  }

  a.pushResults();
}

void calc::LookupPotential::exec(RunTimeEnv* rte,
                             const Operator& op,
                             size_t nrActualInputs) const
{
  DynamicWaveExecArguments a(op,rte,nrActualInputs);
  const LookupTable *tab=
    dynamic_cast<const LookupTable *>(a.firstNonFieldInput());

  Field& result(a.createResult());

  // 1 if all inputs are nonspatial
  size_t fLen=result.nrValues();

  const VField<INT4>      profileId(a[0],fLen);
  const VField<REAL4>   bottomLevel(a[1],fLen);
  const VField<REAL4> segmentLength(a[2],fLen);
  const VField<REAL4>         state(a[3],fLen);

  PRECOND(result.cri()==CRI_f);
  float *r=result.dest_f();
  for(size_t i=0;i<fLen;++i) {
    if (com::oneIsMV(profileId[i],bottomLevel[i])|
        com::oneIsMV(segmentLength[i],state[i]))
      pcr::setMV(r[i]);
    else {
      // identical to dwPotential
      float a=state[i]/segmentLength[i]; // m2
      double h=tableLookup(*tab,profileId[i],a,
          DynamicWaveTable::A, DynamicWaveTable::H); // m
      r[i]=(float)(h+bottomLevel[i]);
    }
  }

  a.pushResults();
}

static double iterateToQnew(
    double Qin,
    double Qold,
    double q,
    double alpha,
    double beta,
    double sliceInSecs,
    double deltaX);

/*!
   \sa $OLDPCRTREE/docs/pcrmanual/manual_updates/dynWaveRouting.doc

The two kinematic variants (kinematic() and kinematicflux/kinematicstate()
have been reworked considerable in two stages. Goal was to have them and dynamicwave working in constitently together, all three use comparable units for their inputs and outputs. The two work stages were:
  - As delivered to JRC May 2006 on base of WIllem March 22 2006 mail.
  - September 2007 (see mail Willem/JRC/Cees)

The result is the October 3 2007 version and on, that is the following in pseudo code:

\code
function kinematic( ldd, Qold, q, alpha, beta, numberOfTimeSlices, dT, dX)
begin
  1 Zoek de pits en lees de waarde van numberOfTimeSlices voor de pit
  foreach pit do
(*    findcatchment *)
    2 Voor de catchment boven de pit do
    begin
      sliceInSecs :=dT/numberOfTimeSlices
      for i:=1 to numberOfTimeSlices do
        begin
          Qnew=iterateToQnew(?,Qold,q,...,sliceInSecs, dX)
          Qold:=QNew;
        end;
    end;
end;

static double iterateToQnew(
    double Qin,
    double Qold,
    double q,
    double alpha,
    double beta,
    double sliceInSecs,
    double deltaX);
\encode

Assuming the above is what we already have, we define the following variant:

kinwavestate, kinwaveflux(ldd, previousState, qChan, alpha, beta, nrTimeslices, dT, dX)
The parameters are identical to the kinematic() ones:
 - Qold has become previousStat = previous state in m3
 - qChan inflow per m channellength m3/m/sec

So the code will compute a state and flux:

\code

kinwaveStateFluxVersion(ldd, previousState, qChan, alpha, beta, nrTimeslices, dT, dX)
begin
  1 Zoek de pits en lees de waarde van numberOfTimeSlices voor de pit
  foreach pit do
(*    findcatchment *)
    2 Voor de catchment boven de pit do
    begin
      Qold = (previousState / (alpha * dX)) ** (1/beta)   [m3/sec]
      Qsum = 0
      sliceInSecs  = dT/numberOfTimeSlices
      for i:=1 to numberOfTimeSlices do
        begin
          Qnew=iterateToQnew(?,Qold,qChan,..., sliceInSecs,dX)
          Qsum = Qsum + QNew
        end;
      State = alpha*(Qnew**beta)*dX
      Flux  = (Qsum/nrTimeslices)
    end;
end;

\endcode
*/
void calc::Kinematic::exec(
    RunTimeEnv* rte,
    const Operator& op,
    size_t nrArgs) const
{

  struct KWVisitor : public TimeSliceVisitor
  {

     float*              d_Qnew;
     CurrentSliceInfo    d_csi;

     std::vector<float>  d_QSumDownStream;
     const VField<float> d_q;
     const VField<float> d_alpha;
     const VField<float> d_beta;
     const VField<float> d_deltaX;

     void     initVertexBeforeSlice(size_t v) {
       d_QSumDownStream[v]=0.0;
     }

     bool mv(size_t pos) const {
      return
        com::oneIsMV(d_QSumDownStream[pos],d_q[pos],d_alpha[pos]) |
        com::oneIsMV(d_beta[pos],d_deltaX[pos]);
     }

     void initPerCatchmentSlice(CurrentSliceInfo const& csi)
     {
       d_csi = csi;
     }

     void visitEdge        (size_t up, size_t down) {
       // send calculated flux to down
       com::inplace_add(d_QSumDownStream[down],d_Qnew[up]);
     }

     void finishVertex     (size_t v) {
       if (mv(v)|pcr::isMV(d_Qnew[v])) {
         pcr::setMV(d_Qnew[v]);
         return;
       }
       d_Qnew[v] = (float)iterateToQnew(
           d_QSumDownStream[v], // summed Q new in for all sub-catchments
           d_Qnew[v],          /* current discharge */
           d_q[v],
           d_alpha[v],
           d_beta[v],
           d_csi.sliceInSecs,
           d_deltaX[v]);
     }

     KWVisitor (Field & qNew,
          VField<INT4>  const& nrTimeSlices,
          Field         const& timestepInSecs,
          ExecArguments const& arg,
          LddGraph      const& lg):

         TimeSliceVisitor(lg,nrTimeSlices,timestepInSecs),
         d_Qnew(qNew.dest_f()),
         d_QSumDownStream(qNew.nrValues()),

         d_q           (arg[2],qNew.nrValues()),
         d_alpha       (arg[3],qNew.nrValues()),
         d_beta        (arg[4],qNew.nrValues()),
         d_deltaX      (arg[7],qNew.nrValues())
       {
         const VField<float> Qold(arg[1],qNew.nrValues());
         // initialize QNew from Qold
         for(size_t i=0; i < qNew.nrValues(); ++i)
               d_Qnew[i] = Qold[i];
       }
  };

  ExecArguments arg(op,rte,nrArgs);
  ScopedLddGraph lgs(rte,arg[0]);
  LddGraph const& lg(lgs.current());
  Field& qNew(arg.createResult());

  const VField<INT4> nrTimeSlices(arg[5],qNew.nrValues());
  KWVisitor v(qNew,nrTimeSlices ,arg[6],arg, lg);

  v.visitPerCachmentSlice();
  arg.pushResults();
}

#include "muskingum.h"
// #include "muskingum8April2009.h"

void calc::KinematicWave::exec(
    RunTimeEnv* rte,
    const Operator& op,
    size_t nrArgs) const
{

  // KinematicWave flux/state visitor
  struct KWFSVisitor : public TimeSliceVisitor
  {

     float*              d_Qnew; // use newState buffer
     float*              d_QSum; // use flux buffer
     CurrentSliceInfo    d_csi;
     std::vector<float>  d_QSumDownStream;
     const VField<float> d_qChan;
     const VField<float> d_alpha;
     const VField<float> d_beta;
     const VField<float> d_deltaX;

     void     initVertexBeforeSlice(size_t v) {
       d_QSumDownStream[v]=0.0;
     }

     bool mv(size_t pos) const {
      return
        com::oneIsMV(d_QSumDownStream[pos],d_qChan[pos],d_alpha[pos]) |
        com::oneIsMV(d_beta[pos],d_deltaX[pos]);
     }

     void initPerCatchmentSlice(CurrentSliceInfo const& csi )
     {
       d_csi = csi;
     }

     void visitEdge        (size_t up, size_t down) {
       // send calculated flux to down
       com::inplace_add(d_QSumDownStream[down],d_Qnew[up]);
     }

     void finishVertex     (size_t v) {
       if (mv(v)|pcr::isMV(d_Qnew[v])) {
         pcr::setMV(d_Qnew[v]);
         return;
       }
       d_Qnew[v] = (float)iterateToQnew(
           d_QSumDownStream[v], // summed Q new in for all sub-catchments
           d_Qnew[v],          /* current discharge */
           d_qChan[v],
           d_alpha[v],
           d_beta[v],
           d_csi.sliceInSecs,
           d_deltaX[v]);
       d_QSum[v] += d_Qnew[v];
     }

     KWFSVisitor (
          Field & newState,
          Field & flux,
          VField<INT4>  const& nrTimeSlices,
          Field         const& timestepInSecsField,
          ExecArguments const& arg,
          LddGraph      const& lg):

         TimeSliceVisitor(lg,nrTimeSlices,timestepInSecsField),
         d_Qnew(newState.dest_f()), // use newState for Qnew buffer
         d_QSum(flux.dest_f()), // use flux for QSum buffer
         d_QSumDownStream(newState.nrValues()),
         d_qChan       (arg[2],newState.nrValues()),
         d_alpha       (arg[3],newState.nrValues()),
         d_beta        (arg[4],newState.nrValues()),
         d_deltaX      (arg[7],newState.nrValues())
       {
         const VField<float> previousState(arg[1],newState.nrValues());
         // initialize Qold as first Qnew value
         // d_Qnew is MV marker used in computeFluxAndState
         for(size_t i=0; i < newState.nrValues(); ++i) {
          if (com::oneIsMV(previousState[i],d_qChan[i],d_alpha[i]) |
             com::oneIsMV(d_beta[i],d_deltaX[i])) {
                pcr::setMV(d_Qnew[i]);
                pcr::setMV(d_QSum[i]);
          } else {
             d_Qnew[i]= std::pow(previousState[i]/(d_alpha[i]*d_deltaX[i]),1/d_beta[i]);
             d_QSum[i] = 0;
          }
        }
       }

     void computeState()
     {
       for(size_t i=0; i < d_QSumDownStream.size(); ++i) {
         if (!pcr::isMV(d_Qnew[i])) {
           // d_Qnew is marker, if that is !mv nothing is mv

           // newState = alpha*(Qnew**beta)*dX:
           d_Qnew[i]  = d_alpha[i] * std::pow(d_Qnew[i],d_beta[i]) * d_deltaX[i];
         }
       }
     }
  };

  struct DivideFluxByNrTimeSlices : public DownstreamVisitor
  {
     float*              d_flux;
     VField<INT4> const& d_nrTimeSlices;
     size_t              d_pitIdOfCurrentCatchment;

     void startCatchment(size_t pitIdOfCatchment)
     {
      d_pitIdOfCurrentCatchment = pitIdOfCatchment;
     }

     void     finishVertex(size_t v)
     {
       if (! pcr::isMV(d_flux[v]))
           d_flux[v] /= d_nrTimeSlices[d_pitIdOfCurrentCatchment];
     }

     DivideFluxByNrTimeSlices(
          Field & flux,
          VField<INT4>  const& nrTimeSlices,
          LddGraph      const& lg):

         DownstreamVisitor(lg),
         d_flux(flux.dest_f()),
         d_nrTimeSlices(nrTimeSlices)
       {
       }
  };

  ExecArguments arg(op,rte,nrArgs);
  ScopedLddGraph lgs(rte,arg[0]);
  LddGraph const& lg(lgs.current());

  arg.createResult();

  Field& newState(arg.result(0));
  Field& flux    (arg.result(1));

  const VField<INT4> nrTimeSlices(arg[5],newState.nrValues());

  KWFSVisitor v(newState,flux,nrTimeSlices ,arg[6],arg, lg);
  v.visitPerCachmentSlice();
  v.computeState();

  DivideFluxByNrTimeSlices df(flux,nrTimeSlices, lg);
  df.visitEntireLdd();

  arg.pushResults();
}

#define MAX_ITERS 3000

static double iterateToQnew(
    double Qin,   /* summed Q new in for all sub-catchments */
    double Qold,  /* current discharge */
    double q,
    double alpha,
    double beta,
    double sliceInSecs,
    double deltaX)
{
    const  double epsilon(1E-12); // iteration epsilon

    // Using Newton-Raphson Method
    typedef long double REAL;
    REAL Qk1;      // Q at loop k+1 for i+1, j+1
    REAL ab_pQ, deltaTX, C;
    int   count;

    REAL Qkx;
    REAL fQkx;
    REAL dfQkx;
    POSTCOND(sizeof(REAL) >= 8);

    // if no input then output = 0
    if ((Qin+Qold+q) == 0)  // +q CW NEW!
        return(0);

    // common terms
    ab_pQ = alpha*beta*std::pow(((Qold+Qin)/2),beta-1);
    deltaTX = sliceInSecs/deltaX;
    C = deltaTX*Qin + alpha*std::pow(Qold,beta) + sliceInSecs*q;

    //  1. Initial guess Qk1.
    //  2. Evaluate function f at Qkx.
    //  3. Evaluate derivative df at Qkx.
    //  4. Check convergence.

    // There's a problem with the first guess of Qkx. fQkx is only defined
    // for Qkx's > 0. Sometimes the first guess results in a Qkx+1 which is
    // negative or 0. In that case we change Qkx+1 to 1e-30. This keeps the
    // convergence loop healthy.
    Qkx   = (deltaTX * Qin + Qold * ab_pQ + sliceInSecs * q) / (deltaTX + ab_pQ);
    Qkx   = MAX(Qkx, 1e-30); /* added test-case calc::KinematicTest::iterate1 */
    fQkx  = deltaTX * Qkx + alpha * std::pow(Qkx, (REAL)beta) - C;   /* Current k */
    dfQkx = deltaTX + alpha * beta * std::pow(Qkx, (REAL)beta - 1);  /* Current k */
    Qkx   -= fQkx / dfQkx;                                /* Next k */
    Qkx   = MAX(Qkx, 1e-30);
    count = 0;
    do {
      fQkx  = deltaTX * Qkx + alpha * std::pow(Qkx, (REAL)beta) - C;   /* Current k */
      dfQkx = deltaTX + alpha * beta * std::pow(Qkx, (REAL)beta - 1);  /* Current k */
      Qkx   -= fQkx / dfQkx;                                /* Next k */
      Qkx   = MAX(Qkx, 1e-30);
      count++;
    } while(std::fabs(fQkx) > epsilon && count < MAX_ITERS);

#ifdef DEBUG_DEVELOP
    /* Our loop should converge in around 2 steps, otherwise something's
     * wrong.
     */
    /*  test-case calc::KinematicTest::iterate2
     *  is such a case, but values are very low
     * 1e-30 is returned
     */
     // if (count == MAX_ITERS) {
     //  printf("\nfQkx %g Qkx %g\n",(double)fQkx, (double)Qkx);
     //  printf("Qin %g \n", Qin);
     //  printf("Qold %g \n", Qold);
     //  printf("q %g \n", q);
     //  printf("alpha %g \n",alpha);
     //  printf("beta %g \n", beta);
     //  printf("sliceInSecs %g \n", sliceInSecs);
     //  printf("deltaX %g \n", deltaX);
     // }
#endif
    Qk1 = Qkx;
    return (double)(MAX(Qk1,0));
}

//------------------------------------------------------------------------------
// DEFINITION OF FREE OPERATORS
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// DEFINITION OF FREE FUNCTIONS
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
/*
    This file is part of rippled: https://github.com/ripple/rippled
    Copyright (c) 2016 Ripple Labs Inc.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose  with  or without fee is hereby granted, provided that the above
    copyright notice and this permission notice appear in all copies.

    THE  SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    WITH  REGARD  TO  THIS  SOFTWARE  INCLUDING  ALL  IMPLIED  WARRANTIES  OF
    MERCHANTABILITY  AND  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    ANY  SPECIAL ,  DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    WHATSOEVER  RESULTING  FROM  LOSS  OF USE, DATA OR PROFITS, WHETHER IN AN
    ACTION  OF  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

#include <ripple/conditions/Condition.h>
#include <ripple/conditions/Fulfillment.h>
#include <ripple/conditions/RsaSha256.h>
#include <ripple/conditions/impl/base64.h>
#include <ripple/protocol/digest.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/sha.h>

#include <boost/algorithm/clamp.hpp>
#include <algorithm>
#include <iterator>

namespace ripple {
namespace cryptoconditions {

namespace detail {

struct rsa_deleter
{
    void operator() (RSA* rsa) const
    {
        RSA_free (rsa);
    }
};

using RsaKey = std::unique_ptr<RSA, rsa_deleter>;

struct bn_deleter
{
    void operator() (BIGNUM* bn) const
    {
        BN_free (bn);
    }
};

using BigNum = std::unique_ptr<BIGNUM, bn_deleter>;

// Check whether the public modulus meets the length
// requirements imposed by section 4.4.1 of the RFC.
bool
checkModulusLength (int len)
{
    if (len <= 0)
        return false;

    return len == boost::algorithm::clamp(len, 128, 512);
}

bool
signHelper (
    RSA* key,
    Slice message,
    Buffer& modulus,
    Buffer& signature)
{
    int const keySize = RSA_size(key);
    if (!checkModulusLength (keySize))
        return false;

    sha256_hasher h;
    h (message.data(), message.size());
    auto digest = static_cast<sha256_hasher::result_type>(h);

    Buffer buf;

    // Pad the result (-1 -> use hash length as salt length)
    if (!RSA_padding_add_PKCS1_PSS(key,
            buf.alloc(keySize), digest.data(),
            EVP_sha256(), -1))
        return false;

    // Sign - we've manually padded the input already.
    auto ret = RSA_private_encrypt(keySize, buf.data(),
        signature.alloc (buf.size()), key, RSA_NO_PADDING);

    if (ret == -1)
        return false;

    BN_bn2bin (key->n, modulus.alloc(BN_num_bytes (key->n)));
    return true;
}

bool
validateHelper (
    RSA* key,
    Slice message,
    Slice signature)
{
    int const keySize = RSA_size(key);
    if (!checkModulusLength (keySize))
        return false;

    Buffer buf;

    auto ret = RSA_public_decrypt(
        keySize,
        signature.data(),
        buf.alloc (keySize),
        key,
        RSA_NO_PADDING);

    if (ret == -1)
        return false;

    sha256_hasher h;
    h (message.data(), message.size());
    auto digest = static_cast<sha256_hasher::result_type>(h);

    return RSA_verify_PKCS1_PSS(key, digest.data(), EVP_sha256(), buf.data(), -1) == 1;
}

bool
parsePayloadHelper(
    Slice s,
    Buffer& modulus,
    Buffer& signature)
{
    auto start = s.data ();
    auto finish = s.data () + s.size();

    std::size_t len;

    std::tie (start, len) = oer::decode_length (
        start, finish);

    if (std::distance (start, finish) < len)
        return false;

    std::memcpy (modulus.alloc (len), start, len);
    std::advance (start, len);

    std::tie (start, len) = oer::decode_length (
        start, finish);

    if (std::distance (start, finish) < len)
        return false;

    std::memcpy (signature.alloc (len), start, len);
    std::advance (start, len);

    // Per 4.4.2 of the RFC we must check whether the
    // signature and modulus consist of the same number
    // of octets:
    if (signature.size() != modulus.size())
        return false;

    // Enforce constraints from the RFC:
    BigNum sig (BN_bin2bn (
        signature.data(), signature.size(), nullptr));

    BigNum mod (BN_bin2bn (
        modulus.data(), modulus.size(), nullptr));

    if (!sig || !mod)
        return false;

    // Per 4.4.1 of the RFC we are required to reject
    // moduli smaller than 128 bytes or greater than
    // 512 bytes.
    int modBytes = BN_num_bytes (mod.get());

    if (!checkModulusLength (modBytes))
        return false;

    // Per 4.4.2 of the RFC we must check that the signature
    // is numerically less than the modulus:
    return BN_cmp (sig.get(), mod.get()) < 0;
}

}

Condition
RsaSha256::condition() const
{
    std::vector<std::uint8_t> m;
    m.reserve (1024);

    oer::encode_octetstring (
        modulus_.size(),
        modulus_.data(),
        modulus_.data() + modulus_.size(),
        std::back_inserter(m));

    sha256_hasher h;
    h (m.data(), m.size());

    Condition cc;
    cc.type = type();
    cc.featureBitmask = features();
    cc.maxFulfillmentLength = payloadSize();

    cc.fingerprint = static_cast<sha256_hasher::result_type>(h);

    return cc;
}

std::size_t
RsaSha256::payloadSize () const
{
    return
        oer::predict_octetstring_size (modulus_.size()) +
        oer::predict_octetstring_size (signature_.size());
}

Buffer
RsaSha256::payload() const
{
    Buffer b (payloadSize());

    auto out = oer::encode_octetstring (
        modulus_.size(),
        modulus_.data(),
        modulus_.data() + modulus_.size(),
        b.data());

    oer::encode_octetstring (
        signature_.size(),
        signature_.data(),
        signature_.data() + modulus_.size(),
        out);

    return b;
}

bool
RsaSha256::validate (Slice data) const
{
    if (!ok())
        return false;

    detail::RsaKey rsa (RSA_new());

    rsa->n = BN_new();
    BN_bin2bn(modulus_.data(), modulus_.size(), rsa->n);

    rsa->e = BN_new();
    BN_set_word (rsa->e, 65537);

    return detail::validateHelper (rsa.get(), data, signature_);
}

/** Sign the given message with an RSA key */
bool
RsaSha256::sign (
    std::string const& key,
    Slice message)
{
    // This ugly const_cast/reinterpret_cast is needed
    // on some machines. Although the documentation
    // suggests that the function accepts a void const*
    // argument, apparently some platforms have OpenSSL
    // libraries that are up-to-date but accept void*.
    auto bio = BIO_new_mem_buf(
        const_cast<void*>(static_cast<void const*>(key.data())),
        key.size());

    if (!bio)
        return false;

    detail::RsaKey rsa (PEM_read_bio_RSAPrivateKey(
        bio, NULL, NULL, NULL));

    BIO_free(bio);

    if (!rsa)
        return false;

    if (detail::signHelper (rsa.get(), message, modulus_, signature_))
        return true;

    modulus_.clear();
    signature_.clear();
    return false;
}

bool
RsaSha256::parsePayload (Slice s)
{
    // The payload may not be empty
    if (!s.empty() && detail::parsePayloadHelper (s, modulus_, signature_))
        return true;

    // Clear the state
    modulus_.clear();
    signature_.clear();
    return false;
}

}

}


//==================================================================================================
/*!
  @file

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_IS_EQZ_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IS_EQZ_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

  /*!

    @ingroup group-predicates
    This function object returns @ref True or @ref False according x is @ref Zero or not.

    @par Header <boost/simd/function/is_eqz.hpp>

    @par Note

      Using `is_eqz(x)` is equivalent to `x == 0`

    @see is_nez, is_lez, is_ltz

    @par Example:

      @snippet is_eqz.cpp is_eqz

    @par Possible output:

      @snippet is_eqz.txt is_eqz

  **/
  as_logical_t<Value> is_eqz(Value const& x);
} }
#endif

#include <boost/simd/function/scalar/is_eqz.hpp>
#include <boost/simd/function/simd/is_eqz.hpp>

#endif


//==============================================================================
//          Copyright 2015 J.T.  Lapreste
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <boost/simd/bitwise/include/functions/swapbytes.hpp>

#include <boost/dispatch/functor/meta/call.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <boost/simd/sdk/config.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/simd/include/functions/splat.hpp>
#include <boost/simd/include/functions/enumerate.hpp>
#include <boost/simd/include/functions/simd/shift_left.hpp>

NT2_TEST_CASE_TPL ( swapbytes,   BOOST_SIMD_SIMD_INTEGRAL_TYPES)
{

  using boost::simd::swapbytes;
  using boost::simd::tag::swapbytes_;
  typedef BOOST_SIMD_DEFAULT_EXTENSION                             ext_t;
  typedef boost::simd::native<T,ext_t>                                vT;

  // specific values tests
  vT a =  boost::simd::enumerate<vT>(0xF0);
  for(std::size_t i=0; i < sizeof(T) ; i++)
  {
    vT za =  boost::simd::shl(a, 8*i);
    NT2_TEST_EQUAL(swapbytes(za), boost::simd::shl(a,(sizeof(T)-i-1)*8));
  }

} // end of test for unsigned_int_


//------------------------------------------//
//  This file is a modified version of      //
//  basics.cpp, which was distributed as    //
//  part of MuJoCo,  Written by Emo Todorov //
//  Copyright (C) 2017 Roboti LLC           //
//  Modifications by Atabak Dehban          //
//------------------------------------------//

#include <iostream>

#include "mujoco.h"
#include "cstdio"
#include "cstdlib"
#include "cstring"
#include "glfw3.h"

// for sleep timers
#include <chrono>
#include <thread>

// Eigen, used by drake
#include <Eigen/Core>
#include <unsupported/Eigen/MatrixFunctions>
#include "drake/systems/controllers/linear_quadratic_regulator.h"

// MuJoCo data structures
mjModel* m = NULL;                  // MuJoCo model
mjData* d = NULL;                   // MuJoCo data
mjvCamera cam;                      // abstract camera
mjvOption opt;                      // visualization options
mjvScene scn;                       // abstract scene
mjrContext con;                     // custom GPU context

// mouse interaction
bool button_left = false;
bool button_middle = false;
bool button_right =  false;
double lastx = 0;
double lasty = 0;

// holders of one step history of time and position to calculate dertivatives
mjtNum position_history = 0;
mjtNum previous_time = 0;

// controller related variables
float_t ctrl_update_freq = 1000;
mjtNum last_update = 0.0;
mjtNum ctrl;

// keyboard callback
void keyboard(GLFWwindow* window, int key, int scancode, int act, int mods)
{
    // backspace: reset simulation
    if( act==GLFW_PRESS && key==GLFW_KEY_BACKSPACE )
    {
        mj_resetData(m, d);
        mj_forward(m, d);
    }
}

// mouse button callback
void mouse_button(GLFWwindow* window, int button, int act, int mods)
{
    // update button state
    button_left =   (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT)==GLFW_PRESS);
    button_middle = (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE)==GLFW_PRESS);
    button_right =  (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT)==GLFW_PRESS);

    // update mouse position
    glfwGetCursorPos(window, &lastx, &lasty);
}

// mouse move callback
void mouse_move(GLFWwindow* window, double xpos, double ypos)
{
    // no buttons down: nothing to do
    if( !button_left && !button_middle && !button_right )
        return;

    // compute mouse displacement, save
    double dx = xpos - lastx;
    double dy = ypos - lasty;
    lastx = xpos;
    lasty = ypos;

    // get current window size
    int width, height;
    glfwGetWindowSize(window, &width, &height);

    // get shift key state
    bool mod_shift = (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)==GLFW_PRESS ||
                      glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT)==GLFW_PRESS);

    // determine action based on mouse button
    mjtMouse action;
    if( button_right )
        action = mod_shift ? mjMOUSE_MOVE_H : mjMOUSE_MOVE_V;
    else if( button_left )
        action = mod_shift ? mjMOUSE_ROTATE_H : mjMOUSE_ROTATE_V;
    else
        action = mjMOUSE_ZOOM;

    // move camera
    mjv_moveCamera(m, action, dx/height, dy/height, &scn, &cam);
}

// scroll callback
void scroll(GLFWwindow* window, double xoffset, double yoffset)
{
    // emulate vertical mouse motion = 5% of window height
    mjv_moveCamera(m, mjMOUSE_ZOOM, 0, -0.05*yoffset, &scn, &cam);
}

// control loop callback
void mycontroller(const mjModel* m, mjData* d)
{
    // printouts for debugging purposes
    mjtObj geom = mjOBJ_GEOM;
    mjtObj body = mjOBJ_BODY;
    mjtObj dof = mjOBJ_JOINT;
    int ball_id = mj_name2id(m, body, "ballbody");
    int rod_id = mj_name2id(m, geom, "rod");
    int pivot_id = mj_name2id(m, dof, "pivot");
    std::cout << "ball body id: " << ball_id << std::endl;
    std::cout << "rod geom id: " << rod_id << std::endl;
    std::cout << "pivot joint id: " << pivot_id << std::endl;
    std::cout << "ball mass: " << m->body_mass[ball_id] << std::endl;
    std::cout << "length of the rod: " << m->geom_size[rod_id*3+1] << std::endl;
    std::cout << "friction coefficient: " << m->dof_damping[pivot_id] << std::endl;
    std::cout << "gravity: " << m->opt.gravity[2] << std::endl;
    std::cout << "Sensor output: " << d->sensordata[0] << std::endl;

    // System dynamics matrices: https://github.com/RobotLocomotion/drake/blob/master/systems/controllers/zmp_planner.h#L306
    Eigen::Matrix<mjtNum , 2, 2> A_;
    Eigen::Matrix<mjtNum , 2, 1> B_;
    Eigen::Matrix<mjtNum , 2, 2> Q_ = Eigen::Matrix<mjtNum , 2, 2>::Identity();
    Eigen::Matrix<mjtNum , 1, 1> R_ = Eigen::Matrix<mjtNum , 1, 1>::Identity();
    Eigen::Matrix<mjtNum , 2, 1> N = Eigen::Matrix<mjtNum , 2, 1>::Zero();

    // Eqs comming from https://youtu.be/XA6B1IxALhk?t=30m3s
    A_(0,0) = 0.0;
    A_(0,1) = 1.0;
    A_(1,0) = - m->opt.gravity[2]*mju_cos(d->sensordata[0])/(m->geom_size[rod_id*3+1]*2);
    A_(1,1) = - m->dof_damping[pivot_id]/(m->body_mass[ball_id]*mju_pow(m->geom_size[rod_id*3+1]*2,2.0));
    B_(0,0) = 0.0;
    B_(1,0) = 1.0;
    Q_ *= 10.0;

    drake::systems::controllers::LinearQuadraticRegulatorResult lqr_result =
            drake::systems::controllers::LinearQuadraticRegulator(A_, B_, Q_, R_, N);
    Eigen::Matrix<mjtNum, 2, 2> S1_ = lqr_result.S;
    Eigen::Matrix<mjtNum, 1, 2> K_= -lqr_result.K;

    // controller with true values, but it is cheating.
//    ctrl = 3.5*(-d->qvel[0]-10.0*d->qpos[0]);

    // controller with sensor readings
    if (previous_time == 0)
    {
        previous_time = d->time;
        return;
    }
    if (d->time - last_update > 1.0/ctrl_update_freq)
    {
        mjtNum vel = (d->sensordata[0] - position_history)/(d->time-previous_time);
        ctrl = K_(0,0)*d->sensordata[0] + K_(0,1)*vel;
        last_update = d->time;
        position_history = d->sensordata[0];
        previous_time = d->time;
    }
    d->ctrl[0] = ctrl;

    std::cout << "torque effort: " << ctrl << std::endl;
}

// main function
int main(int argc, const char** argv)
{

    // activate software
    mj_activate("../../../mjkey.txt");

    // load and compile model
    char error[1000] = "Could not load binary model";

    // check command-line arguments
    if( argc<2 )
        m = mj_loadXML("../../../models/invertedPendulum.xml", 0, error, 1000);

    else
        if( strlen(argv[1])>4 && !strcmp(argv[1]+strlen(argv[1])-4, ".mjb") )
            m = mj_loadModel(argv[1], 0);
        else
            m = mj_loadXML(argv[1], 0, error, 1000);
    if( !m )
        mju_error_s("Load model error: %s", error);

    // make data
    d = mj_makeData(m);

    // init GLFW
    if( !glfwInit() )
        mju_error("Could not initialize GLFW");

    // create window, make OpenGL context current, request v-sync
    GLFWwindow* window = glfwCreateWindow(1200, 900, "Demo", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    // initialize visualization data structures
    mjv_defaultCamera(&cam);
    mjv_defaultOption(&opt);
    mjv_defaultScene(&scn);
    mjr_defaultContext(&con);
    mjv_makeScene(m, &scn, 2000);                // space for 2000 objects
    mjr_makeContext(m, &con, mjFONTSCALE_150);   // model-specific context

    // install GLFW mouse and keyboard callbacks
    glfwSetKeyCallback(window, keyboard);
    glfwSetCursorPosCallback(window, mouse_move);
    glfwSetMouseButtonCallback(window, mouse_button);
    glfwSetScrollCallback(window, scroll);

    // install control callback
    mjcb_control = mycontroller;

    // initial position
    d->qpos[0] = 1.57;

    // run main loop, target real-time simulation and 60 fps rendering
    mjtNum timezero = d->time;
    double_t update_rate = 0.01;

    // making sure the first time step updates the ctrl previous_time
    last_update = timezero-1.0/ctrl_update_freq;

    // use the first while condition if you want to simulate for a period.
//    while( !glfwWindowShouldClose(window) and d->time-timezero < 1.5)
    while( !glfwWindowShouldClose(window))
    {
        // advance interactive simulation for 1/60 sec
        //  Assuming MuJoCo can simulate faster than real-time, which it usually can,
        //  this loop will finish on time for the next frame to be rendered at 60 fps.
        //  Otherwise add a cpu timer and exit this loop when it is time to render.
        mjtNum simstart = d->time;
        while( d->time - simstart < 1.0/60.0 )
            mj_step(m, d);

        // 15 ms is a little smaller than 60 Hz.
        std::this_thread::sleep_for(std::chrono::milliseconds(15));
       // get framebuffer viewport
        mjrRect viewport = {0, 0, 0, 0};
        glfwGetFramebufferSize(window, &viewport.width, &viewport.height);

          // update scene and render
        mjv_updateScene(m, d, &opt, NULL, &cam, mjCAT_ALL, &scn);
        mjr_render(viewport, &scn, &con);

        // swap OpenGL buffers (blocking call due to v-sync)
        glfwSwapBuffers(window);

        // process pending GUI events, call GLFW callbacks
        glfwPollEvents();

    }

    // free visualization storage
    mjv_freeScene(&scn);
    mjr_freeContext(&con);

    // free MuJoCo model and data, deactivate
    mj_deleteData(d);
    mj_deleteModel(m);
    mj_deactivate();

    // terminate GLFW (crashes with Linux NVidia drivers)
#if defined(__APPLE__) || defined(_WIN32)
    glfwTerminate();
#endif
    return 1;
}


#include <Eigen/Core>

#include <numpy_eigen/boost_python_headers.hpp>
Eigen::Matrix<float, 5, Eigen::Dynamic> test_float_5_D(const Eigen::Matrix<float, 5, Eigen::Dynamic> & M)
{
	return M;
}
void export_float_5_D()
{
	boost::python::def("test_float_5_D",test_float_5_D);
}


///////////////////////////////////////////////////////////////////////////////
///
///	\file    OfflineMap.h
///	\author  Paul Ullrich
///	\version August 14, 2014
///
///	<remarks>
///		Copyright 2000-2014 Paul Ullrich
///
///		This file is distributed as part of the Tempest source code package.
///		Permission is granted to use, copy, modify and distribute this
///		source code and its documentation under the terms of the GNU General
///		Public License.  This software is provided "as is" without express
///		or implied warranty.
///	</remarks>

#ifndef _TEMPESTOFFLINEMAP_H_
#define _TEMPESTOFFLINEMAP_H_

#include "moab/MOABConfig.h"

#include "SparseMatrix.h"
#include "DataVector.h"
#include "DataMatrix.h"
#include "DataMatrix3D.h"
#include "OfflineMap.h"
#include <string>
#include <vector>

#ifdef MOAB_HAVE_EIGEN
#include <Eigen/Sparse>
#endif

#include "moab/Remapping/TempestRemapper.hpp"

///////////////////////////////////////////////////////////////////////////////

#define RECTANGULAR_TRUNCATION
// #define TRIANGULAR_TRUNCATION

///////////////////////////////////////////////////////////////////////////////

// Forward declarations
class Mesh;

///////////////////////////////////////////////////////////////////////////////

namespace moab
{

///	<summary>
///		An offline map between two Meshes.
///	</summary>
class TempestOfflineMap : public OfflineMap {

public:

	///	<summary>
	///		Generate the metadata associated with the offline map.
	///	</summary>
	TempestOfflineMap(moab::TempestRemapper* remapper);

	///	<summary>
	///		Define a virtual destructor.
	///	</summary>
	virtual ~TempestOfflineMap();

public:

    // Input / Output types
    enum DiscretizationType
    {
        DiscretizationType_FV,
        DiscretizationType_CGLL,
        DiscretizationType_DGLL
    };

	///	<summary>
	///		Generate the offline map, given the source and target mesh and discretization details.
	///     This method generates the mapping between the two meshes based on the overlap and stores
	///     the result in the SparseMatrix.
	///	</summary>
	moab::ErrorCode GenerateOfflineMap( std::string strInputType="fv", std::string strOutputType="fv",
                                        const int nPin=1, const int nPout=1,
                                        bool fBubble=false, int fMonotoneTypeID=0,
                                        bool fVolumetric=false, bool fNoConservation=false, bool fNoCheck=false,
                                        const std::string srcDofTagName="GLOBAL_ID", const std::string tgtDofTagName="GLOBAL_ID",
                                        const std::string strVariables="",
                                        const std::string strInputData="", const std::string strOutputData="",
                                        const std::string strNColName="", const bool fOutputDouble=false,
                                        const std::string strPreserveVariables="", const bool fPreserveAll=false, const double dFillValueOverride=0.0,
                                        const bool fInputConcave = false, const bool fOutputConcave = false );

	///	<summary>
	///		Generate the metadata associated with the offline map.
	///	</summary>
	// moab::ErrorCode GenerateMetaData();

public:

	///	<summary>
	///		Read the OfflineMap from a NetCDF file.
	///	</summary>
	// virtual void Read(
	// 	const std::string & strSource
	// );

	///	<summary>
	///		Write the TempestOfflineMap to a parallel NetCDF file.
	///	</summary>
	// virtual void Write(
	// 	const std::string & strTarget
	// );

public:
	///	<summary>
	///		Determine if the map is first-order accurate.
	///	</summary>
	virtual bool IsConsistent(
		double dTolerance
	);

	///	<summary>
	///		Determine if the map is conservative.
	///	</summary>
	virtual bool IsConservative(
		double dTolerance
	);

	///	<summary>
	///		Determine if the map is monotone.
	///	</summary>
	virtual bool IsMonotone(
		double dTolerance
	);

	///	<summary>
	///		If we computed the reduction, get the vector representing the source areas for all entities in the mesh
	///	</summary>
	const DataVector<double>& GetGlobalSourceAreas() const;

	///	<summary>
	///		If we computed the reduction, get the vector representing the target areas for all entities in the mesh
	///	</summary>
	const DataVector<double>& GetGlobalTargetAreas() const;

#ifdef MOAB_HAVE_EIGEN
	void InitVectors();
#endif

private:

	///	<summary>
	///		Gather the mapping matrix that was computed in different processors and accumulate the data
	///     on the root so that OfflineMap can be generated in parallel.
	///	</summary>
	moab::ErrorCode GatherAllToRoot();

	///	<summary>
	///		Compute the remapping weights for a FV field defined on the source to a
	///     FV field defined on the target mesh.
	///	</summary>
	void LinearRemapFVtoFV_Tempest_MOAB( int nOrder );

	///	<summary>
	///		Generate the OfflineMap for linear conserative element-average
	///		spectral element to element average remapping.
	///	</summary>
	void LinearRemapSE0_Tempest_MOAB(
		const DataMatrix3D<int> & dataGLLNodes,
		const DataMatrix3D<double> & dataGLLJacobian);

	///	<summary>
	///		Generate the OfflineMap for cubic conserative element-average
	///		spectral element to element average remapping.
	///	</summary>
	void LinearRemapSE4_Tempest_MOAB(
	    const DataMatrix3D<int> & dataGLLNodes,
	    const DataMatrix3D<double> & dataGLLJacobian,
	    int nMonotoneType,
	    bool fContinuousIn,
	    bool fNoConservation);

	///	<summary>
	///		Generate the OfflineMap for remapping from finite volumes to finite
	///		elements using simple sampling of the FV reconstruction.
	///	</summary>
	void LinearRemapFVtoGLL_Simple_MOAB(
		const DataMatrix3D<int> & dataGLLNodes,
		const DataMatrix3D<double> & dataGLLJacobian,
		const DataVector<double> & dataGLLNodalArea,
		int nOrder,
		int nMonotoneType,
		bool fContinuous,
		bool fNoConservation
	);

	///	<summary>
	///		Generate the OfflineMap for remapping from finite volumes to finite
	///		elements using a new experimental method.
	///	</summary>
	void LinearRemapFVtoGLL_Volumetric_MOAB(
		const DataMatrix3D<int> & dataGLLNodes,
		const DataMatrix3D<double> & dataGLLJacobian,
		const DataVector<double> & dataGLLNodalArea,
		int nOrder,
		int nMonotoneType,
		bool fContinuous,
		bool fNoConservation
	);

	///	<summary>
	///		Generate the OfflineMap for remapping from finite volumes to finite
	///		elements.
	///	</summary>
	void LinearRemapFVtoGLL_MOAB(
		const DataMatrix3D<int> & dataGLLNodes,
		const DataMatrix3D<double> & dataGLLJacobian,
		const DataVector<double> & dataGLLNodalArea,
		int nOrder,
		int nMonotoneType,
		bool fContinuous,
		bool fNoConservation
	);

	///	<summary>
	///		Generate the OfflineMap for remapping from finite elements to finite
	///		elements.
	///	</summary>
	void LinearRemapGLLtoGLL2_MOAB(
		const DataMatrix3D<int> & dataGLLNodesIn,
		const DataMatrix3D<double> & dataGLLJacobianIn,
		const DataMatrix3D<int> & dataGLLNodesOut,
		const DataMatrix3D<double> & dataGLLJacobianOut,
		const DataVector<double> & dataNodalAreaOut,
		int nPin,
		int nPout,
		int nMonotoneType,
		bool fContinuousIn,
		bool fContinuousOut,
		bool fNoConservation
	);

	///	<summary>
	///		Generate the OfflineMap for remapping from finite elements to finite
	///		elements (pointwise interpolation).
	///	</summary>
	void LinearRemapGLLtoGLL2_Pointwise_MOAB(
		const DataMatrix3D<int> & dataGLLNodesIn,
		const DataMatrix3D<double> & dataGLLJacobianIn,
		const DataMatrix3D<int> & dataGLLNodesOut,
		const DataMatrix3D<double> & dataGLLJacobianOut,
		const DataVector<double> & dataNodalAreaOut,
		int nPin,
		int nPout,
		int nMonotoneType,
		bool fContinuousIn,
		bool fContinuousOut
	);

	///	<summary>
	///		Store the tag names associated with global DoF ids for source and target meshes
	///	</summary>
	moab::ErrorCode SetDofMapTags(const std::string srcDofTagName,
								  const std::string tgtDofTagName);

	///	<summary>
	///		Compute the association between the solution tag global DoF numbering and
	///		the local matrix numbering so that matvec operations can be performed
	///     consistently.
	///	</summary>
	moab::ErrorCode SetDofMapAssociation(DiscretizationType srcType, bool isSrcContinuous,
		DataMatrix3D<int>* srcdataGLLNodes, DataMatrix3D<int>* srcdataGLLNodesSrc,
		DiscretizationType destType, bool isDestContinuous,
		DataMatrix3D<int>* tgtdataGLLNodes);

	///	<summary>
	///		Copy the local matrix from Tempest SparseMatrix representation (ELL)
	///		to the parallel CSR Eigen Matrix for scalable application of matvec
	///     needed for projections.
	///	</summary>
#ifdef MOAB_HAVE_EIGEN
	void CopyTempestSparseMat_Eigen();
#endif

public:
#ifdef MOAB_HAVE_EIGEN

	typedef Eigen::Matrix< double, 1, Eigen::Dynamic > WeightDRowVector;
	typedef Eigen::Matrix< double, Eigen::Dynamic, 1 > WeightDColVector;
	typedef Eigen::SparseVector<double> WeightSVector;
	typedef Eigen::SparseMatrix<double, Eigen::RowMajor> WeightRMatrix;
	typedef Eigen::SparseMatrix<double, Eigen::ColMajor> WeightCMatrix;

	typedef WeightDRowVector WeightRowVector;
	typedef WeightDColVector WeightColVector;
	typedef WeightRMatrix WeightMatrix;

	///	<summary>
	///		Get the raw reference to the Eigen weight matrix representing the projection from source to destination mesh.
	///	</summary>
	WeightMatrix& GetWeightMatrix();

	///	<summary>
	///		Get the row vector that is amenable for application of A*x operation.
	///	</summary>
	WeightRowVector& GetRowVector();

	///	<summary>
	///		Get the column vector that is amenable for application of A^T*x operation.
	///	</summary>
	WeightColVector& GetColVector();

  ///	<summary>
	///		Get the number of total Degrees-Of-Freedom defined on the source mesh.
	///	</summary>
	int GetSourceGlobalNDofs();

	///	<summary>
	///		Get the number of total Degrees-Of-Freedom defined on the destination mesh.
	///	</summary>
	int GetDestinationGlobalNDofs();

	///	<summary>
	///		Get the number of local Degrees-Of-Freedom defined on the source mesh.
	///	</summary>
	int GetSourceLocalNDofs();

	///	<summary>
	///		Get the number of local Degrees-Of-Freedom defined on the destination mesh.
	///	</summary>
	int GetDestinationLocalNDofs();

	///	<summary>
	///		Get the number of Degrees-Of-Freedom per element on the source mesh.
	///	</summary>
	int GetSourceNDofsPerElement();

	///	<summary>
	///		Get the number of Degrees-Of-Freedom per element on the destination mesh.
	///	</summary>
	int GetDestinationNDofsPerElement();

	///	<summary>
	///		Apply the weight matrix onto the source vector provided as input, and return the column vector (solution projection) after the application
	///     Compute:        \p tgtVals = A * \srcVals, or
	///     if (transpose)  \p tgtVals = A^T * \srcVals
	///	</summary>
	moab::ErrorCode ApplyWeights (std::vector<double>& srcVals, std::vector<double>& tgtVals, bool transpose=false);

	///	<summary>
	///		Parallel I/O with NetCDF to write out the SCRIP file from multiple processors.
	///	</summary>
	void WriteParallelWeightsToFile(std::string filename);

#endif

public:

	///	<summary>
	///		The fundamental remapping operator object.
	///	</summary>
	moab::TempestRemapper* m_remapper;

	///	<summary>
	///		The SparseMatrix representing this operator.
	///	</summary>
	// SparseMatrix<double> m_mapRemapGlobal;
	OfflineMap* m_weightMapGlobal;

	///	<summary>
	///		The boolean flag representing whether the root process has the updated global view.
	///	</summary>
	bool m_globalMapAvailable;

#ifdef MOAB_HAVE_EIGEN

	WeightMatrix m_weightMatrix;
	WeightRowVector m_rowVector;
	WeightColVector m_colVector;

#endif

	///	<summary>
	///		The DataVector that stores the global (GID-based) areas of the source mesh.
	///	</summary>
	// DataVector<double> m_areasSrcGlobal;

	///	<summary>
	///		The DataVector that stores the global (GID-based) areas of the target mesh.
	///	</summary>
	// DataVector<double> m_areasTgtGlobal;

	///	<summary>
	///		The reference to the moab::Core object that contains source/target and overlap sets.
	///	</summary>
	moab::Interface* mbCore;

#ifdef MOAB_HAVE_MPI
	///	<summary>
	///		The reference to the parallel communicator object used by the Core object.
	///	</summary>
	moab::ParallelComm* pcomm;
#endif

	///	<summary>
	///		The original tag data and local to global DoF mapping to associate matrix values to solution
	///	<summary>
	moab::Tag m_dofTagSrc, m_dofTagDest;
	std::vector<unsigned long> row_dofmap, col_dofmap, srccol_dofmap;
	std::vector<unsigned long> row_gdofmap, col_gdofmap, srccol_gdofmap;
	std::vector<unsigned long> row_ldofmap, col_ldofmap, srccol_ldofmap;

	DataMatrix3D<int> dataGLLNodesSrc, dataGLLNodesSrcCov, dataGLLNodesDest;
	DiscretizationType m_srcDiscType, m_destDiscType;
	int m_nTotDofs_Src, m_nTotDofs_SrcCov, m_nTotDofs_Dest;
	int m_nDofsPEl_Src, m_nDofsPEl_Dest;

	Mesh* m_meshInput;
	Mesh* m_meshInputCov;
	Mesh* m_meshOutput;
	Mesh* m_meshOverlap;

	bool is_parallel, is_root;
	int rank, size;
};

///////////////////////////////////////////////////////////////////////////////

inline
const DataVector<double>& TempestOfflineMap::GetGlobalSourceAreas() const {
#ifdef MOAB_HAVE_MPI
  if (pcomm->size() > 1) {
        return m_weightMapGlobal->GetSourceAreas();
	}
	else {
		return this->GetSourceAreas();
	}
#else
  return this->GetSourceAreas();
#endif
}

inline
const DataVector<double>& TempestOfflineMap::GetGlobalTargetAreas() const {
#ifdef MOAB_HAVE_MPI
  if (pcomm->size() > 1) {
        return m_weightMapGlobal->GetTargetAreas();
	}
	else {
		return this->GetTargetAreas();
	}
#else
  return this->GetTargetAreas();
#endif
}

}

#endif


//
// Created by huangkun on 2020/9/9.
//

#ifndef OPENGV2_EVENT_HPP
#define OPENGV2_EVENT_HPP

#include <Eigen/Eigen>
#include <vector>

namespace opengv2 {
    class Event {
        friend std::istream &operator>>(std::istream &is, Event &obj);

    public:
        EIGEN_MAKE_ALIGNED_OPERATOR_NEW

        Event(double timeStamp, const Eigen::Ref<const Eigen::Vector2d> &location, bool polarity) :
                timeStamp_(timeStamp), location_(location), polarity_(polarity) {};

        Event() {};

        inline double timeStamp() const noexcept {
            return timeStamp_;
        }

        inline const Eigen::Vector2d &location() const noexcept {
            return location_;
        }

        inline bool polarity() const noexcept {
            return polarity_;
        }

    protected:
        double timeStamp_;
        Eigen::Vector2d location_; // (width, height), (x,y)
        bool polarity_; // true is positive, false is negative
    };

    inline std::istream &operator>>(std::istream &is, Event &obj) {
        is.read((char *) &(obj.timeStamp_), sizeof(obj.timeStamp_));
        is.read((char *) (obj.location_.data()), sizeof(*(obj.location_.data())));
        is.read((char *) (obj.location_.data() + 1), sizeof(*(obj.location_.data() + 1)));
        is.read((char *) &(obj.polarity_), sizeof(obj.polarity_));
        return is;
    }
}

#endif //OPENGV2_EVENT_HPP