#include <boost/numeric/conversion/cast.hpp>
#include <boost/test/unit_test.hpp>

#include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/debug.hpp"
#include "util/web_mercator.hpp"

#include <osrm/coordinate.hpp>

#include <cmath>

using namespace osrm;
using namespace osrm::util;

BOOST_AUTO_TEST_SUITE(coordinate_calculation_tests)

BOOST_AUTO_TEST_CASE(compute_angle)
{
    // Simple cases
    // North-South straight line
    Coordinate first(FloatLongitude{1}, FloatLatitude{-1});
    Coordinate middle(FloatLongitude{1}, FloatLatitude{0});
    Coordinate end(FloatLongitude{1}, FloatLatitude{1});
    auto angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // North-South-North u-turn
    first = Coordinate(FloatLongitude{1}, FloatLatitude{0});
    middle = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    end = Coordinate(FloatLongitude{1}, FloatLatitude{0});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 0);

    // East-west straight lines are harder, *simple* coordinates only
    // work at the equator.  For other locations, we need to follow
    // a rhumb line.
    first = Coordinate(FloatLongitude{1}, FloatLatitude{0});
    middle = Coordinate(FloatLongitude{2}, FloatLatitude{0});
    end = Coordinate(FloatLongitude{3}, FloatLatitude{0});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // East-West-East u-turn
    first = Coordinate(FloatLongitude{1}, FloatLatitude{0});
    middle = Coordinate(FloatLongitude{2}, FloatLatitude{0});
    end = Coordinate(FloatLongitude{1}, FloatLatitude{0});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 0);

    // 90 degree left turn
    first = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    middle = Coordinate(FloatLongitude{0}, FloatLatitude{1});
    end = Coordinate(FloatLongitude{0}, FloatLatitude{2});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 90);

    // 90 degree right turn
    first = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    middle = Coordinate(FloatLongitude{0}, FloatLatitude{1});
    end = Coordinate(FloatLongitude{0}, FloatLatitude{0});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 270);

    // Weird cases
    // Crossing both the meridians
    first = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    middle = Coordinate(FloatLongitude{0}, FloatLatitude{1});
    end = Coordinate(FloatLongitude{1}, FloatLatitude{-1});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_CLOSE(angle, 53.1, 0.2);

    // All coords in the same spot
    first = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    middle = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    end = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // First two coords in the same spot, then heading north-east
    first = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    middle = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    end = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // First two coords in the same spot, then heading west
    first = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    middle = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    end = Coordinate(FloatLongitude{2}, FloatLatitude{1});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // First two coords in the same spot then heading north
    first = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    middle = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    end = Coordinate(FloatLongitude{1}, FloatLatitude{2});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // Second two coords in the same spot
    first = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    middle = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    end = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // First and last coords on the same spot
    first = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    middle = Coordinate(FloatLongitude{-1}, FloatLatitude{-1});
    end = Coordinate(FloatLongitude{1}, FloatLatitude{1});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 0);

    // Check the antimeridian
    first = Coordinate(FloatLongitude{180}, FloatLatitude{90});
    middle = Coordinate(FloatLongitude{180}, FloatLatitude{0});
    end = Coordinate(FloatLongitude{180}, FloatLatitude{-90});
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);

    // Tiny changes below our calculation resolution
    // This should be equivalent to having two points on the same spot.
    first = Coordinate{FloatLongitude{0}, FloatLatitude{0}};
    middle = Coordinate{FloatLongitude{1}, FloatLatitude{0}};
    end = Coordinate{FloatLongitude{1 + std::numeric_limits<double>::epsilon()}, FloatLatitude{0}};
    angle = coordinate_calculation::computeAngle(first, middle, end);
    BOOST_CHECK_EQUAL(angle, 180);
}

BOOST_AUTO_TEST_CASE(invalid_values)
{
    // Invalid values for unsafe types
    BOOST_CHECK_THROW(coordinate_calculation::computeAngle(
                          Coordinate(UnsafeFloatLongitude{0}, UnsafeFloatLatitude{0}),
                          Coordinate(UnsafeFloatLongitude{1}, UnsafeFloatLatitude{0}),
                          Coordinate(UnsafeFloatLongitude{std::numeric_limits<double>::max()},
                                     UnsafeFloatLatitude{0})),
                      boost::numeric::positive_overflow);
}

// Regression test for bug captured in #1347
BOOST_AUTO_TEST_CASE(regression_test_1347)
{
    Coordinate u(FloatLongitude{-100}, FloatLatitude{10});
    Coordinate v(FloatLongitude{-100.002}, FloatLatitude{10.001});
    Coordinate q(FloatLongitude{-100.001}, FloatLatitude{10.002});

    double d1 = coordinate_calculation::perpendicularDistance(u, v, q);

    double ratio;
    Coordinate nearest_location;
    double d2 = coordinate_calculation::perpendicularDistance(u, v, q, nearest_location, ratio);

    BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
}

BOOST_AUTO_TEST_CASE(regression_point_on_segment)
{
    //  ^
    //  |               t
    //  |
    //  |                 i
    //  |
    //  |---|---|---|---|---|---|---|--->
    //  |
    //  |
    //  |
    //  |
    //  |
    //  |
    //  |
    //  |
    //  |                           s
    FloatCoordinate input{FloatLongitude{55.995715}, FloatLatitude{48.332711}};
    FloatCoordinate start{FloatLongitude{74.140427}, FloatLatitude{-180}};
    FloatCoordinate target{FloatLongitude{53.041084}, FloatLatitude{77.21011}};

    FloatCoordinate nearest;
    double ratio;
    std::tie(ratio, nearest) = coordinate_calculation::projectPointOnSegment(start, target, input);

    FloatCoordinate diff{target.lon - start.lon, target.lat - start.lat};

    BOOST_CHECK_CLOSE(static_cast<double>(start.lon + FloatLongitude{ratio} * diff.lon),
                      static_cast<double>(nearest.lon),
                      0.1);
    BOOST_CHECK_CLOSE(static_cast<double>(start.lat + FloatLatitude{ratio} * diff.lat),
                      static_cast<double>(nearest.lat),
                      0.1);
}

BOOST_AUTO_TEST_CASE(point_on_segment)
{
    //  t
    //  |
    //  |---- i
    //  |
    //  s
    auto result_1 =
        coordinate_calculation::projectPointOnSegment({FloatLongitude{0}, FloatLatitude{0}},
                                                      {FloatLongitude{0}, FloatLatitude{2}},
                                                      {FloatLongitude{2}, FloatLatitude{1}});
    auto reference_ratio_1 = 0.5;
    auto reference_point_1 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{1}};
    BOOST_CHECK_EQUAL(result_1.first, reference_ratio_1);
    BOOST_CHECK_EQUAL(result_1.second.lon, reference_point_1.lon);
    BOOST_CHECK_EQUAL(result_1.second.lat, reference_point_1.lat);

    //  i
    //  :
    //  t
    //  |
    //  |
    //  |
    //  s
    auto result_2 =
        coordinate_calculation::projectPointOnSegment({FloatLongitude{0.}, FloatLatitude{0.}},
                                                      {FloatLongitude{0}, FloatLatitude{2}},
                                                      {FloatLongitude{0}, FloatLatitude{3}});
    auto reference_ratio_2 = 1.;
    auto reference_point_2 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{2}};
    BOOST_CHECK_EQUAL(result_2.first, reference_ratio_2);
    BOOST_CHECK_EQUAL(result_2.second.lon, reference_point_2.lon);
    BOOST_CHECK_EQUAL(result_2.second.lat, reference_point_2.lat);

    //  t
    //  |
    //  |
    //  |
    //  s
    //  :
    //  i
    auto result_3 =
        coordinate_calculation::projectPointOnSegment({FloatLongitude{0.}, FloatLatitude{0.}},
                                                      {FloatLongitude{0}, FloatLatitude{2}},
                                                      {FloatLongitude{0}, FloatLatitude{-1}});
    auto reference_ratio_3 = 0.;
    auto reference_point_3 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{0}};
    BOOST_CHECK_EQUAL(result_3.first, reference_ratio_3);
    BOOST_CHECK_EQUAL(result_3.second.lon, reference_point_3.lon);
    BOOST_CHECK_EQUAL(result_3.second.lat, reference_point_3.lat);

    //     t
    //    /
    //   /.
    //  /  i
    // s
    //
    auto result_4 = coordinate_calculation::projectPointOnSegment(
        {FloatLongitude{0}, FloatLatitude{0}},
        {FloatLongitude{1}, FloatLatitude{1}},
        {FloatLongitude{0.5 + 0.1}, FloatLatitude{0.5 - 0.1}});
    auto reference_ratio_4 = 0.5;
    auto reference_point_4 = FloatCoordinate{FloatLongitude{0.5}, FloatLatitude{0.5}};
    BOOST_CHECK_EQUAL(result_4.first, reference_ratio_4);
    BOOST_CHECK_EQUAL(result_4.second.lon, reference_point_4.lon);
    BOOST_CHECK_EQUAL(result_4.second.lat, reference_point_4.lat);
}

BOOST_AUTO_TEST_CASE(circleCenter)
{
    Coordinate a(FloatLongitude{-100.}, FloatLatitude{10.});
    Coordinate b(FloatLongitude{-100.002}, FloatLatitude{10.001});
    Coordinate c(FloatLongitude{-100.001}, FloatLatitude{10.002});

    auto result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(result);
    BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude{-100.0008333}, FloatLatitude{10.0008333}));

    // Co-linear longitude
    a = Coordinate(FloatLongitude{-100.}, FloatLatitude{10.});
    b = Coordinate(FloatLongitude{-100.001}, FloatLatitude{10.001});
    c = Coordinate(FloatLongitude{-100.001}, FloatLatitude{10.002});
    result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(result);
    BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude{-99.9995}, FloatLatitude{10.0015}));

    // Co-linear longitude, impossible to calculate
    a = Coordinate(FloatLongitude{-100.001}, FloatLatitude{10.});
    b = Coordinate(FloatLongitude{-100.001}, FloatLatitude{10.001});
    c = Coordinate(FloatLongitude{-100.001}, FloatLatitude{10.002});
    result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(!result);

    // Co-linear latitude, this is a real case that failed
    a = Coordinate(FloatLongitude{-112.096234}, FloatLatitude{41.147101});
    b = Coordinate(FloatLongitude{-112.096606}, FloatLatitude{41.147101});
    c = Coordinate(FloatLongitude{-112.096419}, FloatLatitude{41.147259});
    result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(result);
    BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude{-112.09642}, FloatLatitude{41.1470705}));

    // Co-linear latitude, variation
    a = Coordinate(FloatLongitude{-112.096234}, FloatLatitude{41.147101});
    b = Coordinate(FloatLongitude{-112.096606}, FloatLatitude{41.147259});
    c = Coordinate(FloatLongitude{-112.096419}, FloatLatitude{41.147259});
    result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(result);
    BOOST_CHECK_EQUAL(*result, Coordinate(FloatLongitude{-112.0965125}, FloatLatitude{41.1469622}));

    // Co-linear latitude, impossible to calculate
    a = Coordinate(FloatLongitude{-112.096234}, FloatLatitude{41.147259});
    b = Coordinate(FloatLongitude{-112.096606}, FloatLatitude{41.147259});
    c = Coordinate(FloatLongitude{-112.096419}, FloatLatitude{41.147259});
    result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(!result);

    // Out of bounds
    a = Coordinate(FloatLongitude{-112.096234}, FloatLatitude{41.147258});
    b = Coordinate(FloatLongitude{-112.106606}, FloatLatitude{41.147259});
    c = Coordinate(FloatLongitude{-113.096419}, FloatLatitude{41.147258});
    result = coordinate_calculation::circleCenter(a, b, c);
    BOOST_CHECK(!result);
}

// For overflow issue #3483, introduced in 68ee4eab61548. Run with -fsanitize=integer.
BOOST_AUTO_TEST_CASE(squaredEuclideanDistance)
{
    // Overflow happens when left hand side values are smaller than right hand side values,
    // then `lhs - rhs` will be negative but stored in a uint64_t (wraps around).

    Coordinate lhs(FloatLongitude{-180}, FloatLatitude{-90});
    Coordinate rhs(FloatLongitude{180}, FloatLatitude{90});

    const auto result = coordinate_calculation::squaredEuclideanDistance(lhs, rhs);

    BOOST_CHECK_EQUAL(result, 162000000000000000ull);
}

