#include <string>
#include <unordered_map>
#include <boost/test/unit_test.hpp>
#include <sudoku/parallel_solver.h>
#include <sudoku/standard.h>
#include <sudoku/cell_value_parser.h>
#include <sudoku/formatter.h>
#include "util.h"

BOOST_AUTO_TEST_CASE(ParallelSolver_example9x9_4threads)
{
    sudoku::standard::Dimensions dims;
    auto cellValues = sudoku::parseCellValues(
        dims,
        "020000000 000600003 074080000"
        "000003002 080040010 600500000"
        "000010780 500009000 000000040"
    );
    auto expectedSolution = sudoku::parseCellValues(
        dims,
        "126437958 895621473 374985126"
        "457193862 983246517 612578394"
        "269314785 548769231 731852649"
    );

    sudoku::Grid grid(dims, cellValues);
    sudoku::ParallelSolver solver(grid, 4, 10);
    BOOST_REQUIRE(solver.computeNextSolution());
    const auto& actualSolution = solver.getCellValues();
    BOOST_REQUIRE_EQUAL_VECTORS(expectedSolution, actualSolution);
    auto metrics = solver.getMetrics();
    BOOST_CHECK_GT(metrics.duration.count(), 0);
    BOOST_CHECK_GT(metrics.totalBacktracks, 0);
    BOOST_CHECK_GT(metrics.totalGuesses, 0);
}

BOOST_AUTO_TEST_CASE(ParallelSolver_empty9x9_16Threads)
{
    sudoku::standard::Dimensions dims;
    std::vector<sudoku::CellValue> cellValues(dims.getCellCount(), 0);
    sudoku::Grid grid(dims, cellValues);
    sudoku::ParallelSolver solver(grid, 16, 8);

    // Compute 100 solutions. Each solution should be unique; use a
    // hash map to be sure.
    const size_t solutionCount = 100;
    std::string formatString(dims.getCellCount(), '0');
    sudoku::Formatter fmt(dims, formatString);
    std::unordered_map<std::string, size_t> solutions;
    for (size_t solutionNum = 0; solutionNum < solutionCount; ++solutionNum) {
        BOOST_REQUIRE(solver.computeNextSolution());
        solutions[fmt.format(solver.getCellValues())]++;
    }

    // Check that all solutions are unique.
    for (auto it = solutions.begin(); it != solutions.end(); ++it) {
        size_t solutionOcurrences = it->second;
        BOOST_CHECK(solutionOcurrences == 1);
    }
}

BOOST_AUTO_TEST_CASE(ParallelSolver_25x25_2threads)
{
    // I encountered this situation by coincidence. One thread quickly
    // finds a solution, but the others take forever. If the user only
    // wants a single solution, the ParallelSolver destructor hangs
    // because the worker threads are still working and haven't "checked in"
    // with the condition variable.

    sudoku::square::Dimensions dims(5);
    std::vector<sudoku::CellValue> cellValues(dims.getCellCount(), 0);
    sudoku::Grid grid(dims, std::move(cellValues));
    sudoku::ParallelSolver solver(std::move(grid), 2, 1);
    BOOST_REQUIRE(solver.computeNextSolution());
}

BOOST_AUTO_TEST_CASE(ParalellSolver_9x9_2threads_noSolution)
{
    sudoku::standard::Dimensions dims;
    auto cellValues = sudoku::parseCellValues(dims,
        "1 2 3 4 5 6 7 8 0 " // note last cell in row is blocked for all values.
        "0 0 0 0 0 0 0 0 9 "
    );
    sudoku::Grid grid(dims, std::move(cellValues));
    sudoku::ParallelSolver solver(std::move(grid), 2, 1);
    BOOST_REQUIRE(!solver.computeNextSolution());
}

BOOST_AUTO_TEST_CASE(ParallelSolver_findsAllSolutions)
{
    // Using the single-threaded solver, I found 288 total solutions with
    // a 4x4 square sudoku. This test verifies that none of the solutions
    // are lost when using a parallel solver.
    sudoku::square::Dimensions dims(2);
    std::vector<sudoku::CellValue> cellValues(dims.getCellCount(), 0);
    sudoku::Grid grid(dims, cellValues);
    sudoku::ParallelSolver solver(grid, 4, 10);
    auto solutionCount = 0;
    while (solver.computeNextSolution()) {
        solutionCount++;
    }
    BOOST_REQUIRE_EQUAL(solutionCount, 288);
}


/**
 * @brief AVL木
 * @note  AVL木(AVL tree)は高さ平衡(height
 * balanced)2分探索木である.すなわち、各節点xの左右の部分木の高さは高々1しか違わない
 *        AVL木を実現するために各節点に特別な属性を管理する. x.hはxの高さである
 *        他の任意の2分探索木Tと同様、T.rootはその根を指すものと仮定する
 *
 * @note
 * Fhをh番目のフィボナッチ数とするとき、高さhのAVL木には少なくともFh個の節点があることから
 *        n個のAVL木の高さはΟ(lgn)であることがわかる
 *
 * @note  今回は属性pを省略してコードの簡略化を図ることにする
 */

#ifndef AVL_TREE_HPP
#define AVL_TREE_HPP

#include "container.hpp"
#include <algorithm>
#include <boost/assert.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
#include <memory>
#include <optional>
#include <utility>

namespace container {

template <class Key, class T> struct avl_tree_node {
  using height_t = std::int32_t;
  union {
    struct {
      avl_tree_node *l; /**< 左の子    */
      avl_tree_node *r; /**< 右の子    */
    };
    avl_tree_node *c[2]; /**< 左右の子(0:左, 1:右) */
  };
  height_t h; /**< 高さ */
  Key key;    /**< キー    */
  T v;        /**< 付属データ */

  constexpr explicit avl_tree_node(const Key &k, const T &v) noexcept
      : l(nullptr), r(nullptr), h(1), key(k), v(v) {}
};

/**
 * @brief  AVL木
 * @tparam Key     キーの型
 * @tparam T       付属データの型
 * @tparam Compare キーを引数にとる比較述語の型
 */
template <class Key, class T, class Compare = std::less<Key>,
          class Allocator = boost::container::pmr::polymorphic_allocator<
              avl_tree_node<Key, T>>>
struct avl_tree {
  static_assert(std::is_nothrow_constructible_v<Key> &&
                std::is_nothrow_constructible_v<T>);
  using alloc = std::allocator_traits<Allocator>;
  using sides_t = std::int32_t;
  using pair_t = std::pair<const Key, T>;
  using node = avl_tree_node<Key, T>;
  using height_t = typename node::height_t;

  explicit avl_tree(std::size_t n = 32) { allocate_pool(n); }
  ~avl_tree() noexcept { free_pool(); } // 確保した記憶領域の解放

  /**
   * @brief  AVL木からキーkに対応する付属データを返す
   * @note   実行時間はΟ(lgn)
   * @param  const Key& k キーk
   * @return キーkに対応する付属データ
   */
  std::optional<T> find(const Key &k) const {
    const node *x = find(root_, k);
    return x == nullptr ? std::nullopt : std::make_optional(x->v);
  }

  /**
   * @brief AVL木Tにキーkの挿入を行う
   * @note  実行時間はΟ(lgn)
   * @param const Key& k キーk
   * @param const T& v   付属データv
   * @return キーkに対応していた付属データ
   */
  std::optional<T> insert(const Key &k, const T &v) {
    std::optional<T> opt = std::nullopt;
    root_ = insert(root_, k, v, opt);
    return opt;
  }

  /**
   * @brief AVL木Tからキーkを持つ節点の削除を行う
   * @note  実行時間はΟ(lgn)
   * @param const Key&git  k キーk
   * @return キーkに対応していた付属データ
   */
  std::optional<T> erase(const Key &k) {
    std::optional<T> opt = std::nullopt;
    root_ = erase(root_, k, opt);
    return opt;
  }

  /**
   * @brief  中間順木巡回を行う
   * @note   n個の節点を持つ2分探索木の巡回はΘ(n)かかる
   * @tparam class F const Key&を引数に取る関数オブジェクトの型
   * @param F fn     const T&を引数に取る関数オブジェクト
   */
  template <class F> void inorder(F fn) { inorder(root_, fn); }

private:
  /**
   * @brief  中間順木巡回を行う
   * @note   n個の節点を持つ2分探索木の巡回はΘ(n)かかる
   * @tparam class F const Key&を引数に取る関数の型
   * @param F fn     const Key&を引数に取る関数
   * @param node*x   巡回を行う部分木の根
   */
  template <class F> void inorder(node *x, F fn) {
    if (x == nullptr) {
      return;
    } // xがNILを指すとき、再帰は底をつく
    inorder(x->l, fn);
    fn(x->key, x->v);
    inorder(x->r,
            fn); // xの左右の子を根とする部分木に対して中間順木巡回を行う
  }

  /**
   * @brief  AVL木からキーkに対応する付属データを返す
   * @note   実行時間はΟ(lgn)
   * @param  const Key& k キーk
   * @return キーkに対応する付属データへのポインタ
   */
  node *find(node *x, const Key &k) const {
    if (x == nullptr || eq(x->key, k)) {
      return x;
    } else {
      return find(cmp_(k, x->key) ? x->l : x->r, k);
    }
  }

  /**
   * @brief 節点xを根とする部分木にキーkの挿入を行う
   * @param node*x       節点x
   * @param node*z       キーkを持つ節点z
   */
  node *insert(node *x, const Key &k, const T &v, std::optional<T> &opt) {
    if (x == nullptr) {
      return create_node(k, v);
    }                      // xがNILを指すとき、再帰は底をつく
    if (cmp_(k, x->key)) { // xの適切な子に再帰し、
      x->l = insert(x->l, k, v, opt);
    } else if (cmp_(x->key, k)) {
      x->r = insert(x->r, k, v, opt);
    } else {
      opt = x->v;
      x->v = v;
      return x;
    }
    return balance(x); // xを根とする部分木を高さ平衡にする
  }

  /**
   * @brief 節点xを根とする部分木からキーkを削除する
   * @param node*x       節点x
   * @param const Key& k キーk
   */
  node *erase(node *x, const Key &k, std::optional<T> &opt) {
    if (x == nullptr) {
      return nullptr;
    } // キーkはAVL木Tに存在しなかった
    if (cmp_(k, x->key)) {
      x->l = erase(x->l, k, opt);
      return balance(x);
    } // xの適切な子に再帰し、
    if (cmp_(x->key, k)) {
      x->r = erase(x->r, k, opt);
      return balance(x);
    } // xを根とする部分木を高さ平衡にする
    opt = x->v;
    node *y = x->l,
         *z = x->r; // x.key == kのとき、yをxの左の子、zをxの右の子とし、
    destroy_node(x); // xを解放する
    if (z == nullptr) {
      return y;
    } // zがNILを指しているならば、新たな部分木の根としてyを返す
    node *w = leftmost(
        z); // zがNILを指していないならば、wをzを根とする部分木の中で最も左の子とする
    w->r = erase__(
        z); // zに対して再帰する.そして、wの右の子に新たな部分木を受け取る
    w->l = y;          // yをwの左の子にする
    return balance(w); // wを根とする部分木を高さ平衡にして戻る
  }

  /**
   * @brief
   * 節点xの左右の部分木はそれぞれ高さ平衡しており、その左右の子の高さの差は2以下であるとする
   *         xを入力とし、xを根とする部分木を高さ平衡になるように変換する
   * @note   回転は高々2回であるため実行時間はΟ(1)
   * @param  node*x 節点x
   * @return 高さ平衡な部分木の根
   */
  static node *balance(node *x) {
    x->h = reheight(x); // xの高さを更新する
    if (bias(x) > 1) {  // 左に2つ分偏っている場合、left-l
                        // caseおよびleft-r caseが考えられる
      if (bias(x->l) < 0) {
        x->l = left_rotate(x->l);
      } // l-r caseならば、左回転を行うことで、left-l caseに帰着させる
      return right_rotate(x); // 右回転を行うことでleft-l
                              // caseを解消し、高さ平衡を満たす部分木の根を返す
    }
    if (bias(x) < -1) { // 右に2つ分偏っている場合、right-r
                        // caseおよびright-l caseが考えられる
      if (bias(x->r) > 0) {
        x->r = right_rotate(x->r);
      } // r-l caseならば、右回転を行うことで、right-r
        // caseに帰着させる
      return left_rotate(x); // 左回転を行うことでright-r
                             // caseを解消し、高さ平衡を満たす部分木の根を返す
    }
    return x; // 高さ平衡の場合、xを返す
  }
  /**
   * @brief
   * 節点xからy(xのjの子)へのリンクを"ピボット"とするi回転で、回転の結果、
   *         yが部分木の新しい根となり、xがyのiの子、yのiの子がxのjの子になる
   * @note   x.c[j] != NILを仮定している. 実行時間はΟ(1)
   * @param  node*   x  節点x
   * @param  sides_t i  添字i(0のとき左、1のとき右)
   * @param  sides_t j  添字j(0のとき左、1のとき右)
   */
  static node *rotate(node *x, sides_t i, sides_t j) {
    node *y = x->c[j];  // yをxのjの子とする
    x->c[j] = y->c[i];  // yのi部分木をxのj部分木にする
    y->c[i] = x;        // xをyのiの子にする
    x->h = reheight(x); // xの高さを更新する
    y->h = reheight(y); // yの高さを更新する
    return y;           // 部分木の新しい根yを返す
  }
  static node *left_rotate(node *x) { return rotate(x, 0, 1); }
  static node *right_rotate(node *x) { return rotate(x, 1, 0); }

