#ifndef THYME_SPACES_DISCRETE
#define THYME_SPACES_DISCRETE

#include <Eigen/Dense>
#include <random>

namespace thyme::spaces {

/*
 *
 * Partial Discrete space stub from thyme
 *
 */
class Discrete {
   public:
    using value_shape = Eigen::MatrixXd;
    using value_type = size_t;

    Discrete(std::size_t m = 1) : m_m(m) {
        std::random_device rd;
        m_gen = std::mt19937(rd());  // get global seed here
        m_dis = std::uniform_int_distribution<int>(0, m_m - 1);
    }
    value_type sample() { return m_dis(m_gen); }
    value_type max(const value_shape& values) {
        size_t max_index;
        values.col(0).maxCoeff(&max_index);
        return max_index;
    }

   private:
    std::size_t m_m;
    std::uniform_int_distribution<int> m_dis;
    std::mt19937 m_gen;
};

}  // namespace thyme::spaces

#endif


/**
 * @file sort_policy_test.cpp
 * @author Ryan Curtin
 *
 * Tests for each of the implementations of the SortPolicy class.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/tree/binary_space_tree.hpp>

// Classes to test.
#include <mlpack/methods/neighbor_search/sort_policies/nearest_neighbor_sort.hpp>
#include <mlpack/methods/neighbor_search/sort_policies/furthest_neighbor_sort.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::neighbor;
using namespace mlpack::bound;
using namespace mlpack::tree;
using namespace mlpack::metric;

BOOST_AUTO_TEST_SUITE(SortPolicyTest);

// Tests for NearestNeighborSort

/**
 * Ensure the best distance for nearest neighbors is 0.
 */
BOOST_AUTO_TEST_CASE(NnsBestDistance)
{
  BOOST_REQUIRE(NearestNeighborSort::BestDistance() == 0);
}

/**
 * Ensure the worst distance for nearest neighbors is DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(NnsWorstDistance)
{
  BOOST_REQUIRE(NearestNeighborSort::WorstDistance() == DBL_MAX);
}

/**
 * Make sure the comparison works for values strictly less than the reference.
 */
BOOST_AUTO_TEST_CASE(NnsIsBetterStrict)
{
  BOOST_REQUIRE(NearestNeighborSort::IsBetter(5.0, 6.0) == true);
}

/**
 * Warn in case the comparison is not strict.
 */
BOOST_AUTO_TEST_CASE(NnsIsBetterNotStrict)
{
  BOOST_WARN(NearestNeighborSort::IsBetter(6.0, 6.0) == true);
}

/**
 * A simple test case of where to insert when all the values in the list are
 * DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(NnsSortDistanceAllDblMax)
{
  arma::vec list(5);
  list.fill(DBL_MAX);
  arma::Col<size_t> indices(5);
  indices.fill(0);

  // Should be inserted at the head of the list.
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, indices, 5.0) == 0);
}

/**
 * Another test case, where we are just putting the new value in the middle of
 * the list.
 */
BOOST_AUTO_TEST_CASE(NnsSortDistance2)
{
  arma::vec list(3);
  list[0] = 0.66;
  list[1] = 0.89;
  list[2] = 1.14;
  arma::Col<size_t> indices(3);
  indices.fill(0);

  // Run a couple possibilities through.
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, indices, 0.61) == 0);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, indices, 0.76) == 1);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, indices, 0.99) == 2);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, indices, 1.22) ==
      (size_t() - 1));
}

/**
 * Very simple sanity check to ensure that bounds are working alright.  We will
 * use a one-dimensional bound for simplicity.
 */
BOOST_AUTO_TEST_CASE(NnsNodeToNodeDistance)
{
  // Well, there's no easy way to make HRectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::mat dataset("1");
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType nodeOne(dataset);
  arma::vec utility(1);
  utility[0] = 0;

  nodeOne.Bound() = HRectBound<EuclideanDistance>(1);
  nodeOne.Bound() |= utility;
  utility[0] = 1;
  nodeOne.Bound() |= utility;

  TreeType nodeTwo(dataset);
  nodeTwo.Bound() = HRectBound<EuclideanDistance>(1);

  utility[0] = 5;
  nodeTwo.Bound() |= utility;
  utility[0] = 6;
  nodeTwo.Bound() |= utility;

  // This should use the L2 distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&nodeOne,
      &nodeTwo), 4.0, 1e-5);

  // And another just to be sure, from the other side.
  nodeTwo.Bound().Clear();
  utility[0] = -2;
  nodeTwo.Bound() |= utility;
  utility[0] = -1;
  nodeTwo.Bound() |= utility;

  // Again, the distance is the L2 distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&nodeOne,
      &nodeTwo), 1.0, 1e-5);

  // Now, when the bounds overlap.
  nodeTwo.Bound().Clear();
  utility[0] = -0.5;
  nodeTwo.Bound() |= utility;
  utility[0] = 0.5;
  nodeTwo.Bound() |= utility;

  BOOST_REQUIRE_SMALL(NearestNeighborSort::BestNodeToNodeDistance(&nodeOne,
      &nodeTwo), 1e-5);
}

/**
 * Another very simple sanity check for the point-to-node case, again in one
 * dimension.
 */
BOOST_AUTO_TEST_CASE(NnsPointToNodeDistance)
{
  // Well, there's no easy way to make HRectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  arma::mat dataset("1");
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType node(dataset);
  node.Bound() = HRectBound<EuclideanDistance>(1);
  node.Bound() |= utility;
  utility[0] = 1;
  node.Bound() |= utility;

  arma::vec point(1);
  point[0] = -0.5;

  // The distance is the L2 distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.5, 1e-5);

  // Now from the other side of the bound.
  point[0] = 1.5;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.5, 1e-5);

  // And now when the point is inside the bound.
  point[0] = 0.5;

  BOOST_REQUIRE_SMALL(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 1e-5);
}

// Tests for FurthestNeighborSort

/**
 * Ensure the best distance for furthest neighbors is DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(FnsBestDistance)
{
  BOOST_REQUIRE(FurthestNeighborSort::BestDistance() == DBL_MAX);
}

/**
 * Ensure the worst distance for furthest neighbors is 0.
 */
BOOST_AUTO_TEST_CASE(FnsWorstDistance)
{
  BOOST_REQUIRE(FurthestNeighborSort::WorstDistance() == 0);
}

/**
 * Make sure the comparison works for values strictly less than the reference.
 */
BOOST_AUTO_TEST_CASE(FnsIsBetterStrict)
{
  BOOST_REQUIRE(FurthestNeighborSort::IsBetter(5.0, 4.0) == true);
}

/**
 * Warn in case the comparison is not strict.
 */
BOOST_AUTO_TEST_CASE(FnsIsBetterNotStrict)
{
  BOOST_WARN(FurthestNeighborSort::IsBetter(6.0, 6.0) == true);
}

/**
 * A simple test case of where to insert when all the values in the list are
 * 0.
 */
BOOST_AUTO_TEST_CASE(FnsSortDistanceAllZero)
{
  arma::vec list(5);
  list.fill(0);
  arma::Col<size_t> indices(5);
  indices.fill(0);

  // Should be inserted at the head of the list.
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, indices, 5.0) == 0);
}

/**
 * Another test case, where we are just putting the new value in the middle of
 * the list.
 */
BOOST_AUTO_TEST_CASE(FnsSortDistance2)
{
  arma::vec list(3);
  list[0] = 1.14;
  list[1] = 0.89;
  list[2] = 0.66;
  arma::Col<size_t> indices(3);
  indices.fill(0);

  // Run a couple possibilities through.
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, indices, 1.22) == 0);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, indices, 0.93) == 1);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, indices, 0.68) == 2);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, indices, 0.62) ==
      (size_t() - 1));
}

/**
 * Very simple sanity check to ensure that bounds are working alright.  We will
 * use a one-dimensional bound for simplicity.
 */
BOOST_AUTO_TEST_CASE(FnsNodeToNodeDistance)
{
  // Well, there's no easy way to make HRectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  arma::mat dataset("1");
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType nodeOne(dataset);
  nodeOne.Bound() = HRectBound<EuclideanDistance>(1);
  nodeOne.Bound() |= utility;
  utility[0] = 1;
  nodeOne.Bound() |= utility;

  TreeType nodeTwo(dataset);
  nodeTwo.Bound() = HRectBound<EuclideanDistance>(1);
  utility[0] = 5;
  nodeTwo.Bound() |= utility;
  utility[0] = 6;
  nodeTwo.Bound() |= utility;

  // This should use the L2 distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&nodeOne,
      &nodeTwo), 6.0, 1e-5);

  // And another just to be sure, from the other side.
  nodeTwo.Bound().Clear();
  utility[0] = -2;
  nodeTwo.Bound() |= utility;
  utility[0] = -1;
  nodeTwo.Bound() |= utility;

  // Again, the distance is the L2 distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&nodeOne,
      &nodeTwo), 3.0, 1e-5);

  // Now, when the bounds overlap.
  nodeTwo.Bound().Clear();
  utility[0] = -0.5;
  nodeTwo.Bound() |= utility;
  utility[0] = 0.5;
  nodeTwo.Bound() |= utility;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&nodeOne,
      &nodeTwo), 1.5, 1e-5);
}

/**
 * Another very simple sanity check for the point-to-node case, again in one
 * dimension.
 */
BOOST_AUTO_TEST_CASE(FnsPointToNodeDistance)
{
  // Well, there's no easy way to make HRectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  arma::mat dataset("1");
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType node(dataset);
  node.Bound() = HRectBound<EuclideanDistance>(1);
  node.Bound() |= utility;
  utility[0] = 1;
  node.Bound() |= utility;

  arma::vec point(1);
  point[0] = -0.5;

  // The distance is the L2 distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), 1.5, 1e-5);

  // Now from the other side of the bound.
  point[0] = 1.5;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), 1.5, 1e-5);

  // And now when the point is inside the bound.
  point[0] = 0.5;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.5, 1e-5);
}

BOOST_AUTO_TEST_SUITE_END();


//
//                              libieeep1788
//
//   An implementation of the preliminary IEEE P1788 standard for
//   interval arithmetic
//
//
//   Copyright 2013 - 2015
//
//   Marco Nehmeier (nehmeier@informatik.uni-wuerzburg.de)
//   Department of Computer Science,
//   University of Wuerzburg, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#define BOOST_TEST_MODULE "Integration: IO [infsup/interval, infsup/decorated_interval, p1788/flavor/infsup/setbased/mpfr_bin_ieee754_flavor]"
#include "test/util/boost_test_wrapper.hpp"

#include <boost/test/output_test_stream.hpp>

#include "p1788/p1788.hpp"

#include <sstream>

template<typename T>
using I = p1788::infsup::interval<T, p1788::flavor::infsup::setbased::mpfr_bin_ieee754_flavor>;

template<typename T>
using DI = p1788::infsup::decorated_interval<T, p1788::flavor::infsup::setbased::mpfr_bin_ieee754_flavor>;

typedef p1788::decoration::decoration DEC;

const double INF_D = std::numeric_limits<double>::infinity();