BOOST_AUTO_TEST_CASE(vertical_regression)
{
    // check a vertical line for its bearing
    std::vector<Coordinate> coordinates;
    for (std::size_t i = 0; i < 100; ++i)
        coordinates.push_back(Coordinate(FloatLongitude{0.0}, FloatLatitude{i / 100.0}));

    const auto regression =
        util::coordinate_calculation::leastSquareRegression(coordinates.begin(), coordinates.end());
    const auto is_valid =
        util::angularDeviation(
            util::coordinate_calculation::bearing(regression.first, regression.second), 0) < 2;
    BOOST_CHECK(is_valid);
}

BOOST_AUTO_TEST_CASE(sinus_curve)
{
    // create a full sinus curve, sampled in 3.6 degree
    std::vector<Coordinate> coordinates;
    for (std::size_t i = 0; i < 360; ++i)
        coordinates.push_back(Coordinate(
            FloatLongitude{i / 360.0},
            FloatLatitude{sin(util::coordinate_calculation::detail::degToRad(i / 360.0))}));

    const auto regression =
        util::coordinate_calculation::leastSquareRegression(coordinates.begin(), coordinates.end());
    const auto is_valid =
        util::angularDeviation(
            util::coordinate_calculation::bearing(regression.first, regression.second), 90) < 2;

    BOOST_CHECK(is_valid);
}

BOOST_AUTO_TEST_CASE(parallel_lines_slight_offset)
{
    std::vector<Coordinate> coordinates_lhs;
    for (std::size_t i = 0; i < 100; ++i)
        coordinates_lhs.push_back(Coordinate(util::FloatLongitude{(50 - (rand() % 101)) / 100000.0},
                                             util::FloatLatitude{i / 100000.0}));
    std::vector<Coordinate> coordinates_rhs;
    for (std::size_t i = 0; i < 100; ++i)
        coordinates_rhs.push_back(
            Coordinate(util::FloatLongitude{(150 - (rand() % 101)) / 100000.0},
                       util::FloatLatitude{i / 100000.0}));

    const auto are_parallel = util::coordinate_calculation::areParallel(coordinates_lhs.begin(),
                                                                        coordinates_lhs.end(),
                                                                        coordinates_rhs.begin(),
                                                                        coordinates_rhs.end());
    BOOST_CHECK(are_parallel);
}

BOOST_AUTO_TEST_CASE(consistent_invalid_bearing_result)
{
    const auto pos1 = Coordinate(util::FloatLongitude{0.}, util::FloatLatitude{0.});
    const auto pos2 = Coordinate(util::FloatLongitude{5.}, util::FloatLatitude{5.});
    const auto pos3 = Coordinate(util::FloatLongitude{-5.}, util::FloatLatitude{-5.});

    BOOST_CHECK_EQUAL(0., util::coordinate_calculation::bearing(pos1, pos1));
    BOOST_CHECK_EQUAL(0., util::coordinate_calculation::bearing(pos2, pos2));
    BOOST_CHECK_EQUAL(0., util::coordinate_calculation::bearing(pos3, pos3));
}

// Regression test for bug captured in #3516
BOOST_AUTO_TEST_CASE(regression_test_3516)
{
    Coordinate u(FloatLongitude{-73.989687}, FloatLatitude{40.752288});
    Coordinate v(FloatLongitude{-73.990134}, FloatLatitude{40.751658});
    Coordinate q(FloatLongitude{-73.99039}, FloatLatitude{40.75171});

    BOOST_CHECK_EQUAL(Coordinate{web_mercator::toWGS84(web_mercator::fromWGS84(u))}, u);
    BOOST_CHECK_EQUAL(Coordinate{web_mercator::toWGS84(web_mercator::fromWGS84(v))}, v);

    double ratio;
    Coordinate nearest_location;
    coordinate_calculation::perpendicularDistance(u, v, q, nearest_location, ratio);

    BOOST_CHECK_EQUAL(ratio, 1.);
    BOOST_CHECK_EQUAL(nearest_location, v);
}

BOOST_AUTO_TEST_CASE(computeArea)
{
    using osrm::util::coordinate_calculation::computeArea;

    //
    auto rhombus = std::vector<Coordinate>{{FloatLongitude{.00}, FloatLatitude{.00}},
                                           {FloatLongitude{.01}, FloatLatitude{.01}},
                                           {FloatLongitude{.02}, FloatLatitude{.00}},
                                           {FloatLongitude{.01}, FloatLatitude{-.01}},
                                           {FloatLongitude{.00}, FloatLatitude{.00}}};

    BOOST_CHECK_CLOSE(2 * 1112.263 * 1112.263, computeArea(rhombus), 1e-3);

    // edge cases
    auto self_intersection = std::vector<Coordinate>{{FloatLongitude{.00}, FloatLatitude{.00}},
                                                     {FloatLongitude{.00}, FloatLatitude{.02}},
                                                     {FloatLongitude{.01}, FloatLatitude{.01}},
                                                     {FloatLongitude{.02}, FloatLatitude{.00}},
                                                     {FloatLongitude{.02}, FloatLatitude{.02}},
                                                     {FloatLongitude{.01}, FloatLatitude{.01}},
                                                     {FloatLongitude{.00}, FloatLatitude{.00}}};
    BOOST_CHECK(computeArea(self_intersection) < 1e-3);
    BOOST_CHECK_CLOSE(0, computeArea({}), 1e-3);
}

BOOST_AUTO_TEST_SUITE_END()


//---------------------------------------------------------------------------//
// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
//
// 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
//
// See http://kylelutz.github.com/compute for more information.
//---------------------------------------------------------------------------//

#define BOOST_TEST_MODULE TestUnique
#include <boost/test/unit_test.hpp>

#include <boost/compute/function.hpp>
#include <boost/compute/algorithm/iota.hpp>
#include <boost/compute/algorithm/none_of.hpp>
#include <boost/compute/algorithm/transform.hpp>
#include <boost/compute/algorithm/unique.hpp>
#include <boost/compute/container/vector.hpp>

#include "check_macros.hpp"
#include "context_setup.hpp"

namespace compute = boost::compute;

BOOST_AUTO_TEST_CASE(unique_int)
{
    int data[] = {1, 6, 6, 4, 2, 2, 4};

    compute::vector<int> input(data, data + 7, queue);

    compute::vector<int>::iterator iter =
        compute::unique(input.begin(), input.end(), queue);

    BOOST_VERIFY(iter == input.begin() + 5);
    CHECK_RANGE_EQUAL(int, 7, input, (1, 6, 4, 2, 4, 2, 4));
}

BOOST_AUTO_TEST_CASE(all_same_float)
{
    compute::vector<float> vec(1024, context);
    compute::fill(vec.begin(), vec.end(), 3.14f, queue);

    compute::vector<float>::iterator iter =
        compute::unique(vec.begin(), vec.end(), queue);

    BOOST_VERIFY(iter == vec.begin() + 1);

    float first;
    compute::copy_n(vec.begin(), 1, &first, queue);
    BOOST_CHECK_EQUAL(first, 3.14f);
}

BOOST_AUTO_TEST_CASE(unique_even_uints)
{
    using compute::uint_;

    // create vector filled with [0, 1, 2, ...]
    compute::vector<uint_> vec(1024, context);
    compute::iota(vec.begin(), vec.end(), 0, queue);

    // all should be unique
    compute::vector<uint_>::iterator iter = compute::unique(
        vec.begin(), vec.end(), queue
    );
    BOOST_VERIFY(iter == vec.end());

    // if odd, return the prior even number, else return the number
    BOOST_COMPUTE_FUNCTION(uint_, odd_to_even, (uint_ x),
    {
        if(x & 1){
            return x - 1;
        }
        else {
            return x;
        }
    });

    // set all odd numbers the previous even number
    compute::transform(
        vec.begin(), vec.end(), vec.begin(), odd_to_even, queue
    );

    // now the vector should contain [0, 0, 2, 2, 4, 4, ...]
    iter = compute::unique(vec.begin(), vec.end(), queue);
    BOOST_VERIFY(iter == vec.begin() + (vec.size() / 2));

    // ensure all of the values are even
    BOOST_COMPUTE_FUNCTION(bool, is_odd, (uint_ x),
    {
        return x & 1;
    });
    BOOST_VERIFY(compute::none_of(vec.begin(), vec.end(), is_odd, queue));
}

BOOST_AUTO_TEST_SUITE_END()


#include <boost/iterator/transform_iterator.hpp>
#include <iostream>
#include <vector>
#include <list>

int squared(int n) {
    return n*n;
}

int main(int argc, char *argv[]) {
    int vector[] = {45, 34, 33, 12, 4, 54, 6, 57, 68, 79};
    int n = sizeof(vector)/sizeof(int);

    auto begin = boost::make_transform_iterator(vector, squared);
    auto end = boost::make_transform_iterator(vector + n, squared);

    std::copy(begin, end, std::ostream_iterator<int>(std::cout, " "));

    return EXIT_SUCCESS;
}


#include <iostream>
#include <sstream>
#include <utility>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>

static const int num_nodes = 4;

main()
{
    // Vertices
    enum nodes {A, B, C, D};

    // Make the graph /////////////////

    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS> graph_t;
    graph_t g(num_nodes);

    // Fill in the graph
    boost::add_edge(A, B, g);
    boost::add_edge(B, C, g);
    boost::add_edge(A, D, g);

    // Print the graph ////////////////

    typedef boost::property_map<graph_t, boost::vertex_index_t>::type index_map_t;
    index_map_t index = boost::get(boost::vertex_index, g);

    typedef boost::graph_traits<graph_t>::vertex_iterator vertex_iterator_t;
    std::pair<vertex_iterator_t, vertex_iterator_t> vp;

    // Print vertices
    std::ostringstream oss;

    for(vp = boost::vertices(g) ; vp.first != vp.second ; ++vp.first) {
        oss << index[*vp.first] << " ";
    }

    std::cout << "vertices(g) = { " << oss.str() << "}" << std::endl;

    oss.str("");

    // Print edges

    boost::graph_traits<graph_t>::edge_iterator ei, ei_end;
    for(tie(ei, ei_end) = boost::edges(g) ; ei != ei_end ; ++ei) {
        oss << "(" << index[boost::source(*ei, g)] << "," << index[boost::target(*ei, g)] << ") ";
    }

    std::cout << "edges(g) = { " << oss.str() << "}" << std::endl;

}