  /**
   * @brief 節点xを根とする部分木の中から最も左にある子を取得する
   * @param node*x 節点x
   */
  static node *leftmost(node *x) { return x->l ? leftmost(x->l) : x; }

  /**
   * @brief xを根とする部分木の最も左の子を削除する補助関数
   * @param node*x 節点x
   */
  static node *erase__(node *x) {
    if (x->l == nullptr) {
      return x->r;
    }
    x->l = erase__(x->l);
    return balance(x);
  }

private:
  /**< @brief 節点xの高さを取得する  */
  static constexpr height_t height(node *x) noexcept { return x ? x->h : 0; }
  /**< @brief 節点xの更新される高さを返す */
  static constexpr height_t reheight(node *x) noexcept {
    return std::max(height(x->l), height(x->r)) + 1;
  }
  /**< @brief 節点xの左右の子の高さの差(x.l - x.r)を返す */
  static constexpr height_t bias(node *x) noexcept {
    return height(x->l) - height(x->r);
  }

private:
  /**< @brief 節点xの記憶領域の確保を行う */
  node *create_node(const Key &k, const T &v) {
    BOOST_ASSERT_MSG(size_ < cap_, "AVL tree capacity over.");
    node *x = pool_ + size_;
    alloc::construct(alloc_, x, k, v);
    size_++;
    return x;
  }

  /**< @brief 節点xの記憶領域の解放を行う */
  void destroy_node(node *x) noexcept {
    alloc::destroy(alloc_, x);
    size_--;
  }

  /**< @brief 節点xを根とした部分木を再帰的に解放する*/
  void postorder_destroy_nodes(node *x) noexcept {
    if (x == nullptr) {
      return;
    }
    postorder_destroy_nodes(x->l);
    postorder_destroy_nodes(x->r);
    destroy_node(x);
  }

  /**< @brief メモリプールの解放 */
  void free_pool() noexcept {
    postorder_destroy_nodes(root_);
    alloc::deallocate(alloc_, pool_, cap_);
    root_ = pool_ = nullptr;
    size_ = cap_ = 0;
  }

  /**< @brief メモリプールの確保 */
  void allocate_pool(std::size_t n) {
    pool_ = alloc::allocate(alloc_, n);
    cap_ = n;
  }

private:
  /**< ＠brief キーlとキーrの非同値判定を行う */
  inline bool neq(const Key &l, const Key &r) const {
    return (cmp_(l, r) || cmp_(r, l));
  }
  /**< ＠brief キーlとキーrの同値判定を行う */
  inline bool eq(const Key &l, const Key &r) const { return !neq(l, r); }

private:
  node *root_ = nullptr; /**< AVL木の根 */
  std::size_t cap_ = 0;  /**< AVL木のバッファサイズ    */
  std::size_t size_ = 0; /**< AVL木のサイズ           */
  node *pool_ = nullptr; /**< AVL木の節点用メモリプール */
  Compare cmp_;          /**< 比較述語  */
  Allocator alloc_;      /**< アロケータ */
};

} // namespace container

#endif // end of AVL_TREE_HPP


//==================================================================================================
/**
  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)
**/
//==================================================================================================
#include <boost/simd/range/range.hpp>
#include <boost/simd/literal.hpp>
#include <boost/simd/pack.hpp>
#include <boost/simd/memory/allocator.hpp>
#include <boost/range.hpp>
#include <simd_test.hpp>
#include <vector>

using namespace boost::simd::literal;

template<typename Range, typename Out> inline void mycopy(Range const& r, Out dst)
{
  for( auto const& p : r)  *dst++ = p;
}

STF_CASE_TPL("distance", STF_NUMERIC_TYPES)
{
  using boost::simd::range;
  using boost::simd::pack;

  std::vector<T> data(pack<T>::static_size*3), data2(24);

  auto rng  = range(data);
  auto rng8 = range(data2, 8_c);

  STF_EQUAL( std::distance(boost::begin(rng) , boost::end(rng) ), 3 );
  STF_EQUAL( std::distance(boost::begin(rng8), boost::end(rng8)), 3 );
}

STF_CASE_TPL("iteration", STF_NUMERIC_TYPES)
{
  using boost::simd::range;
  using boost::simd::pack;

  std::vector<pack<T>,boost::simd::allocator<T>>  dst(3), ref(3);
  std::vector<T>          data(pack<T>::static_size*3);

  for(std::size_t i=0;i<data.size();i++)
    data[i] = i/pack<T>::static_size+1;

  for(std::size_t i=0;i<ref.size();i++)
    ref[i] = pack<T>(i+1);

  auto simd_range = range(data);
  mycopy(simd_range , dst.begin());

  STF_ALL_EQUAL( ref, dst );
}


#ifndef FAST_GICP_FAST_VGICP_HPP
#define FAST_GICP_FAST_VGICP_HPP

#include <unordered_map>

#include <Eigen/Core>
#include <Eigen/Geometry>

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/search/kdtree.h>
#include <pcl/registration/registration.h>

#include <sophus/so3.hpp>
#include <fast_gicp/gicp/gicp_settings.hpp>
#include <fast_gicp/gicp/fast_vgicp_voxel.hpp>

namespace fast_gicp {

/**
 * @brief Fast Voxelized GICP algorithm boosted with OpenMP
 */
template<typename PointSource, typename PointTarget>
class FastVGICP : public pcl::Registration<PointSource, PointTarget, float> {
public:
  using Scalar = float;
  using Matrix4 = typename pcl::Registration<PointSource, PointTarget, Scalar>::Matrix4;

  using PointCloudSource = typename pcl::Registration<PointSource, PointTarget, Scalar>::PointCloudSource;
  using PointCloudSourcePtr = typename PointCloudSource::Ptr;
  using PointCloudSourceConstPtr = typename PointCloudSource::ConstPtr;

  using PointCloudTarget = typename pcl::Registration<PointSource, PointTarget, Scalar>::PointCloudTarget;
  using PointCloudTargetPtr = typename PointCloudTarget::Ptr;
  using PointCloudTargetConstPtr = typename PointCloudTarget::ConstPtr;

  using Ptr = boost::shared_ptr<FastVGICP<PointSource, PointTarget>>;

  using pcl::Registration<PointSource, PointTarget, Scalar>::reg_name_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::input_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::target_;

  using pcl::Registration<PointSource, PointTarget, Scalar>::nr_iterations_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::max_iterations_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::final_transformation_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::transformation_epsilon_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::converged_;
  using pcl::Registration<PointSource, PointTarget, Scalar>::corr_dist_threshold_;

  FastVGICP();
  virtual ~FastVGICP() override;

  void setRotationEpsilon(double eps);

  void setNumThreads(int n);

  void setResolution(double resolution);

  void setCorrespondenceRandomness(int k);

  void setRegularizationMethod(RegularizationMethod method);

  void setNeighborSearchMethod(NeighborSearchMethod method);

  void setVoxelAccumulationMode(VoxelAccumulationMode mode);

  void swapSourceAndTarget();

  void clearSource();

  void clearTarget();

  virtual void setInputSource(const PointCloudSourceConstPtr& cloud) override;

  virtual void setInputTarget(const PointCloudTargetConstPtr& cloud) override;

protected:
  virtual void computeTransformation(PointCloudSource& output, const Matrix4& guess) override;

private:
  void create_voxelmap(const PointCloudTargetConstPtr& cloud);
  std::vector<Eigen::Vector3i, Eigen::aligned_allocator<Eigen::Vector3i>> neighbor_offsets() const;

  Eigen::Vector3i voxel_coord(const Eigen::Vector4f& x) const;
  Eigen::Vector4f voxel_origin(const Eigen::Vector3i& coord) const;
  GaussianVoxel::Ptr lookup_voxel(const Eigen::Vector3i& x) const;

  bool is_converged(const Eigen::Matrix<float, 6, 1>& delta) const;

  Eigen::VectorXf loss_ls(const Eigen::Matrix<float, 6, 1>& x, Eigen::MatrixXf* J) const;

  template<typename PointT>
  bool calculate_covariances(const boost::shared_ptr<const pcl::PointCloud<PointT>>& cloud, pcl::search::KdTree<PointT>& kdtree, std::vector<Matrix4, Eigen::aligned_allocator<Matrix4>>& covariances);

private:
  int num_threads_;
  int k_correspondences_;
  double rotation_epsilon_;

  std::unique_ptr<pcl::search::KdTree<PointSource>> source_kdtree;
  std::unique_ptr<pcl::search::KdTree<PointTarget>> target_kdtree;

  std::vector<Matrix4, Eigen::aligned_allocator<Matrix4>> source_covs;
  std::vector<Matrix4, Eigen::aligned_allocator<Matrix4>> target_covs;

  double voxel_resolution_;
  NeighborSearchMethod search_method_;
  RegularizationMethod regularization_method_;
  VoxelAccumulationMode voxel_mode_;

  using VoxelMap = std::unordered_map<Eigen::Vector3i, GaussianVoxel::Ptr,  //用Eigen::Vector3i作为key
                                      Vector3iHash,
                                      std::equal_to<Eigen::Vector3i>,
                                      Eigen::aligned_allocator<std::pair<Eigen::Vector3i, GaussianVoxel::Ptr>>>;
  VoxelMap voxels;
};
}  // namespace fast_gicp

#endif


/*

Copyright (c) 2007, Un Shyam
Copyright (c) 2007-2009, 2011-2012, 2014-2019, Arvid Norberg
Copyright (c) 2016-2017, Alden Torres
All rights reserved.

You may use, distribute and modify this code under the terms of the BSD license,
see LICENSE file.
*/

#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
#define TORRENT_PE_CRYPTO_HPP_INCLUDED

#if !defined TORRENT_DISABLE_ENCRYPTION

#include "libtorrent/config.hpp"

#include "libtorrent/aux_/disable_warnings_push.hpp"
#include <boost/multiprecision/cpp_int.hpp>
#include "libtorrent/aux_/disable_warnings_pop.hpp"

#include "libtorrent/aux_/receive_buffer.hpp"
#include "libtorrent/sha1_hash.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/span.hpp"
#include "libtorrent/aux_/array.hpp"

#include <list>
#include <array>
#include <cstdint>

namespace libtorrent::aux {

	namespace mp = boost::multiprecision;

	using key_t = mp::number<mp::cpp_int_backend<768, 768, mp::unsigned_magnitude, mp::unchecked, void>>;

	TORRENT_EXTRA_EXPORT std::array<char, 96> export_key(key_t const& k);

	// RC4 state from libtomcrypt
	struct rc4 {
		int x;
		int y;
		aux::array<std::uint8_t, 256> buf;
	};

	// TODO: 3 dh_key_exchange should probably move into its own file
	class TORRENT_EXTRA_EXPORT dh_key_exchange
	{
	public:
		dh_key_exchange();
		bool good() const { return true; }

		// Get local public key
		key_t const& get_local_key() const { return m_dh_local_key; }

		// read remote_pubkey, generate and store shared secret in
		// m_dh_shared_secret.
		void compute_secret(std::uint8_t const* remote_pubkey);
		void compute_secret(key_t const& remote_pubkey);

		key_t const& get_secret() const { return m_dh_shared_secret; }

		sha1_hash const& get_hash_xor_mask() const { return m_xor_mask; }

	private:

		key_t m_dh_local_key;
		key_t m_dh_local_secret;
		key_t m_dh_shared_secret;
		sha1_hash m_xor_mask;
	};

	struct TORRENT_EXTRA_EXPORT encryption_handler
	{
		std::tuple<int, span<span<char const>>>
		encrypt(span<span<char>> iovec);

		int decrypt(aux::crypto_receive_buffer& recv_buffer
			, std::size_t& bytes_transferred);

		bool switch_send_crypto(std::shared_ptr<crypto_plugin> crypto
			, int pending_encryption);

		void switch_recv_crypto(std::shared_ptr<crypto_plugin> crypto
			, aux::crypto_receive_buffer& recv_buffer);

		bool is_send_plaintext() const
		{
			return m_send_barriers.empty() || m_send_barriers.back().next != INT_MAX;
		}