BOOST_AUTO_TEST_CASE(integration_output_test)
{
    boost::test_tools::output_test_stream output;

    output << I<double>::empty();
    BOOST_CHECK( output.is_equal( "[empty]" ) );

    output << I<double>::entire();
    BOOST_CHECK( output.is_equal( "[entire]" ) );

    output << I<float>(1.0,2.1);
    BOOST_CHECK( output.is_equal( "[1,2.10001]" ) );

    output << I<double>(0.0,-0.0);
    BOOST_CHECK( output.is_equal( "[-0,0]" ) );

    output << DI<double>::nai();
    BOOST_CHECK( output.is_equal( "[nai]" ) );

    output << DI<double>::empty();
    BOOST_CHECK( output.is_equal( "[empty]" ) );

    output << DI<double>::entire();
    BOOST_CHECK( output.is_equal( "[entire]_dac" ) );

    output << DI<double>(1.0,2.1);
    BOOST_CHECK( output.is_equal( "[1,2.10001]_com" ) );

    output << p1788::io::uncertain_form;

    output << I<double>::entire();
    BOOST_CHECK( output.is_equal( "0.000000??" ) );

    output << DI<double>::entire();
    BOOST_CHECK( output.is_equal( "0.000000??_dac" ) );
}

BOOST_AUTO_TEST_CASE(integration_input_test)
{
    {
        I<double> x;
        std::istringstream is("[empty]");
        is >> x;
        BOOST_CHECK( is_empty( x) );
        BOOST_CHECK(is);
    }

    {
        I<double> x;
        std::istringstream is("[entire]");
        is >> x;
        BOOST_CHECK( is_entire( x) );
        BOOST_CHECK(is);
    }

    {
        I<double> x;
        std::istringstream is("[1,2.1]");
        is >> x;
        BOOST_CHECK_EQUAL( x, I<double>(1.0,2.1) );
        BOOST_CHECK(is);
    }

    {
        I<double> x;
        std::istringstream is("0.000000??");
        is >> x;
        BOOST_CHECK( is_entire( x) );
        BOOST_CHECK(is);
    }

    {
        DI<double> x;
        std::istringstream is("[nai]");
        is >> x;
        BOOST_CHECK( is_nai( x) );
        BOOST_CHECK(is);
    }

    {
        DI<float> x;
        std::istringstream is("[empty]");
        is >> x;
        BOOST_CHECK( is_empty( x) );
        BOOST_CHECK(is);
    }

    {
        DI<double> x;
        std::istringstream is("[entire]_def");
        is >> x;
        BOOST_CHECK_EQUAL( x, DI<double>(-INF_D, INF_D, DEC::def) );
        BOOST_CHECK(is);
    }

    {
        DI<double> x;
        std::istringstream is("[1,2.1]_trv");
        is >> x;
        BOOST_CHECK_EQUAL( x, DI<double>(1.0, 2.1, DEC::trv) );
        BOOST_CHECK(is);
    }

    {
        DI<double> x;
        std::istringstream is("0.000000??");
        is >> x;
        BOOST_CHECK_EQUAL( x, DI<double>(-INF_D, INF_D, DEC::dac) );
        BOOST_CHECK(is);
    }
}


#ifndef SUPERGENIUS_SCALE_TYPES_HPP
#define SUPERGENIUS_SCALE_TYPES_HPP

#include <vector>

#include <boost/multiprecision/cpp_int.hpp>
#include <outcome/outcome.hpp>

namespace sgns::scale {
  /**
   * @brief convenience alias for arrays of bytes
   */
  using ByteArray = std::vector<uint8_t>;
  /**
   * @brief represents compact integer value
   */
  using CompactInteger = boost::multiprecision::cpp_int;

  /// @brief OptionalBool is internal extended bool type
  enum class OptionalBool : uint8_t { NONE_ = 0u, FALSE_ = 1u, TRUE_ = 2u };
}  // namespace sgns::scale

namespace sgns::scale::compact {
  /**
   * @brief categories of compact encoding
   */
  struct EncodingCategoryLimits {
    // min integer encoded by 2 bytes
    constexpr static size_t kMinUint16 = (1ul << 6u);
    // min integer encoded by 4 bytes
    constexpr static size_t kMinUint32 = (1ul << 14u);
    // min integer encoded as multibyte
    constexpr static size_t kMinBigInteger = (1ul << 30u);
  };
}  // namespace sgns::scale::compact
#endif  // SUPERGENIUS_SCALE_TYPES_HPP


#define BOOST_TEST_MODULE pcraster geo utils
#include <boost/test/unit_test.hpp>
#include "com_math.h"
#include "geo_rasterboundaries.h"
#include "geo_simpleraster.h"
#include "geo_util.h"