/*
 [auto_generated]
 boost/numeric/odeint/stepper/generation.hpp

 [begin_description]
 Forward header for the factory functions. Includes all files from the generation directory.
 [end_description]

 Copyright 2011 Karsten Ahnert
 Copyright 2011 Mario Mulansky

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

#ifndef BOOST_NUMERIC_ODEINT_STEPPER_GENERATION_HPP_INCLUDED
#define BOOST_NUMERIC_ODEINT_STEPPER_GENERATION_HPP_INCLUDED

#include <boost/numeric/odeint/stepper/generation/make_controlled.hpp>
#include <boost/numeric/odeint/stepper/generation/make_dense_output.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_controlled_runge_kutta.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_dense_output_runge_kutta.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_cash_karp54_cl.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_cash_karp54.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_dopri5.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_fehlberg78.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_controlled_adams_bashforth_m.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_rosenbrock4.hpp>

#endif // BOOST_NUMERIC_ODEINT_STEPPER_GENERATION_HPP_INCLUDED


// -*- coding: utf-8 -*-
#include <doctest/doctest.h>  // for ResultBuilder

#include <boost/graph/adjacency_list.hpp>                 // for adjacency_list
#include <boost/graph/detail/adj_list_edge_iterator.hpp>  // for adj_list_ed...
#include <boost/graph/detail/adjacency_list.hpp>          // for get, vertices
#include <boost/graph/graph_selectors.hpp>                // for directedS
#include <boost/graph/graph_traits.hpp>                   // for graph_traits
#include <boost/graph/properties.hpp>                     // for edge_weight_t
#include <boost/iterator/iterator_facade.hpp>             // for operator!=
#include <boost/move/utility_core.hpp>                    // for move
#include <boost/pending/property.hpp>                     // for property
#include <iterator>                                       // for begin
#include <list>                                           // for operator==
#include <netoptim/neg_cycle.hpp>                         // for negCycleFinder
#include <py2cpp/nx2bgl.hpp>                              // for grAdaptor
#include <type_traits>                                    // for move
#include <utility>                                        // for pair
#include <vector>                                         // for vector

using graph_t = boost::adjacency_list<
    boost::listS, boost::vecS, boost::directedS, boost::no_property,
    boost::property<boost::edge_weight_t, int, boost::property<boost::edge_index_t, int>>>;
using Vertex = boost::graph_traits<graph_t>::vertex_descriptor;
// using Edge_it = boost::graph_traits<graph_t>::edge_iterator;

static py::grAdaptor<graph_t> create_test_case1() {
    using Edge = std::pair<int, int>;
    const auto num_nodes = 5;
    enum nodes { A, B, C, D, E };
    static Edge edge_array[] = {Edge{A, B}, Edge{B, C}, Edge{C, D}, Edge{D, E}, Edge{E, A}};
    int weights[] = {-5, 1, 1, 1, 1};
    int num_arcs = sizeof(edge_array) / sizeof(Edge);
    auto g = graph_t(edge_array, edge_array + num_arcs, weights, num_nodes);
    return py::grAdaptor<graph_t>{std::move(g)};
}

static py::grAdaptor<graph_t> create_test_case2() {
    using Edge = std::pair<int, int>;
    const auto num_nodes = 5;
    enum nodes { A, B, C, D, E };
    static Edge edge_array[] = {Edge{A, B}, Edge{B, C}, Edge{C, D}, Edge{D, E}, Edge{E, A}};
    int weights[] = {2, 1, 1, 1, 1};
    int num_arcs = sizeof(edge_array) / sizeof(Edge);
    auto g = graph_t(edge_array, edge_array + num_arcs, weights, num_nodes);
    return py::grAdaptor<graph_t>{std::move(g)};
}

static auto create_test_case_timing() -> py::grAdaptor<graph_t> {
    using Edge = std::pair<int, int>;
    constexpr auto num_nodes = 3;
    enum nodes { A, B, C };
    static Edge edge_array[] = {Edge{A, B}, Edge{B, A}, Edge{B, C}, Edge{C, B},
                                Edge{B, C}, Edge{C, B}, Edge{C, A}, Edge{A, C}};
    int weights[] = {7, 0, 3, 1, 6, 4, 2, 5};
    constexpr int num_arcs = sizeof(edge_array) / sizeof(Edge);
    auto g = graph_t(edge_array, edge_array + num_arcs, weights, num_nodes);
    return py::grAdaptor<graph_t>{std::move(g)};
}

static auto create_test_case_timing2() -> py::grAdaptor<graph_t> {
    using Edge = std::pair<int, int>;
    constexpr auto num_nodes = 3;
    enum nodes { A, B, C };
    static Edge edge_array[] = {Edge{A, B}, Edge{B, A}, Edge{B, C}, Edge{C, B},
                                Edge{B, C}, Edge{C, B}, Edge{C, A}, Edge{A, C}};
    int weights[] = {3, -4, -1, -3, 2, 0, -2, 1};
    constexpr int num_arcs = sizeof(edge_array) / sizeof(Edge);
    auto g = graph_t(edge_array, edge_array + num_arcs, weights, num_nodes);
    return py::grAdaptor<graph_t>{std::move(g)};
}

auto do_case(const py::grAdaptor<graph_t>& G) -> bool {
    using edge_t = decltype(*(std::begin(G.edges())));

    const auto get_weight = [&](const edge_t& e) -> int {
        const auto& weightmap = boost::get(boost::edge_weight, G);
        return weightmap[e];
    };

    auto dist = std::vector<int>(G.number_of_nodes(), 0);
    auto N = negCycleFinder<py::grAdaptor<graph_t>>{G};
    const auto cycle = N.find_neg_cycle(dist, get_weight);
    return !cycle.empty();
}

auto do_case_float(const py::grAdaptor<graph_t>& G) -> bool {
    using edge_t = decltype(*(std::begin(G.edges())));

    const auto get_weight = [&](const edge_t& e) -> double {
        const auto& weightmap = boost::get(boost::edge_weight, G);
        return weightmap[e];
    };

    auto dist = std::vector<double>(G.number_of_nodes(), 0.0);
    auto N = negCycleFinder<py::grAdaptor<graph_t>>{G};
    const auto cycle = N.find_neg_cycle(dist, get_weight);
    return !cycle.empty();
}

TEST_CASE("Test Negative Cycle (boost)") {
    const auto G = create_test_case1();
    const auto hasNeg = do_case(G);
    CHECK(hasNeg);
}

TEST_CASE("Test No Negative Cycle (boost)") {
    const auto G = create_test_case2();
    const auto hasNeg = do_case(G);
    CHECK(!hasNeg);
}

TEST_CASE("Test Timing Graph (boost)") {
    const auto G = create_test_case_timing();
    const auto hasNeg = do_case(G);
    CHECK(!hasNeg);
}

TEST_CASE("Test Timing Graph 2 (boost)") {
    const auto G = create_test_case_timing2();
    const auto hasNeg = do_case(G);
    CHECK(hasNeg);
}

TEST_CASE("Test Timing Graph float (boost)") {
    const auto G = create_test_case_timing();
    const auto hasNeg = do_case_float(G);
    CHECK(!hasNeg);
}

TEST_CASE("Test Timing Graph 2 (boost)") {
    const auto G = create_test_case_timing2();
    const auto hasNeg = do_case_float(G);
    CHECK(hasNeg);
}


/// MIT License
///
/// Copyright (c) 2017 Bjoern Barz
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.

#include <math.h>
#include <limits>
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Cholesky>
#include <Eigen/Jacobi>     // required for LLT::rankUpdate()

#define ITML_ERR_A0 -1
#define ITML_ERR_NO_CONSTRAINTS -2
#define ITML_ERR_INVALID_CONSTRAINTS -3
#define ITML_ERR_CHOL -4

/**
* Stores the indices of two similar or dissimilar samples.
*/
typedef struct {
    int i; /**< Index of first sample. */
    int j; /**< Index of second sample. */
} itml_pair;

/**
* Learns a Mahalanobis distance metric `(x-y)^T * A * (x-y)` from given data and constraints using
* Information Theoretic Metric Learning (ITML).
*
* ITML minimizes the differential relative entropy between two multivariate Gaussians under constraints
* on the distance function, which can be formulated into a Bregman optimization problem by minimizing the
* LogDet divergence subject to linear constraints.
* Unlike some other methods, ITML does not rely on an eigenvalue computation or semi-definite programming.
*
* The constraints enforced by ITML have the following form:
*
* - `(x-y)^T * A * (x-y) < th_pos` for two similar samples `x` and `y`
* - `(x-y)^T * A * (x-y) > th_neg` for two dissimilar samples `x` and `y`
*
* In theory, individual thresholds could be specified for all pairs, but this implementation only supports
* constant `th_pos` and `th_neg` at the moment.
*
* Reference:
* Jason V. Davis, Brian Kulis, Prateek Jain, Suvrit Sra, Inderjit S. Dhillon.
* "Information-Theoretic Metric Learning."
* International Conference on Machine Learning (ITML), 2007.
*
* @param[in] n The number of samples.
*
* @param[in] d The number of dimensions of the data.
*
* @param[in] pX Pointer to an n-by-d matrix `X` containing one sample per row, stored in row-major order.
*
* @param[in,out] pA Pointer to a row-major d-by-d matrix `A` which initially contains the prior metric serving
* as a regularizer (usually the identity matrix or inverse covariance). The algorithm will update this matrix
* in-place, so that it will finally contain the learned metric or its Cholesky decomposition, depending on the
* value of `return_metric`.
*
* @param[in] nb_pos Number of similarity constraints.
*
* @param[in] pos Pointer to an array of `nb_pos` similarity constraints, given as pairs of indices of similar
* samples in `X`.
*
* @param[in] nb_neg Number of dissimilarity constraints.
*
* @param[in] neg Pointer to an array of `nb_neg` dissimilarity constraints, given as pairs of indices of
* dissimilar samples in `X`.
*
* @param[in] th_pos Threshold for distances of similar samples. ITML enforces the given pairs of similar samples
* to have a distance less than this threshold.
*
* @param[in] th_neg Threshold for distances of dissimilar samples. ITML enforces the given pairs of dissimilar
* samples to have a distance greater than this threshold.
*
* @param[in] return_metric The algorithm actually learns the Cholesky decomposition `U` of the metric `A` with
* `A = U^T * U`, which can be used to transform the data into a space where the Euclidean distance corresponds to
* the learned metric. This matrix `U` will be stored in the matrix pointed to by `pA`. If, however, the actual
* metric `A` is desired, this parameter can be set to `true` to obtain `A` in the matrix pointed to by `pA`.
*
* @param[in] gamma Controls the trade-off between satisyfing the given constraints and minimizing the divergence
* from the prior metric.
* Higher `gamma` puts more weight on the constraints, while lower `gamma` enforces stronger regularization.
*
* @param[in] max_iter Maximum number of iterations.
*
* @param[in] conv_th Convergence threshold.
*
* @param[in] verbose If set to `true`, information about convergence will be written to `stderr` during learning.
*
* @return On success, returns the number of iterations needed until convergence.
* If this is equal to `max_iter`, the algorithm terminated prematurely without reaching convergence.
* In the case of error, one of the following error codes is returned:
*   - `ITML_ERR_A0` (not used anymore): The given prior metric is not positive-semidefinite.
*   - `ITML_ERR_NO_CONSTRAINTS`: No non-trivial constraints have been given.
*   - `ITML_ERR_INVALID_CONSTRAINTS`: Some of the given indices of similar or dissimilar pairs are out of bounds.
*   - `ITML_ERR_CHOL`: Cholesky decomposition of learned metric failed.
*/
template<typename F>
int itml(int n, int d, const F * pX, F * pA,
         int nb_pos, const itml_pair * pos, int nb_neg, const itml_pair * neg, F th_pos, F th_neg,
         bool return_metric = false, F gamma = 1.0, int max_iter = 1000, F conv_th = 0.001, bool verbose = false)
{
    // General local variables
    int i;
    int num_pos, num_neg, num_constraints; // effective number of positive/negative constraints
    const itml_pair * pair;
    const F eps = std::numeric_limits<F>::epsilon();

    // Wrapper around array pointers
    typedef Eigen::Matrix<F, Eigen::Dynamic, 1> Vector;
    typedef Eigen::Matrix<F, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Matrix;
    Eigen::Map<const Matrix> X(pX, n, d);
    Eigen::Map<Matrix> A(pA, d, d);
    Eigen::SelfAdjointView<Eigen::Map<Matrix>, Eigen::Upper> As = A.template selfadjointView<Eigen::Upper>();

    // Slice rows from X according to constraints
    Matrix vv(nb_pos + nb_neg, d);
    num_pos = num_neg = num_constraints = 0;
    for (i = 0, pair = pos; i < nb_pos; ++i, ++pair)
    {
        if (pair->i < 0 || pair->i >= n || pair->j < 0 || pair->j >= n)
            return ITML_ERR_INVALID_CONSTRAINTS;
        vv.row(num_constraints) = X.row(pair->i) - X.row(pair->j);
        if (vv.row(num_constraints).squaredNorm() > eps)
        {
            ++num_pos;
            ++num_constraints;
        }
    }
    for (i = 0, pair = neg; i < nb_neg; ++i, ++pair)
    {
        if (pair->i < 0 || pair->i >= n || pair->j < 0 || pair->j >= n)
            return ITML_ERR_INVALID_CONSTRAINTS;
        vv.row(num_constraints) = X.row(pair->i) - X.row(pair->j);
        if (vv.row(num_constraints).squaredNorm() > eps)
        {
            ++num_neg;
            ++num_constraints;
        }
    }
    if (num_constraints == 0)
        return ITML_ERR_NO_CONSTRAINTS;

    // Initialize ITML-specific variables
    int sign;
    F dist, alpha, beta, normsum, conv;
    F gamma_proj = std::isinf(gamma) ? 1 : gamma/(gamma+1);
    Vector Av(d);
    Vector lambda = Vector::Zero(num_constraints);
    Vector lambda_old = Vector::Zero(num_constraints);
    Vector bhat(num_constraints);
    bhat.head(num_pos).setConstant(th_pos);
    bhat.tail(num_neg).setConstant(th_neg);

    // Iterative optimization algorithm
    int it;
    for (it = 0; it < max_iter; ++it)
    {
        // Perform update for all constraints
        for (i = 0; i < num_constraints; ++i)
        {
            sign = (i < num_pos) ? 1 : -1;
            Av.noalias() = As * vv.row(i).transpose();
            dist = vv.row(i).dot(Av);
            alpha = std::min(lambda(i), sign * gamma_proj * (1/dist - 1/bhat(i)));
            lambda(i) -= alpha;
            beta = sign * alpha / (1 - sign * alpha * dist);
            bhat(i) = 1 / ((1 / bhat(i)) + sign * (alpha / gamma));
            As.rankUpdate(Av, beta);
        }

        // Check for convergence
        normsum = lambda.norm() + lambda_old.norm();
        if (normsum < eps)
        {
            conv = std::numeric_limits<F>::infinity();
            break;
        }
        conv = (lambda_old - lambda).cwiseAbs().sum();
        conv /= normsum;
        if (conv < conv_th)
            break;
        lambda_old = lambda;
        if (verbose)
            std::cerr << "itml iter: " << it << ", conv = " << conv << std::endl;
    }

    if (verbose)
    {
        if (it < max_iter)
            std::cerr << "itml converged at iter: " << it << ", conv = " << conv << std::endl;
        else
            std::cerr << "itml did not converge after " << it << " iterations, conv = " << conv << std::endl;
    }

    // Store computed metric or its Cholesky decomposition in pA
    A = As;
    if (!return_metric)
    {
        Eigen::LLT<Matrix, Eigen::Upper> llt(A);
        if (llt.info() != Eigen::Success)
            return ITML_ERR_CHOL;
        A = llt.matrixU().toDenseMatrix();
    }

    return it;
}