		bool is_recv_plaintext() const
		{
			return m_dec_handler.get() == nullptr;
		}

	private:
		struct barrier
		{
			barrier(std::shared_ptr<crypto_plugin> plugin, int n)
				: enc_handler(plugin), next(n) {}
			std::shared_ptr<crypto_plugin> enc_handler;
			// number of bytes to next barrier
			int next;
		};
		std::list<barrier> m_send_barriers;
		std::shared_ptr<crypto_plugin> m_dec_handler;
	};

	struct TORRENT_EXTRA_EXPORT rc4_handler : crypto_plugin
	{
	public:
		rc4_handler();

		// Input keys must be 20 bytes
		void set_incoming_key(span<char const> key) override;
		void set_outgoing_key(span<char const> key) override;

		std::tuple<int, span<span<char const>>>
		encrypt(span<span<char>> buf) override;

		std::tuple<int, int, int> decrypt(span<span<char>> buf) override;

	private:
		rc4 m_rc4_incoming;
		rc4 m_rc4_outgoing;

		// determines whether or not encryption and decryption is enabled
		bool m_encrypt;
		bool m_decrypt;
	};

} // namespace libtorrent::aux

#endif // TORRENT_DISABLE_ENCRYPTION

#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED


// -*-C++-*-
/*
  (c) Copyright 2007, Hewlett-Packard Development Company, LP

  See the file named COPYING for license details
*/

/*
  =pod

  =head1 NAME

  dsstatgroupby - Calculate some derived value from a dataseries and calculate a statistic over it.

  =head1 SYNOPSIS

  % dsstatgroupby I<extent-type-match> I<statistic-description>... from file...

  =head1 STATISTIC DESCRIPTION

  Each statistic is described by a minimum of two arguments -- the statistic type and the expression.
  Two types of statistic types are currently implemented basic (mean, stddev, min, max), and quantile
  (percentile/100).  The expression implements the standard + - * / () and constants.  Two optional
  arguments can be added.  where I<expr> adds in a conditional expression so you could calculate
  separate statistics over large and small files.  group by <field> specifies a column that should be
  used for grouping the statistics.

  =head1 DESCRIPTION

  dsstatgroupby processes one or more input files calculating multiple statistics in a single pass
  over that input file.

*/

#include <boost/format.hpp>

#include <DataSeries/DSStatGroupByModule.hpp>
#include <DataSeries/TypeIndexModule.hpp>
#include <DataSeries/PrefetchBufferModule.hpp>
#include <DataSeries/SequenceModule.hpp>

using namespace std;
using boost::format;

void
usage(const std::string &program_name, const std::string &error)
{
    // TODO: should we make the usage ... from <prefix> in <file...>?
    cerr << error << "\n"
         << "Usage: " << program_name
         << " <extent-type-match> (<stat-type> <expr> [where <expr>] [group by <group-by>])+\n"
         << "  from file...\n"
         << "\n"
         << "  stat-types include:\n\n"
         << "    basic, quantile\n\n"
         << DSExpr::usage();
    exit(0);
}

int
main(int argc, char *_argv[])
{
    // converting to string from char * makes argv[i] == "blah" work.
    vector<string> argv;
    argv.reserve(argc);
    for (int i=0; i<argc; ++i) {
        argv.push_back(string(_argv[i]));
    }
    if (argc <= 5) usage(argv[0], "insufficient arguments");

    string extent_type_match(argv[1]);

    TypeIndexModule source(extent_type_match);
    PrefetchBufferModule *prefetch = new PrefetchBufferModule(source, 64*1024*1024);

    SequenceModule seq(prefetch);

    uint32_t argpos;
    for (argpos = 2; argpos < argv.size();) {
        if (argv[argpos] == "from")
            break;
        if (argpos + 2 + 2 > argv.size()) { // stat-type, expr + from, file
            usage(argv[0], "missing from in arguments");
        }
        string stat_type(argv[argpos]);
        ++argpos;
        if (!DSStatGroupByModule::validStatType(stat_type)) {
            usage(argv[0], str(format("'%s' is an invalid stat type") % stat_type));
        }

        string expr(argv[argpos]);
        ++argpos;

        string where_expr;
        if (argv[argpos] == "where") {
            ++argpos;
            where_expr = argv[argpos];
            ++argpos;
        }

        string group_by;

        if (argv[argpos] == "group" && argv[argpos+1] == "by" && argpos + 2 < argv.size()) {
            group_by = argv[argpos + 2];
            argpos += 3;
        }

        seq.addModule(new DSStatGroupByModule(seq.tail(), expr, group_by,
                                              stat_type, where_expr));
    }

    if (argpos >= argv.size() || argv[argpos] != "from") {
        usage(argv[0], "missing from in arguments");
    }
    ++argpos;
    for (;argpos<argv.size(); ++argpos) {
        source.addSource(argv[argpos]);
    }

    seq.getAndDeleteShared();

    RowAnalysisModule::printAllResults(seq, 1);

    printf("\n");
    printf("# extents: %.2f MB -> %.2f MB\n",
           (double)(source.total_compressed_bytes)/(1024.0*1024),
           (double)(source.total_uncompressed_bytes)/(1024.0*1024));
    printf("#                    common\n");
    printf("# MB compressed:   %8.2f\n",
           (double)source.total_compressed_bytes/(1024.0*1024));
    printf("# MB uncompressed: %8.2f\n",
           (double)source.total_uncompressed_bytes/(1024.0*1024));
    printf("# wait fraction :  %8.2f\n",
           source.waitFraction());

    return 0;
}


#include "testsuite.h"
#include <blitz/array.h>

#ifdef BZ_HAVE_STL
#include <iterator>
#include <algorithm>
BZ_USING_NAMESPACE(std)
#endif

BZ_USING_NAMESPACE(blitz)

void check(const Array<int,2>& A, const Array<int,1>& b)
{
    int i = 0;
    Array<int,2>::const_iterator beg = A.begin(), end = A.end();
    Array<int,2>::const_iterator iter = beg;

    while (iter != end) {
        BZTEST((*iter++) == b(i++));
    }
    BZTEST(i == A.numElements());

    while (iter!=beg) {
        BZTEST((*--iter) == b(--i));
    }
    BZTEST(i == 0);
}

#ifdef BZ_HAVE_STL
template <typename _Iter>
void checkInterface(_Iter iter)
{
    typedef typename iterator_traits<_Iter>::value_type value_type;
    typedef typename iterator_traits<_Iter>::reference reference;
    typedef typename iterator_traits<_Iter>::pointer pointer;
    value_type x = *iter;
    BZTEST(*iter == x);
    reference y(x);
    pointer p = &(*iter);
    BZTEST(*p == y);
}
#endif // BZ_HAVE_STL

int main()
{
  {
    Array<int,2> A(2,3);
    A = 0, 1, 2,
        3, 4, 5;
    Array<int,1> b(6);
    b = 0, 1, 2, 3, 4, 5;

    check(A, b);
  }

  {
    Array<int,2> A(2,3,FortranArray<2>());
    A = tensor::i * 3 + tensor::j;
    Array<int,1> b(6);
    b = 4, 7, 5, 8, 6, 9;
    check(A,b);
  }

#if 0
  {
    Array<int,2> B(5,5,FortranArray<2>());
    B = tensor::i + 5 * tensor::j;

    B.reverseSelf(1);
    check(B);
  }
#endif

  {
    Array<int,2> B(6,6,FortranArray<2>());
    B = tensor::i * 6 + tensor::j;
    Array<int,1> b(12);
    b = 7, 13, 19, 8, 14, 20, 9, 15, 21, 10, 16, 22;
    check(B(Range(1,3),Range(1,4)), b);
  }

  {
    Array<int,2> B;
    Array<int,2>::iterator iter = B.begin(), end = B.end();
    BZTEST(iter == end);
  }

#ifdef BZ_HAVE_STL
  {
    Array<int,2> A(3,3);
    A = 1, 2, 3,
        3, 2, 1,
        4, 3, 2;
    replace(A.begin(), A.end(), 3, 0); // replace each 3 with 0
    Array<int,1> b(9);
    b = 1, 2, 0, 0, 2, 1, 4, 0, 2;
    check(A,b);
    Array<int,2>::iterator iter;
    iter = adjacent_find(A.begin(),A.end());
    TinyVector<int,2> pos = iter.position(), ans(0,2);
    BZTEST(pos[0] == ans[0] && pos[1] == ans[1]);
    checkInterface(iter);
    const Array<int,2>& B(A);
    Array<int,2>::const_iterator citer = B.begin();
    checkInterface(citer);
  }
#endif // BZ_HAVE_STL

}


// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test

// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to 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)

#if defined(_MSC_VER)
#  pragma warning( disable : 4244 )
#  pragma warning( disable : 4267 )
#endif

#include <fstream>
#include <sstream>

#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/timer.hpp>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/multi/geometries/multi_geometries.hpp>

#include <boost/geometry/extensions/io/svg/svg_mapper.hpp>
#include <boost/geometry/extensions/algorithms/midpoints.hpp>

#include <common/common_settings.hpp>
#include <common/make_square_polygon.hpp>

namespace bg = boost::geometry;