BOOST_AUTO_TEST_CASE(raster2boundaries)
{
  using namespace geo;

  {
    // Create raster:
    // 1 2 3
    // 4 5 6
    // 7 8 9
    SimpleRaster<double> raster(3, 3);
    raster.cell(0, 0) = 1.0;
    raster.cell(0, 1) = 2.0;
    raster.cell(0, 2) = 3.0;
    raster.cell(1, 0) = 4.0;
    raster.cell(1, 1) = 5.0;
    raster.cell(1, 2) = 6.0;
    raster.cell(2, 0) = 7.0;
    raster.cell(2, 1) = 8.0;
    raster.cell(2, 2) = 9.0;

    // Create RasterBoundaries object.
    RasterBoundaries<double> boundaries(3, 3);

    // Convert to boundary values.
    raster2Boundaries(raster, boundaries);

    // Test.
    // Vertical boundaries.
    BOOST_CHECK(boundaries.leftBoundary(0, 0) == 1.0);
    BOOST_CHECK(boundaries.rightBoundary(0, 0) == 1.5);
    BOOST_CHECK(boundaries.rightBoundary(0, 1) == 2.5);
    BOOST_CHECK(boundaries.rightBoundary(0, 2) == 3.0);
    BOOST_CHECK(boundaries.leftBoundary(1, 0) == 4.0);
    BOOST_CHECK(boundaries.rightBoundary(1, 0) == 4.5);
    BOOST_CHECK(boundaries.rightBoundary(1, 1) == 5.5);
    BOOST_CHECK(boundaries.rightBoundary(1, 2) == 6.0);
    BOOST_CHECK(boundaries.leftBoundary(2, 0) == 7.0);
    BOOST_CHECK(boundaries.rightBoundary(2, 0) == 7.5);
    BOOST_CHECK(boundaries.rightBoundary(2, 1) == 8.5);
    BOOST_CHECK(boundaries.rightBoundary(2, 2) == 9.0);

    // Horizontal boundaries.
    BOOST_CHECK(boundaries.topBoundary(0, 0) == 1.0);
    BOOST_CHECK(boundaries.topBoundary(0, 1) == 2.0);
    BOOST_CHECK(boundaries.topBoundary(0, 2) == 3.0);
    BOOST_CHECK(boundaries.bottomBoundary(0, 0) == 2.5);
    BOOST_CHECK(boundaries.bottomBoundary(0, 1) == 3.5);
    BOOST_CHECK(boundaries.bottomBoundary(0, 2) == 4.5);
    BOOST_CHECK(boundaries.bottomBoundary(1, 0) == 5.5);
    BOOST_CHECK(boundaries.bottomBoundary(1, 1) == 6.5);
    BOOST_CHECK(boundaries.bottomBoundary(1, 2) == 7.5);
    BOOST_CHECK(boundaries.bottomBoundary(2, 0) == 7.0);
    BOOST_CHECK(boundaries.bottomBoundary(2, 1) == 8.0);
    BOOST_CHECK(boundaries.bottomBoundary(2, 2) == 9.0);
  }

  {
    // Create raster:
    // 1  2 3
    // 4 MV 6
    // 7  8 9
    SimpleRaster<double> raster(3, 3);
    raster.cell(0, 0) = 1.0;
    raster.cell(0, 1) = 2.0;
    raster.cell(0, 2) = 3.0;
    raster.cell(1, 0) = 4.0;
    pcr::setMV(raster.cell(1, 1));
    raster.cell(1, 2) = 6.0;
    raster.cell(2, 0) = 7.0;
    raster.cell(2, 1) = 8.0;
    raster.cell(2, 2) = 9.0;

    // Create RasterBoundaries object.
    RasterBoundaries<double> boundaries(3, 3);

    // Convert to boundary values.
    raster2Boundaries(raster, boundaries);

    // Test.
    // Vertical boundaries.
    BOOST_CHECK(boundaries.leftBoundary(0, 0) == 1.0);
    BOOST_CHECK(boundaries.rightBoundary(0, 0) == 1.5);
    BOOST_CHECK(boundaries.rightBoundary(0, 1) == 2.5);
    BOOST_CHECK(boundaries.rightBoundary(0, 2) == 3.0);

    BOOST_CHECK(boundaries.leftBoundary(1, 0) == 4.0);
    BOOST_CHECK(boundaries.rightBoundary(1, 0) == 4.0);
    BOOST_CHECK(boundaries.rightBoundary(1, 1) == 6.0);
    BOOST_CHECK(boundaries.rightBoundary(1, 2) == 6.0);
    BOOST_CHECK(boundaries.leftBoundary(2, 0) == 7.0);
    BOOST_CHECK(boundaries.rightBoundary(2, 0) == 7.5);
    BOOST_CHECK(boundaries.rightBoundary(2, 1) == 8.5);
    BOOST_CHECK(boundaries.rightBoundary(2, 2) == 9.0);

    // Horizontal boundaries.
    BOOST_CHECK(boundaries.topBoundary(0, 0) == 1.0);
    BOOST_CHECK(boundaries.topBoundary(0, 1) == 2.0);
    BOOST_CHECK(boundaries.topBoundary(0, 2) == 3.0);
    BOOST_CHECK(boundaries.bottomBoundary(0, 0) == 2.5);
    BOOST_CHECK(boundaries.bottomBoundary(0, 1) == 2.0);
    BOOST_CHECK(boundaries.bottomBoundary(0, 2) == 4.5);

    BOOST_CHECK(boundaries.bottomBoundary(1, 0) == 5.5);
    BOOST_CHECK(boundaries.bottomBoundary(1, 1) == 8.0);
    BOOST_CHECK(boundaries.bottomBoundary(1, 2) == 7.5);

    BOOST_CHECK(boundaries.bottomBoundary(2, 0) == 7.0);
    BOOST_CHECK(boundaries.bottomBoundary(2, 1) == 8.0);
    BOOST_CHECK(boundaries.bottomBoundary(2, 2) == 9.0);
  }

  {
    // Create raster:
    // MV MV MV
    // MV MV  6
    // MV MV MV
    SimpleRaster<double> raster(3, 3);
    pcr::setMV(raster.cell(0, 0));
    pcr::setMV(raster.cell(0, 1));
    pcr::setMV(raster.cell(0, 2));
    pcr::setMV(raster.cell(1, 0));
    pcr::setMV(raster.cell(1, 1));
    raster.cell(1, 2) = 6.0;
    pcr::setMV(raster.cell(2, 0));
    pcr::setMV(raster.cell(2, 1));
    pcr::setMV(raster.cell(2, 2));

    // Create RasterBoundaries object.
    RasterBoundaries<double> boundaries(3, 3);

    // Convert to boundary values.
    raster2Boundaries(raster, boundaries);

    // Test.
    // Vertical boundaries.
    BOOST_CHECK(pcr::isMV(boundaries.leftBoundary(0, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(0, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(0, 1)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(0, 2)));

    BOOST_CHECK(pcr::isMV(boundaries.leftBoundary(1, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(1, 0)));
    BOOST_CHECK(boundaries.rightBoundary(1, 1) == 6.0);
    BOOST_CHECK(boundaries.leftBoundary(1, 2) == 6.0);
    BOOST_CHECK(boundaries.rightBoundary(1, 2) == 6.0);

    BOOST_CHECK(pcr::isMV(boundaries.leftBoundary(2, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(2, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(2, 1)));
    BOOST_CHECK(pcr::isMV(boundaries.rightBoundary(2, 2)));

    // Horizontal boundaries.
    BOOST_CHECK(pcr::isMV(boundaries.topBoundary(0, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.topBoundary(0, 1)));
    BOOST_CHECK(pcr::isMV(boundaries.topBoundary(0, 2)));

    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(0, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(0, 1)));
    BOOST_CHECK(boundaries.bottomBoundary(0, 2) == 6.0);

    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(1, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(1, 1)));
    BOOST_CHECK(boundaries.topBoundary(1, 2) == 6.0);
    BOOST_CHECK(boundaries.bottomBoundary(1, 2) == 6.0);

    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(2, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(2, 1)));
    BOOST_CHECK(pcr::isMV(boundaries.bottomBoundary(2, 2)));

    BOOST_CHECK(pcr::isMV(boundaries.topBoundary(2, 0)));
    BOOST_CHECK(pcr::isMV(boundaries.topBoundary(2, 1)));
    BOOST_CHECK(boundaries.topBoundary(2, 2) == 6.0);
  }
}

BOOST_AUTO_TEST_CASE(magnitude)
{
  using namespace geo;

  RasterBoundaries<double> velocity(3, 3);

  velocity.leftBoundary(0, 0) = 1.0;
  velocity.leftBoundary(1, 0) = 3.0;
  velocity.leftBoundary(2, 0) = 4.0;
  velocity.rightBoundary(0, 0) = 3.0;
  velocity.rightBoundary(0, 1) = 4.0;
  velocity.rightBoundary(0, 2) = 1.0;
  velocity.rightBoundary(1, 0) = 4.0;
  velocity.rightBoundary(1, 1) = 1.0;
  velocity.rightBoundary(1, 2) = 3.0;
  velocity.rightBoundary(2, 0) = 1.0;
  velocity.rightBoundary(2, 1) = 3.0;
  velocity.rightBoundary(2, 2) = 4.0;

  velocity.topBoundary(0, 0) = 1.0;
  velocity.topBoundary(0, 1) = 3.0;
  velocity.topBoundary(0, 2) = 4.0;
  velocity.bottomBoundary(0, 0) = 3.0;
  velocity.bottomBoundary(0, 1) = 4.0;
  velocity.bottomBoundary(0, 2) = 1.0;
  velocity.bottomBoundary(1, 0) = 4.0;
  velocity.bottomBoundary(1, 1) = 1.0;
  velocity.bottomBoundary(1, 2) = 3.0;
  velocity.bottomBoundary(2, 0) = 1.0;
  velocity.bottomBoundary(2, 1) = 3.0;
  velocity.bottomBoundary(2, 2) = 4.0;

  RasterBoundaries<double> magnitude(3, 3);
  geo::magnitude(velocity, velocity, magnitude);

  // Vertical boundaries.
  BOOST_CHECK(com::equal_epsilon(magnitude.leftBoundary(0, 0),  std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.leftBoundary(1, 0),  std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.leftBoundary(2, 0),  std::sqrt(32.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(0, 0), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(0, 1), std::sqrt(32.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(0, 2), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(1, 0), std::sqrt(32.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(1, 1), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(1, 2), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(2, 0), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(2, 1), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.rightBoundary(2, 2), std::sqrt(32.0)));

  // Horizontal boundaries.
  BOOST_CHECK(com::equal_epsilon(magnitude.topBoundary(0, 0), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.topBoundary(0, 1), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.topBoundary(0, 2), std::sqrt(32.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(0, 0), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(0, 1), std::sqrt(32.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(0, 2), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(1, 0), std::sqrt(32.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(1, 1), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(1, 2), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(2, 0), std::sqrt( 2.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(2, 1), std::sqrt(18.0)));
  BOOST_CHECK(com::equal_epsilon(magnitude.bottomBoundary(2, 2), std::sqrt(32.0)));
}


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

    @copyright 2016 NumScale SAS

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

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{
  /*!
    @ingroup group-swar
    This function object returns a vector extracted from the concatanation
    of `x` and `y` (resp. `x` and itself when only one argument is given).

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

    @par Semantic:

    Denote by `L` the common length of `x` and `y`.
    Let `c[i] = x[i]` and `c[i + L] = y[i]`.
    If N is positive then returns `(c[N], c[N + 1], ..., c[N + L - 1])`
    If `N + L - 1 >= 2L` then returns
    `(c[N], c[N + 1], ..., C[2L - 1], 0, ..., 0)`.

    If N is negative then

    @code
    Value r = slide<N>(x, y);
    @endcode

    is equivalent to

    @code
    Value r = slide<L - N>(x, y);
    @endcode

  **/
  ///@{
  template<std::size_t N> Value slide(Value const& x, Value const& y);
  template<std::size_t N> Value slide(Value const& x);
  ///@}
} }
#endif

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

#endif


#ifndef _LDAPLUSPLUS_OPTIMIZATION_GRADIENT_DESCENT_HPP_
#define _LDAPLUSPLUS_OPTIMIZATION_GRADIENT_DESCENT_HPP_

#include <functional>
#include <memory>

#include <Eigen/Core>

namespace ldaplusplus {
namespace optimization {

/**
 * LineSearch is an interface that is meant to be used to update the parameter
 * x0 in the direction 'direction' by (probably) performing a line search for
 * the best value.
 */
template <typename ProblemType, typename ParameterType>
class LineSearch
{
    public:
        typedef typename ParameterType::Scalar Scalar;

        /**
         * Search for a good enough function value in the direction given and
         * the function given.
         *
         * This function changes its parameter x0 which is passed by reference.
         *
         * @param  problem   The function to be minimized
         * @param  x0        The improved position (passed by reference)
         * @param  grad_x0   The gradient at the initial x0
         * @param  direction The direction of search which can be different than
         *                  the gradient to account for Newton methods
         * @return The function value at the final x0
         */
        virtual Scalar search(
            const ProblemType &problem,
            Eigen::Ref<ParameterType> x0,
            const ParameterType &grad_x0,
            const ParameterType &direction
        ) = 0;

        virtual ~LineSearch(){};
};

/**
 * ConstantLineSearch simply updates the parameter by a costant factor of the
 * direction performing no line search actually.
 */
template <typename ProblemType, typename ParameterType>
class ConstantLineSearch : public LineSearch<ProblemType, ParameterType>
{
    public:
        typedef typename ParameterType::Scalar Scalar;

        /**
         * @param alpha The amount to move towards the search direction
         */
        ConstantLineSearch(Scalar alpha) : alpha_(alpha) {}

        Scalar search(
            const ProblemType &problem,
            Eigen::Ref<ParameterType> x0,
            const ParameterType &grad_x0,
            const ParameterType &direction
        ) {
            x0 -= alpha_ * direction;

            return problem.value(x0);
        }

    private:
        Scalar alpha_;
};

/**
 * Armijo line search is a simple backtracking line search where the Armijo
 * condition is required.
 *
 * The Armijo condition is the following if \f$p_k\f$ is the negative direction and
 * \f$g_k\f$ the gradient. In Armijo line search we search the largest \f$a_k
 * \in \{\tau^n \mid n \in \{0\} \cup \mathbb{N}\}\f$ for which the Armijo
 * condition stands.
 *
 *  \f[
 *      f(x_k - a_k p_k) \leq f(x_k) - a_k b g_k^T p_k
 *  \f]
 *
 *  \f$f(x_k) - a_k b g_k^T p_k\f$ is a linear approximation of the function at
 *  \f$x_k\f$ (scaled by \f$b\f$) that we assume to be the upper bound for the
 *  decrease.
 *
 *  In all the above \f$p_k\f$ is assumed to be of **unit length**.
 *
 *  See [Wolfe Conditions](https://en.wikipedia.org/wiki/Wolfe_conditions).
 */
template <typename ProblemType, typename ParameterType>
class ArmijoLineSearch : public LineSearch<ProblemType, ParameterType>
{
    public:
        typedef typename ParameterType::Scalar Scalar;

        /**
         * @param beta The amount of scaling to do the linear decrease
         * @param tau  Defines the set of \f$a_k\f$ to try in the line search
         */
        ArmijoLineSearch(Scalar beta=0.001, Scalar tau=0.5) : beta_(beta),
                                                              tau_(tau)
        {}

        Scalar search(
            const ProblemType &problem,
            Eigen::Ref<ParameterType> x0,
            const ParameterType &grad_x0,
            const ParameterType &direction
        ) {
            ParameterType x_copy(x0.rows(), x0.cols());
            Scalar value_x0 = problem.value(x0);
            Scalar decrease = beta_ * (grad_x0.array() * direction.array()).sum();
            Scalar value = value_x0;
            Scalar a = 1.0/tau_;

            while (value > value_x0 - a * decrease) {
                a *= tau_;
                x_copy = x0 - a * direction;
                value = problem.value(x_copy);
            }

            x0 -= a * direction;

            return value;
        }

    private:
        Scalar beta_;
        Scalar tau_;
};

/**
 * A very simple implementation of batch gradient descent.
 *
 * Given a problem, a line search and a starting point it performs the
 * following simple iteration.
 *
 * 1. Repeat the following until convergence
 * 2. Compute the gradient
 * 3. Search in the direction of the gradient for sufficient decrease
 *
 * Convergence is decided by another part of the program through injection of a
 * callback.
 *
 * TODO: Maybe bind the problem type through an interface
 */
template <typename ProblemType, typename ParameterType>
class GradientDescent
{
    public:
        typedef typename ParameterType::Scalar Scalar;

        /**
         * @param line_search A line search method
         * @param progress    A callback that decides when the optimization has
         *                    ended; it can also be used to get informed about
         *                    the progress of the optimization
         */
        GradientDescent(
            std::shared_ptr<LineSearch<ProblemType, ParameterType> > line_search,
            std::function<bool(Scalar, Scalar, size_t)> progress
        ) : line_search_(line_search),
            progress_(progress)
        {}

        /**
         * Minimize the function defined in the 'problem' argument.
         *
         * The 'problem' argument should implement the functions value() and
         * gradient() in order to be used with the GradientDescent class.
         *
         * @param problem The function being minimized
         * @param x0      The initial position during our minimization (it will
         *                be overwritten with the optimal position)
         */
        void minimize(const ProblemType &problem, Eigen::Ref<ParameterType> x0) {
            // allocate memory for the gradient
            ParameterType grad(x0.rows(), x0.cols());

            // Keep the value in this variable
            Scalar value = problem.value(x0);

            // And the iterations in this one
            size_t iterations = 0;

            // Whether we stop or not is decided by someone else
            while (progress_(value, grad.template lpNorm<Eigen::Infinity>(), iterations++)) {
                problem.gradient(x0, grad);
                value = line_search_->search(problem, x0, grad, grad);
            }
        }

    private:
        std::shared_ptr<LineSearch<ProblemType, ParameterType> > line_search_;
        std::function<bool(Scalar, Scalar, size_t)> progress_;
};

}  // namespace optimization
}  // namespace ldaplusplus

#endif // _LDAPLUSPLUS_OPTIMIZATION_GRADIENT_DESCENT_HPP_


/*
 * Copyright (c) 2013, Christian Gehring, Hannes Sommer, Paul Furgale, Remo Diethelm
 * 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 Autonomous Systems Lab, ETH Zurich 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 Christian Gehring, Hannes Sommer, Paul Furgale,
 * Remo Diethelm 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.
 *
*/

#pragma once

#include <Eigen/Core>

#include "kindr/math/LinearAlgebra.hpp"
#include "kindr/common/common.hpp"
#include "kindr/common/assert_macros.hpp"
#include "kindr/common/assert_macros_eigen.hpp"
#include "kindr/rotations/RotationDiffBase.hpp"
#include "kindr/rotations/Rotation.hpp"

namespace kindr {

/*! \class EulerAnglesZyxDiff
 * \brief Implementation of time derivatives of Euler angles (Z,Y',X'' / yaw,pitch,roll) based on Eigen::Matrix<Scalar, 3, 1>
 *
 * The following two typedefs are provided for convenience:
 *   - EulerAnglesZyxDiffAD for primitive type double
 *   - EulerAnglesZyxDoffAF for primitive type float
 * \tparam PrimType_ the primitive type of the data (double or float)
 * \ingroup rotations
 */
template<typename PrimType_>
class EulerAnglesZyxDiff : public RotationDiffBase<EulerAnglesZyxDiff<PrimType_>> {
 private:
  /*! \brief The base type.
   */
  typedef Eigen::Matrix<PrimType_, 3, 1> Base;

  /*! \brief data container [yaw; pitch; roll]
   */
  Base zyxDiff_;

 public:
  /*! \brief The implementation type.
   *  The implementation type is always an Eigen object.
   */
  typedef Base Implementation;

  /*! \brief The primitive type.
   *  Float/Double
   */
  typedef PrimType_ Scalar;

  /*! \brief Default constructor.
   */
  EulerAnglesZyxDiff()
    : zyxDiff_(Base::Zero()) {
  }

  /*! \brief Constructor using three scalars.
   *  \param yaw      time derivative of first rotation angle around Z axis
   *  \param pitch    time derivative of second rotation angle around Y' axis
   *  \param roll     time derivative of third rotation angle around X'' axis
   */
  EulerAnglesZyxDiff(Scalar yaw, Scalar pitch, Scalar roll)
    : zyxDiff_(yaw,pitch,roll) {
  }

  /*! \brief Constructor using a time derivative with a different parameterization
   *
   * \param rotation  rotation
   * \param other     other time derivative
   */
  template<typename RotationDerived_, typename OtherDerived_>
  inline explicit EulerAnglesZyxDiff(const RotationBase<RotationDerived_>& rotation, const RotationDiffBase<OtherDerived_>& other)
    : zyxDiff_(internal::RotationDiffConversionTraits<EulerAnglesZyxDiff, OtherDerived_, RotationDerived_>::convert(rotation.derived(), other.derived()).toImplementation()){
  }

  /*! \brief Cast to another representation of the time derivative of a rotation
   *  \param other   other rotation
   *  \returns reference
   */
  template<typename OtherDerived_, typename RotationDerived_>
  OtherDerived_ cast(const RotationBase<RotationDerived_>& rotation) const {
    return internal::RotationDiffConversionTraits<OtherDerived_, EulerAnglesZyxDiff, RotationDerived_>::convert(rotation.derived(), *this);
  }

  /*! \brief Constructor using Eigen::Matrix.
   *  \param other   Eigen::Matrix<Scalar, 3, 1> [yaw; pitch; roll]
   */
  explicit EulerAnglesZyxDiff(const Base& other)
    : zyxDiff_(other) {
  }

  /*! \brief Cast to the implementation type.
   *  \returns the implementation for direct manipulation (recommended only for advanced users)
   */
  inline Base& toImplementation() {
    return static_cast<Base&>(zyxDiff_);
  }

  /*! \brief Cast to the implementation type.
   *  \returns the implementation for direct manipulation (recommended only for advanced users)
   */
  inline const Base& toImplementation() const {
    return static_cast<const Base&>(zyxDiff_);
  }

  inline Base& vector() {
    return toImplementation();
  }

  inline const Base& vector() const {
    return toImplementation();
  }

  /*! \brief Reading access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with reading access
    */
   inline Scalar yaw() const {
     return toImplementation()(0);
   }

   /*! \brief Reading access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with reading access
    */
   inline Scalar pitch() const {
     return toImplementation()(1);
   }

   /*! \brief Reading access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with reading access
    */
   inline Scalar roll() const {
     return toImplementation()(2);
   }

   /*! \brief Writing access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with writing access
    */
   inline Scalar& yaw() {
     return toImplementation()(0);
   }

   /*! \brief Writing access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with writing access
    */
   inline Scalar& pitch() {
     return toImplementation()(1);
   }

   /*! \brief Writing access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with writing access
    */
   inline Scalar& roll() {
     return toImplementation()(2);
   }

   /*! \brief Reading access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with reading access
    */
   inline Scalar z() const {
     return toImplementation()(0);
   }

   /*! \brief Reading access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with reading access
    */
   inline Scalar y() const {
     return toImplementation()(1);
   }

   /*! \brief Reading access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with reading access
    */
   inline Scalar x() const {
     return toImplementation()(2);
   }

   /*! \brief Writing access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with writing access
    */
   inline Scalar& z() {
     return toImplementation()(0);
   }

   /*! \brief Writing access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with writing access
    */
   inline Scalar& y() {
     return toImplementation()(1);
   }

   /*! \brief Writing access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with writing access
    */
   inline Scalar& x() {
     return toImplementation()(2);
   }

   /*! \brief Sets all time derivatives to zero.
    *  \returns reference
    */
   EulerAnglesZyxDiff& setZero() {
     this->toImplementation().setZero();
     return *this;
   }

   /*! \brief Get zero element.
    *  \returns zero element
    */
   static EulerAnglesZyxDiff Zero() {
     return EulerAnglesZyxDiff(Base::Zero());
   }

   /*! \brief Addition of two angular velocities.
    */
   using RotationDiffBase<EulerAnglesZyxDiff<PrimType_>>::operator+; // otherwise ambiguous EulerAnglesDiffBase and Eigen

   /*! \brief Subtraction of two angular velocities.
    */
   using RotationDiffBase<EulerAnglesZyxDiff<PrimType_>>::operator-; // otherwise ambiguous EulerAnglesDiffBase and Eigen

   /*! \brief Used for printing the object with std::cout.
    *
    *   Prints: yaw pitch roll
    *  \returns std::stream object
    */
   friend std::ostream& operator << (std::ostream& out, const EulerAnglesZyxDiff& diff) {
     out << diff.toImplementation().transpose();
     return out;
   }
};

//! \brief Time derivative of Euler angles with z-y-x convention and primitive type double
typedef EulerAnglesZyxDiff<double> EulerAnglesZyxDiffPD;
//! \brief Time derivative of Euler angles with z-y-x convention and primitive type float
typedef EulerAnglesZyxDiff<float> EulerAnglesZyxDiffPF;
//! \brief Time derivative of Euler angles with z-y-x convention and primitive type double
typedef EulerAnglesZyxDiff<double> EulerAnglesZyxDiffD;
//! \brief Time derivative of Euler angles with z-y-x convention and primitive type float
typedef EulerAnglesZyxDiff<float> EulerAnglesZyxDiffF;

namespace internal {

template<typename PrimType_>
class RotationDiffConversionTraits<EulerAnglesZyxDiff<PrimType_>, LocalAngularVelocity<PrimType_>, EulerAnglesZyx<PrimType_>> {
 public:
  inline static EulerAnglesZyxDiff<PrimType_> convert(const EulerAnglesZyx<PrimType_>& eulerAngles, const LocalAngularVelocity<PrimType_>& angularVelocity) {
    return EulerAnglesZyxDiff<PrimType_>(eulerAngles.getMappingFromLocalAngularVelocityToDiff()*angularVelocity.vector());
  }
};

} // namespace internal
} // namespace kindr


//=======================================================================
// Copyright (c)
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
/**
 * @file dreyfus_wagner_test.cpp
 * @brief
 * @author Maciej Andrejczuk, Piotr Wygocki
 * @version 1.0
 * @date 2013-08-04
 */

#include "test_utils/sample_graph.hpp"

#include "paal/steiner_tree/dreyfus_wagner.hpp"

#include <boost/test/unit_test.hpp>

#include <cmath>

using namespace paal;

BOOST_AUTO_TEST_SUITE(dreyfus_wagner)

BOOST_AUTO_TEST_CASE(test_basic) {
    typedef sample_graphs_metrics SGM;
    auto gm = SGM::get_graph_metric_steiner();
    std::vector<int> terminals = { SGM::A, SGM::B, SGM::C, SGM::D };
    std::vector<int> nonterminals = { SGM::E };
    auto dw = make_dreyfus_wagner(gm, terminals, nonterminals);
    dw.solve();
    BOOST_CHECK_EQUAL(dw.get_cost(), 4);
    BOOST_CHECK_EQUAL(dw.get_steiner_elements().size(), 1u);
    BOOST_CHECK_EQUAL(dw.get_edges().size(), 4u);
}

BOOST_AUTO_TEST_CASE(test_medium) {
    typedef sample_graphs_metrics SGM;
    auto gm = SGM::get_graph_metric_medium();
    std::vector<int> terminals = { SGM::A, SGM::B, SGM::C,
                                   SGM::F, SGM::G, SGM::H };
    std::vector<int> nonterminals = { SGM::D, SGM::E };
    auto dw = make_dreyfus_wagner(gm, terminals, nonterminals);
    dw.solve();
    BOOST_CHECK_EQUAL(dw.get_cost(), 15);
    BOOST_CHECK_EQUAL(dw.get_steiner_elements().size(), 0u);
    BOOST_CHECK_EQUAL(dw.get_edges().size(), 5u);
}

BOOST_AUTO_TEST_CASE(dreyfus_wagner_euclidean_metric_test) {
    using Points = std::vector<std::pair<int, int>>;

    data_structures::euclidean_metric<int> em;
    Points terminals, nonterminals;
    std::tie(em, terminals, nonterminals) =
        sample_graphs_metrics::get_euclidean_steiner_sample();

    auto dw = make_dreyfus_wagner(em, terminals, nonterminals);
    dw.solve();

    BOOST_CHECK_EQUAL(dw.get_steiner_elements().size(), std::size_t(1));
    BOOST_CHECK(*dw.get_steiner_elements().begin() == std::make_pair(1, 1));
    BOOST_CHECK_CLOSE(dw.get_cost(), 4 * std::sqrt(2), 1e-6);
}

BOOST_AUTO_TEST_SUITE_END()


#include "catch.hpp"

#undef NDEBUG

#include <boost/numeric/ublas/io.hpp>
#include "IntaRNA/AccessibilityBasePair.h"

using namespace IntaRNA;

TEST_CASE("AccessibilityBasePair", "[AccessibilityBasePair]") {

	// setup easylogging++ stuff if not already done
	#include "testEasyLoggingSetup.icc"

  SECTION("ED test long") {

	const std::string seq = "gguccacguccaa";
	RnaSequence rna("test", seq);
	AccessibilityBasePair acc(rna, 10, NULL);

//    std::cout <<"\n\n########\n";
//    for (int i =0; i<acc.getSequence().size(); i++) {
//    	std::cout <<(i);
//    	for (int j=0; j <acc.getSequence().size(); j++) {
//    		if (j<i) {
//    			std::cout <<" ---";
//    		} else {
//    			std::cout <<" "<<acc.getED(i,j);
//    		}
//    	}
//    	std::cout <<std::endl;
//    }
//    std::cout <<"########\n";

    REQUIRE( E_equal( acc.getED(0, 6), 452 ) );
    REQUIRE( E_equal( acc.getED(0, 12), 584 ) );
    REQUIRE( E_equal( acc.getED(1, 3), 237 ) );
    REQUIRE( E_equal( acc.getED(1, 5), 275 ) );
    REQUIRE( E_equal( acc.getED(3, 4), 51 ) );
    REQUIRE( E_equal( acc.getED(4, 7), 197 ) );
    REQUIRE( E_equal( acc.getED(4, 12), 584 ) );
    REQUIRE( E_equal( acc.getED(5, 5), 0) );
    REQUIRE( E_equal( acc.getED(5, 10), 362 ) );
    REQUIRE( E_equal( acc.getED(6, 6), 13 ) );
    REQUIRE( E_equal( acc.getED(10, 11), 55 ) );
    REQUIRE( E_equal( acc.getED(11, 12), 19 ) );

  }

  SECTION("ED test short") {

	const std::string seq = "GG";
	RnaSequence rna("test", seq);
	AccessibilityBasePair acc(rna, 2, NULL);

	REQUIRE( E_equal( acc.getED(0, 0), 0 ) );
	REQUIRE( E_equal( acc.getED(1, 1), 0 ) );
	REQUIRE( E_equal( acc.getED(0, 1), 0 ) );

  }
}


/*
 *  connectivity_functions.hpp
 *
 *
 *  Created by Andrea Bedini on 24/Nov/2011.
 *  Copyright (c) 2011-2014, Andrea Bedini <andrea.bedini@gmail.com>.
 *
 *  Distributed under the terms of the Modified BSD License.
 *  The full license is in the file COPYING, distributed as part of
 *  this software.
 *
 */

#ifndef CONNECTIVITY_FUNCTIONS_HPP
#define CONNECTIVITY_FUNCTIONS_HPP

#include <boost/cstdint.hpp>

#include <algorithm>
#include <cstddef>

namespace connectivity_functions {
  using boost::uint8_t;

  void connect(unsigned int n, uint8_t* a, unsigned int i, unsigned int j)
  {
    uint8_t li = a[i], lj = a[j];
    std::replace(a, a + n, lj, li);
  }

  void detach(unsigned int n, uint8_t* a, unsigned int i)
  {
    a[i] = n + 1;
  }

  bool connected(const uint8_t* a, unsigned int i, unsigned int j)
  {
    return a[i] == a[j];
  }

  bool is_singleton(unsigned int n, const uint8_t* a, unsigned int i)
  {
    return std::count(a, a + n, a[i]) == 1;
  }

  void canonicalize(unsigned int n, uint8_t* a)
  {
    const unsigned int max = 50;
    uint8_t table[max];
    std::fill(table, table + max, 0);

    unsigned int k = 1;
    for (unsigned int i = 0; i < n; ++i) {
      if (table[a[i]])
	a[i] = table[a[i]];
      else {
	table[a[i]] = k;
	a[i] = k;
	++ k;
      }
    }
  }

  template<class F>
  void decompose(unsigned int n, const uint8_t* a, F f)
  {
    const unsigned int max = 50;
    int table[max];
    std::fill(table, table + max, -1);

    unsigned int j = 0;
    for (unsigned int i = 0; i < n; ++i) {
      if (table[a[i]] != -1)
	f(table[a[i]], j);
      table[a[i]] = j;
      j ++;
    }
  }
}

#endif


/*
 * Copyright 2020 IFPEN-CEA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <boost/lexical_cast.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/variables_map.hpp>

#include <arccore/message_passing_mpi/StandaloneMpiMessagePassingMng.h>
#include <arccore/base/StringBuilder.h>

#include <alien/kernels/simple_csr/algebra/SimpleCSRLinearAlgebra.h>

#include <alien/kernels/sycl/SYCLPrecomp.h>
#include <alien/kernels/sycl/data/SYCLBEllPackMatrix.h>
#include <alien/kernels/sycl/data/SYCLVector.h>
#include <alien/kernels/sycl/algebra/SYCLLinearAlgebra.h>
#include <alien/kernels/sycl/algebra/SYCLInternalLinearAlgebra.h>

#include "alien/kernels/sycl/data/SYCLEnv.h"
#include "alien/kernels/sycl/data/SYCLEnvInternal.h"
#include <alien/kernels/sycl/algebra/SYCLKernelInternal.h>

#include <alien/ref/AlienRefSemantic.h>

#include <alien/utils/StdTimer.h>

int main(int argc, char** argv)
{

  using namespace boost::program_options;
  options_description desc;
  // clang-format off
  desc.add_options()
      ("help", "produce help")
      ("size",    value<int>()->default_value(16),            "size")
      ("nb-test", value<int>()->default_value(1),             "nb tests")
      ("test",    value<std::string>()->default_value("all"), "test")
      ("dot-algo", value<int>()->default_value(0),            "dot algo choice") ;
  // clang-format on

  variables_map vm;
  store(parse_command_line(argc, argv, desc), vm);
  notify(vm);

  if (vm.count("help")) {
    std::cout << desc << "\n";
    return 1;
  }

  MPI_Init(&argc, &argv);
  auto* pm = Arccore::MessagePassing::Mpi::StandaloneMpiMessagePassingMng::create(MPI_COMM_WORLD);
  bool is_parallel = pm->commSize() > 1;

  auto* trace_mng = Arccore::arccoreCreateDefaultTraceMng();
  Alien::Integer my_rank = pm->commRank();
  Arccore::StringBuilder filename("sycl.log");
  Arccore::ReferenceCounter<Arccore::ITraceStream> ofile;
  if (pm->commSize() > 1) {
    filename += pm->commRank();
    ofile = Arccore::ITraceStream::createFileStream(filename.toString());
    trace_mng->setRedirectStream(ofile.get());
  }
  trace_mng->finishInitialize();

  Alien::setTraceMng(trace_mng);
  Alien::setVerbosityLevel(Alien::Verbosity::Debug);

  trace_mng->info() << "INFO START SYCL TEST";

  // clang-format off
  typedef Alien::StdTimer   TimerType;
  typedef TimerType::Sentry SentryType;
  // clang-format on

  TimerType timer;

  using namespace Alien;
  //Alien::ITraceMng* trace_mng = AlienTest::Environment::traceMng();

  // clang-format off
  std::string test    = vm["test"].as<std::string>() ;
  int nb_test         = vm["nb-test"].as<int>() ;
  Integer global_size = vm["size"].as<int>() ;
  // clang-format on

  const Alien::Space s(global_size, "MySpace");
  Alien::MatrixDistribution mdist(s, s, pm);
  Alien::VectorDistribution vdist(s, pm);
  Alien::Matrix A(mdist); // A.setName("A") ;
  Alien::Vector x(vdist); // x.setName("x") ;
  Alien::Vector y(vdist); // y.setName("y") ;
  Alien::Vector r(vdist); // r.setName("r") ;
  //Alien::Real lambda = 0.5;

  auto local_size = vdist.localSize();
  auto offset = vdist.offset();
  {
    Alien::MatrixProfiler profiler(A);
    for (Integer i = 0; i < local_size; ++i) {
      Integer row = offset + i;
      profiler.addMatrixEntry(row, row);
      if (row + 1 < global_size)
        profiler.addMatrixEntry(row, row + 1);
      if (row - 1 >= 0)
        profiler.addMatrixEntry(row, row - 1);
    }
  }
  {
    Alien::ProfiledMatrixBuilder builder(A, Alien::ProfiledMatrixOptions::eResetValues);
    for (Integer i = 0; i < local_size; ++i) {
      Integer row = offset + i;
      builder(row, row) = 2.;
      if (row + 1 < global_size)
        builder(row, row + 1) = -1.;
      if (row - 1 >= 0)
        builder(row, row - 1) = -1.;
    }
  }
  {
    Alien::LocalVectorWriter writer(x);
    for (Integer i = 0; i < local_size; ++i)
      writer[i] = 1.;
  }
  {
    Alien::LocalVectorWriter writer(y);
    for (Integer i = 0; i < local_size; ++i)
      writer[i] = offset + i;
  }

  {
    Alien::LocalVectorWriter writer(r);
    for (Integer i = 0; i < local_size; ++i)
      writer[i] = 0.;
  }

  Alien::SimpleCSRLinearAlgebra csr_alg;
  Alien::SYCLLinearAlgebra sycl_alg;

  if ((test.compare("all") == 0) || (test.compare("copy") == 0)) {
    trace_mng->info() << "TEST COPY : r = y";
    {
      // clang-format off
      auto const& csr_y = y.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      auto&       csr_r = r.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      // clang-format on
      for (int i = 0; i < nb_test; ++i) {
        SentryType s(timer, "CSR-COPY");
        csr_alg.copy(y, r);
      }
    }
    {
      // clang-format off
      auto const& sycl_y = y.impl()->get<Alien::BackEnd::tag::sycl>() ;
      auto&       sycl_r = r.impl()->get<Alien::BackEnd::tag::sycl>() ;
      // clang-format on
      for (int i = 0; i < nb_test; ++i) {
        SentryType s(timer, "SYLC-COPY");
        sycl_alg.copy(y, r);
      }
    }
    {
      Alien::LocalVectorReader reader(r);
      for (Integer i = 0; i < std::min(10, local_size); ++i) {
        trace_mng->info() << "R[" << i << "]=" << reader[i];
      }
    }
  }

  if ((test.compare("all") == 0) || (test.compare("axpy") == 0)) {
    trace_mng->info() << "TEST AXPY : y += a*x ";
    {
      // clang-format off
      auto const& csr_x = x.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      auto&       csr_y = y.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      // clang-format on
      for (int i = 0; i < nb_test; ++i) {
        SentryType s(timer, "CSR-AXPY");
        csr_alg.axpy(1., x, y);
      }
    }
    {
      // clang-format off
      auto const& sycl_x = x.impl()->get<Alien::BackEnd::tag::sycl>() ;
      auto&       sycl_y = y.impl()->get<Alien::BackEnd::tag::sycl>() ;
      // clang-format on
      for (int i = 0; i < nb_test; ++i) {
        SentryType s(timer, "SYCL-AXPY");
        sycl_alg.axpy(1., x, y);
      }
    }

    {
      Alien::LocalVectorReader reader(y);
      for (Integer i = 0; i < std::min(10, local_size); ++i) {
        trace_mng->info() << "Y[" << i << "]=" << reader[i];
      }
    }
  }

  if ((test.compare("all") == 0) || (test.compare("dot") == 0)) {
    trace_mng->info() << "TEST DOT : dot(x,y) ";
    Real x_dot_y_ref = 0.;
    {
      Alien::LocalVectorReader reader_x(x);
      Alien::LocalVectorReader reader_y(y);
      for (Integer i = 0; i < local_size; ++i)
        x_dot_y_ref += reader_x[i] * reader_y[i];
      if (is_parallel)
        x_dot_y_ref = Arccore::MessagePassing::mpAllReduce(pm,
                                                           Arccore::MessagePassing::ReduceSum,
                                                           x_dot_y_ref);
    }
    Real x_dot_y = 0.;
    Real x_dot_y2 = 0.;
    Alien::SYCLInternalLinearAlgebra::FutureType f_x_dot_y(x_dot_y2);

    {
      auto const& csr_x = x.impl()->get<Alien::BackEnd::tag::simplecsr>();
      auto const& csr_y = y.impl()->get<Alien::BackEnd::tag::simplecsr>();

      for (int itest = 0; itest < nb_test; ++itest) {
        //std::cout<<itest<<"*";
        SentryType s(timer, "CSR-DOT");
        x_dot_y = csr_alg.dot(x, y);
      }
      //std::cout<<std::endl ;
    }
    {
      int dot_algo = vm["dot-algo"].as<int>();
      Alien::SYCLInternalLinearAlgebra internal_sycl_alg;
      internal_sycl_alg.setDotAlgo(dot_algo);
      auto const& sycl_x = x.impl()->get<Alien::BackEnd::tag::sycl>();
      auto const& sycl_y = y.impl()->get<Alien::BackEnd::tag::sycl>();

      for (int itest = 0; itest < nb_test; ++itest) {
        //std::cout<<itest<<"*";
        SentryType s(timer, "SYLC-DOT");
        x_dot_y = internal_sycl_alg.dot(sycl_x, sycl_y);
      }
      for (int itest = 0; itest < nb_test; ++itest) {
        //std::cout<<itest<<"*";
        SentryType s(timer, "SYLC-DOT-F");
        internal_sycl_alg.dot(sycl_x, sycl_y, f_x_dot_y);
      }

      //std::cout<<std::endl ;
    }
    trace_mng->info() << "SYCL DOT(X,Y) = " << x_dot_y << ", F-DOT = " << f_x_dot_y.get() << ", REF=" << x_dot_y_ref;
  }

  if ((test.compare("all") == 0) || (test.compare("mult") == 0)) {
    trace_mng->info() << "TEST SPMV : y = A*x ";
    {
      // clang-format off
      auto const& csr_A = A.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      auto const& csr_x = x.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      auto&       csr_y = y.impl()->get<Alien::BackEnd::tag::simplecsr>() ;
      // clang-format on
      for (int i = 0; i < nb_test; ++i) {
        SentryType s(timer, "CSR-SPMV");
        csr_alg.mult(A, x, y);
      }
    }
    {
      Alien::LocalVectorReader reader(y);
      for (Integer i = 0; i < std::min(10, local_size); ++i) {
        trace_mng->info() << my_rank << " CSR Y[" << i << "]=" << reader[i];
      }
    }
    {
      // clang-format off
      auto const& sycl_A = A.impl()->get<Alien::BackEnd::tag::sycl>() ;
      auto const& sycl_x = x.impl()->get<Alien::BackEnd::tag::sycl>() ;
      auto&       sycl_y = y.impl()->get<Alien::BackEnd::tag::sycl>() ;
      // clang-format on
      for (int i = 0; i < nb_test; ++i) {
        SentryType s(timer, "SYLC-SPMV");
        sycl_alg.mult(A, x, y);
      }
    }
    {
      Alien::LocalVectorReader reader(y);
      for (Integer i = 0; i < std::min(10, local_size); ++i) {
        trace_mng->info() << my_rank << " SYCL Y[" << i << "]=" << reader[i];
      }
    }
  }

  timer.printInfo(trace_mng->info().file(), "SYCL-BENCH");

  trace_mng->info() << "INFO FINALIZE SYCL TEST";

  MPI_Finalize();

  return 0;
}


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <boost/simd/boolean/include/functions/if_one_else_zero.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>

#include <boost/simd/include/constants/one.hpp>
#include <boost/simd/include/constants/inf.hpp>
#include <boost/simd/include/constants/zero.hpp>
#include <boost/simd/include/constants/minf.hpp>
#include <boost/simd/include/constants/mone.hpp>
#include <boost/simd/include/constants/nan.hpp>
#include <boost/simd/include/constants/half.hpp>
#include <boost/simd/include/constants/two.hpp>
#include <boost/simd/include/constants/quarter.hpp>

NT2_TEST_CASE_TPL ( if_one_else_zero_real,  BOOST_SIMD_REAL_TYPES)
{

  using boost::simd::if_one_else_zero;
  using boost::simd::tag::if_one_else_zero_;
  using boost::simd::logical;
  typedef typename boost::dispatch::meta::call<if_one_else_zero_(T)>::type r_t;
  typedef typename boost::common_type<T>::type wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( r_t, wished_r_t );

  // specific values tests
  NT2_TEST_EQUAL(if_one_else_zero(T(0)), 0);
  NT2_TEST_EQUAL(if_one_else_zero(T(1)), 1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Inf<T>()) , 1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Minf<T>()),1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Nan<T>()) , 1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Zero<T>()),0);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::True< boost::simd::logical<T> >()), 1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::False< boost::simd::logical<T> >()), 0);
} // end of test for floating_

NT2_TEST_CASE_TPL ( if_one_else_zero_signed_int,  BOOST_SIMD_INTEGRAL_SIGNED_TYPES)
{

  using boost::simd::if_one_else_zero;
  using boost::simd::tag::if_one_else_zero_;
  using boost::simd::logical;
  typedef typename boost::dispatch::meta::call<if_one_else_zero_(T)>::type r_t;
  typedef typename boost::common_type<T>::type wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( r_t, wished_r_t );

  // specific values tests
  NT2_TEST_EQUAL(if_one_else_zero(T(0)), 0);
  NT2_TEST_EQUAL(if_one_else_zero(T(1)), 1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::True< boost::simd::logical<T> >()), 1);
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::False< boost::simd::logical<T> >()), 0);
} // end of test for signed_int_

NT2_TEST_CASE_TPL ( if_one_else_zero_real__1_0,  BOOST_SIMD_REAL_TYPES)
{

  using boost::simd::if_one_else_zero;
  using boost::simd::tag::if_one_else_zero_;
  typedef typename boost::dispatch::meta::call<if_one_else_zero_(T)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( r_t, wished_r_t );

  // specific values tests
  NT2_TEST_EQUAL(if_one_else_zero(-boost::simd::Zero<T>()), r_t(false));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Half<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Inf<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Minf<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Mone<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Nan<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::One<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Quarter<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Two<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Zero<T>()), r_t(false));
} // end of test for floating_

NT2_TEST_CASE_TPL ( if_one_else_zero_signed_int__1_0,  BOOST_SIMD_INTEGRAL_SIGNED_TYPES)
{

  using boost::simd::if_one_else_zero;
  using boost::simd::tag::if_one_else_zero_;
  typedef typename boost::dispatch::meta::call<if_one_else_zero_(T)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( r_t, wished_r_t );

  // specific values tests
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Mone<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::One<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Two<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Zero<T>()), r_t(false));
} // end of test for signed_int_

NT2_TEST_CASE_TPL ( if_one_else_zero_unsigned_int__1_0,  BOOST_SIMD_UNSIGNED_TYPES)
{

  using boost::simd::if_one_else_zero;
  using boost::simd::tag::if_one_else_zero_;
  typedef typename boost::dispatch::meta::call<if_one_else_zero_(T)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( r_t, wished_r_t );

  // specific values tests
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::One<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Two<T>()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::Zero<T>()), r_t(false));
} // end of test for unsigned_int_

NT2_TEST_CASE_TPL ( if_one_else_zerol,  BOOST_SIMD_SIMD_TYPES)
{

  using boost::simd::if_one_else_zero;
  using boost::simd::tag::if_one_else_zero_;
  typedef typename boost::dispatch::meta::call<if_one_else_zero_(T)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( r_t, wished_r_t );

  // specific values tests
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::True< boost::simd::logical<T> >()), r_t(true));
  NT2_TEST_EQUAL(if_one_else_zero(boost::simd::False< boost::simd::logical<T> >()), r_t(false));
} // end of test for unsigned_int_


// Copyright Louis Dionne 2013-2017
// Copyright Jason Rice 2017
// 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 TEST_SUPPORT_COUNTER_HPP
#define TEST_SUPPORT_COUNTER_HPP

#include <boost/hana/fwd/at.hpp>
#include <boost/hana/fwd/concept/iterable.hpp>
#include <boost/hana/fwd/drop_front.hpp>
#include <boost/hana/fwd/is_empty.hpp>
#include <boost/hana/integral_constant.hpp>

// Counter - an infinite iterable for the masses

struct Counter_tag { };

template <std::size_t N = 0>
struct Counter {
    using hana_tag = Counter_tag;
    static constexpr std::size_t value = N;
};

namespace boost { namespace hana {
    //////////////////////////////////////////////////////////////////////////
    // Iterable
    //////////////////////////////////////////////////////////////////////////
    template <>
    struct at_impl<Counter_tag> {
        template <typename T, typename N>
        static constexpr decltype(auto) apply(T, N) {
            return hana::size_c<T::value + N::value>;
        }
    };

    template <>
    struct drop_front_impl<Counter_tag> {
        template <typename T, typename N>
        static constexpr auto apply(T, N) {
            return Counter<T::value + N::value>{};
        }
    };

    template <>
    struct is_empty_impl<Counter_tag> {
        template <typename Xs>
        static constexpr auto apply(Xs)
            -> hana::false_
        { return {}; }
    };
}} // end namespace boost::hana

#endif // !TEST_SUPPORT_COUNTER_HPP


// (C) Copyright David James Pearce 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
//
// Email: david.pearce@mcs.vuw.ac.nz
//
// Notes
// =====
// This is basically a very simplistic approach
// to topological ordering the graph. It uses
// the standard (exhaustive) topological sort
// function.

#ifndef SIMPLE_TOPOLOGICAL_ORDER_HPP
#define SIMPLE_TOPOLOGICAL_ORDER_HPP

#include <stdexcept>
#include <boost/property_map.hpp>
#include <boost/graph/topological_sort.hpp>
#include "oto_tags.hpp"

#ifdef SOTO_GENERATE_STATS
extern unsigned int algo_count;
#endif

template<class T, class N2I>
class simple_topological_order;

template<class T, class N2I>
void sto_dfs_visit(unsigned int n, unsigned int &count,
		   typename boost::property_map<T, N2I>::type &n2i,
		   simple_topological_order<T,N2I> &g) {
  // some useful typedefs

#ifdef SOTO_GENERATE_STATS
  ++algo_count;
#endif

  typedef typename T::out_edge_iterator out_iterator;

  // could undoubtedly optimise this get away. It
  // might be expensive for all I know ...

  g._visited[n]=true;

  out_iterator i,iend;
  for(tie(i,iend) = out_edges(n,g); i!=iend;++i) {

#ifdef SOTO_GENERATE_STATS
    ++algo_count;
#endif

    unsigned int w(target(*i,g));
    if(!g._visited[w]) {
      sto_dfs_visit(w,count,n2i,g);
    }
  }

  n2i[n] = --count;
}

template<class InputIter, class T, class N2I>
void add_edges(InputIter b, InputIter e,
	       simple_topological_order<T,N2I> &g) {
  bool flag(false);

  typedef typename boost::property_map<T, N2I>::type N2iMap;
  N2iMap n2i = get(N2I(),g);

  for(;b!=e;++b) {
    if(add_edge(static_cast<typename T::vertex_descriptor>(b->first),
		static_cast<typename T::vertex_descriptor>(b->second),
		static_cast<T&>(g)).second) {
      unsigned int hn2i(n2i[b->second]);
      unsigned int tn2i(n2i[b->first]);

      if(hn2i < tn2i) { flag = true; }
    }
  }

  if(flag) {
    unsigned int c(num_vertices(g));
    unsigned int count(num_vertices(g));
    for(unsigned int i=0;i!=c;++i) {
      if(!g._visited[i]) {
	sto_dfs_visit(i,count,n2i,g);
      }
    }
    fill(g._visited.begin(),g._visited.end(),false);
  }
}

template<class T, class N2I = n2i_t>
class simple_topological_order : public T {
public:
  typedef simple_topological_order<T,N2I> self;
  friend void add_edges<>(typename std::vector<std::pair<unsigned int, unsigned int> >::iterator,
			  typename std::vector<std::pair<unsigned int, unsigned int> >::iterator,
			  self &);
  friend void sto_dfs_visit<>(unsigned int, unsigned int &,
			      typename boost::property_map<T, N2I>::type &,
			      self &);
private:
  std::vector<bool> _visited; // useful and not too expensive.
public:
  simple_topological_order(T const &g, unsigned int acc = 1)
    : T(g), _visited(num_vertices(g),false) {

    // use the topological sort function to
    // order the vertices correctly ...

    typedef typename boost::property_map<T, N2I>::type N2iMap;
    N2iMap n2i = get(N2I(),*this);

    unsigned int count(num_vertices(g));
    for(unsigned int i=0;i!=num_vertices(g);++i) {
      if(!_visited[i]) {
	sto_dfs_visit(i,count,n2i,*this);
      }
    }
    assert(count == 0);
    fill(_visited.begin(),_visited.end(),false);
  }

  simple_topological_order(typename T::vertices_size_type n,
			       unsigned int acc = 1)
    : T(n), _visited(n,false) {
    typedef typename boost::property_map<T, N2I>::type N2iMap;
    N2iMap n2i = get(N2I(),*this);

    unsigned int counter(0);
    typename T::vertex_iterator i,iend;
    for(tie(i,iend) = vertices(*this);i!=iend;++i) {
      n2i[*i]=counter++;
    }
  }
};

#endif


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

    @copyright 2016 NumScale SAS

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

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

  /*!
    @ingroup group-ieee
    This function object returns the greatest representable
    value  strictly less than the parameter except:

    - for entries of floating types

       - prev(Valmin) is Minf

       - prev(Inf) is Valmax

       - prev(Minf) is Minf

       - prev(Nan) is Nan

    - for entries of integral type

      - prev(Valmin) is Valmax

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

    @see prev, nextafter, successor, predecessor

    @par Example:

      @snippet prev.cpp prev

    @par Possible output:

      @snippet prev.txt prev

  **/
  Value prev(Value const& x);
} }
#endif

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

#endif


#include <algorithm>
#include <boost/foreach.hpp>

#include "constants.hpp"
#include "fragment_model.hpp"
#include "fragbias.hpp"

FragBias::FragBias(FragmentModel* fm)
{
    // lengths used for interpolation
    const pos_t lengths[] = {
        25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300,
        325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700,
        750, 800, 850, 900, 950, 1000, 1100, 1200, 1300, 1500, 1600,
        1700, 1800, 1900, 2000, 2500, 3000, 3500, 4000, 4500, 5000
    };

    this->lengths.resize(sizeof(lengths) / sizeof(pos_t));
    std::copy(lengths, lengths + this->lengths.size(), this->lengths.begin());

    // assumed fragmentation probability
    this->fm = fm;
    p = (1.0 / fm->frag_len_med()) / 2.0;
    double omp = 1.0 - p;
    max_non_frag_run = std::max<pos_t>(1, lround(log(1e-5) / log(omp)));

    non_frag_run_pr_sum.resize(max_non_frag_run);
    non_frag_run_pr.resize(max_non_frag_run);

    non_frag_run_pr[0] = 1.0;
    non_frag_run_pr_sum[0] = 1.0;
    for (pos_t m = 1; m < max_non_frag_run; ++m) {
        non_frag_run_pr_sum[m] = non_frag_run_pr_sum[m - 1] + pow(omp, m - 1) / (double) m;
        non_frag_run_pr[m] = pow(omp, m - 1);
    }

    BOOST_FOREACH (pos_t l, this->lengths) {
        std::vector<float> fb(l);
        compute(&fb.at(0), 0, l, l);
        bias.push_back(fb);
    }
}

void FragBias::compute(float* out, pos_t from, pos_t to, pos_t l)
{
        // Four cases:
        for (pos_t u = from; u < to; ++u) out[u] = 0.0;

#if 0
        // enrichment of end positions assuming the end position is
        // primed first
        // Case 1: no fragmentation
        double c = (1.0 / l) * (l - 1 < max_non_frag_run ? non_frag_run_pr[l - 1] : 0.0);
        for (pos_t v = from; v < to; ++v) {
            double select_pr = fm->frag_len_c(v) / v;
            out[v] = c * select_pr;
        }

        // Case 2: read contained in a fragment at the left end of the
        //         transcript
        for (pos_t v = from; v < to; ++v) {
            for (pos_t j = v; j < std::min<pos_t>(l, v + max_non_frag_run); ++j) {
                double select_pr = fm->frag_len_c(v) / v;
                double run_pr = j - 1 < max_non_frag_run ? non_frag_run_pr[j - 1] : 0.0;
                out[v] += p * run_pr * (1.0 / j) * select_pr;
            }
        }

        // Case 3: read contained a fragment at the right end
        for (pos_t v = from; v < to; ++v) {
            for (pos_t i = std::max<pos_t>(0, v - max_non_frag_run); i < v; ++i) {
                double select_pr = fm->frag_len_c(v - i) / (v - i);
                double run_pr = l - i - 1 < max_non_frag_run ? non_frag_run_pr[l - i - 1] : 0.0;
                out[v] += p * run_pr * (1.0 / ((l - i))) * select_pr;
            }
        }

        // Case 4: read flanked by fragmentation breakpoints
        for (pos_t v = from; v < to; ++v) {
            for (pos_t h = 1; h < std::min<pos_t>(max_non_frag_run, v); ++h) {
                double run_pr1 = non_frag_run_pr_sum[
                    std::min<pos_t>((l - v)+ h, max_non_frag_run - 1)];
                double run_pr2 = non_frag_run_pr_sum[
                    std::min<pos_t>(h, max_non_frag_run - 1)];

                out[v] += p * p * (fm->frag_len_c(h) / h) *
                    (run_pr1 - run_pr2);
            }
        }
#endif

        // enrichment of start positions assuming the start position
        // is primed first.
        // Case 1: no fragmentation
        double c = (1.0 / l) * (l - 1 < max_non_frag_run ? non_frag_run_pr[l - 1] : 0.0);
        for (pos_t u = from; u < to; ++u) {
            double select_pr = fm->frag_len_c(l - u + 1) / (l - u + 1);
            out[u] = c * select_pr;
        }

        // Case 2: read contained in a fragment at the left end of the
        //         transcript
        for (pos_t u = from; u < to; ++u) {
            for (pos_t j = u + 1; j < std::min<pos_t>(l, u + max_non_frag_run); ++j) {
                double select_pr = fm->frag_len_c(j - u) / (j - u);
                double run_pr = j - 1 < max_non_frag_run ? non_frag_run_pr[j - 1] : 0.0;
                out[u] += p * run_pr * (1.0 / j) * select_pr;
            }
        }

        // Case 3: read contained a fragment at the right end
        for (pos_t u = from; u < to; ++u) {
            for (pos_t i = std::max<pos_t>(0, u - max_non_frag_run); i < u; ++i) {
                double select_pr = fm->frag_len_c(l - u + 1) / (l - u + 1);
                double run_pr = l - i - 1 < max_non_frag_run ? non_frag_run_pr[l - i - 1] : 0.0;
                out[u] += p * run_pr * (1.0 / ((l - i))) * select_pr;
            }
        }

        // Case 4: read flanked by fragmentation breakpoints
        for (pos_t u = from; u < to; ++u) {
            for (pos_t h = 1; h < std::min<pos_t>(max_non_frag_run, l - u); ++h) {
                double run_pr1 = non_frag_run_pr_sum[
                    std::min<pos_t>(u + h, max_non_frag_run - 1)];
                double run_pr2 = non_frag_run_pr_sum[
                    std::min<pos_t>(h, max_non_frag_run - 1)];

                out[u] += p * p * (fm->frag_len_c(h) / h) *
                    (run_pr1 - run_pr2);
            }
        }

        for (pos_t u = from; u < to; ++u) {
            out[u] *= constants::fragbias_scale;
        }
}

void FragBias::get_bias(float* out, pos_t l)
{
    unsigned int a;
    // extrapolate downwards
    if (l < lengths.front()) {
        a = 0;
    }
    // extrapolate upwards
    else if (l >= lengths.back()) {
        a = lengths.size() - 2;
    }
    // interpolate
    else {
        std::vector<pos_t>::iterator a_it =
            std::upper_bound(lengths.begin(), lengths.end(), l);
        a = a_it - lengths.begin() - 1;
    }

    unsigned int b = a + 1;

    pos_t al = lengths[a];
    pos_t bl = lengths[b];

    double z = (double) (l - al) / (double) (bl - al);

    // extrapolation can be very very wrong, so we just explicitly compute the
    // ends and copy the middles.
    pos_t endlen = 0;
    if (b == lengths.size() - 1) {
        z = 0.0;
        endlen = constants::fragbias_endlen;
    }
    pos_t to = std::min<pos_t>(l, endlen);
    compute(out, 0, to, l);
    compute(out, std::max<pos_t>(to, l - endlen), l, l);

    for (pos_t u = endlen; u < l - endlen; ++u) {
        double r = (double) u / (double) (l - 1);
        pos_t au = lround(r * (al - 1));
        pos_t bu = lround(r * (bl - 1));
        double slope = bias[b][bu] - bias[a][au];

        out[u] = bias[a][au] + z * slope;
    }
}


/*
 * =====================================================================================
 *
 *       Filename:  test_network.cpp
 *
 *    Description:  Network implementation testing program
 *
 *        Version:  1.0
 *        Created:  12/03/2011 12:52:41 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Sabelnikov Daniel (), dsabelnikov@gmail.com
 *        Company:
 *
 * =====================================================================================
 */

#include <stdlib.h>
#include <stdio.h>
#include "common/common_include.h"
#include "network/network.h"
#include "emulation/emulator_frontend.h"

#include "tools/topology_factory.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

using namespace mb;

namespace fs = boost::filesystem;

#define ASSERT(condition, message) LOG_IF(FATAL, !(condition)) << "Test #" << test << " failed: " << message;
#define START_TEST(msg) LOG(INFO) << "------------"; LOG(INFO) << "Starting Test #" << ++test << ". " << msg;

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:
 * =====================================================================================
 */
int main ( int argc, char *argv[] )
{
	google::InitGoogleLogging( argv[0] );
	google::InstallFailureSignalHandler();

	int test = 0;

	LOG(INFO) << "Executing tests of Network and Topology implementation...";

	START_TEST("Creating an instance of Topology: Topology(7,2,2)");
	Topology tp(7, 2, 2);
	ASSERT(tp.get_total_size() == 7, "Invalid total size of topology!");
	ASSERT(tp.get_input_size() == 2, "Invalid input size of topology!");
	ASSERT(tp.get_output_size() == 2, "Invalid output size of topology!");

	START_TEST("Creating a default instance of Topology: Topology()");
	Topology tp1(7,2,2);
	LOG(INFO) << "   Created: total_size: " << tp1.get_total_size() << ", input_size = "
				<< tp1.get_input_size() << ", output_size = " << tp1.get_output_size();

	START_TEST("Adding connections: [0,1]-[2,3,4]-[5,6]");
	tp.add_connection(0, 2);
	tp.add_connection(0, 3);
	tp.add_connection(0, 4);

	tp.add_connection(1, 2);
	tp.add_connection(1, 3);
	tp.add_connection(1, 4);

	tp.add_connection(2, 5);
	tp.add_connection(3, 5);
	tp.add_connection(4, 5);

	tp.add_connection(2, 6);
	tp.add_connection(3, 6);
	tp.add_connection(4, 6);

	ASSERT( !tp.is_connected(0, 1),"Error 0-1");
	ASSERT( tp.is_connected(0, 2), "Error 0-2");
	ASSERT( tp.is_connected(0, 3), "Error 0-3");
	ASSERT( tp.is_connected(1, 2), "Error 1-2");
	ASSERT( tp.is_connected(1, 4), "Error 1-4");
	ASSERT( !tp.is_connected(0, 5), "Error 0-5");
	ASSERT( !tp.is_connected(5, 6), "Error 5-6");

	START_TEST("Analyze and get depth. ");
	ASSERT( TopologyAnalyze::analyze_and_get_depth(&tp) == 3, "Invalid depth got from analyzer!");

	START_TEST("Creating a random network with max_weight = 1.0, and bias = 0.5 ...");
	NetworkPtr net( new Network(&tp, 1.0, 0.5) );
	for (uint i = 0; i < tp.get_total_size(); i++){
		for (uint j = 0; j < tp.get_total_size(); j++){
			t_weight w = net->get_weight(i, j);
			ASSERT(w >= -1.0 && w <= 1.0, "Weight was found more than 1.0!");
		}
	}
	//net->print( &LOG(INFO) );

	START_TEST("Emulator testing!");

	EmulatorFrontend ef;

	boost::shared_array<t_data> input( new t_data[3] );
	input[0] = 1;
	input[1] = 1;
	input[2] = 1;

	net->set_weight(0, 2, 0.5);
	net->set_weight(0, 3, 0.5);
	net->set_weight(0, 4, 0.5);

	net->set_weight(1, 2, 0.5);
	net->set_weight(1, 3, 0.5);
	net->set_weight(1, 4, 0.5);

	net->set_weight(2, 5, 0.33333333);
	net->set_weight(3, 5, 0.33333333);
	net->set_weight(4, 5, 0.33333333);

	net->set_weight(2, 6, 0.33333333);
	net->set_weight(3, 6, 0.33333333);
	net->set_weight(4, 6, 0.33333333);

	net->set_bias(0, 0);
	net->set_bias(1, 0);
	net->set_bias(2, 0);
	net->set_bias(3, 0);
	net->set_bias(4, 0);
	net->set_bias(5, 0);
	net->set_bias(6, 0);

	t_data expected = 1 / (1 + exp(-1));
	expected = 1 / (1 + exp(-expected));

	boost::shared_array<t_data> output = ef.single_run(net, input);

	ASSERT(output[0] == expected, "Didn't get expected output! output: " << output[0] << ", expected: " << expected);
	ASSERT(output[1] == expected, "Didn't get expected output! output: " << output[1] << ", expected: " << expected);

	input[0] = 0;
	input[1] = 0;
	input[2] = 0;

	output = ef.single_run(net, input);

	ASSERT(output[0] == 0, "Didn't get expected output! output: " << output[0] << ", expected: " << 0);
	ASSERT(output[1] == 0, "Didn't get expected output! output: " << output[1] << ", expected: " << 0);

	// -- with biases
	//
	input[0] = 1;
	input[1] = 1;
	input[2] = 1;

	net->set_bias(2, 0.2);
	net->set_bias(3, 0.2);
	net->set_bias(4, 0.2);

	net->set_bias(5, 0.1);
	net->set_bias(6, 0.6);

	expected = 1 / (1 + exp( - 1.2));
	t_data expected2 = 1 / (1 + exp( - expected - 0.6));
	expected = 1 / (1 + exp( - expected - 0.1));

	output = ef.single_run(net, input);

	ASSERT(output[0] == expected, "Didn't get expected output! output: " << output[0] << ", expected: " << expected);
	ASSERT(output[1] == expected2, "Didn't get expected output! output: " << output[1] << ", expected: " << expected2);

	START_TEST("Creating a topology with TopologyFactory.");

	std::vector<uint> layers;
	layers.push_back( 3 );
	layers.push_back( 2 );

	boost::shared_ptr<Topology> tp2(
		TopologyFactory::create_connected_layers_topology(1, 1, layers) );

	NetworkPtr net2( new Network( tp2.get(), 1.0, 1.0 ) );

	ASSERT(net2->get_weight(0,1) != 0, "Wrong topology");
	ASSERT(net2->get_weight(0,2) != 0, "Wrong topology");
	ASSERT(net2->get_weight(0,3) != 0, "Wrong topology");
	ASSERT(net2->get_weight(0,4) == 0, "Wrong topology");
	ASSERT(net2->get_weight(0,5) == 0, "Wrong topology");
	ASSERT(net2->get_weight(5,6) != 0, "Wrong topology");
	ASSERT(net2->get_weight(4,6) != 0, "Wrong topology");
	ASSERT(net2->get_weight(3,6) == 0, "Wrong topology");

	START_TEST("Testing serialization algorithms.");
	fs::path net_file("./___test.mbn");
	fs::ofstream out_file( net_file, std::ios_base::out );
	net2->serialize( &out_file );
	out_file.close();

	fs::ifstream in_file( net_file, std::ios_base::in );
	NetworkPtr net3( new Network( &in_file ) );
	in_file.close();

	for (uint i = 0; i < tp.get_total_size(); i++){
		for (uint j = 0; j < tp.get_total_size(); j++){
			ASSERT( net2->get_weight(i, j) == net3->get_weight(i, j), "Serialization error! i = " << i << ", j = " << j << ", net1: " << net2->get_weight(i, j) << ", net2: " << net3->get_weight(i, j));
		}
		ASSERT( net2->get_bias(i) == net3->get_bias(i), "Serialization error! i = " << i);
	}

    return EXIT_SUCCESS;
}				/* ----------  end of function main  ---------- */


#pragma once
#include <Eigen/Dense>
#include <array>
#include <cmath>
#include <iostream>
#include <memory>
#include <vector>

#include "datastructures/boost.hpp"
#include "datastructures/tree.hpp"

namespace space {
// Forward some class names.
class Vertex;
class Element2D;
class InitialTriangulation;
class HierarchicalBasisFn;
}  // namespace space

namespace datastructures {
template <>
struct NodeTrait<space::Vertex> {
  static constexpr size_t N_parents = 2;
  static constexpr size_t N_children = 4;
};
template <>
struct NodeTrait<space::Element2D> {
  static constexpr size_t N_parents = 1;
  static constexpr size_t N_children = 2;
};
}  // namespace datastructures

namespace space {
class Vertex : public datastructures::Node<Vertex> {
 public:
  const double x, y;
  bool on_domain_boundary;
  SmallVector<Element2D *, 4> patch;

  // This are the vertices that are bisected to create the current vertex.
  StaticVector<Vertex *, 2> godparents;
  StaticVector<Element2D *, 2> parents_element;

  // Constructor given parents.
  Vertex(const std::vector<Vertex *> &parents, double x, double y,
         bool on_domain_boundary)
      : Node(parents), x(x), y(y), on_domain_boundary(on_domain_boundary) {}

  friend std::ostream &operator<<(std::ostream &os, const Vertex &vertex) {
    os << "V(" << vertex.x << ", " << vertex.y << ")";
    return os;
  }

  bool Refine();
  bool is_full() const;

  // This returns the associated HierarchicalBasisFn.
  HierarchicalBasisFn *RefineHierarchicalBasisFn();

 protected:
  // Protected constructor for creating a metaroot.
  Vertex(Deque<Vertex> *container)
      : Node(container), x(NAN), y(NAN), on_domain_boundary(false) {}

  // There is a mapping between a vertex and a basis function.
  HierarchicalBasisFn *phi_ = nullptr;

  friend datastructures::Tree<Vertex>;
  friend Element2D;
  friend InitialTriangulation;
};

class Element2D : public datastructures::BinaryNode<Element2D> {
 public:
  std::array<Element2D *, 3> neighbours{nullptr};

  // Constructors given the parent.
  explicit Element2D(Element2D *parent, const std::array<Vertex *, 3> &vertices,
                     double area);
  explicit Element2D(Element2D *parent, const std::array<Vertex *, 3> &vertices)
      : Element2D(parent, vertices, parent->area() / 2.0) {}

  double area() const { return area_; }
  const std::array<Vertex *, 3> &vertices() const { return vertices_; }
  Vertex *newest_vertex() const { return vertices_[0]; }
  std::array<Vertex *, 2> edge(int i) const;
  std::array<Vertex *, 2> reversed_edge(int i) const;

  inline bool TouchesDomainBoundary() const {
    for (auto nbr : neighbours)
      if (!nbr) return true;
    return false;
  }

  Eigen::Vector3d BarycentricCoordinates(double x, double y) const;
  std::pair<double, double> GlobalCoordinates(double bary2, double bary3) const;
  const Eigen::Matrix3d &StiffnessMatrix() const { return stiff_mat_; }

  bool Refine();

  friend std::ostream &operator<<(std::ostream &os, const Element2D &elem) {
    if (elem.is_metaroot()) {
      os << "Element2D(MR)";
    } else {
      os << "Element2D(" << elem.level() << ", (";
      for (const auto &vertex : elem.vertices()) {
        if (vertex != *elem.vertices().begin()) os << ", ";
        os << *vertex;
      }
      os << "))";
    }
    return os;
  }

 protected:
  double area_;
  std::array<Vertex *, 3> vertices_;
  Eigen::Matrix3d stiff_mat_;

  // Protected constructor for creating a metaroot.
  Element2D(Deque<Element2D> *container) : BinaryNode(container), area_(-1) {}

  // Refinement methods.
  Vertex *CreateNewVertex(Element2D *nbr = nullptr);
  std::array<Element2D *, 2> Bisect(Vertex *new_vertex = nullptr);
  void BisectWithNbr();

  friend datastructures::Tree<Element2D>;
  friend InitialTriangulation;
};

};  // namespace space


#include <boost/type_traits/arithmetic_traits.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/function/scalar/two_split.hpp>
#include <scalar_test.hpp>
#include <boost/simd/detail/dispatch/meta/as_integer.hpp>
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/minf.hpp>
#include <boost/simd/constant/mone.hpp>
#include <boost/simd/constant/nan.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/constant/eps.hpp>
#include <boost/simd/constant/half.hpp>
#include <utility>

STF_CASE_TPL(" two_split", STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::two_split;

  STF_EXPR_IS( (two_split(T()))
                  , (std::pair<T,T>)
                  );

  T eps_ = bs::Eps<T>();
  T one_ = bs::One<T>();

  std::pair<T,T> p;

  p = two_split(one_-eps_);
  STF_EQUAL(p.first, one_);
  STF_EQUAL(p.second, -eps_);
}


#include <boost/numeric/odeint/stepper/base/symplectic_rkn_stepper_base.hpp>


#ifndef LBP_SILTP_HPP
#define LBP_SILTP_HPP

#include <lbp/defs.hpp>
#include <lbp/utils.hpp>
#include <lbp/detail/neighborhoods.hpp>
#include <lbp/detail/sampling.hpp>

#include <opencv2/core.hpp>

#include <boost/hana/integral_constant.hpp>
#include <boost/hana/functional/demux.hpp>

#include <boost/integer.hpp>

//
// @inproceedings{liao2010modeling,
//   title={Modeling pixel process with scale invariant local patterns for background subtraction in complex scenes},
//   author={Liao, Shengcai and Zhao, Guoying and Kellokumpu, Vili and Pietik{\"a}inen, Matti and Li, Stan Z},
//   booktitle={Computer Vision and Pattern Recognition (CVPR), 2010 IEEE Conference on},
//   pages={1301--1306},
//   year={2010},
//   organization={IEEE}
// }/
//

namespace lbp {
namespace siltp_detail {

template< typename T >
auto siltp = [](auto N, auto S) {
    return [=](const cv::Mat& src, size_t i, size_t j, const T& tau) {
        using namespace cv;
        using namespace hana::literals;

        const auto c = S (src, i, j);

        const auto lhs = saturate_cast< T > ((1. - tau) * c);
        const auto rhs = saturate_cast< T > ((1. + tau) * c);

        return boost::hana::fold_left (
            N, 0, [&, shift = 0](auto accum, auto x) mutable {
                const auto g = S (src, i + x [0_c], j + x [1_c]);
                return accum | (
                    (g > rhs ? 1 : (g < lhs ? 2 : 0)) << (shift++ * 2));
            });
    };
};

} // namespace siltp_detail

template< typename T, size_t R, size_t P >
auto siltp = [](const cv::Mat& src, const T& tau = T { }) {
    using value_type = typename boost::uint_t< P * 2 >::least;

    cv::Mat dst (src.size (), opencv_type< value_type >, cv::Scalar (0));

    auto op = siltp_detail::siltp< T > (
        detail::circular_neighborhood< R, P >,
        detail::nearest_sampler< T >);

#pragma omp parallel for
    for (size_t i = R; i < src.rows - R; ++i) {
        for (size_t j = R; j < src.cols - R; ++j) {
            dst.at< value_type > (i, j) = op (src, i, j, tau);
        }
    }

    return dst;
};

} // namespace lbp

#endif // LBP_SILTP_HPP