extern "C"
{

int itml_float(int n, int d, float * pX, float * pA,
               int nb_pos, const itml_pair * pos, int nb_neg, const itml_pair * neg, float th_pos, float th_neg,
               bool return_metric = false, float gamma = 1.0, int max_iter = 1000, float conv_th = 0.001, bool verbose = false)
{
    return itml(n, d, pX, pA, nb_pos, pos, nb_neg, neg, th_pos, th_neg, return_metric, gamma, max_iter, conv_th, verbose);
}

int itml_double(int n, int d, double * pX, double * pA,
                int nb_pos, const itml_pair * pos, int nb_neg, const itml_pair * neg, double th_pos, double th_neg,
                bool return_metric = false, double gamma = 1.0, int max_iter = 1000, double conv_th = 0.001, bool verbose = false)
{
    return itml(n, d, pX, pA, nb_pos, pos, nb_neg, neg, th_pos, th_neg, return_metric, gamma, max_iter, conv_th, verbose);
}

}


/**
 * \file boost/numeric/ublasx/operation/round.hpp
 *
 * \brief Apply the \c std::round function to a vector or matrix expression.
 *
 * Copyright (c) 2011, Marco Guazzone
 *
 * 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)
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */

#ifndef BOOST_NUMERIC_UBLASX_OPERATION_ROUND_HPP
#define BOOST_NUMERIC_UBLASX_OPERATION_ROUND_HPP

#include <boost/numeric/ublas/traits.hpp>
#include <boost/numeric/ublasx/expression/matrix_unary_functor.hpp>
#include <boost/numeric/ublasx/expression/vector_unary_functor.hpp>
#include <cmath>
#include <complex>

//#if __cplusplus > 199711L
// C++0x has ::std::round
//#   define BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_ ::std
//#else
// Use customer-made round function
#   define BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_ detail
//#endif // __cpluplus

namespace boost { namespace numeric { namespace ublasx {

using namespace ::boost::numeric::ublas;

namespace detail {

template <typename VectorExprT>
struct vector_round_functor_traits
{
	typedef VectorExprT input_expression_type;
	typedef typename vector_traits<input_expression_type>::value_type signature_argument_type;
	typedef signature_argument_type signature_result_type;
	typedef vector_unary_functor_traits<
				input_expression_type,
				signature_result_type (signature_argument_type)
			> unary_functor_expression_type;
	typedef typename unary_functor_expression_type::result_type result_type;
	typedef typename unary_functor_expression_type::expression_type expression_type;
};

template <typename MatrixExprT>
struct matrix_round_functor_traits
{
	typedef MatrixExprT input_expression_type;
	typedef typename matrix_traits<input_expression_type>::value_type signature_argument_type;
	typedef signature_argument_type signature_result_type;
	typedef matrix_unary_functor_traits<
				input_expression_type,
				signature_result_type (signature_argument_type)
			> unary_functor_expression_type;
	typedef typename unary_functor_expression_type::result_type result_type;
	typedef typename unary_functor_expression_type::expression_type expression_type;
};

//namespace /*<unnamed>*/ {

/// Auxiliary function used to replace ::std::round when that is not available.
template <typename T>
BOOST_UBLAS_INLINE
T round(T x)
{
	return (x > 0.0) ? ::std::floor(x + 0.5) : ::std::ceil(x - 0.5);
}

/// Auxiliary function used to replace ::std::round when that is not available.
template <typename T>
BOOST_UBLAS_INLINE
::std::complex<T> round(::std::complex<T> x)
{
	T r = (x.real() > 0.0) ? ::std::floor(x.real() + 0.5) : ::std::ceil(x.real() - 0.5);
	T i = (x.imag() > 0.0) ? ::std::floor(x.imag() + 0.5) : ::std::ceil(x.imag() - 0.5);

	return ::std::complex<T>(r,i);
}

//} // Namespace <unnamed>

} // Namespace detail

/**
 * \brief Applies the \c std::round function to a given vector expression.
 *
 * \tparam VectorExprT The type of the input vector expression.
 *
 * \param ve The input vector expression.
 * \return A vector expression representing the application of \c std::round to
 *  each element of \a ve.
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */
template <typename VectorExprT>
BOOST_UBLAS_INLINE
typename detail::vector_round_functor_traits<VectorExprT>::result_type round(vector_expression<VectorExprT> const& ve)
{
	typedef typename detail::vector_round_functor_traits<VectorExprT>::expression_type expression_type;
	typedef typename detail::vector_round_functor_traits<VectorExprT>::signature_argument_type signature_argument_type;
	typedef typename detail::vector_round_functor_traits<VectorExprT>::signature_result_type signature_result_type;

//	return expression_type(ve(), BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_::round<signature_result_type>);
//	signature_result_type (*)(ptr_round_fun)(signature_argument_type)(BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_::round);
	typedef signature_result_type(*fun_ptr_type)(signature_argument_type);
	fun_ptr_type ptr_round_fun(&BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_::round);
	return expression_type(ve(), ptr_round_fun);
}

/**
 * \brief Applies the \c std::round function to a given matrix expression.
 *
 * \tparam MatrixExprT The type of the input matrix expression.
 *
 * \param me The input matrix expression.
 * \return A matrix expression representing the application of \c std::round to
 *  each element of \a me.
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */
template <typename MatrixExprT>
BOOST_UBLAS_INLINE
typename detail::matrix_round_functor_traits<MatrixExprT>::result_type round(matrix_expression<MatrixExprT> const& me)
{
	typedef typename detail::matrix_round_functor_traits<MatrixExprT>::expression_type expression_type;
	typedef typename detail::matrix_round_functor_traits<MatrixExprT>::signature_argument_type signature_argument_type;
	typedef typename detail::matrix_round_functor_traits<MatrixExprT>::signature_result_type signature_result_type;

//	return expression_type(me(), BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_::round<signature_result_type>(signature_argument_type));
	typedef signature_result_type(*fun_ptr_type)(signature_argument_type);
	fun_ptr_type ptr_round_fun(&BOOST_NUMERIC_UBLASX_OPERATION_ROUND_NS_::round);
	return expression_type(me(), ptr_round_fun);
}

}}} // Namespace boost::numeric::ublasx

#endif // BOOST_NUMERIC_UBLASX_OPERATION_ROUND_HPP


// Copyright (C) 2019 Paul Keir
//
// 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)
#include <boost/yap/yap.hpp>

#include <boost/test/minimal.hpp>

namespace yap = boost::yap;

int test_main(int, char * [])
{
    // Test replacements(), which returns a transform object
    {
        using namespace boost::yap::literals;

        auto expr_in  = 1_p * 2_p;

        auto xform    = yap::replacements(6,9);
        auto expr_out = yap::transform(expr_in,xform);
        auto result   = yap::evaluate(expr_out);
        BOOST_CHECK(result == 54);

#ifndef _MSC_VER // Tsk, tsk.
        constexpr auto cxform    = yap::replacements(6);
        constexpr auto cexpr_out = yap::transform(1_p,cxform);
        constexpr auto cresult   = yap::evaluate(cexpr_out);
        static_assert(cresult == 6,"");
#endif
    }

    // Test evaluation(), which returns a transform object
    {
        using namespace boost::yap::literals;

        auto expr_in  = 1_p * 2_p;

        auto xform    = yap::evaluation(7,10);
        auto result   = yap::transform(expr_in,xform);
        BOOST_CHECK(result == 70);

#ifndef _MSC_VER // Tsk, tsk.
        constexpr auto cxform    = yap::evaluation(7);
        constexpr auto cresult   = yap::transform(1_p,cxform);
        static_assert(cresult == 7,"");
#endif
    }

    // Test replace_placeholders(), which returns an expression
    {
        using namespace boost::yap::literals;

        auto expr_in  = 1_p * 2_p;

        auto expr_out = yap::replace_placeholders(expr_in,8,11);
        auto result   = yap::evaluate(expr_out);
        BOOST_CHECK(result == 88);

#ifndef _MSC_VER // Tsk, tsk.
        constexpr auto cexpr_out = yap::replace_placeholders(1_p,8);
        constexpr auto cresult   = yap::evaluate(cexpr_out);
        static_assert(cresult == 8,"");
#endif
    }

    return 0;
}


#include "SpanningTree.h"
#include "defs.h"

#include <boost/graph/prim_minimum_spanning_tree.hpp>

#include <iostream>

SpanningTree::SpanningTree(const size_t size)
{
  tree.resize(size); // must be resize not reserve for prim's alg.
}

SpanningTree::~SpanningTree(void)
{

}

size_t
SpanningTree::size(void)
{
  return tree.size();
}

Vertex
SpanningTree::get(const size_t index)
{
  return tree.data()[index];
}

SpanningTree *
SpanningTree::fromGraph(UndirectedGraph *const g)
{
  SpanningTree *newTree = new SpanningTree(num_vertices(*g));
  prim_minimum_spanning_tree(*g, &newTree->tree[0]);
  return newTree;
}

void
SpanningTree::print(void) const
{
  for (size_t i = 0; i != tree.size(); ++i)
  {
    if (tree.data()[i] != i)
      std::cout << "parent[" << i << "] = " << tree.data()[i] << std::endl;
    else
      std::cout << "parent[" << i << "] = no parent" << std::endl;
  }
}

std::string
SpanningTree::toString(void) const
{
  std::ostringstream os;
  std::streambuf *coutbuf = std::cout.rdbuf();
  std::cout.rdbuf(os.rdbuf());

  print();

  std::cout.rdbuf(coutbuf);

  return os.str();
}


#include "Day06-MemoryReallocation.h"

#include <AdventOfCodeCommon/DisableLibraryWarningsMacros.h>

__BEGIN_LIBRARIES_DISABLE_WARNINGS
#include <boost/functional/hash/hash.hpp>

#include <unordered_set>
#include <algorithm>
__END_LIBRARIES_DISABLE_WARNINGS