template <typename Geometry1, typename Geometry2, typename Geometry3>
void create_svg(std::string const& filename
                , Geometry1 const& mp
                , Geometry2 const& ls
                , Geometry3 const& difference
                , Geometry3 const& intersection
                )
{
    typedef typename boost::geometry::point_type<Geometry1>::type point_type;

    std::ofstream svg(filename.c_str());
    boost::geometry::svg_mapper<point_type> mapper(svg, 800, 800);

    boost::geometry::model::box<point_type> box;
    bg::envelope(mp, box);
    bg::buffer(box, box, 1.0);
    mapper.add(box);
    bg::envelope(ls, box);
    bg::buffer(box, box, 1.0);
    mapper.add(box);

    mapper.map(mp, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:3");
    mapper.map(ls, "stroke-opacity:0.9;stroke:rgb(0,0,0);stroke-width:1");

    mapper.map(intersection,"opacity:0.6;stroke:rgb(0,128,0);stroke-width:5");
    mapper.map(difference,  "opacity:0.6;stroke:rgb(255,0,255);stroke-width:5"); //;stroke-dasharray:1,7;stroke-linecap:round
}

template <typename Linestring, typename Generator, typename Settings>
inline void make_random_linestring(Linestring& line, Generator& generator, Settings const& settings)
{
    using namespace boost::geometry;

    typedef typename point_type<Linestring>::type point_type;
    typedef typename coordinate_type<Linestring>::type coordinate_type;

    coordinate_type x, y;
    x = generator();
    y = generator();

    int count = 3 + generator() % 6;
    int d = 0; // direction

    for (int i = 0; i <= count && x <= settings.field_size; i++, x++, d = 1 - d)
    {
        append(line, make<point_type>(x, y + d));
        append(line, make<point_type>(x, y + 1 - d));
    }

    if (d == 0 && generator() % 4 < 3 && y >= 2)
    {
        d = 1 - d;
        x--;
        y -= 2;
        count = 3 + generator() % 6;
        for (int i = 0; i <= count && x >= 0; i++, x--, d = 1 - d)
        {
            append(line, make<point_type>(x, y + d));
            append(line, make<point_type>(x, y + 1 - d));
        }
    }

    //if (settings.triangular)
    //{
    //    // Remove a point, generator says which
    //    int c = generator() % 4;
    //    if (c >= 1 && c <= 3)
    //    {
    //        ring.erase(ring.begin() + c);
    //    }
    //}
}

template<typename Geometry>
class inside_check
{
    Geometry const& m_geo;
    bool& m_result;
public :

    inside_check(Geometry const& geo, bool& result)
        : m_geo(geo)
        , m_result(result)
    {}

    inline inside_check<Geometry> operator=(inside_check<Geometry> const& input)
    {
        return inside_check<Geometry>(input.m_geo, input.m_result);
    }

    template <typename Point>
    inline void operator()(Point const& p)
    {
        if (! bg::covered_by(p, m_geo))
        {
            if (m_result)
            {
                std::cout << "Does not fulfill inside check" << std::endl;
            }
            m_result = false;
        }
    }
};

template<typename Geometry>
class outside_check
{
    Geometry const& m_geo;
    bool& m_result;
public :
    outside_check(Geometry const& geo, bool& result)
        : m_geo(geo)
        , m_result(result)
    {}

    inline outside_check<Geometry> operator=(outside_check<Geometry> const& input)
    {
        return outside_check<Geometry>(input.m_geo, input.m_result);
    }

    template <typename Point>
    inline void operator()(Point const& p)
    {
        if (bg::within(p, m_geo))
        {
            if (m_result)
            {
                std::cout << "Does not fulfill outside check" << std::endl;
            }
            m_result = false;
        }
    }
};

template<typename Segment>
class border2_check
{
    Segment const& m_segment;
    bool& m_result;

public :
    border2_check(Segment const& seg, bool& result)
        : m_segment(seg)
        , m_result(result)
    {}

    inline border2_check<Segment> operator=(border2_check<Segment> const& input)
    {
        return border2_check<Segment>(input.m_segment, input.m_result);
    }

    template <typename Segment2>
    inline void operator()(Segment2 const& segment)
    {
        // Create copies (TODO: find out why referring_segment does not compile)
        typedef typename bg::point_type<Segment2>::type pt;
        typedef bg::model::segment<pt> segment_type;

        typedef bg::strategy::intersection::relate_cartesian_segments
                    <
                        bg::policies::relate::segments_intersection_points
                            <
                                segment_type,
                                segment_type,
                                bg::segment_intersection_points<pt>
                            >
                    > policy;

        segment_type seg1, seg2;
        bg::convert(m_segment, seg1);
        bg::convert(segment, seg2);
        bg::segment_intersection_points<pt> is = policy::apply(seg1, seg2);

        if (is.count == 2)
        {
            if (m_result)
            {
                std::cout << "Does not fulfill border2 check" << std::endl;
            }
            m_result = true;
        }
    }
};

template<typename Geometry>
class border_check
{
    Geometry const& m_geo;
    bool& m_result;
public :
    border_check(Geometry const& geo, bool& result)
        : m_geo(geo)
        , m_result(result)
    {}

    inline border_check<Geometry> operator=(border_check<Geometry> const& input)
    {
        return border_check<Geometry>(input.m_geo, input.m_result);
    }

    template <typename Segment>
    inline void operator()(Segment const& s)
    {
        bool on_border = false;
        border2_check<Segment> checker(s, on_border);
        bg::for_each_segment(m_geo, checker);

        if (on_border)
        {
            if (m_result)
            {
                std::cout << "Does not fulfill border check" << std::endl;
            }
            m_result = false;
        }
    }
};

template <typename MultiPolygon, typename Linestring, typename Settings>
bool verify(std::string const& caseid, MultiPolygon const& mp, Linestring const& ls, Settings const& settings)
{
    bg::model::multi_linestring<Linestring> difference, intersection;
    bg::difference(ls, mp, difference);
    bg::intersection(ls, mp, intersection);

    //typedef typename bg::length_result_type<point_type>::type length_type;

    bool result = true;

    // 1) Check by length
    typedef double length_type;
    length_type len_input = bg::length(ls);
    length_type len_difference = bg::length(difference);
    length_type len_intersection = bg::length(intersection);
    if (! bg::math::equals(len_input, len_difference + len_intersection))
    {
        std::cout << "Input: " << len_input
            << " difference: " << len_difference
            << " intersection: " << len_intersection
            << std::endl;

        std::cout << "Does not fulfill length check" << std::endl;

        result = false;
    }

    // 2) Check by within and covered by
    inside_check<MultiPolygon> ic(mp, result);
    bg::for_each_point(intersection, ic);

    outside_check<MultiPolygon> oc(mp, result);
    bg::for_each_point(difference, oc);

    border_check<MultiPolygon> bc(mp, result);
    bg::for_each_segment(difference, bc);

    // 3) check also the mid-points from the difference to remove false positives
    BOOST_FOREACH(Linestring const& d, difference)
    {
        Linestring difference_midpoints;
        bg::midpoints(d, false, std::back_inserter(difference_midpoints));
        outside_check<MultiPolygon> ocm(mp, result);
        bg::for_each_point(difference_midpoints, ocm);
    }

    bool svg = settings.svg;
    bool wkt = settings.wkt;
    if (! result)
    {
        std::cout << "ERROR " << caseid << std::endl;
        std::cout << bg::wkt(mp) << std::endl;
        std::cout << bg::wkt(ls) << std::endl;
        svg = true;
        wkt = true;
    }

    if (svg)
    {
        std::ostringstream filename;
        filename << caseid << "_"
            << typeid(typename bg::coordinate_type<Linestring>::type).name()
            << ".svg";
        create_svg(filename.str(), mp, ls, difference, intersection);
    }

    if (wkt)
    {
        std::ostringstream filename;
        filename << caseid << "_"
            << typeid(typename bg::coordinate_type<Linestring>::type).name()
            << ".wkt";
        std::ofstream stream(filename.str().c_str());
        stream << bg::wkt(mp) << std::endl;
        stream << bg::wkt(ls) << std::endl;
    }

    return result;
}

template <typename MultiPolygon, typename Generator>
bool test_linear_areal(MultiPolygon& result, int& index,
            Generator& generator,
            int level, common_settings const& settings)
{
    MultiPolygon p, q;

    // Generate two boxes
    if (level == 0)
    {
        p.resize(1);
        q.resize(1);
        make_square_polygon(p.front(), generator, settings);
        make_square_polygon(q.front(), generator, settings);
        bg::correct(p);
        bg::correct(q);
    }
    else
    {
        bg::correct(p);
        bg::correct(q);
        if (! test_linear_areal(p, index, generator, level - 1, settings)
            || ! test_linear_areal(q, index, generator, level - 1, settings))
        {
            return false;
        }
    }

    typedef typename boost::range_value<MultiPolygon>::type polygon;

    MultiPolygon mp;
    bg::detail::union_::union_insert
        <
            polygon
        >(p, q, std::back_inserter(mp));

    bg::unique(mp);
    bg::simplify(mp, result, 0.01);
    bg::correct(mp);

    // Generate a linestring
    typedef typename bg::point_type<MultiPolygon>::type point_type;
    typedef bg::model::linestring<point_type> linestring_type;
    linestring_type ls;
    make_random_linestring(ls, generator, settings);

    std::ostringstream out;
    out << "recursive_la_" << index++ << "_" << level;
    return verify(out.str(), mp, ls, settings);
}

template <typename T, bool Clockwise, bool Closed>
void test_all(int seed, int count, int level, common_settings const& settings)
{
    boost::timer t;

    typedef boost::minstd_rand base_generator_type;

    base_generator_type generator(seed);

    boost::uniform_int<> random_coordinate(0, settings.field_size - 1);
    boost::variate_generator<base_generator_type&, boost::uniform_int<> >
        coordinate_generator(generator, random_coordinate);

    typedef bg::model::polygon
        <
            bg::model::d2::point_xy<T>, Clockwise, Closed
        > polygon;
    typedef bg::model::multi_polygon<polygon> mp;

    int index = 0;
    for(int i = 0; i < count; i++)
    {
        mp p;
        test_linear_areal<mp>(p, index, coordinate_generator, level, settings);
    }
    std::cout
        << "geometries: " << index
        << " type: " << typeid(T).name()
        << " time: " << t.elapsed()  << std::endl;
}

int main(int argc, char** argv)
{
    try
    {
        namespace po = boost::program_options;
        po::options_description description("=== recursive_polygons_linear_areal ===\nAllowed options");

        int count = 1;
        int seed = static_cast<unsigned int>(std::time(0));
        int level = 3;
        bool ccw = false;
        bool open = false;
        common_settings settings;
        std::string form = "box";

        description.add_options()
            ("help", "Help message")
            ("seed", po::value<int>(&seed), "Initialization seed for random generator")
            ("count", po::value<int>(&count)->default_value(1), "Number of tests")
            ("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
            ("level", po::value<int>(&level)->default_value(3), "Level to reach (higher->slower)")
            ("form", po::value<std::string>(&form)->default_value("box"), "Form of the polygons (box, triangle)")
            ("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
            ("open", po::value<bool>(&open)->default_value(false), "Open polygons")
            ("size", po::value<int>(&settings.field_size)->default_value(10), "Size of the field")
            ("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
            ("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
        ;

        po::variables_map varmap;
        po::store(po::parse_command_line(argc, argv, description), varmap);
        po::notify(varmap);

        if (varmap.count("help")
            || (form != "box" && form != "triangle"))
        {
            std::cout << description << std::endl;
            return 1;
        }

        settings.triangular = form != "box";

        if (ccw && open)
        {
            test_all<double, false, false>(seed, count, level, settings);
        }
        else if (ccw)
        {
            test_all<double, false, true>(seed, count, level, settings);
        }
        else if (open)
        {
            test_all<double, true, false>(seed, count, level, settings);
        }
        else
        {
            test_all<double, true, true>(seed, count, level, settings);
        }

#if defined(HAVE_TTMATH)
        // test_all<ttmath_big, true, true>(seed, count, max, svg, level);
#endif
    }
    catch(std::exception const& e)
    {
        std::cout << "Exception " << e.what() << std::endl;
    }
    catch(...)
    {
        std::cout << "Other exception" << std::endl;
    }

    return 0;
}


// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

#include <array>
#include <boost/functional/hash.hpp>
#include <cstddef>
#include <memory>
#include <unordered_set>
#include <utility>
#include <vector>

#include "DataStructures/Tensor/Tensor.hpp"
#include "Domain/CoordinateMaps/Affine.hpp"
#include "Domain/CoordinateMaps/CoordinateMap.hpp"
#include "Domain/CoordinateMaps/CoordinateMap.tpp"
#include "Domain/CoordinateMaps/ProductMaps.hpp"
#include "Domain/CoordinateMaps/ProductMaps.tpp"
#include "Domain/Creators/AlignedLattice.hpp"
#include "Domain/Creators/DomainCreator.hpp"
#include "Domain/Domain.hpp"
#include "Framework/TestCreation.hpp"
#include "Framework/TestHelpers.hpp"
#include "Helpers/Domain/DomainTestHelpers.hpp"
#include "Parallel/RegisterDerivedClassesWithCharm.hpp"

namespace Frame {
struct Inertial;
}  // namespace Frame

namespace domain {
namespace {
template <size_t VolumeDim>
void test_aligned_blocks(
    const creators::AlignedLattice<VolumeDim>& aligned_blocks) noexcept {
  const auto domain = aligned_blocks.create_domain();
  test_initial_domain(domain, aligned_blocks.initial_refinement_levels());

  Parallel::register_classes_in_list<
      typename creators::AlignedLattice<VolumeDim>::maps_list>();
  test_serialization(domain);
}
}  // namespace

SPECTRE_TEST_CASE("Unit.Domain.Creators.AlignedLattice", "[Domain][Unit]") {
  const auto domain_creator_1d =
      TestHelpers::test_factory_creation<DomainCreator<1>>(
          "AlignedLattice:\n"
          "  BlockBounds: [[0.1, 2.6, 5.1, 5.2, 7.2]]\n"
          "  IsPeriodicIn: [false]\n"
          "  InitialGridPoints: [3]\n"
          "  InitialLevels: [2]\n"
          "  RefinedLevels: []\n"
          "  RefinedGridPoints: []\n"
          "  BlocksToExclude: []\n");
  const auto* aligned_blocks_creator_1d =
      dynamic_cast<const creators::AlignedLattice<1>*>(domain_creator_1d.get());
  test_aligned_blocks(*aligned_blocks_creator_1d);

  const auto domain_creator_2d =
      TestHelpers::test_factory_creation<DomainCreator<2>>(
          "AlignedLattice:\n"
          "  BlockBounds: [[0.1, 2.6, 5.1], [-0.4, 3.2, 6.2, 8.9]]\n"
          "  IsPeriodicIn: [false, true]\n"
          "  InitialGridPoints: [3, 4]\n"
          "  InitialLevels: [2, 1]\n"
          "  RefinedLevels: []\n"
          "  RefinedGridPoints: []\n"
          "  BlocksToExclude: []\n");
  const auto* aligned_blocks_creator_2d =
      dynamic_cast<const creators::AlignedLattice<2>*>(domain_creator_2d.get());
  test_aligned_blocks(*aligned_blocks_creator_2d);

  const auto domain_creator_3d =
      TestHelpers::test_factory_creation<DomainCreator<3>>(
          "AlignedLattice:\n"
          "  BlockBounds: [[0.1, 2.6, 5.1], [-0.4, 3.2, 6.2], [-0.2, 3.2]]\n"
          "  IsPeriodicIn: [false, true, false]\n"
          "  InitialGridPoints: [3, 4, 5]\n"
          "  InitialLevels: [2, 1, 0]\n"
          "  RefinedLevels: []\n"
          "  RefinedGridPoints: []\n"
          "  BlocksToExclude: []\n");
  const auto* aligned_blocks_creator_3d =
      dynamic_cast<const creators::AlignedLattice<3>*>(domain_creator_3d.get());
  test_aligned_blocks(*aligned_blocks_creator_3d);

  const auto cubical_shell_domain =
      TestHelpers::test_factory_creation<DomainCreator<3>>(
          "AlignedLattice:\n"
          "  BlockBounds: [[0.1, 2.6, 5.1, 6.0], [-0.4, 3.2, 6.2, 7.0], "
          "[-0.2, 3.2, 4.0, 5.2]]\n"
          "  IsPeriodicIn: [false, false, false]\n"
          "  InitialGridPoints: [3, 4, 5]\n"
          "  InitialLevels: [2, 1, 0]\n"
          "  RefinedLevels: []\n"
          "  RefinedGridPoints: []\n"
          "  BlocksToExclude: [[1, 1, 1]]");
  const auto* cubical_shell_creator_3d =
      dynamic_cast<const creators::AlignedLattice<3>*>(
          cubical_shell_domain.get());
  test_aligned_blocks(*cubical_shell_creator_3d);

  const auto unit_cubical_shell_domain =
      TestHelpers::test_factory_creation<DomainCreator<3>>(
          "AlignedLattice:\n"
          "  BlockBounds: [[-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5], "
          "[-1.5, -0.5, 0.5, 1.5]]\n"
          "  IsPeriodicIn: [false, false, false]\n"
          "  InitialGridPoints: [5, 5, 5]\n"
          "  InitialLevels: [1, 1, 1]\n"
          "  RefinedLevels: []\n"
          "  RefinedGridPoints: []\n"
          "  BlocksToExclude: [[1, 1, 1]]");
  const auto* unit_cubical_shell_creator_3d =
      dynamic_cast<const creators::AlignedLattice<3>*>(
          unit_cubical_shell_domain.get());
  test_aligned_blocks(*unit_cubical_shell_creator_3d);

  {
    // Expected domain refinement:
    // 23 23 67
    // 23 45 67
    // 23 XX 45
    const auto refined_domain =
        TestHelpers::test_factory_creation<DomainCreator<2>>(
            "AlignedLattice:\n"
            "  BlockBounds: [[70, 71, 72, 73], [90, 91, 92, 93]]\n"
            "  IsPeriodicIn: [false, false]\n"
            "  InitialGridPoints: [2, 3]\n"
            "  InitialLevels: [0, 0]\n"
            "  BlocksToExclude: [[1, 0]]\n"
            "  RefinedLevels: []\n"
            "  RefinedGridPoints:\n"
            "  - LowerCornerIndex: [1, 0]\n"
            "    UpperCornerIndex: [3, 2]\n"
            "    Refinement: [4, 5]\n"
            "  - LowerCornerIndex: [2, 1]\n"
            "    UpperCornerIndex: [3, 3]\n"
            "    Refinement: [6, 7]");
    std::unordered_set<
        std::pair<std::vector<double>, std::array<size_t, 2>>,
        boost::hash<std::pair<std::vector<double>, std::array<size_t, 2>>>>
        expected_blocks{{{70.0, 90.0}, {{2, 3}}}, {{72.0, 90.0}, {{4, 5}}},
                        {{70.0, 91.0}, {{2, 3}}}, {{71.0, 91.0}, {{4, 5}}},
                        {{72.0, 91.0}, {{6, 7}}}, {{70.0, 92.0}, {{2, 3}}},
                        {{71.0, 92.0}, {{2, 3}}}, {{72.0, 92.0}, {{6, 7}}}};
    const auto domain = refined_domain->create_domain();
    test_initial_domain(domain, refined_domain->initial_refinement_levels());

    const auto& blocks = domain.blocks();
    const auto extents = refined_domain->initial_extents();
    REQUIRE(blocks.size() == extents.size());
    for (size_t i = 0; i < blocks.size(); ++i) {
      const auto location =
          blocks[i]
              .stationary_map()(
                  tnsr::I<double, 2, Frame::Logical>{{{-1.0, -1.0}}})
              .get_vector_of_data()
              .second;
      INFO("Unexpected block");
      CAPTURE(location);
      CAPTURE(extents[i]);
      CHECK(expected_blocks.erase({location, extents[i]}) == 1);
    }
    CAPTURE(expected_blocks);
    CHECK(expected_blocks.empty());
  }

  {
    // Expected domain refinement:
    // 25 25 46
    // 25 35 46
    // 25 XX 35
    const auto refined_domain =
        TestHelpers::test_factory_creation<DomainCreator<2>>(
            "AlignedLattice:\n"
            "  BlockBounds: [[70, 71, 72, 73], [90, 91, 92, 93]]\n"
            "  IsPeriodicIn: [false, false]\n"
            "  InitialGridPoints: [10, 10]\n"
            "  InitialLevels: [2, 5]\n"
            "  BlocksToExclude: [[1, 0]]\n"
            "  RefinedGridPoints: []\n"
            "  RefinedLevels:\n"
            "  - LowerCornerIndex: [1, 0]\n"
            "    UpperCornerIndex: [3, 2]\n"
            "    Refinement: [3, 5]\n"
            "  - LowerCornerIndex: [2, 1]\n"
            "    UpperCornerIndex: [3, 3]\n"
            "    Refinement: [4, 6]");
    std::unordered_set<
        std::pair<std::vector<double>, std::array<size_t, 2>>,
        boost::hash<std::pair<std::vector<double>, std::array<size_t, 2>>>>
        expected_blocks{{{70.0, 90.0}, {{2, 5}}}, {{72.0, 90.0}, {{3, 5}}},
                        {{70.0, 91.0}, {{2, 5}}}, {{71.0, 91.0}, {{3, 5}}},
                        {{72.0, 91.0}, {{4, 6}}}, {{70.0, 92.0}, {{2, 5}}},
                        {{71.0, 92.0}, {{2, 5}}}, {{72.0, 92.0}, {{4, 6}}}};
    const auto domain = refined_domain->create_domain();
    const auto refinement_levels = refined_domain->initial_refinement_levels();
    test_initial_domain(domain, refinement_levels);

    const auto& blocks = domain.blocks();
    REQUIRE(blocks.size() == refinement_levels.size());
    for (size_t i = 0; i < blocks.size(); ++i) {
      const auto location =
          blocks[i]
              .stationary_map()(
                  tnsr::I<double, 2, Frame::Logical>{{{-1.0, -1.0}}})
              .get_vector_of_data()
              .second;
      INFO("Unexpected block");
      CAPTURE(location);
      CAPTURE(refinement_levels[i]);
      CHECK(expected_blocks.erase({location, refinement_levels[i]}) == 1);
    }
    CAPTURE(expected_blocks);
    CHECK(expected_blocks.empty());
  }
}

// [[OutputRegex, Cannot exclude blocks as well as have periodic boundary
// conditions!]]
SPECTRE_TEST_CASE("Unit.Domain.Creators.AlignedLattice.Error",
                  "[Unit][ErrorHandling]") {
  ERROR_TEST();
  const auto failed_cubical_shell_domain =
      TestHelpers::test_factory_creation<DomainCreator<3>>(
          "AlignedLattice:\n"
          "  BlockBounds: [[-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5], "
          "[-1.5, -0.5, 0.5, 1.5]]\n"
          "  IsPeriodicIn: [true, false, false]\n"
          "  InitialGridPoints: [5, 5, 5]\n"
          "  InitialLevels: [1, 1, 1]\n"
          "  RefinedLevels: []\n"
          "  RefinedGridPoints: []\n"
          "  BlocksToExclude: [[1, 1, 1]]");
}
}  // namespace domain


#include <UnitTest++/UnitTest++.h>
#include <stdexcept>
#include <iostream>
#include <cmath>
#include <limits>
#include <boost/filesystem.hpp>
#include <fstream>

#include "coela_utility/src/string_utils.h"
#include "coela_utility/src/histogram_container.h"

#include "coela_core/src/ccd_image.h"
#include "coela_analysis/src/psf_models.h"
#include "coela_analysis/src/minuit_psf_models.h"

#include <Minuit2/MnPrint.h>

using namespace coela;
using namespace std;

SUITE(minuit_psf_models)
{

    string test_suite_output_dir= string(UnitTestSuite::GetSuiteName()) + "_tests/";
    TEST(Run_Standard_Suite_Setup) {
        cout << "*** \""<< UnitTestSuite::GetSuiteName() <<"\" unit tests running ***" <<endl;
        boost::filesystem::create_directories(test_suite_output_dir);
    }

    TEST(Position_MnPar_interface) {
        psf_fitting::Mn2_models::PositionFit posn;
        posn.centre=CcdPosition(3.14,2.55);
        posn.error_estimate=CcdPixelShift(0.04,0.03);

        ROOT::Minuit2::MnUserParameters pars;
        string prefix = "Testing_PositionFit_Interface_";
        psf_fitting::Mn2_models::PositionFit::set_MnPars(posn, &pars, prefix);

        psf_fitting::Mn2_models::PositionFit recovered_posn =
            psf_fitting::Mn2_models::PositionFit::pull_from_MnPars(pars, prefix);

        CHECK_EQUAL(posn.centre, recovered_posn.centre);
        CHECK_EQUAL(posn.error_estimate, recovered_posn.error_estimate);

    }

    TEST(gaussian_MnPar_interface) {
        CcdPosition centre(3.14,2.718);
        CcdPixelShift error_est(0.4,0.5);

        psf_models::GaussianPsfModel g_model(5.5, 2.3);
        psf_fitting::Mn2_models::PsfFit<psf_models::GaussianPsfModel> g_fit;
        g_fit.model = g_model;
        g_fit.Position.centre=centre;
        g_fit.Position.error_estimate=error_est;

        ROOT::Minuit2::MnUserParameters pars;

        string prefix = "testing_mnpars_interface_";

        psf_fitting::Mn2_models::GaussianPsf::
        set_MnPars_from_PsfFit(g_fit, &pars, prefix);

//        cout<<pars<<endl;

        psf_fitting::Mn2_models::
        PsfFit<psf_models::GaussianPsfModel> pulled_fit =
            psf_fitting::Mn2_models::GaussianPsf::pull_PsfFit_from_MnPars(pars,  prefix);

        CHECK_EQUAL(g_fit.model.sigma_in_CCD_pix, pulled_fit.model.sigma_in_CCD_pix);
        //etc. (to do)

    }

}


#include <iostream>

#include <bs/ewma.hpp>
#include <bs/frame_range.hpp>
#include <bs/grimson_gmm.hpp>
#include <bs/utils.hpp>

#include <boost/make_shared.hpp>
#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <range/v3/front.hpp>
#include <range/v3/action/take.hpp>
#include <range/v3/view/take.hpp>

#include <opencv2/highgui.hpp>
using namespace cv;

#include <options.hpp>
#include <run.hpp>

//
// options_t::options_t is specific to each example:
//
options_t::options_t (int argc, char** argv) {
    {
        auto tmp = std::make_pair (
            "program", po::variable_value (std::string (argv [0]), false));
        map_.insert (tmp);
    }

    po::options_description generic ("Generic options");
    po::options_description config ("Configuration options");

    generic.add_options ()
    ("version", "version")
    ("help", "this");

    config.add_options ()
    ("display,d", "display frames.")

    ("input,i", po::value< std::string > ()->default_value ("0"),
     "input (file or stream index).")

    ("size,s", po::value< size_t > ()->default_value (4UL),
     "maximum number of distributions.")

    ("alpha,a", po::value< double > ()->default_value (.005),
     "learning alpha.")

    ("threshold,t", po::value< double > ()->default_value (2.5),
     "variance threshold for matching a distribution.")

    ("variance,v", po::value< double > ()->default_value (16.),
     "default variance for new distributions.")

    ("weight-threshold,b", po::value< double > ()->default_value (.7),
     "maximum weight (probability) for likely background distributions.");

    desc_ = boost::make_shared< po::options_description > ();

    desc_->add (generic);
    desc_->add (config);

    store (po::command_line_parser (argc, argv).options (*desc_).run (), map_);

    notify (map_);
}

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

static void
program_options_from (int& argc, char** argv) {
    bool complete_invocation = false;

    options_t program_options (argc, argv);

    if (program_options.have ("version")) {
        std::cout << "OpenCV v3.1\n";
        complete_invocation = true;
    }

    if (program_options.have ("help")) {
        std::cout << program_options.description () << std::endl;
        complete_invocation = true;
    }

    if (complete_invocation)
        exit (0);

    global_options (program_options);
}

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

static void
process_grimson_gmm (cv::VideoCapture& cap, const options_t& opts) {
    const bool display = opts.have ("display");

    bs::grimson_gmm_t grimson_gmm (
        opts ["size"].as< size_t > (),
        opts ["alpha"].as< double > (),
        opts ["threshold"].as< double > (),
        opts ["variance"].as< double > (),
        opts ["weight-threshold"].as< double > ());

    namedWindow ("Grimson GMM");
    namedWindow ("Grimson GMM background");

    moveWindow ("Grimson GMM", 0, 0);
    moveWindow ("Grimson GMM background", 512, 0);

    for (auto& frame : bs::getframes_from (cap)) {
        bs::frame_delay temp { 0 };

        auto src = bs::resize_frame (frame, 512. / frame.cols);

        if (display) {
            imshow ("Grimson GMM", grimson_gmm (src));
            imshow ("Grimson GMM background", grimson_gmm.background ());
        }

        if (temp.wait_for_key (27))
            break;
    }
}

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

int main (int argc, char** argv) {
    program_options_from (argc, argv);
    return run_with (process_grimson_gmm, global_options ()), 0;
}


#include <boost/filesystem.hpp>
#include "particionar.cpp"
#include "../config.hpp"

int main()
{
    arma_rng::set_seed_random();

    mat datos;
    datos.load(config::sourceDir + "/guia1/icgtp1datos/irisbin.csv");

    // Leave K out

    vector<ic::Particion> particiones = ic::leaveKOut(datos, 15);
    string carpetaParticiones = config::sourceDir + "/guia1/icgtp1datos/particionesIrisKOut/";
    boost::filesystem::create_directory(carpetaParticiones);
    ic::guardarParticiones(particiones, carpetaParticiones);

    // Leave one out

    particiones = ic::leaveKOut(datos, 1);
    carpetaParticiones = config::sourceDir + "/guia1/icgtp1datos/particionesIris1Out/";
    boost::filesystem::create_directory(carpetaParticiones);
    ic::guardarParticiones(particiones, carpetaParticiones);

    return 0;
}


/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2019, University of Stuttgart
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the University of Stuttgart nor the names
 *     of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written
 *     permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Andreas Orthey */

#include "MultiLevelPlanningCommon.h"
#include "../KinematicChain.h"
#include <ompl/base/SpaceInformation.h>
#include <ompl/tools/benchmark/Benchmark.h>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>

const unsigned int numLinks = 15;
const double runtime_limit = 5;
const double memory_limit = 4096;
const int run_count = 2;

const double linkLength = 1.0 / numLinks;

namespace ot = ompl::tools;
namespace og = ompl::geometric;
std::vector<Environment> envs;

Environment createCustomHornEnvironment(unsigned int d)
{
    double narrowPassageWidth = log((double)d) / (double)d;
    return createHornEnvironment(d, narrowPassageWidth);
}

ob::PlannerPtr GetQRRT(std::vector<int> sequenceLinks, ob::SpaceInformationPtr si)
{
    // ompl::msg::setLogLevel(ompl::msg::LOG_DEV2);
    std::vector<ob::SpaceInformationPtr> si_vec;

    for (unsigned int k = 0; k < sequenceLinks.size(); k++)
    {
        int links = sequenceLinks.at(k);
        assert(links < numLinks);

        OMPL_INFORM("Create MultiLevel Chain with %d links.", links);
        auto spaceK(std::make_shared<KinematicChainSpace>(links, linkLength, &envs.at(links)));

        auto siK = std::make_shared<ob::SpaceInformation>(spaceK);
        siK->setStateValidityChecker(std::make_shared<KinematicChainValidityChecker>(siK));
        spaceK->setup();
        si_vec.push_back(siK);
    }

    OMPL_INFORM("Add Original Chain with %d links.", numLinks);
    si_vec.push_back(si);

    auto planner = std::make_shared<ompl::multilevel::QRRT>(si_vec);

    std::string qName = "QRRT[";
    for (unsigned int k = 0; k < sequenceLinks.size(); k++)
    {
        int links = sequenceLinks.at(k);
        qName += std::to_string(links) + ",";
    }
    qName += std::to_string(numLinks);
    qName += "]";
    planner->setName(qName);
    return planner;
}

std::vector<std::vector<int>> getAdmissibleProjections(int dim)
{
    std::vector<std::vector<int>> projections;
    // projections.push_back(std::vector<int>{});
    // projections.push_back(std::vector<int>{2});
    // projections.push_back(std::vector<int>{3});

    // unsigned int K = ceil(dim*0.5);
    // for(uint k = 0; k < K; k++){
    //   std::vector<int> kStep;
    //   if(k>0) boost::push_back(kStep, boost::irange(2, dim, k));
    //   projections.push_back(kStep);
    // }
    // for(int k = 2; k < dim; k++){
    //   std::vector<int> kStep{k};
    //   projections.push_back(kStep);
    //   for(int j = k+1; j < dim; j++){
    //     std::vector<int> kjStep{k,j};
    //     projections.push_back(kjStep);
    //   }
    // }
    std::vector<int> discrete;
    boost::push_back(discrete, boost::irange(2, dim + 1));

    std::vector<int> twoStep;
    boost::push_back(twoStep, boost::irange(2, dim + 1, 2));

    if (twoStep.back() != dim)
        twoStep.push_back(dim);

    projections.push_back(twoStep);
    projections.push_back(discrete);

    auto last = std::unique(projections.begin(), projections.end());
    projections.erase(last, projections.end());

    std::cout << "Projections for dim " << dim << std::endl;
    for(unsigned int k = 0; k < projections.size(); k++){
        std::vector<int> pk = projections.at(k);
        std::cout << k << ": ";
        for(unsigned int j = 0; j < pk.size(); j++){
          std::cout << pk.at(j) << (j<pk.size()-1?",":"");
        }
        std::cout << std::endl;
    }

    return projections;
}

int main()
{
    Environment env = createCustomHornEnvironment(numLinks);
    // Environment env = createHornEnvironment(numLinks, log((double)numLinks) / (double)numLinks);
    OMPL_INFORM("Original Chain has %d links", numLinks);
    for (unsigned int k = 0; k < numLinks; k++)
    {
        envs.push_back(createCustomHornEnvironment((k>0?k:1)));
    }

    auto chain(std::make_shared<KinematicChainSpace>(numLinks, linkLength, &env));
    ompl::geometric::SimpleSetup ss(chain);

    ss.setStateValidityChecker(std::make_shared<KinematicChainValidityChecker>(ss.getSpaceInformation()));

    ompl::base::ScopedState<> start(chain), goal(chain);
    std::vector<double> startVec(numLinks, boost::math::constants::pi<double>() / (double)numLinks);
    std::vector<double> goalVec(numLinks, 0);
    startVec[0] = 0.;
    goalVec[0] = boost::math::constants::pi<double>() - .001;
    chain->setup();
    chain->copyFromReals(start.get(), startVec);
    chain->copyFromReals(goal.get(), goalVec);
    ss.setStartAndGoalStates(start, goal);

    ompl::tools::Benchmark benchmark(ss, "KinematicChain");
    benchmark.addExperimentParameter("num_links", "INTEGER", std::to_string(numLinks));

    //############################################################################
    // Compare QRRT with different QuotientSpace sequences to other OMPL planner
    //############################################################################
    ob::SpaceInformationPtr si = ss.getSpaceInformation();
    ob::ProblemDefinitionPtr pdef = ss.getProblemDefinition();

    addPlanner(benchmark, std::make_shared<og::STRIDE>(si));
    addPlanner(benchmark, std::make_shared<og::KPIECE1>(si));
    addPlanner(benchmark, std::make_shared<og::EST>(si));
    addPlanner(benchmark, std::make_shared<og::PRM>(si));

    std::vector<std::vector<int>> admissibleProjections = getAdmissibleProjections(numLinks-1);
    for (unsigned int k = 0; k < admissibleProjections.size(); k++)
    {
        std::vector<int> proj = admissibleProjections.at(k);
        ob::PlannerPtr plannerK = GetQRRT(proj, si);
        addPlanner(benchmark, plannerK);
    }

    printEstimatedTimeToCompletion(numberPlanners, run_count, runtime_limit);

    ot::Benchmark::Request request;
    request.maxTime = runtime_limit;
    request.maxMem = memory_limit;
    request.runCount = run_count;
    request.simplify = false;
    request.displayProgress = false;
    numberRuns = numberPlanners * run_count;

    benchmark.setPostRunEvent(std::bind(&PostRunEvent, std::placeholders::_1, std::placeholders::_2));

    benchmark.benchmark(request);
    benchmark.saveResultsToFile(boost::str(boost::format("kinematic_%i.log") % numLinks).c_str());

    printBenchmarkResults(benchmark);
    return 0;
}


/**
 * @file       Benchmark.cpp
 *
 * @brief      Benchmarking tests for Zerocoin.
 *
 * @author     Ian Miers, Christina Garman and Matthew Green
 * @date       June 2013
 *
 * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
 * @license    This project is released under the MIT license.
 **/
// Copyright (c) 2017-2018 The PIVX developers
// Copyright (c) 2018 The BlacerCoin developers

#include <boost/test/unit_test.hpp>
#include <string>
#include <iostream>
#include <fstream>
// #include <curses.h>
#include <exception>
#include <cstdlib>
#include <sys/time.h>
#include "streams.h"
#include "libzerocoin/ParamGeneration.h"
#include "libzerocoin/Denominations.h"
#include "libzerocoin/Coin.h"
#include "libzerocoin/CoinSpend.h"
#include "libzerocoin/Accumulator.h"

using namespace std;
using namespace libzerocoin;

#define COLOR_STR_GREEN   "\033[32m"
#define COLOR_STR_NORMAL  "\033[0m"
#define COLOR_STR_RED     "\033[31m"

#define TESTS_COINS_TO_ACCUMULATE   50

// Global test counters
uint32_t    ggNumTests        = 0;
uint32_t    ggSuccessfulTests = 0;

// Global coin array
PrivateCoin    *ggCoins[TESTS_COINS_TO_ACCUMULATE];

// Global params
ZerocoinParams *gg_Params;

//////////
// Utility routines
//////////

class Timer
{
	timeval timer[2];

public:

	timeval start()
	{
		gettimeofday(&this->timer[0], NULL);
		return this->timer[0];
	}

	timeval stop()
	{
		gettimeofday(&this->timer[1], NULL);
		return this->timer[1];
	}

	int duration() const
	{
		int secs(this->timer[1].tv_sec - this->timer[0].tv_sec);
		int usecs(this->timer[1].tv_usec - this->timer[0].tv_usec);

		if(usecs < 0)
		{
			--secs;
			usecs += 1000000;
		}

		return static_cast<int>(secs * 1000 + usecs / 1000.0 + 0.5);
	}
};

// Global timer
Timer timer;

void
gLogTestResult(string testName, bool (*testPtr)())
{
	string colorGreen(COLOR_STR_GREEN);
	string colorNormal(COLOR_STR_NORMAL);
	string colorRed(COLOR_STR_RED);

	cout << "Testing if " << testName << "..." << endl;

	bool testResult = testPtr();

	if (testResult == true) {
		cout << "\t" << colorGreen << "[PASS]"  << colorNormal << endl;
		ggSuccessfulTests++;
	} else {
		cout << colorRed << "\t[FAIL]" << colorNormal << endl;
	}

	ggNumTests++;
}

CBigNum
gGetTestModulus()
{
	static CBigNum testModulus(0);

	// TODO: should use a hard-coded RSA modulus for testing
	if (!testModulus) {
		CBigNum p, q;
		p = CBigNum::generatePrime(1024, false);
		q = CBigNum::generatePrime(1024, false);
		testModulus = p * q;
	}

	return testModulus;
}

//////////
// Test routines
//////////

bool
Testb_GenRSAModulus()
{
	CBigNum result = gGetTestModulus();

	if (!result) {
		return false;
	}
	else {
		return true;
	}
}

bool
Testb_CalcParamSizes()
{
	bool result = true;
#if 0

	uint32_t pLen, qLen;

	try {
		calculateGroupParamLengths(4000, 80, &pLen, &qLen);
		if (pLen < 1024 || qLen < 256) {
			result = false;
		}
		calculateGroupParamLengths(4000, 96, &pLen, &qLen);
		if (pLen < 2048 || qLen < 256) {
			result = false;
		}
		calculateGroupParamLengths(4000, 112, &pLen, &qLen);
		if (pLen < 3072 || qLen < 320) {
			result = false;
		}
		calculateGroupParamLengths(4000, 120, &pLen, &qLen);
		if (pLen < 3072 || qLen < 320) {
			result = false;
		}
		calculateGroupParamLengths(4000, 128, &pLen, &qLen);
		if (pLen < 3072 || qLen < 320) {
			result = false;
		}
	} catch (exception &e) {
		result = false;
	}
#endif

	return result;
}

bool
Testb_GenerateGroupParams()
{
	uint32_t pLen = 1024, qLen = 256, count;
	IntegerGroupParams group;

	for (count = 0; count < 1; count++) {

		try {
			group = deriveIntegerGroupParams(calculateSeed(gGetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen);
		} catch (std::runtime_error e) {
			cout << "Caught exception " << e.what() << endl;
			return false;
		}

		// Now perform some simple tests on the resulting parameters
		if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) {
			return false;
		}

		CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus);
		//cout << "g^q mod p = " << c << endl;
		if (!(c.isOne())) return false;

		// Try at multiple parameter sizes
		pLen = pLen * 1.5;
		qLen = qLen * 1.5;
	}

	return true;
}

bool
Testb_ParamGen()
{
	bool result = true;

	try {
		timer.start();
		// Instantiating testParams runs the parameter generation code
		ZerocoinParams testParams(gGetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL);
		timer.stop();

		cout << "\tPARAMGEN ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl;
	} catch (runtime_error e) {
		cout << e.what() << endl;
		result = false;
	}

	return result;
}

bool
Testb_Accumulator()
{
	// This test assumes a list of coins were generated during
	// the Testb_MintCoin() test.
	if (ggCoins[0] == NULL) {
		return false;
	}
	try {
		// Accumulate the coin list from first to last into one accumulator
            Accumulator accOne(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE);
            Accumulator accTwo(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE);
            Accumulator accThree(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE);
            Accumulator accFour(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE);
		AccumulatorWitness wThree(gg_Params, accThree, ggCoins[0]->getPublicCoin());

		for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
			accOne += ggCoins[i]->getPublicCoin();
			accTwo += ggCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin();
			accThree += ggCoins[i]->getPublicCoin();
			wThree += ggCoins[i]->getPublicCoin();
			if(i != 0) {
				accFour += ggCoins[i]->getPublicCoin();
			}
		}

		// Compare the accumulated results
		if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) {
			cout << "Accumulators don't match" << endl;
			return false;
		}

		if(accFour.getValue() != wThree.getValue()) {
			cout << "Witness math not working," << endl;
			return false;
		}

		// Verify that the witness is correct
		if (!wThree.VerifyWitness(accThree, ggCoins[0]->getPublicCoin()) ) {
			cout << "Witness not valid" << endl;
			return false;
		}

	} catch (runtime_error e) {
		cout << e.what() << endl;
        return false;
	}

	return true;
}

bool
Testb_MintCoin()
{
	try {
		// Generate a list of coins
		timer.start();
		for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
            ggCoins[i] = new PrivateCoin(gg_Params,CoinDenomination::ZQ_ONE);
		}
		timer.stop();
	} catch (exception &e) {
		return false;
	}

	cout << "\tMINT ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Coin: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl;

	return true;
}

bool
Testb_MintAndSpend()
{
	try {
		// This test assumes a list of coins were generated in Testb_MintCoin()
		if (ggCoins[0] == NULL)
		{
			// No coins: mint some.
			Testb_MintCoin();
			if (ggCoins[0] == NULL) {
				return false;
			}
		}

		// Accumulate the list of generated coins into a fresh accumulator.
		// The first one gets marked as accumulated for a witness, the
		// others just get accumulated normally.
        Accumulator acc(&gg_Params->accumulatorParams,CoinDenomination::ZQ_ONE);
		AccumulatorWitness wAcc(gg_Params, acc, ggCoins[0]->getPublicCoin());

		timer.start();
		for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
			acc += ggCoins[i]->getPublicCoin();
		}
		timer.stop();

		cout << "\tACCUMULATOR ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl;

		timer.start();
		for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
			wAcc +=ggCoins[i]->getPublicCoin();
		}
		timer.stop();

		cout << "\tWITNESS ELAPSED TIME: \n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl;

		// Now spend the coin
		timer.start();
		CoinSpend spend(gg_Params, gg_Params, *(ggCoins[0]), acc, 0, wAcc, 0, SpendType::SPEND); //(0) presstab
		timer.stop();

		cout << "\tSPEND ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl;

		// Serialize the proof and deserialize into newSpend
		CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);

		timer.start();
		ss << spend;
		timer.stop();

		CoinSpend newSpend(gg_Params, gg_Params, ss);

		cout << "\tSERIALIZE ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl;

		// Finally, see if we can verify the deserialized proof (return our result)
		timer.start();
		bool ret = newSpend.Verify(acc);
		timer.stop();

		cout << "\tSPEND VERIFY ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl;

		return ret;
	} catch (runtime_error &e) {
		cout << e.what() << endl;
		return false;
	}

	return false;
}