namespace AdventOfCode
{
namespace Year2017
{
namespace Day06
{

template<typename T>
unsigned wrappingForwardDistance(const T& from, const T& to, size_t size)
{
    if (to > from)
    {
        return to - from;
    }
    else
    {
        return size - (from - to);
    }
}

void redistribute(MemoryBanks& banks)
{
    auto maxElementIter = std::max_element(banks.begin(), banks.end());
    unsigned maxValue = *maxElementIter;
    *maxElementIter = 0;

    for (auto iter = banks.begin(); iter != banks.end(); ++iter)
    {
        unsigned& bank = *iter;
        unsigned distance = wrappingForwardDistance(maxElementIter, iter, banks.size());

        unsigned increments = 0;

        if (maxValue >= distance)
        {
            // First increment
            ++increments;

            // All other subsequent increments
            unsigned remainingValue = maxValue - distance;
            increments += (remainingValue / banks.size());
        }

        bank += increments;
    }
}

unsigned numUniqueRedistributions(MemoryBanks banks)
{
    if (banks.empty())
    {
        return 1;
    }

    std::unordered_set<MemoryBanks, boost::hash<MemoryBanks>> banksOccurences;

    while (true)
    {
        bool insertionTookPlace;
        std::tie(std::ignore, insertionTookPlace) = banksOccurences.insert(banks);

        if (!insertionTookPlace)
        {
            break;
        }

        redistribute(banks);
    }

    return banksOccurences.size();
}

unsigned cyclesUntilReoccurs(MemoryBanks banks)
{
    if (banks.empty())
    {
        return 1;
    }

    std::vector<MemoryBanks> allCyclesInOrder;

    while (true)
    {
        // Could also store the unordered_set (in the same way as in part 1) in addition to the vector to improve lookup time here
        auto foundIter = std::find(allCyclesInOrder.begin(), allCyclesInOrder.end(), banks);
        if (foundIter != allCyclesInOrder.end())
        {
            return allCyclesInOrder.end() - foundIter;
        }

        allCyclesInOrder.push_back(banks);

        redistribute(banks);
    }
}

}
}
}


// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2008 Steven Watanabe
//
// 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 tutorial.cpp

\brief Basic tutorial using SI units.

\details
Tutorial
Defines a function that computes the work, in joules,
done by exerting a force in newtons over a specified distance
in meters and outputs the result to std::cout.

Also code for computing the complex impedance
using std::complex<double> as the value type.

Output:
@verbatim
//[tutorial_output
F  = 2 N
dx = 2 m
E  = 4 J

V   = (12.5,0) V
I   = (3,4) A
Z   = (1.5,-2) Ohm
I*Z = (12.5,0) V
I*Z == V? true
//]
@endverbatim
*/

//[tutorial_code
#include <complex>
#include <iostream>

#include <boost/typeof/std/complex.hpp>

#include <boost/units/systems/si/energy.hpp>
#include <boost/units/systems/si/force.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/electric_potential.hpp>
#include <boost/units/systems/si/current.hpp>
#include <boost/units/systems/si/resistance.hpp>
#include <boost/units/systems/si/io.hpp>

using namespace boost::units;
using namespace boost::units::si;

quantity<energy>
work(const quantity<force>& F, const quantity<length>& dx)
{
    return F * dx; // Defines the relation: work = force * distance.
}

int main()
{
    /// Test calculation of work.
    quantity<force>     F(2.0 * newton); // Define a quantity of force.
    quantity<length>    dx(2.0 * meter); // and a distance,
    quantity<energy>    E(work(F,dx));  // and calculate the work done.

    std::cout << "F  = " << F << std::endl
              << "dx = " << dx << std::endl
              << "E  = " << E << std::endl
              << std::endl;

    /// Test and check complex quantities.
    typedef std::complex<double> complex_type; // double real and imaginary parts.

    // Define some complex electrical quantities.
    quantity<electric_potential, complex_type> v = complex_type(12.5, 0.0) * volts;
    quantity<current, complex_type>            i = complex_type(3.0, 4.0) * amperes;
    quantity<resistance, complex_type>         z = complex_type(1.5, -2.0) * ohms;

    std::cout << "V   = " << v << std::endl
              << "I   = " << i << std::endl
              << "Z   = " << z << std::endl
              // Calculate from Ohm's law voltage = current * resistance.
              << "I * Z = " << i * z << std::endl
              // Check defined V is equal to calculated.
              << "I * Z == V? " << std::boolalpha << (i * z == v) << std::endl
              << std::endl;
    return 0;
}
//]


//          Copyright Alain Miniussi 2014.
// 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)

// Authors: Alain Miniussi

#include <vector>
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <functional>

#include <boost/mpi/communicator.hpp>
#include <boost/mpi/collectives.hpp>
#include <boost/mpi/environment.hpp>
#include <boost/mpi/cartesian_communicator.hpp>

#include <boost/test/minimal.hpp>

namespace mpi = boost::mpi;

struct topo_minimum {
  mpi::cartesian_dimension
  operator()(mpi::cartesian_dimension const& d1,
             mpi::cartesian_dimension const& d2 ) const {
    return mpi::cartesian_dimension(std::min(d1.size, d2.size),
                                    d1.periodic && d2.periodic);
  }
};

std::string topology_description( mpi::cartesian_topology const&  topo ) {
  std::ostringstream out;
  std::copy(topo.begin(), topo.end(), std::ostream_iterator<mpi::cartesian_dimension>(out, " "));
  out << std::flush;
  return out.str();
}

// Check that everyone agrees on the coordinates
void test_coordinates_consistency( mpi::cartesian_communicator const& cc,
                                   std::vector<int> const& coords )
{
  cc.barrier(); // flush IOs for nice printing
  bool master = cc.rank() == 0;
  if (master) {
    std::cout << "Test coordinates consistency.\n";
  }
  for(int p = 0; p < cc.size(); ++p) {
    std::vector<int> min(cc.ndims());
    std::vector<int> local(cc.coordinates(p));
    mpi::reduce(cc, &local.front(), local.size(),
                &(min[0]), mpi::minimum<int>(), p);
    cc.barrier();
    if (p == cc.rank()) {
      BOOST_CHECK(std::equal(coords.begin(), coords.end(), min.begin()));
      std::ostringstream out;
      out << "proc " << p << " at (";
      std::copy(min.begin(), min.end(), std::ostream_iterator<int>(out, " "));
      out << ")\n";
      std::cout << out.str();
    }
  }
}

void test_shifted_coords( mpi::cartesian_communicator const& cc, int pos,  mpi::cartesian_dimension desc, int dim )
{
  if (desc.periodic) {
    for (int i = -(desc.size); i < desc.size; ++i) {
      std::pair<int,int> rks = cc.shifted_ranks(dim, i);
      int src = cc.coordinates(rks.first)[dim];
      int dst = cc.coordinates(rks.second)[dim];
      if (pos == (dim/2)) {
        std::ostringstream out;
        out << "Rank " << cc.rank() << ", dim. " << dim << ", pos " << pos << ", in " << desc << ' ';
        out << "shifted pos: " << src << ", " << dst << '\n';
        std::cout << out.str();
      }
    }
  }
}

void test_shifted_coords( mpi::cartesian_communicator const& cc)
{
  cc.barrier(); // flush IOs for nice printing
  std::vector<int> coords;
  mpi::cartesian_topology topo(cc.ndims());
  cc.topology(topo, coords);
  bool master = cc.rank() == 0;
  if (master) {
    std::cout << "Testing shifts with topology " << topo << '\n';
  }
  for(int i = 0; i < cc.ndims(); ++i) {
    if (master) {
      std::cout << " for dimension " << i << ": " << topo[i] << '\n';
    }
    test_shifted_coords( cc, coords[i], topo[i], i );
  }
}

void test_topology_consistency( mpi::cartesian_communicator const& cc)
{
  cc.barrier(); // flush IOs for nice printing
  mpi::cartesian_topology itopo(cc.ndims());
  mpi::cartesian_topology otopo(cc.ndims());
  std::vector<int>  coords(cc.ndims());
  cc.topology(itopo, coords);
  bool master = cc.rank() == 0;
  if (master) {
    std::cout << "Test topology consistency of" << itopo << "(on master)\n";
    std::cout << "Check that everyone agrees on the dimensions.\n";
  }
  mpi::all_reduce(cc,
                  &(itopo[0]), itopo.size(), &(otopo[0]),
                  topo_minimum());
  BOOST_CHECK(std::equal(itopo.begin(), itopo.end(), otopo.begin()));
  if (master) {
    std::cout << "We agree on " << topology_description(otopo) << '\n';
  }
  test_coordinates_consistency( cc, coords );
}

void test_cartesian_topology( mpi::cartesian_communicator const& cc)
{
  BOOST_CHECK(cc.has_cartesian_topology());
  for( int r = 0; r < cc.size(); ++r) {
    cc.barrier();
    if (r == cc.rank()) {
      std::vector<int> coords = cc.coordinates(r);
      std::cout << "Process of cartesian rank " << cc.rank()
                << " has coordinates (";
      std::copy(coords.begin(), coords.end(), std::ostream_iterator<int>(std::cout," "));
      std::cout << ")\n";
    }
  }
  test_topology_consistency(cc);
  test_shifted_coords(cc);
  std::vector<int> even;
  for(int i = 0; i < cc.ndims(); i += 2) {
    even.push_back(i);
  }
  cc.barrier();
  mpi::cartesian_communicator cce(cc, even);
}

void test_cartesian_topology( mpi::communicator const& world, mpi::cartesian_topology const& topo)
{
  mpi::cartesian_communicator cc(world, topo, true);
  if (cc) {
    BOOST_CHECK(cc.has_cartesian_topology());
    BOOST_CHECK(cc.ndims() == int(topo.size()));
    if (cc.rank() == 0) {
      std::cout << "Asked topology " << topo << ", got " << cc.topology() << '\n';
    }
    test_cartesian_topology(cc);
  } else {
    std::ostringstream out;
    out << world.rank() << " was left outside the cartesian grid\n";
    std::cout << out.str();
  }
}

int test_main(int argc, char* argv[])
{
  mpi::environment env(argc, argv);

  mpi::communicator world;
  int const ndim = world.size() >= 24 ? 3 : 2;
  mpi::cartesian_topology topo(ndim);
  typedef mpi::cartesian_dimension cd;
  if (topo.size() == 3) {
    topo[0] = cd(2,true);
    topo[1] = cd(3,false);
    topo[2] = cd(4, true);
  } else {
    if (world.size() >= 6) {
      topo[0] = cd(2,true);
      topo[1] = cd(3, false);
    } else {
      topo[0] = cd(1,true);
      topo[1] = cd(1, false);
    }
  }
  test_cartesian_topology( world, topo);
#if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
  world.barrier();
  if (world.rank()==0) {
    std::cout << "Testing move constructor.\n";
  }
  test_cartesian_topology( world, std::move(topo));
#endif
  return 0;
}


/* eigen_require.hpp
 *
 *  Created on: 27 Jun 2019
 *      Author: Fabian Meyer
 */

#ifndef LSQCPP_EIGEN_REQUIRE_HPP_
#define LSQCPP_EIGEN_REQUIRE_HPP_

#include <Eigen/Geometry>
#include <catch2/catch.hpp>

#define REQUIRE_MATRIX_APPROX(a, b, eps) do {                                 \
        REQUIRE(a.cols() == b.cols());                                        \
        REQUIRE(a.rows() == b.rows());                                        \
        for(Index _c = 0; _c < a.cols(); ++_c)                                \
            for(Index _r = 0; _r < a.rows(); ++_r)                            \
                REQUIRE(Approx(a(_r, _c)).margin(eps) == b(_r, _c));          \
    } while(0)

#define REQUIRE_MATRIX(a, b) do {                                             \
        REQUIRE(a.cols() == b.cols());                                        \
        REQUIRE(a.rows() == b.rows());                                        \
        for(Index _c = 0; _c < a.cols(); ++_c)                                \
            for(Index _r = 0; _r < a.rows(); ++_r)                            \
                REQUIRE(a(_r, _c) == b(_r, _c));                              \
    } while(0)

#define REQUIRE_NOT_MATRIX_APPROX(a, b, eps) do {                             \
        REQUIRE(a.cols() == b.cols());                                        \
        REQUIRE(a.rows() == b.rows());                                        \
        for(Index _c = 0; _c < a.cols(); ++_c)                                \
            for(Index _r = 0; _r < a.rows(); ++_r)                            \
                REQUIRE(Approx(a(_r, _c)).margin(eps) != b(_r, _c));          \
    } while(0)

#define REQUIRE_NOT_MATRIX(a, b) do {                                         \
        REQUIRE(a.cols() == b.cols());                                        \
        REQUIRE(a.rows() == b.rows());                                        \
        for(Index _c = 0; _c < a.cols(); ++_c)                                \
            for(Index _r = 0; _r < a.rows(); ++_r)                            \
                REQUIRE(a(_r, _c) != b(_r, _c));                              \
    } while(0)

#endif


#include <iostream>
#include <unistd>

#include <boost/numeric/mtl/mtl.hpp>
#include <boost/timer.hpp>

/*
  First run: 87ns + 74ns dynamic types
             67ns + 42ns static types (r6809) (CET needs 52ns if run alone???)
             71ns + 46ns static types with unrolled by hand (r6810)
*/

#define STATIC_TYPES

#ifdef STATIC_TYPES
   typedef mtl::dense_vector<double, mtl::parameters<mtl::tag::col_major, mtl::fixed::dimension<3>, true> > vec;
#else
   typedef mtl::dense_vector<double> vec;
#endif

using namespace std;

int main()
{

    vec u(3), v(3), w(3), x(3);

    u= 3., 4, 6; v= 7, 9, 3; w= 7, 2, 4;

    const int rep= 10000000;
    boost::timer time;
    for(int i= 0; i < rep; i++) {
	x= dot(v, u) * w + 4.0 * v + 2 * w;
    }
    std::cout << "Compute time (CET) = " << 1000000000.*time.elapsed() / rep << "ns" << std::endl;

    time.restart();
    for(int i= 0; i < rep; i++) {
	x= dot(v, u) * (w+= 4.0 * v + 2 * w);
    }
    std::cout << "Compute time (RET) = " << 1000000000.*time.elapsed() / rep << "ns" << std::endl;

    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
//==============================================================================
// cover for functor ellik in scalar mode
#include <nt2/elliptic/include/functions/ellipke.hpp>

#include <boost/simd/sdk/simd/io.hpp>
#include <cmath>
#include <iostream>
#include <boost/simd/sdk/simd/native.hpp>
#include <nt2/include/constants/eps.hpp>
#include <nt2/include/functions/ellpk.hpp>
#include <nt2/include/functions/ellpe.hpp>
#include <nt2/include/constants/zero.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/sdk/meta/scalar_of.hpp>
#include <nt2/sdk/unit/args.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/cover.hpp>
#include <vector>

template < class T > struct ellipk1
{
  T operator()(const T & x)
  {
    typedef typename nt2::meta::scalar_of<T>::type sT;
    T a1 = nt2::Zero<T>();
    T a0 = nt2::ellipke(x, nt2::Eps<sT>(),a1);
    return a0;
  }
};

 template < class T > struct ellipk2
{
  T operator()(const T & x)
  {
    typedef typename nt2::meta::scalar_of<T>::type sT;
    T a1 = nt2::Zero<T>();
    nt2::ellipke(x, nt2::Eps<sT>(), a1);
    return a1;
  }
};

NT2_TEST_CASE_TPL(ellipke_0,  NT2_SIMD_REAL_TYPES)
{
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;

  using nt2::unit::args;
  const std::size_t NR = args("samples", NT2_NB_RANDOM_TEST);
  const double ulpd = args("ulpd", 2);

  const T min0 = args("min0", T(0));
  const T max0 = args("max0", T(1));
  std::cout << "Argument samples #0 chosen in range: [" << min0 << ",  " << max0 << "]" << std::endl;
  NT2_CREATE_BUF(a0,T, NR, min0, max0);

  std::vector<T> ref1(NR), ref2(NR);
  for(std::size_t i=0; i!=NR; ++i)
  {
    nt2::ellipke(a0[i], nt2::Eps<T>(),ref1[i],ref2[i]);
  }

  NT2_COVER_FN_ULP_EQUAL(ellipk1<vT>() , ((vT, a0)), ref1, ulpd);
  NT2_COVER_FN_ULP_EQUAL(ellipk2<vT>() , ((vT, a0)), ref2, ulpd);

}


//==============================================================================
//         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
//==============================================================================
#define NT2_UNIT_MODULE "nt2 polynom toolbox - polyval/scalar Mode"

//////////////////////////////////////////////////////////////////////////////
// unit test behavior of polynom components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created  by jt the 06/03/2011
///
#include <nt2/include/functions/polyval.hpp>
#include <nt2/include/functions/polyfit.hpp>
#include <nt2/include/functions/complexify.hpp>
#include <nt2/include/functions/isulpequal.hpp>
#include <boost/type_traits/is_same.hpp>
#include <nt2/sdk/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/memory/buffer.hpp>
#include <nt2/include/constants/real.hpp>
#include <nt2/table.hpp>

#include <boost/array.hpp>

NT2_TEST_CASE_TPL ( polyval_real__1_0,  NT2_REAL_TYPES)
{
 typedef std::complex<T> cT;
  using nt2::polyval;
  using nt2::tag::polyval_;
  nt2::table<cT> x =  nt2::complexify(nt2::_(T(1), T(4)));
  nt2::table<cT> p =  nt2::complexify(nt2::_(T(1), T(4)));
  NT2_DISPLAY(polyval(p, cT(1)));
  NT2_TEST_EQUAL(polyval(p, cT(1)), cT(10));
  NT2_TEST_EQUAL(polyval(p, cT(2)), cT(26));

  NT2_DISPLAY(polyval(p, nt2::complexify(nt2::_(T(1), T(4)))));
  T cv[] = { 10, 26, 58, 112 };
  nt2::table<T> v(nt2::of_size(1, 4), &cv[0], &cv[4]);
  nt2::table<cT> vv =  nt2::complexify(v);
  NT2_TEST(nt2::isulpequal(vv, polyval(p,x), 0.5));
} // end of test for floating_

// NT2_TEST_CASE_TPL ( polyval_real__2_0,  NT2_REAL_TYPES)
// {
//   using nt2::polyfit;
//   using nt2::tag::polyfit_;
//   nt2::table<T> x =  nt2::reshape(nt2::_(T(1), T(4)), nt2::of_size(2, 2));
//   nt2::table<T> p =  nt2::_(T(1), T(3));
//   std::cout << 0 << std::endl;
//   nt2::table<T> y =  nt2::polyval(p, x);
//   y(nt2::end_) = T(26);
//   std::cout << 1 << std::endl;
//   nt2::table<T> r;
//   size_t df;
//   T normr;
//   nt2::table<T> mu;
//   nt2::tie(p, r, df, normr, mu) = polyfit(x, y, 2);
//   std::cout << 2 << std::endl;
//   NT2_DISPLAY(p);
//   NT2_DISPLAY(r);
//   NT2_DISPLAY(df);
//   NT2_DISPLAY(normr);
//   NT2_DISPLAY(mu);
//   NT2_DISPLAY(polyval(p, (x-mu(1))/mu(2)));
//   NT2_DISPLAY(polyval(p, x, mu));
//   nt2::table<T> delta;
//   nt2::table<T> xx =  nt2::reshape(nt2::_(T(1), T(0.5), T(4.5)), 2, 4);
// //  y = polyval(p, xx, r, df, normr, mu);
//   NT2_DISPLAY(y);
//   tie(y, delta) = polyval(p, xx, r, df, normr);
//   NT2_DISPLAY(y);
//   NT2_DISPLAY(delta);
// } // end of test for floating_

// NT2_TEST_CASE_TPL ( polyval_real__3_0,  NT2_REAL_TYPES)
// {
//   using nt2::polyfit;
//   using nt2::tag::polyfit_;
//   nt2::table<T> x =  nt2::_(T(1), T(4));
//   nt2::table<T> p =  nt2::_(T(1), T(3));
//   std::cout << 0 << std::endl;
//   nt2::table<T> y =  nt2::polyval(p, x);
//   std::cout << 1 << std::endl;
//   nt2::table<T> r;
//   T df, normr;
//   nt2::table<T> mu;
//   nt2:: polyfit_infos<T> s;
//   nt2::tie(p, s) = polyfit(x, y);
//   std::cout << 2 << std::endl;
//   NT2_DISPLAY(p);
//   NT2_DISPLAY(s.r);
//   NT2_DISPLAY(s.df);
//   NT2_DISPLAY(s.normr);
// //   NT2_DISPLAY(mu);
// //   NT2_DISPLAY(polyval(p, (x-mu(1))/mu(2)));
// //   NT2_DISPLAY(polyval(p, x, mu));
// //   nt2::table<T> delta;
// //   nt2::table<T> xx =  nt2::_(T(1), T(0.5), T(4));
// //   tie(y, delta) = polyval(p, xx, r, df, normr, mu);
// //   NT2_DISPLAY(y);
// //   NT2_DISPLAY(delta);
// } // end of test for floating_


#include "eigentypes.h"
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/external/eigen/eigen_algebra.hpp>

#ifndef RUNDOWN
#define RUNDOWN

template < typename Stepper, typename Model, typename Observer >
struct rundown{
  rundown(Model & state, double start, double end, double error = 1e-10 , double firststep = 0.01){
    using namespace boost::numeric::odeint;

    // define stepper with error control works only with C++11 standard!
    auto cstepper = make_controlled( error , error , Stepper() );

  // check whether input scale is lower then output scale:
  if (end>start)
    integrate_adaptive(cstepper, Model(), state, start, end, abs(firststep), Observer());

  else{ // start integration across thresholds

  // get thresholds from state type
  Eigen::VectorXd scales= state.logthresholds();

  double here = start; // helping variable

  // integrate to next threshold
  for (int i=scales.size()-1; i>=0; i--){
    if (scales[i] > end){
      integrate_adaptive(cstepper, Model(), state, here, scales[i], -abs(firststep), Observer());
      state.integrate_out(i);
      here = scales[i];
    }
    else integrate_adaptive(cstepper, Model(), state, here, end, -abs(firststep), Observer());
  }

  // integrate to end
  if (scales[0] > end)
    integrate_adaptive(cstepper, Model(), state, scales[0], end, -abs(firststep), Observer());
  } // else
  } // contructor
};

// specialisation without observer
template < typename Stepper, typename Model >
struct rundown <Stepper, Model, void>{
  rundown(Model & state, double start, double end, double error = 1e-10 , double firststep = 0.01){
      // define stepper with error control works only with C++11 standard!
    auto cstepper = make_controlled( error , error , Stepper() );
  using namespace boost::numeric::odeint;

  // check whether input scale is lower then output scale:
  if (end>start)
    integrate_adaptive(cstepper, Model(), state, start, end, abs(firststep));

  else{ // start integration across thresholds

  // get thresholds from state type
    Eigen::VectorXd scales= state.logthresholds();

  double here = start; // helping vairable

  // integrate to next threshold
  for (int i=scales.size()-1; i>=0; i--){
    if (scales[i] > end){
      integrate_adaptive(cstepper, Model(), state, here, scales[i], -abs(firststep));
      state.integrate_out(i);
      here = scales[i];
    }
    else integrate_adaptive(cstepper, Model(), state, here, end, -abs(firststep));
  }

  // integrate to end
  if (scales[0] > end)
    integrate_adaptive(cstepper, Model(), state, scales[0], end, -abs(firststep));
  } // else
  } // contructor
};

#endif


#include "test_number.h"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_real.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <type_traits>
#include <iostream>

template<unsigned>
struct parse_int;

template<unsigned int Radix>
struct parse_int_base {
    boost::spirit::qi::int_parser<long long, Radix> parser;
};

template<>
struct parse_int<10> : private parse_int_base<10>
{
    template<typename It>
    bool run(It b, It e) const
    {
        long long result = 0;
        return (boost::spirit::qi::parse(b, e, parser, result) && b == e);
    }
};

template<>
struct parse_int<8> : private parse_int_base<8>
{
    template<typename It>
    bool run(It b, It e) const
    {
        long long result = 0;
        return (boost::spirit::qi::parse(b, e, parser, result) && b == e);
    }
};

template<>
struct parse_int<16> : private parse_int_base<16>
{
    template<typename It>
    bool run(It b, It e) const
    {
        long long result = 0;
        return (boost::spirit::qi::parse(b, e, parser, result) && b == e);
    }
};

struct parse_real {
    template<typename It>
    bool operator () (It from, It to) const
    {
        long double d = 0.0;
        return boost::spirit::qi::parse(from, to, parser, d) && from == to;
    }

private:
    using parser_type = boost::spirit::qi::real_parser<long double>;
    parser_type parser;

};

//template <typename RetType = int, unsigned Radix = 10, typename Parser = typename boost::spirit::qi::int_parser<RetType, Radix> >
template <unsigned Radix = 10, typename It = std::string::const_iterator>
bool is_integer(It from, It to)
{
    using parser_type = parse_int<Radix>;

    static const parser_type parser = parse_int<Radix>{};

    return  parser.run(from, to);

}
#if 0
int redix_type(const char* type) {
    static const std::string types[] = {
        std::string{"dec"}, std::string{"hex"}, std::string{"oct"}
    };
    if (type == types[0]) {
        return 10;
    } else if (type == types[1]) {
        return 16;
    } else if (type == types[2]) {
        return 8;
    } else {
        return 10;
    }
}
#endif
int guess_type(const std::string& str, std::string::size_type& offset) {

    if (str.size() > 1 && str[0] == '0' && std::isdigit(str[1])) {  // maybe octal
        offset = 1;
        return 8;
    }
    if (str.size() > 2 && str[0] == '0') {
        if (str[1] == 'x' || str[1] == 'X') {
            offset = 2;
            return 16;
        }
    }
    return -1;
}

bool predicte(std::string str)
{
    std::string::size_type off = 0;
    int t = guess_type(str, off);
    if (t != -1) {
        switch (t) {
        case 8:
            return is_integer<8>(str.cbegin()+off, str.cend());
        case 16:
            return is_integer<16>(str.cbegin() + off, str.cend());
        default:
            break;
        }
    }
    // we don't know what it is, so just guess
    return is_integer<10>(str.cbegin(), str.cend()) || is_integer<16>(str.cbegin(), str.cend())
        || is_integer<8>(str.cbegin(), str.cend());
}

bool is_number(std::string str)
{
    static const parse_real pr = parse_real{};

    boost::algorithm::trim(str);    // remove any leading and trailing spaces - so we would only work on whats mater
    if (str.empty()) {
        return false;
    }
    return predicte(str) || pr(str.cbegin(), str.cend());
}


/*
 *
 * Copyright (c) Toon Knapen & Kresimir Fresl 2003
 *
 * Permission to copy, modify, use and distribute this software
 * for any non-commercial or commercial purpose is granted provided
 * that this license appear on all copies of the software source code.
 *
 * Authors assume no responsibility whatsoever for its use and makes
 * no guarantees about its quality, correctness or reliability.
 *
 * KF acknowledges the support of the Faculty of Civil Engineering,
 * University of Zagreb, Croatia.
 *
 */

#ifndef BOOST_NUMERIC_BINDINGS_LAPACK_LAPACK_HPP
#define BOOST_NUMERIC_BINDINGS_LAPACK_LAPACK_HPP

// linear systems

#include <boost/numeric/bindings/lapack/gesv.hpp>
#include <boost/numeric/bindings/lapack/posv.hpp>
#include <boost/numeric/bindings/lapack/ppsv.hpp>
#include <boost/numeric/bindings/lapack/sysv.hpp>
#include <boost/numeric/bindings/lapack/spsv.hpp>
#include <boost/numeric/bindings/lapack/hesv.hpp>
#include <boost/numeric/bindings/lapack/hpsv.hpp>

// linear systems

#include <boost/numeric/bindings/lapack/gels.hpp>
#include <boost/numeric/bindings/lapack/gelss.hpp>
#include <boost/numeric/bindings/lapack/gelsd.hpp>

// eigenproblems

#include <boost/numeric/bindings/lapack/gees.hpp>
#include <boost/numeric/bindings/lapack/trevc.hpp>
#include <boost/numeric/bindings/lapack/trexc.hpp>
#include <boost/numeric/bindings/lapack/hbev.hpp>
#include <boost/numeric/bindings/lapack/syev.hpp>

// SVD

#include <boost/numeric/bindings/lapack/gesvd.hpp>
#include <boost/numeric/bindings/lapack/gesdd.hpp>
#include <boost/numeric/bindings/lapack/sygv.hpp>

// Miscellaneous
// QR
#include <boost/numeric/bindings/lapack/geqrf.hpp>
#include <boost/numeric/bindings/lapack/ormqr.hpp>
#include <boost/numeric/bindings/lapack/orgqr.hpp>

#endif // BOOST_NUMERIC_BINDINGS_LAPACK_LAPACK_HPP


/*
This tutorial demonstrates how to extract NARF descriptors at NARF keypoint positions from a range image.
The executable enables us to load a point cloud from disc (or create it if not given),
extract interest points on it and then calculate the descriptors at these positions.
It then visualizes these positions, both in an image and a 3D viewer.
*/

#include "stdafx.h"
#include <iostream>
#include <boost/thread/thread.hpp>
#include <pcl/point_types.h>
#include <pcl/range_image/range_image.h>
#include <pcl/keypoints/narf_keypoint.h>
#include <pcl/features/narf_descriptor.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/visualization/range_image_visualizer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include "KinnectGrabber.h"

int main()
{
	pcl::io::OpenNI2Grabber grabber;
	KinnectGrabber<pcl::PointXYZRGBA> v(grabber);
	v.run();

	pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
	cloud = v.getLatestCloud();

	if (cloud == nullptr)
	{
		std::cout << "Get cloud failed!" << std::endl;
	}
	else
	{
		// get point cloud
		const pcl::PointCloud<pcl::PointXYZRGBA>& point_cloud = *cloud;

		// Create a range image of a 1deg angular resolution
		float angularResolution = (float)(0.1f * (M_PI / 180.0f));  //   0.1 degree in radians
		float maxAngleWidth = (float)(360.0f * (M_PI / 180.0f));  // 360.0 degree in radians
		float maxAngleHeight = (float)(180.0f * (M_PI / 180.0f));  // 180.0 degree in radians

		Eigen::Affine3f sensorPose = (Eigen::Affine3f)Eigen::Translation3f(0.0f, 0.0f, 0.0f);
		pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
		float noiseLevel = 0.05;
		float minRange = 0.0f;
		int borderSize = 1;

		boost::shared_ptr<pcl::RangeImage> range_image_ptr(new pcl::RangeImage);
		pcl::RangeImage& range_image = *range_image_ptr;
		range_image.createFromPointCloud(point_cloud, angularResolution, maxAngleWidth, maxAngleHeight,
			sensorPose, coordinate_frame, noiseLevel, minRange, borderSize);

		pcl::PointCloud<pcl::PointWithViewpoint> far_ranges;
		range_image.integrateFarRanges(far_ranges);

		// -----Open 3D viewer and add point cloud-----
		// --------------------------------------------
		pcl::visualization::PCLVisualizer viewer("3D Viewer");
		viewer.setBackgroundColor(1, 1, 1);
		pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> range_image_color_handler(range_image_ptr, 0, 0, 0);
		viewer.addPointCloud(range_image_ptr, range_image_color_handler, "range image");
		viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");
		//viewer.addCoordinateSystem (1.0f, "global");
		//PointCloudColorHandlerCustom<PointType> point_cloud_color_handler (point_cloud_ptr, 150, 150, 150);
		//viewer.addPointCloud (point_cloud_ptr, point_cloud_color_handler, "original point cloud");
		viewer.initCameraParameters();
		setViewerPose(viewer, range_image.getTransformationToWorldSystem());

		// -----Show range image-----
		// --------------------------
		pcl::visualization::RangeImageVisualizer range_image_widget("Range image");
		range_image_widget.showRangeImage(range_image);

		// extract NARF keypoints
		pcl::RangeImageBorderExtractor range_image_border_extrctor;
		pcl::NarfKeypoint narf_keypoint_detector;
		narf_keypoint_detector.setRangeImageBorderExtractor(&range_image_border_extrctor);
		narf_keypoint_detector.setRangeImage(&range_image);
		narf_keypoint_detector.getParameters().support_size = 0.2f;

		pcl::PointCloud<int> keypoint_indices;
		narf_keypoint_detector.compute(keypoint_indices);
		std::cout << "Found" << keypoint_indices.size() << "key points.\n";

		// show keypoints in 3D viewer
		pcl::PointCloud<pcl::PointXYZRGBA>::Ptr keypoints_ptr(new pcl::PointCloud<pcl::PointXYZRGBA>);
		pcl::PointCloud<pcl::PointXYZRGBA>& keypoints = *keypoints_ptr;
		keypoints.points.resize(keypoint_indices.points.size());
		for (size_t i= 0; i < keypoint_indices.points.size(); ++i)
		{
			keypoints.points[i].getVector3fMap() = range_image.points[keypoint_indices.points[i]].getVector3fMap();
		}
		pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGBA> keypoints_color_handler(keypoints_ptr, 0, 255, 0);
		viewer.addPointCloud<pcl::PointXYZRGBA>(keypoints_ptr, keypoints_color_handler, "keypoints");
		viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "keypoints");

		// extract NARF descriptors for interet points
		std::vector<int> keypoint_indices2;
		keypoint_indices2.resize(keypoint_indices.size());
		for (size_t i = 0; i < keypoint_indices.size(); ++i)
		{
			keypoint_indices2[i] = keypoint_indices[i];
		}
		pcl::NarfDescriptor narf_descriptor(&range_image, &keypoint_indices2);
		narf_descriptor.getParameters().support_size = 0.2f;
		narf_descriptor.getParameters().rotation_invariant = true;
		pcl::PointCloud<pcl::Narf36> narf_descriptors;
		narf_descriptor.compute(narf_descriptors);

		std::cout << "Extracted" << narf_descriptors.size() << "descriptors for "
			<< keypoint_indices.points.size() << " keypoints.\n";

		while (!viewer.wasStopped())
		{
			range_image_widget.spinOnce();
			viewer.spinOnce();
			boost::this_thread::sleep(boost::posix_time::microseconds(100));;
		}
	}

	return 0;
}