void
Testb_RunAllTests()
{
	// Make a new set of parameters from a random RSA modulus
	gg_Params = new ZerocoinParams(gGetTestModulus());

	ggNumTests = ggSuccessfulTests = 0;
	for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
		ggCoins[i] = NULL;
	}

	// Run through all of the Zerocoin tests
	gLogTestResult("an RSA modulus can be generated", Testb_GenRSAModulus);
	gLogTestResult("parameter sizes are correct", Testb_CalcParamSizes);
	gLogTestResult("group/field parameters can be generated", Testb_GenerateGroupParams);
	gLogTestResult("parameter generation is correct", Testb_ParamGen);
	gLogTestResult("coins can be minted", Testb_MintCoin);
	gLogTestResult("the accumulator works", Testb_Accumulator);
	gLogTestResult("a minted coin can be spent", Testb_MintAndSpend);

	// Summarize test results
	if (ggSuccessfulTests < ggNumTests) {
		cout << endl << "ERROR: SOME TESTS FAILED" << endl;
	}

	// Clear any generated coins
	for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
		delete ggCoins[i];
	}

	cout << ggSuccessfulTests << " out of " << ggNumTests << " tests passed." << endl << endl;
	delete gg_Params;
}
BOOST_AUTO_TEST_SUITE(benchmark_zerocoin)

BOOST_AUTO_TEST_CASE(benchmark_test)
{
	cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " benchmark utility." << endl << endl;

	Testb_RunAllTests();
}
BOOST_AUTO_TEST_SUITE_END()


/**
 * @file calc-jump.cpp
 *
 * @brief calculate jump polynomial.
 *
 * @author Mutsuo Saito (Hiroshima University)
 * @author Makoto Matsumoto (The University of Tokyo)
 *
 * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto,
 * Hiroshima University and The University of Tokyo.
 * All rights reserved.
 *
 * The 3-clause BSD License is applied to this software, see
 * LICENSE.txt
 */
#include <iostream>
#include <iomanip>
#include <string>
#include <inttypes.h>
#include <stdint.h>
#include <NTL/GF2X.h>
#include "SFMT-calc-jump.hpp"

using namespace NTL;
using namespace std;
using namespace sfmt;

int main(int argc, char * argv[]) {
    if (argc <= 1) {
	cout << argv[0] << " deg" << endl;
	return -1;
    }
    string step_string = argv[1];
    GF2X poly;
    uint64_t d = strtoull(argv[1], NULL, 10);
    SetCoeff(poly, d, 1);
    string tmp;
    polytostring(tmp, poly);
    cout << "string: " << tmp << endl;
    cout << "poly: " << poly << endl;
    GF2X r;
    GF2X s;
    string diff;
    for (int i = 0; i < 10; i++) {
	random(r, 1234);
	polytostring(tmp, r);
	cout << "1:" << tmp << endl;
	stringtopoly(s, tmp);
	polytostring(diff, s);
	cout << "2:" <<diff << endl;
	if (r != s) {
	    cout << "bad!" << endl;
	    long degree = deg(r);
	    if (degree != deg(s)) {
		cout << "deg(s) = " << deg(s)
		     << " deg(r) = " << deg(r) << endl;
		break;
	    }
	}
	if (tmp != diff) {
	    cout << "bad!" << endl;
	    int len = tmp.length();
	    for (int j = 0; j < len; j++) {
		cout << "[" << tmp[j] << diff[j] << "]";
		if (tmp[j] != diff[j]) {
		    cout << "!" << endl;
		    break;
		}
	    }
	    break;
	}
    }
    return 0;
}