// File: element_matrix.cpp

#include <iostream>
#include <vector>
#include <boost/numeric/mtl/mtl.hpp>

using namespace mtl;

template <typename Matrix>
void fill(Matrix& m)
{
    // Matrices are not initialized by default
    m= 0.0;

    // Type of m's elements
    typedef typename Collection<Matrix>::value_type value_type;

    // Create inserter for matrix m
    // Existing values are not overwritten but inserted
    mat::inserter<Matrix, update_plus<value_type> > ins(m, 3);

    // Define element matrix (array)
    double m1[2][2]= {{1.0, -.4}, {-0.5, 2.0}};

    // Corresponding indices of the elements
    std::vector<int> v1(2);
    v1[0]= 1; v1[1]= 3;

    // Insert element matrix
    ins << element_array(m1, v1);

    // Insert same array with different indices
    v1[0]= 0; v1[1]= 2;
    ins << element_array(m1, v1);

    // Use element matrix type with dynamic size
    dense2D<double> m2(2, 3);
    m2[0][0]= 1; m2[0][1]= 0.2; m2[0][2]= 0.1;
    m2[1][0]= 2; m2[1][1]= 1.2; m2[1][2]= 1.1;

    // Vector for column indices
    dense_vector<int> v2(3);
    // Indices can be out of order
    v2[0]= 4; v2[1]= 1; v2[2]= 3;

    // Use element_matrix and separate vectors for row and column indices
    ins << element_matrix(m2, v1, v2);
}

int main(int, char**)
{
    // Matrices of different types
    compressed2D<double>              A(5, 5);
    dense2D<double>                   B(5, 5);
    morton_dense<float, morton_mask>  C(5, 5);

    // Fill the matrices generically
    fill(A); fill(B); fill(C);
    std::cout << "A is \n" << with_format(A, 4, 3)
	      << "\nB is \n" << with_format(B, 4, 3)
	      << "\nC is \n" << with_format(C, 4, 3);

    return 0;
}