// Copyright (c) 2019 Graphcore Ltd. All rights reserved.
#define BOOST_TEST_MODULE Namescope0LogicalIf

#include <../test_runner.hpp>
#include <boost/test/unit_test.hpp>
#include <filereader.hpp>
#include <popart/builder.hpp>
#include <popart/inputshapeinfo.hpp>
#include <popart/tensorinfo.hpp>
#include <popart/tensornames.hpp>

using namespace popart;

BOOST_AUTO_TEST_CASE(LogicalIf_namescope0) {
  TensorInfo info{"FLOAT", std::vector<int64_t>{2, 2}};
  TensorInfo infoBool{"BOOL", std::vector<int64_t>{}};
  std::vector<TestTensor> inputs;
  std::vector<TestTensor> outputs;

  TestRunner runner;
  runner.patterns.enableInPlace(false);

  runner.buildModel([&](Builder &builder) {
    auto aiOnnx       = builder.aiOnnxOpset9();
    auto in0          = builder.addInputTensor(info);
    auto in1          = builder.addInputTensor(info);
    auto in_condition = builder.addInputTensor(infoBool);

    // in0 + in1
    auto &then_branch = [in0, in1](Builder &parent_builder) -> Builder & {
      Builder &builder = parent_builder.createSubgraphBuilder();
      auto aiOnnx      = builder.aiOnnxOpset9();
      builder.addInputTensorFromParentGraph(in0);
      builder.addInputTensorFromParentGraph(in1);

      // could get identical name as else_branch
      auto out0 = aiOnnx.add({in0, in1});
      builder.addOutputTensor(out0);
      return builder;
    }(builder);

    // 2*(in0 + in1)
    auto &else_branch = [in0, in1](Builder &parent_builder) -> Builder & {
      Builder &builder = parent_builder.createSubgraphBuilder();
      auto aiOnnx      = builder.aiOnnxOpset9();
      auto aiGraphcore = builder.aiGraphcoreOpset1();
      builder.addInputTensorFromParentGraph(in0);
      builder.addInputTensorFromParentGraph(in1);

      // could get identical name as then_branch
      auto out0 = aiOnnx.add({in0, in1});
      auto out1 = aiGraphcore.scale({out0}, 2);
      builder.addOutputTensor(out1);
      return builder;
    }(builder);

    auto out =
        aiOnnx.logical_if({in_condition}, 1, else_branch, then_branch)[0];
    inputs.push_back(
        TestTensor::create<float>(in0, {1, 2, 3, 4}, info.shape()));
    inputs.push_back(
        TestTensor::create<float>(in1, {2, 3, 4, 5}, info.shape()));
    inputs.push_back(TestTensor::create<bool>(in_condition, infoBool.shape()));
    outputs.push_back(TestTensor::create<float>(out, info.shape()));

    return out;
  });

  // Check true branch
  inputs.back().setData<char>({1});
  runner.checkResult(
      [](TestTensor &result) {
        auto data = result.getDataCopy<float>();
        std::vector<float> expected{3, 5, 7, 9};
        BOOST_CHECK(data == expected);
      },
      inputs,
      outputs);

  // Check false branch
  inputs.back().setData<char>({0});
  runner.checkResult(
      [](TestTensor &result) {
        auto data = result.getDataCopy<float>();
        std::vector<float> expected{6, 10, 14, 18};
        BOOST_CHECK(data == expected);
      },
      inputs,
      outputs);
}


//==================================================================================================
/*!
  @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_DETAIL_CONSTANT_LIMITEXPONENT_HPP_INCLUDED
#define BOOST_SIMD_DETAIL_CONSTANT_LIMITEXPONENT_HPP_INCLUDED

#include <boost/simd/config.hpp>
#include <boost/simd/detail/brigand.hpp>
#include <boost/simd/detail/dispatch.hpp>
#include <boost/simd/detail/constant_traits.hpp>
#include <boost/simd/detail/dispatch/function/make_callable.hpp>
#include <boost/simd/detail/dispatch/hierarchy/functions.hpp>
#include <boost/simd/detail/dispatch/as.hpp>

/*

    @ingroup group-constant

    Generate the limit exposant of floating point numbers,  that is Maxexponant+1

    @par Semantic:

    @code
    as_integer<T> r = Limitexponent<T>();
    @endcode

    @code
    if T is double
      r =  1024;
    else if T is float
      r =  128;
    @endcode

    @return The Limitexponent constant for the proper type
  */

namespace boost { namespace simd
{
  namespace tag
  {
    struct limitexponent_ : boost::dispatch::constant_value_<limitexponent_>
    {
      BOOST_DISPATCH_MAKE_CALLABLE(ext,limitexponent_,boost::dispatch::constant_value_<limitexponent_>);

      struct value_map
      {
        template<typename X>
        static std::integral_constant<X,0> value(boost::dispatch::integer_<X> const&);

        template<typename X>
        static std::integral_constant<std::int32_t,128> value(boost::dispatch::single_<X> const&);

        template<typename X>
        static std::integral_constant<std::int64_t,1024> value(boost::dispatch::double_<X> const&);
      };
    };
  }

  namespace ext
  {
    BOOST_DISPATCH_FUNCTION_DECLARATION(tag, limitexponent_)
  }

  namespace detail
  {
    BOOST_DISPATCH_CALLABLE_DEFINITION(tag::limitexponent_,limitexponent);
  }

  template<typename T> BOOST_FORCEINLINE auto Limitexponent()
  BOOST_NOEXCEPT_DECLTYPE(detail::limitexponent( boost::dispatch::as_<T>{}))
  {
    return detail::limitexponent( boost::dispatch::as_<T>{} );
  }
} }