#include "graph_map/map_node.h"
#include <boost/serialization/export.hpp>
BOOST_CLASS_EXPORT(perception_oru::libgraphMap::MapNode)
namespace perception_oru{
namespace libgraphMap{
Node::Node(){
  static unsigned int num_nodes=0;
  id_=num_nodes;
  num_nodes++;
  pose_=Eigen::Affine3d::Identity();
}

Affine3d Node::GetPose() const{
  return pose_;
}
bool Node::operator ==(const Node& node_compare){
  if(id_==node_compare.id_ && pose_.isApprox(node_compare.pose_))
    return true;
  else return false;
}

bool Node::WithinRadius(const Affine3d &pose, const double &radius){

  double distance= Eigen::Vector3d(pose.translation()-pose_.translation()).norm();
  if(distance<radius)
    return true;
  else return false;
}

MapNode::MapNode(const Eigen::Affine3d &pose,const MapParamPtr &mapparam){
  pose_=pose;
  map_=GraphFactory::CreateMapType(mapparam);
}
MapNode::MapNode(){
  map_=NULL;
}

string MapNode::ToString(){
  stringstream ss;
  ss<<"MapNode:\ninitialized: "<<initialized_<<"\nid:"<<id_<<"\nPosition(x,y,z):"<<pose_.translation().transpose()<<endl;;
  ss<<map_->ToString();
  return ss.str();
}

void MapNode::updateMap(const Eigen::Affine3d &Tnow,pcl::PointCloud<pcl::PointXYZ> &cloud){
  map_->update(Tnow,cloud);
  initialized_=true;
}

void MapNode::updateMap(const Eigen::Affine3d &Tnow,pcl::PointCloud<velodyne_pointcloud::PointXYZIR> &cloud){
  map_->update(Tnow,cloud);
  initialized_=true;
}

}
}
//#include <graph_map/map_node_impl.h>


/*=============================================================================
    Copyright (c) 2001-2006 Joel de Guzman
    Copyright (c) 2005-2006 Dan Marsden

    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)
==============================================================================*/
#include <boost/array.hpp>
#include <boost/timer.hpp>

#include <boost/fusion/algorithm/iteration/accumulate.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/algorithm/transformation/zip.hpp>
#include <boost/fusion/sequence/intrinsic/at.hpp>
#include <boost/fusion/adapted/array.hpp>
#include <boost/fusion/sequence/intrinsic/at.hpp>

#include <boost/type_traits/remove_reference.hpp>

#include <algorithm>
#include <numeric>
#include <functional>
#include <iostream>
#include <cmath>
#include <limits>

#ifdef _MSC_VER
// inline aggressively
# pragma inline_recursion(on) // turn on inline recursion
# pragma inline_depth(255)    // max inline depth
#endif

int const REPEAT_COUNT = 10;

double const duration = 0.5;

namespace
{
    struct poly_add
    {
        template<typename Sig>
        struct result;

        template<typename Lhs, typename Rhs>
        struct result<poly_add(Lhs, Rhs)>
            : boost::remove_reference<Lhs>
        {};

        template<typename Lhs, typename Rhs>
        Lhs operator()(const Lhs& lhs, const Rhs& rhs) const
        {
            return lhs + rhs;
        }
    };

    struct poly_mult
    {
        template<typename Sig>
        struct result;

        template<typename Lhs, typename Rhs>
        struct result<poly_mult(Lhs, Rhs)>
            : boost::remove_reference<Lhs>
        {};

        template<typename Lhs, typename Rhs>
        Lhs operator()(const Lhs& lhs, const Rhs& rhs) const
        {
            return lhs * rhs;
        }
    };

    template<int N>
    double time_for_std_inner_product(int& j)
    {
        boost::timer tim;
        int i = 0;
        long long iter = 65536;
        long long counter, repeats;
        double result = (std::numeric_limits<double>::max)();
        double runtime = 0;
        double run;
        boost::array<int, N> arr1;
        boost::array<int, N> arr2;
        std::generate(arr1.begin(), arr1.end(), rand);
        std::generate(arr2.begin(), arr2.end(), rand);
        do
        {
            tim.restart();
            for(counter = 0; counter < iter; ++counter)
            {
                i = std::inner_product(arr1.begin(), arr1.end(), arr2.begin(), 0);
                static_cast<void>(i);
            }
            runtime = tim.elapsed();
            iter *= 2;
        } while(runtime < duration);
        iter /= 2;

        // repeat test and report least value for consistency:
        for(repeats = 0; repeats < REPEAT_COUNT; ++repeats)
        {
            tim.restart();
            for(counter = 0; counter < iter; ++counter)
            {
                i = std::inner_product(arr1.begin(), arr1.end(), arr2.begin(), 0);
                j += i;
            }
            run = tim.elapsed();
            result = (std::min)(run, result);
        }
        std::cout << i << std::endl;
        return result / iter;
    }

    struct poly_combine
    {
        template<typename Sig>
        struct result;

        template<typename Lhs, typename Rhs>
        struct result<poly_combine(Lhs, Rhs)>
            : boost::remove_reference<Rhs>
        {};

        template<typename Lhs, typename Rhs>
        typename result<poly_combine(Lhs,Rhs)>::type
        operator()(const Lhs& lhs, const Rhs& rhs) const
        {
            return rhs + boost::fusion::at_c<0>(lhs) * boost::fusion::at_c<1>(lhs);
        }
    };

    template<int N>
    double time_for_fusion_inner_product2(int& j)
    {
        boost::timer tim;
        int i = 0;
        long long iter = 65536;
        long long counter, repeats;
        double result = (std::numeric_limits<double>::max)();
        double runtime = 0;
        double run;
        boost::array<int, N> arr1;
        boost::array<int, N> arr2;
        std::generate(arr1.begin(), arr1.end(), rand);
        std::generate(arr2.begin(), arr2.end(), rand);
        do
        {
            tim.restart();
            for(counter = 0; counter < iter; ++counter)
            {
                i = boost::fusion::accumulate(
                    boost::fusion::zip(arr1, arr2), 0, poly_combine());
                static_cast<void>(i);
            }
            runtime = tim.elapsed();
            iter *= 2;
        } while(runtime < duration);
        iter /= 2;

        std::cout << iter << " iterations" << std::endl;

        // repeat test and report least value for consistency:
        for(repeats = 0; repeats < REPEAT_COUNT; ++repeats)
        {
            tim.restart();
            for(counter = 0; counter < iter; ++counter)
            {
                i = boost::fusion::accumulate(
                    boost::fusion::zip(arr1, arr2), 0, poly_combine());
                j += i;
            }
            run = tim.elapsed();
            result = (std::min)(run, result);
        }
        std::cout << i << std::endl;
        return result / iter;
    }
}

int main()
{
    int total = 0;
    int res;

    std::cout << "short inner_product std test " << time_for_std_inner_product<8>(res) << std::endl;
    total += res;
    std::cout << "short inner_product fusion 2 test " << time_for_fusion_inner_product2<8>(res) << std::endl;
    total += res;

    std::cout << "medium inner_product std test " << time_for_std_inner_product<64>(res) << std::endl;
    total += res;
    std::cout << "medium inner_product fusion 2 test " << time_for_fusion_inner_product2<64>(res) << std::endl;
    total += res;

#if 0 // Leads to ICE with MSVC 8.0
    std::cout << "long inner_product std test " << time_for_std_inner_product<128>(res) << std::endl;
    total += res;
    std::cout << "long inner_product fusion 2 test " << time_for_fusion_inner_product2<128>(res) << std::endl;
    total += res;
#endif

    return total;
}


//==================================================================================================
/*!
  @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_REM_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_REM_HPP_INCLUDED

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

 /*!

    @ingroup group-oerator
    Function object implementing rem capabilities

    Computes the remainder of division.
    The return value is x-n*y, where n is the value x/y,
    rounded toward zero.

    @par semantic:
    For any given value @c x, @c y of type @c T:

    @code
    T r = rem({option, }x, y);
    @endcode

    if there is no option the call is similar to:
    @code
    T r = x-div(fix, x, y)*y;
    @endcode

    else option can be ceil, floor, fix, round, nearbyint (in the namespace booost::simd)
    and the code is similar to :

    @code
    T r = x-div(option, x, y)*y;
    @endcode

    @Notes

    -Supported types
     unsigned types are not supported but for the option @c fix, as in other cases result can be negative

    -Limiting values for floating entries:

       -  if x is +/-inf , Nan is returned
       -  if x is +/-0 and y is not 0 x is returned
       -  If y is +/-0, Nan is returned
       -  If either argument is NaN, Nan is returned

       If insurance of correct 0 sign in the second case does not matter for you, using the fast_ decorator
    can gain some cycles.

    @par Decorators

    with floating entries decorator std_ calls the stdlibc++ corresponding function (caution : no simd acceleration)

      -option fix        calls std::fmod
      -option nearbyint calls std::remainder
      The other options have no standard correspondant

    fast_ for floating entries,  but if x is +/-0 and y is not 0  +/-0 is returned with a non garanteed sign.

  **/
  Value rem(Value const & v0, value const& y);
} }
#endif

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

#endif


/*
Copyright 2016 Andrich van Wyk

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <Eigen/Core>
#include <iostream>

#include "domain.h"
#include "gtest/gtest.h"
#include "particle.h"
#include "pso.h"
#include "pso_functions.h"
#include "random.h"

using Eigen::ArrayXd;
using std::cout;
using std::endl;
using cswarm::pso::gbest;
using cswarm::pso::lbest;

double spherical(const ArrayXd& position) {
  return (position * position).sum();
}

TEST(PSOTest, should_construct) {
  auto rng = std::make_shared<Random>(1L);
  auto d = Domain(-5.0, 5.0, 30);
  auto p = PSOParameters(0.72, 1.4, 1.4, 1.0, 5);
  auto pso = PSO(5, d, p, spherical, lbest, rng);
}

TEST(PSOTest, should_optimize) {
  auto rng = std::make_shared<Random>(1L);
  auto d = Domain(-5.0, 5.0, 10);
  auto p = PSOParameters(0.72, 1.4, 1.4, 1.0, 5);
  auto pso = PSO(25, d, p, spherical, gbest, rng);

  auto result = pso.optimize(10);
}


//---------------------------------------------------------------------------//
//!
//! \file   tstInverseMomentumConversion.cpp
//! \author Alex Robinson
//! \brief  The inverse momentum conversion unit tests
//!
//---------------------------------------------------------------------------//

// Boost Includes
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/cgs.hpp>

// Trilinos Includes
#include <Teuchos_UnitTestHarness.hpp>

// FRENSIE Includes
#include "Utility_InverseMomentumUnits.hpp"
#include "Utility_RawPhysicalConstants.hpp"

using namespace Utility::Units;
using boost::units::quantity;

//---------------------------------------------------------------------------//
// Tests
//---------------------------------------------------------------------------//
// Check that the inverse momentum units can be converted
TEUCHOS_UNIT_TEST( InverseMomentumConversion, convert )
{
  quantity<InverseAtomicMomentum>
    inverse_atomic_momentum_q( 1.0*inverse_mec_momentum );

  quantity<InverseMeCMomentum>
    inverse_mec_momentum_q( 1.0*inverse_atomic_momentum );

  TEST_FLOATING_EQUALITY(
			inverse_atomic_momentum_q.value(),
			Utility::RawPhysicalConstants::fine_structure_constant,
			1e-15 );
  TEST_FLOATING_EQUALITY(
		inverse_mec_momentum_q.value(),
		Utility::RawPhysicalConstants::inverse_fine_structure_constant,
		1e-15 );
}

//---------------------------------------------------------------------------//
// end tstInverseMomentumConversion.cpp
//---------------------------------------------------------------------------//


/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/list/instance.hpp>

#include <cassert>
#include <string>
using namespace boost::hana;
using namespace std::string_literals;

int main() {
    //! [main]
    assert(
        sequence<List>(
            list(list("a1"s, "a2"s), list("b1"s), list("c1", "c2", "c3"))
        )
        ==
        list(
            list("a1"s, "b1"s, "c1"s),
            list("a1"s, "b1"s, "c2"s),
            list("a1"s, "b1"s, "c3"s),

            list("a2"s, "b1"s, "c1"s),
            list("a2"s, "b1"s, "c2"s),
            list("a2"s, "b1"s, "c3"s)
        )
    );
    //! [main]
}