#include <boost/simd/arch/common/scalar/constant/constant_value.hpp>
#include <boost/simd/arch/common/simd/constant/constant_value.hpp>

#endif


#include <Eigen/Core>
#include "macros.h"

TRAJOPT_API Eigen::MatrixXf getSpherePoints(int n);


#include "binary_search.h"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <stdexcept>
#include <vector>
#include <cstddef>

#define EXERCISM_RUN_ALL_TESTS
using namespace std;

// Binary-Search exercise test case data version 1.3.0

BOOST_AUTO_TEST_CASE(finds_a_value_in_an_array_with_one_element)
{
    const std::vector<int> data {6};

    const std::size_t actual = binary_search::find(data, 6);

    const std::size_t expected = 0;

    BOOST_TEST(expected == actual);
}

#if defined(EXERCISM_RUN_ALL_TESTS)
BOOST_AUTO_TEST_CASE(finds_a_value_in_the_middle_of_an_array)
{
    const std::vector<int> data {1, 3, 4, 6, 8, 9, 11};

    const std::size_t actual = binary_search::find(data, 6);

    const std::size_t expected = 3;

    BOOST_TEST(expected == actual);
}

BOOST_AUTO_TEST_CASE(finds_a_value_at_the_beginning_of_an_array)
{
    const std::vector<int> data {1, 3, 4, 6, 8, 9, 11};

    const std::size_t actual = binary_search::find(data, 1);

    const std::size_t expected = 0;

    BOOST_TEST(expected == actual);
}

BOOST_AUTO_TEST_CASE(finds_a_value_at_the_end_of_an_array)
{
    const std::vector<int> data {1, 3, 4, 6, 8, 9, 11};

    const std::size_t actual = binary_search::find(data, 11);

    const std::size_t expected = 6;

    BOOST_TEST(expected == actual);
}

BOOST_AUTO_TEST_CASE(finds_a_value_in_an_array_of_odd_length)
{
    const std::vector<int> data {1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634};

    const std::size_t actual = binary_search::find(data, 144);

    const std::size_t expected = 9;

    BOOST_TEST(expected == actual);
}

BOOST_AUTO_TEST_CASE(finds_a_value_in_an_array_of_even_length)
{
    const std::vector<int> data {1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377};

    const std::size_t actual = binary_search::find(data, 21);

    const std::size_t expected = 5;

    BOOST_TEST(expected == actual);
}

BOOST_AUTO_TEST_CASE(identifies_that_a_value_is_not_included_in_the_array)
{
    const std::vector<int> data {1, 3, 4, 6, 8, 9, 11};

    BOOST_REQUIRE_THROW(binary_search::find(data, 7), std::domain_error);
}

BOOST_AUTO_TEST_CASE(a_value_smaller_than_the_arrays_smallest_value_is_not_found)
{
    const std::vector<int> data {1, 3, 4, 6, 8, 9, 11};

    BOOST_REQUIRE_THROW(binary_search::find(data, 0), std::domain_error);
}

BOOST_AUTO_TEST_CASE(a_value_larger_than_the_arrays_largest_value_is_not_found)
{
    const std::vector<int> data {1, 3, 4, 6, 8, 9, 11};

    BOOST_REQUIRE_THROW(binary_search::find(data, 13), std::domain_error);
}

BOOST_AUTO_TEST_CASE(nothing_is_found_in_an_empty_array)
{
    const std::vector<int> data {};

    BOOST_REQUIRE_THROW(binary_search::find(data, 1), std::domain_error);
}

BOOST_AUTO_TEST_CASE(nothing_is_found_when_the_left_and_right_bounds_cross)
{
    const std::vector<int> data {1, 2};

    BOOST_REQUIRE_THROW(binary_search::find(data, 0), std::domain_error);
}

#endif


// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#include <boost/hana/ext/boost/mpl/integral_c.hpp>

#include <boost/hana/assert.hpp>
#include <boost/hana/core/tag_of.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/tuple.hpp>

#include <laws/base.hpp>
#include <laws/comparable.hpp>
#include <laws/constant.hpp>
#include <laws/euclidean_ring.hpp>
#include <laws/group.hpp>
#include <laws/hashable.hpp>
#include <laws/logical.hpp>
#include <laws/monoid.hpp>
#include <laws/orderable.hpp>
#include <laws/ring.hpp>

#include <boost/mpl/bool.hpp>
#include <boost/mpl/char.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/long.hpp>
#include <boost/mpl/size_t.hpp>

#include <cstddef>
#include <type_traits>
using namespace boost::hana;
namespace mpl = boost::mpl;

int main() {
    auto ints = make<tuple_tag>(
        mpl::int_<-10>{}, mpl::int_<-2>{}, mpl::integral_c<int, 0>{},
        mpl::integral_c<int, 1>{}, mpl::integral_c<int, 3>{}
    );
    (void)ints;

#if BOOST_HANA_TEST_PART == 1
    //////////////////////////////////////////////////////////////////////////
    // Make sure the tag is correct
    //////////////////////////////////////////////////////////////////////////
    {
        static_assert(std::is_same<
            tag_of_t<mpl::bool_<true>>,
            ext::boost::mpl::integral_c_tag<bool>
        >::value, "");

        static_assert(std::is_same<
            tag_of_t<mpl::int_<0>>,
            ext::boost::mpl::integral_c_tag<int>
        >::value, "");

        static_assert(std::is_same<
            tag_of_t<mpl::long_<0>>,
            ext::boost::mpl::integral_c_tag<long>
        >::value, "");

        static_assert(std::is_same<
            tag_of_t<mpl::size_t<0>>,
            ext::boost::mpl::integral_c_tag<std::size_t>
        >::value, "");

        static_assert(std::is_same<
            tag_of_t<mpl::integral_c<int, 0>>,
            ext::boost::mpl::integral_c_tag<int>
        >::value, "");

        static_assert(std::is_same<
            tag_of_t<mpl::char_<0>>,
            ext::boost::mpl::integral_c_tag<char>
        >::value, "");
    }

    //////////////////////////////////////////////////////////////////////////
    // Interoperation with hana::integral_constant
    //////////////////////////////////////////////////////////////////////////
    {
        BOOST_HANA_CONSTANT_CHECK(mpl::integral_c<int, 1>{} == int_c<1>);
        BOOST_HANA_CONSTANT_CHECK(mpl::integral_c<int, 1>{} == long_c<1>);

        BOOST_HANA_CONSTANT_CHECK(mpl::integral_c<int, 2>{} != int_c<3>);
    }

    //////////////////////////////////////////////////////////////////////////
    // Constant
    //////////////////////////////////////////////////////////////////////////
    {
        // value
        static_assert(value(mpl::integral_c<int, 0>{}) == 0, "");
        static_assert(value(mpl::integral_c<int, 1>{}) == 1, "");
        static_assert(value(mpl::integral_c<int, 3>{}) == 3, "");

        // laws
        test::TestConstant<ext::boost::mpl::integral_c_tag<int>>{ints, tuple_t<int, long, long long>};
    }

#elif BOOST_HANA_TEST_PART == 2
    //////////////////////////////////////////////////////////////////////////
    // Monoid, Group, Ring, EuclideanRing
    //////////////////////////////////////////////////////////////////////////
    test::TestMonoid<ext::boost::mpl::integral_c_tag<int>>{ints};
    test::TestGroup<ext::boost::mpl::integral_c_tag<int>>{ints};

#elif BOOST_HANA_TEST_PART == 3
    test::TestRing<ext::boost::mpl::integral_c_tag<int>>{ints};
    test::TestEuclideanRing<ext::boost::mpl::integral_c_tag<int>>{ints};

#elif BOOST_HANA_TEST_PART == 4 || BOOST_HANA_TEST_PART == 5
    //////////////////////////////////////////////////////////////////////////
    // Logical
    //////////////////////////////////////////////////////////////////////////
    {
        auto t = test::ct_eq<3>{};
        auto e = test::ct_eq<4>{};

        // eval_if
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                eval_if(mpl::true_{}, always(t), always(e)),
                t
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                eval_if(mpl::false_{}, always(t), always(e)),
                e
            ));
        }

        // not_
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                not_(mpl::true_{}),
                mpl::false_{}
            ));
            BOOST_HANA_CONSTANT_CHECK(equal(
                not_(mpl::false_{}),
                mpl::true_{}
            ));
        }

        // laws
#if BOOST_HANA_TEST_PART == 4

        auto ints = make<tuple_tag>(
            mpl::int_<-2>{}, mpl::integral_c<int, 0>{}, mpl::integral_c<int, 3>{}
        );
        test::TestLogical<ext::boost::mpl::integral_c_tag<int>>{ints};

#elif BOOST_HANA_TEST_PART == 5

        auto bools = make<tuple_tag>(
            mpl::true_{}, mpl::false_{},
            mpl::integral_c<bool, true>{}, mpl::integral_c<bool, false>{}
        );
        test::TestLogical<ext::boost::mpl::integral_c_tag<bool>>{bools};

#endif
    }

#elif BOOST_HANA_TEST_PART == 6
    //////////////////////////////////////////////////////////////////////////
    // Comparable
    //////////////////////////////////////////////////////////////////////////
    test::TestComparable<ext::boost::mpl::integral_c_tag<int>>{ints};
    test::TestHashable<ext::boost::mpl::integral_c_tag<void>>{ints};

#elif BOOST_HANA_TEST_PART == 7
    //////////////////////////////////////////////////////////////////////////
    // Orderable
    //////////////////////////////////////////////////////////////////////////
    test::TestOrderable<ext::boost::mpl::integral_c_tag<int>>{ints};
#endif
}


//==============================================================================
//         Copyright 2003 - 2012 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012        MetaScale SAS
//
//          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
//==============================================================================
#ifndef NT2_SDK_UNIT_DETAILS_HELPERS_HPP_INCLUDED
#define NT2_SDK_UNIT_DETAILS_HELPERS_HPP_INCLUDED

#include <nt2/include/functions/splat.hpp>
#include <nt2/include/constants/valmin.hpp>
#include <nt2/include/constants/valmax.hpp>
#include <boost/dispatch/meta/is_signed.hpp>
#include <boost/mpl/bool.hpp>

namespace nt2
{
  ////////////////////////////////////////////////////////////////////////////////
  // roll a random number (will be nt2::rand afterward)
  ////////////////////////////////////////////////////////////////////////////////
  template<class T, class X,  class Y, bool B>
  struct typed_inner_roll;

  template<class T, class X,  class Y>
  struct typed_inner_roll<T, X, Y, true>
  {
    static inline T call(X mn, Y mx)
    {
      // mn is supposed less than mx
      double r1 = ((double)::rand()/RAND_MAX);
      if(mx == 0)
      {
        return nt2::splat<T>(r1*mn);
      }
      else if (mn == 0)
      {
        return nt2::splat<T>(r1*mx);
      }
      else
      {
        double fac =  0.5*nt2::abs(double(mn)/double(mx));
        double r2 = ((double)::rand()/RAND_MAX);
        return nt2::splat<T>((r1 > fac) ? r2*mn : r2*mx);
      }
    }
  };

  template<class T, class X,  class Y>
  struct typed_inner_roll<T, X, Y, false>
  {
    static inline T call(X mn, Y mx)
    {
      double r = ((double)::rand()/RAND_MAX)*(mx-mn) + mn;
      return nt2::splat<T>(r);
    }
  };

  template<class T,class X, class Y> inline T roll(X mn, Y mx)
  {
    return typed_inner_roll<T, X, Y, boost::dispatch::meta::is_signed<T>::value>::call(mn, mx);
  }

  //=================================================================================
  template<class T, bool B>
  struct inner_roll;

  template<class T>
  struct inner_roll<T, true>
  {
    static inline T call()
    {
      double r1 = ((double)::rand()/RAND_MAX);
      double r2 = ((double)::rand()/RAND_MAX);
      return nt2::splat<T>((r1 > 0.5) ? r2*nt2::Valmin<T>() : r2*nt2::Valmax<T>());
    }
  };

  template<class T>
  struct inner_roll<T, false>
  {
    static inline T call()
    {
      double r1 = ((double)::rand()/RAND_MAX);
      return nt2::splat<T>(r1*nt2::Valmax<T>());
    }
  };

  template<class T> inline T roll()
  {
    return inner_roll<T, boost::dispatch::meta::is_signed<T>::value>::call();
  }

}
using nt2::roll;

#endif


// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test

// Copyright (c) 2014, Oracle and/or its affiliates.

// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#include <test_geometries/custom_lon_lat_point.hpp>

#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>

namespace bg = boost::geometry;

struct dummy {};

int main()
{
    bg::concepts::check
        <
            ro_lon_lat_point<double, bg::cs::geographic<dummy> > const
        >();

    return 0;
}