/*
 Copyright (C) 2020 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

// clang-format off
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
// clang-format on
#include <oret/datapaths.hpp>
#include <oret/toplevelfixture.hpp>

#include <boost/make_shared.hpp>

#include <ored/configuration/curveconfigurations.hpp>
#include <ored/marketdata/csvloader.hpp>
#include <ored/marketdata/todaysmarket.hpp>
#include <ored/utilities/csvfilereader.hpp>
#include <ored/utilities/parsers.hpp>

using namespace std;
using namespace boost::unit_test_framework;
using namespace QuantLib;
using namespace QuantExt;
using namespace ore::data;

namespace bdata = boost::unit_test::data;

namespace {

boost::shared_ptr<TodaysMarket> createTodaysMarket(const Date& asof, const string& inputDir) {

    auto conventions = boost::make_shared<Conventions>();
    // conventions->fromFile(TEST_INPUT_FILE(string(inputDir + "/conventions.xml")));

    auto curveConfigs = boost::make_shared<CurveConfigurations>();
    curveConfigs->fromFile(TEST_INPUT_FILE(string(inputDir + "/curveconfig.xml")));

    auto todaysMarketParameters = boost::make_shared<TodaysMarketParameters>();
    todaysMarketParameters->fromFile(TEST_INPUT_FILE(string(inputDir + "/todaysmarket.xml")));

    auto loader = boost::make_shared<CSVLoader>(TEST_INPUT_FILE(string(inputDir + "/market.txt")),
                                                TEST_INPUT_FILE(string(inputDir + "/fixings.txt")), false);

    return boost::make_shared<TodaysMarket>(asof, todaysMarketParameters, loader, curveConfigs, conventions);
}

}

BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)

BOOST_AUTO_TEST_SUITE(BaseCorrelationCurveTests)

// Sub-directories containing input data to test various base correlation curve and market data set-ups
vector<string> setups{
    "exp_terms_exp_dps_curve",
    "exp_terms_exp_dps_surface",
    "exp_terms_wc_dps_curve",
    "exp_terms_wc_dps_surface",
    "wc_terms_exp_dps_curve",
    "wc_terms_exp_dps_surface",
    "wc_terms_wc_dps_curve",
    "wc_terms_wc_dps_surface"
};

BOOST_DATA_TEST_CASE(testBaseCorrelationStructureBuilding, bdata::make(setups), setup) {

    BOOST_TEST_MESSAGE("Testing base correlation structure building using setup in " << setup);

    Date asof(19, Oct, 2020);
    Settings::instance().evaluationDate() = asof;

    auto todaysMarket = createTodaysMarket(asof, setup);

    // Get the built base correlation structure.
    auto bc = todaysMarket->baseCorrelation("BASE_CORR_TEST");

    // These are the values used in the test configurations.
    Calendar calendar = parseCalendar("US settlement");
    BusinessDayConvention bdc = Following;

    // Tolerance for comparison.
    Real tol = 1e-12;

    // Read in the expected results.
    string filename = setup + "/expected.csv";
    CSVFileReader reader(TEST_INPUT_FILE(filename), true, ",");
    BOOST_REQUIRE_EQUAL(reader.numberOfColumns(), 3);

    BOOST_TEST_MESSAGE("term,detachment,expected_bc,calculated_bc,difference");
    while (reader.next()) {

        // Get the term, detachment point and expected base correlation
        Period term = parsePeriod(reader.get(0));
        Real dp = parseReal(reader.get(1));
        Real expBc = parseReal(reader.get(2));

        // Check
        Date d = calendar.advance(asof, term, bdc);
        Real calcBc = bc->correlation(d, dp);
        Real difference = expBc - calcBc;
        BOOST_TEST_MESSAGE(term << "," << fixed << setprecision(12) << dp << "," <<
            expBc << "," << calcBc << "," << difference);
        BOOST_CHECK_SMALL(difference, tol);
    }
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


#include <boost/test/unit_test.hpp>
#include "algorithms/data_structures/bt/bt_inorder_traversal.hpp"

BOOST_AUTO_TEST_SUITE(BTInorderTraversal)

BOOST_AUTO_TEST_CASE(empty_bt)
{
    Types::DS::NodeBT<int>* bt = nullptr;
    const std::vector<int> expected;
    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderRecursive(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterative(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterativeMorris(bt));

    Types::DS::DeleteBT(&bt);
}

BOOST_AUTO_TEST_CASE(only_one_node)
{
    Types::DS::NodeBT<int>* bt = Types::DS::CreateBST<int>({10});
    const std::vector<int> expected = {10};
    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderRecursive(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterative(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterativeMorris(bt));

    Types::DS::DeleteBT(&bt);
}

BOOST_AUTO_TEST_CASE(valid_bt)
{
    Types::DS::NodeBT<int>* bt = Types::DS::CreateBST<int>({2, 1, 2, 3});
    const std::vector<int> expected = {1, 2, 2, 3};
    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderRecursive(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterative(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterativeMorris(bt));

    Types::DS::DeleteBT(&bt);
}

BOOST_AUTO_TEST_CASE(valid_v_shape_bt)
{
    Types::DS::NodeBT<int>* bt = Types::DS::CreateBST<int>({10, 5, 3, 20, 30});
    const std::vector<int> expected = {3, 5, 10, 20, 30};
    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderRecursive(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterative(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterativeMorris(bt));

    Types::DS::DeleteBT(&bt);
}

BOOST_AUTO_TEST_CASE(valid_full_bt)
{
    Types::DS::NodeBT<int>* bt = Types::DS::CreateBST<int>({10, 5, 4, 6, 20, 15, 30});
    const std::vector<int> expected = {4, 5, 6, 10, 15, 20, 30};
    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderRecursive(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterative(bt));

    BOOST_CHECK(expected ==
                Algo::DS::BT::InorderTraversal::InorderIterativeMorris(bt));

    Types::DS::DeleteBT(&bt);
}

BOOST_AUTO_TEST_SUITE_END()


// Boost.Polygon library polygon_segment_test.cpp file

//          Copyright Andrii Sydorchuk 2012.
// 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://www.boost.org for updates, documentation, and revision history.

#include <algorithm>
#include <list>

#define BOOST_TEST_MODULE POLYGON_SEGMENT_TEST
#include <boost/mpl/list.hpp>
#include <boost/test/test_case_template.hpp>

#include "boost/polygon/polygon.hpp"
using namespace boost::polygon;

typedef boost::mpl::list<int> test_types;

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_data_test, T, test_types) {
  typedef point_data<T> point_type;
  typedef segment_data<T> segment_type;
  point_type point1(1, 2);
  point_type point2(3, 4);
  segment_type segment1(point1, point2);
  segment_type segment2 = segment1;

  BOOST_CHECK(segment1.low() == point1);
  BOOST_CHECK(segment1.high() == point2);
  BOOST_CHECK(segment1.get(LOW) == point1);
  BOOST_CHECK(segment1.get(HIGH) == point2);
  BOOST_CHECK(segment1 == segment2);
  BOOST_CHECK(!(segment1 != segment2));
  BOOST_CHECK(!(segment1 < segment2));
  BOOST_CHECK(!(segment1 > segment1));
  BOOST_CHECK(segment1 <= segment2);
  BOOST_CHECK(segment1 >= segment2);

  segment1.low(point2);
  segment1.high(point1);
  BOOST_CHECK(segment1.low() == point2);
  BOOST_CHECK(segment1.high() == point1);
  BOOST_CHECK(!(segment1 == segment2));
  BOOST_CHECK(segment1 != segment2);

  segment2.set(LOW, point2);
  segment2.set(HIGH, point1);
  BOOST_CHECK(segment1 == segment2);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_traits_test, T, test_types) {
  typedef point_data<T> point_type;
  typedef segment_data<T> segment_type;

  point_type point1(1, 2);
  point_type point2(3, 4);
  segment_type segment = segment_mutable_traits<segment_type>::construct(point1, point2);

  BOOST_CHECK(segment_traits<segment_type>::get(segment, LOW) == point1);
  BOOST_CHECK(segment_traits<segment_type>::get(segment, HIGH) == point2);

  segment_mutable_traits<segment_type>::set(segment, LOW, point2);
  segment_mutable_traits<segment_type>::set(segment, HIGH, point1);

  BOOST_CHECK(segment_traits<segment_type>::get(segment, LOW) == point2);
  BOOST_CHECK(segment_traits<segment_type>::get(segment, HIGH) == point1);
}

template <typename T>
struct Segment {
  point_data<T> p0;
  point_data<T> p1;
};

namespace boost {
namespace polygon {
  template <typename T>
  struct geometry_concept< Segment<T> > {
    typedef segment_concept type;
  };

  template <typename T>
  struct segment_traits< Segment<T> > {
    typedef T coordinate_type;
    typedef point_data<T> point_type;

    static point_type get(const Segment<T>& segment, direction_1d dir) {
      return dir.to_int() ? segment.p1 : segment.p0;
    }
  };

  template <typename T>
  struct segment_mutable_traits< Segment<T> > {
    typedef point_data<T> point_type;

    static inline void set(Segment<T>& segment, direction_1d dir, const point_type& point) {
      if (dir.to_int()) {
        segment.p1 = point;
      } else {
        segment.p0 = point;
      }
    }

    static inline Segment<T> construct(const point_type& point1, const point_type& point2) {
      Segment<T> segment;
      segment.p0 = point1;
      segment.p1 = point2;
      return segment;
    }
  };
}
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test1, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(1, 2);
  point_type point2(3, 4);
  point_type point3(2, 3);
  segment_type segment1 = construct<segment_type>(point1, point2);
  BOOST_CHECK(segment1.p0 == point1);
  BOOST_CHECK(segment1.p1 == point2);
  BOOST_CHECK(get(segment1, LOW) == point1);
  BOOST_CHECK(low(segment1) == point1);
  BOOST_CHECK(get(segment1, HIGH) == point2);
  BOOST_CHECK(high(segment1) == point2);
  BOOST_CHECK(center(segment1) == point3);

  set(segment1, LOW, point2);
  set(segment1, HIGH, point1);
  BOOST_CHECK(segment1.p0 == point2);
  BOOST_CHECK(segment1.p1 == point1);
  BOOST_CHECK(get(segment1, LOW) == point2);
  BOOST_CHECK(get(segment1, HIGH) == point1);
  low(segment1, point1);
  high(segment1, point2);
  BOOST_CHECK(segment1.p0 == point1);
  BOOST_CHECK(segment1.p1 == point2);

  segment_data<T> segment2 = copy_construct< segment_data<T> >(segment1);
  BOOST_CHECK(segment1.p0 == segment2.low());
  BOOST_CHECK(segment1.p1 == segment2.high());
  BOOST_CHECK(equivalence(segment1, segment2));

  segment_data<T> segment3 = construct< segment_data<T> >(point2, point1);
  assign(segment1, segment3);
  BOOST_CHECK(segment1.p0 == point2);
  BOOST_CHECK(segment1.p1 == point1);
  BOOST_CHECK(!equivalence(segment1, segment2));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test2, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(1, 2);
  point_type point2(2, 4);
  point_type point3(0, 0);
  point_type point4(5, 10);
  point_type point5(1, 3);
  point_type point6(2, 3);
  point_type point7(100, 201);
  point_type point8(100, 200);
  point_type point9(100, 199);
  segment_type segment1 = construct<segment_type>(point1, point2);
  segment_type segment2 = construct<segment_type>(point2, point1);
  segment_type segment3 = construct<segment_type>(point1, point5);

  BOOST_CHECK(orientation(segment1, point1) == 0);
  BOOST_CHECK(orientation(segment1, point2) == 0);
  BOOST_CHECK(orientation(segment1, point3) == 0);
  BOOST_CHECK(orientation(segment1, point4) == 0);
  BOOST_CHECK(orientation(segment1, point5) == 1);
  BOOST_CHECK(orientation(segment2, point5) == -1);
  BOOST_CHECK(orientation(segment1, point6) == -1);
  BOOST_CHECK(orientation(segment2, point6) == 1);
  BOOST_CHECK(orientation(segment1, point7) == 1);
  BOOST_CHECK(orientation(segment2, point7) == -1);
  BOOST_CHECK(orientation(segment1, point8) == 0);
  BOOST_CHECK(orientation(segment1, point9) == -1);
  BOOST_CHECK(orientation(segment2, point9) == 1);
  BOOST_CHECK(orientation(segment3, point6) == -1);
  BOOST_CHECK(orientation(segment3, point3) == 1);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test3, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  segment_type segment1 = construct<segment_type>(point_type(0, 0), point_type(1, 2));
  segment_type segment2 = construct<segment_type>(point_type(0, 0), point_type(2, 4));
  segment_type segment3 = construct<segment_type>(point_type(0, 0), point_type(2, 3));
  segment_type segment4 = construct<segment_type>(point_type(0, 0), point_type(2, 5));
  segment_type segment5 = construct<segment_type>(point_type(0, 2), point_type(2, 0));

  BOOST_CHECK(orientation(segment1, segment2) == 0);
  BOOST_CHECK(orientation(segment1, segment3) == -1);
  BOOST_CHECK(orientation(segment3, segment1) == 1);
  BOOST_CHECK(orientation(segment1, segment4) == 1);
  BOOST_CHECK(orientation(segment4, segment1) == -1);
  BOOST_CHECK(orientation(segment1, segment5) == -1);
  BOOST_CHECK(orientation(segment5, segment1) == 1);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test4, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(1, 2);
  point_type point2(3, 6);
  point_type point3(2, 4);
  point_type point4(4, 8);
  point_type point5(0, 0);
  segment_type segment = construct<segment_type>(point1, point2);

  BOOST_CHECK(contains(segment, point1, true));
  BOOST_CHECK(contains(segment, point2, true));
  BOOST_CHECK(!contains(segment, point1, false));
  BOOST_CHECK(!contains(segment, point2, false));
  BOOST_CHECK(contains(segment, point3, false));
  BOOST_CHECK(!contains(segment, point4, true));
  BOOST_CHECK(!contains(segment, point5, true));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test5, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(0, 0);
  point_type point2(10, 0);
  point_type point3(5, 0);
  point_type point4(-1, 0);
  point_type point5(11, 0);
  segment_type segment = construct<segment_type>(point1, point2);

  BOOST_CHECK(contains(segment, point1, true));
  BOOST_CHECK(contains(segment, point2, true));
  BOOST_CHECK(!contains(segment, point1, false));
  BOOST_CHECK(!contains(segment, point2, false));
  BOOST_CHECK(contains(segment, point3, false));
  BOOST_CHECK(!contains(segment, point4, true));
  BOOST_CHECK(!contains(segment, point5, true));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test6, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(0, 0);
  point_type point2(1, 2);
  point_type point3(2, 4);
  point_type point4(3, 6);
  point_type point5(4, 8);
  point_type point6(5, 10);
  segment_type segment1 = construct<segment_type>(point2, point5);
  segment_type segment2 = construct<segment_type>(point3, point4);
  segment_type segment3 = construct<segment_type>(point1, point3);
  segment_type segment4 = construct<segment_type>(point4, point6);

  BOOST_CHECK(contains(segment1, segment2, false));
  BOOST_CHECK(!contains(segment2, segment1, true));
  BOOST_CHECK(!contains(segment1, segment3, true));
  BOOST_CHECK(!contains(segment1, segment4, true));
  BOOST_CHECK(contains(segment1, segment1, true));
  BOOST_CHECK(!contains(segment1, segment1, false));
}

template<typename T>
struct Transformer {
  void scale(T& x, T& y) const {
    x *= 2;
    y *= 2;
  }

  void transform(T& x, T& y) const {
    T tmp = x;
    x = y;
    y = tmp;
  }
};

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test7, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(1, 2);
  point_type point2(4, 6);
  segment_type segment1 = construct<segment_type>(point1, point2);

  scale_up(segment1, 3);
  BOOST_CHECK(low(segment1) == point_type(3, 6));
  BOOST_CHECK(high(segment1) == point_type(12, 18));

  scale_down(segment1, 3);
  BOOST_CHECK(low(segment1) == point1);
  BOOST_CHECK(high(segment1) == point2);
  BOOST_CHECK(length(segment1) == 5);

  move(segment1, HORIZONTAL, 1);
  move(segment1, VERTICAL, 2);
  BOOST_CHECK(low(segment1) == point_type(2, 4));
  BOOST_CHECK(high(segment1) == point_type(5, 8));
  BOOST_CHECK(length(segment1) == 5);

  convolve(segment1, point_type(1, 2));
  BOOST_CHECK(low(segment1) == point_type(3, 6));
  BOOST_CHECK(high(segment1) == point_type(6, 10));

  deconvolve(segment1, point_type(2, 4));
  BOOST_CHECK(low(segment1) == point1);
  BOOST_CHECK(high(segment1) == point2);

  scale(segment1, Transformer<T>());
  BOOST_CHECK(low(segment1) == point_type(2, 4));
  BOOST_CHECK(high(segment1) == point_type(8, 12));
  transform(segment1, Transformer<T>());
  BOOST_CHECK(low(segment1) == point_type(4, 2));
  BOOST_CHECK(high(segment1) == point_type(12, 8));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test8, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  segment_type segment1 = construct<segment_type>(point_type(0, 0), point_type(1, 2));
  segment_type segment2 = construct<segment_type>(point_type(1, 2), point_type(2, 4));
  segment_type segment3 = construct<segment_type>(point_type(2, 4), point_type(0, 4));
  segment_type segment4 = construct<segment_type>(point_type(0, 4), point_type(0, 0));

  BOOST_CHECK(abuts(segment1, segment2, HIGH));
  BOOST_CHECK(abuts(segment2, segment3, HIGH));
  BOOST_CHECK(abuts(segment3, segment4, HIGH));
  BOOST_CHECK(abuts(segment4, segment1, HIGH));

  BOOST_CHECK(!abuts(segment1, segment2, LOW));
  BOOST_CHECK(!abuts(segment2, segment3, LOW));
  BOOST_CHECK(!abuts(segment3, segment4, LOW));
  BOOST_CHECK(!abuts(segment4, segment1, LOW));

  BOOST_CHECK(abuts(segment2, segment1));
  BOOST_CHECK(abuts(segment3, segment2));
  BOOST_CHECK(abuts(segment4, segment3));
  BOOST_CHECK(abuts(segment1, segment4));

  BOOST_CHECK(!abuts(segment1, segment3));
  BOOST_CHECK(!abuts(segment2, segment4));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test9, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  segment_type segment1 = construct<segment_type>(point_type(0, 0), point_type(2, 2));
  segment_type segment2 = construct<segment_type>(point_type(1, 1), point_type(3, 3));
  segment_type segment3 = construct<segment_type>(point_type(2, 2), point_type(-1, -1));
  segment_type segment4 = construct<segment_type>(point_type(1, 3), point_type(3, 1));
  segment_type segment5 = construct<segment_type>(point_type(2, 2), point_type(1, 3));

  BOOST_CHECK(intersects(segment1, segment2, false));
  BOOST_CHECK(intersects(segment1, segment2, true));
  BOOST_CHECK(intersects(segment1, segment3, false));
  BOOST_CHECK(intersects(segment1, segment3, true));
  BOOST_CHECK(intersects(segment2, segment3, false));
  BOOST_CHECK(intersects(segment2, segment3, true));
  BOOST_CHECK(intersects(segment4, segment3, false));
  BOOST_CHECK(intersects(segment4, segment3, true));
  BOOST_CHECK(intersects(segment4, segment2, false));
  BOOST_CHECK(intersects(segment4, segment2, true));
  BOOST_CHECK(!intersects(segment3, segment5, false));
  BOOST_CHECK(intersects(segment3, segment5, true));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test10, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  segment_type segment1 = construct<segment_type>(point_type(0, 0), point_type(0, 2));
  segment_type segment2 = construct<segment_type>(point_type(0, 1), point_type(0, 3));
  segment_type segment3 = construct<segment_type>(point_type(0, 1), point_type(0, 2));
  segment_type segment4 = construct<segment_type>(point_type(0, 2), point_type(0, 3));
  segment_type segment5 = construct<segment_type>(point_type(0, 2), point_type(2, 2));
  segment_type segment6 = construct<segment_type>(point_type(0, 1), point_type(1, 1));

  BOOST_CHECK(intersects(segment1, segment1, false));
  BOOST_CHECK(intersects(segment1, segment1, true));
  BOOST_CHECK(intersects(segment1, segment2, false));
  BOOST_CHECK(intersects(segment1, segment2, true));
  BOOST_CHECK(intersects(segment1, segment3, false));
  BOOST_CHECK(intersects(segment1, segment3, true));
  BOOST_CHECK(intersects(segment2, segment3, false));
  BOOST_CHECK(intersects(segment2, segment3, true));
  BOOST_CHECK(!intersects(segment1, segment4, false));
  BOOST_CHECK(intersects(segment1, segment4, true));
  BOOST_CHECK(!intersects(segment1, segment5, false));
  BOOST_CHECK(intersects(segment1, segment5, true));
  BOOST_CHECK(intersects(segment1, segment6, false));
  BOOST_CHECK(intersects(segment1, segment6, true));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test11, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  point_type point1(1, 2);
  point_type point2(7, 10);
  segment_type segment1 = construct<segment_type>(point1, point2);

  BOOST_CHECK(euclidean_distance(segment1, point1) == 0.0);
  BOOST_CHECK(euclidean_distance(segment1, point2) == 0.0);
  BOOST_CHECK(euclidean_distance(segment1, point_type(10, 14)) == 5.0);
  BOOST_CHECK(euclidean_distance(segment1, point_type(-3, -1)) == 5.0);
  BOOST_CHECK(euclidean_distance(segment1, point_type(0, 9)) == 5.0);
  BOOST_CHECK(euclidean_distance(segment1, point_type(8, 3)) == 5.0);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test12, T, test_types) {
  typedef point_data<T> point_type;
  typedef Segment<T> segment_type;

  segment_type segment1 = construct<segment_type>(point_type(0, 0), point_type(3, 4));
  segment_type segment2 = construct<segment_type>(point_type(2, 0), point_type(0, 2));
  segment_type segment3 = construct<segment_type>(point_type(1, -7), point_type(10, 5));
  segment_type segment4 = construct<segment_type>(point_type(7, 7), point_type(10, 11));

  BOOST_CHECK(euclidean_distance(segment1, segment2) == 0.0);
  BOOST_CHECK(euclidean_distance(segment1, segment3) == 5.0);
  BOOST_CHECK(euclidean_distance(segment1, segment4) == 5.0);
}


/**
 * @file ipdgfem.cc
 * @brief NPDE homework IPDGFEM code
 * @author Philippe Peter
 * @date 22.11.2019
 * @copyright Developed at ETH Zurich
 */

#include "ipdgfem.h"

#include <Eigen/Core>

namespace IPDGFEM {

/* SAM_LISTING_BEGIN_1 */
Eigen::VectorXd dummyFunction(double x, int n) {
#if SOLUTION
  // Appears only in mastersolution
  return Eigen::Vector2d::Constant(1.0);
#else
  // Appears only in mysolution and templates
  return Eigen::Vector2d::Zero();
#endif
}
/* SAM_LISTING_END_1 */

}  // namespace IPDGFEM


/*
 [auto_generated]
 boost/numeric/odeint/util/ublas_wrapper.hpp

 [begin_description]
 Resizing for ublas::vector and ublas::matrix
 [end_description]

 Copyright 2009-2011 Karsten Ahnert
 Copyright 2009-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_UTIL_UBLAS_WRAPPER_HPP_INCLUDED
#define BOOST_NUMERIC_ODEINT_UTIL_UBLAS_WRAPPER_HPP_INCLUDED

#include <boost/type_traits/integral_constant.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/lu.hpp>

#include <boost/numeric/odeint/util/is_resizeable.hpp>
#include <boost/numeric/odeint/util/state_wrapper.hpp>

namespace boost {
namespace numeric {
namespace odeint {

/*
 * resizeable specialization for boost::numeric::ublas::vector
 */
template< class T , class A >
struct is_resizeable< boost::numeric::ublas::vector< T , A > >
{
    typedef boost::true_type type;
    const static bool value = type::value;
};

/*
 * resizeable specialization for boost::numeric::ublas::matrix
 */
template< class T , class L , class A >
struct is_resizeable< boost::numeric::ublas::matrix< T , L , A > >
{
    typedef boost::true_type type;
    const static bool value = type::value;
};

/*
 * resizeable specialization for boost::numeric::ublas::permutation_matrix
 */
template< class T , class A >
struct is_resizeable< boost::numeric::ublas::permutation_matrix< T , A > >
{
    typedef boost::true_type type;
    const static bool value = type::value;
};

// specialization for ublas::matrix
// same size and resize specialization for matrix-matrix resizing
template< class T , class L , class A , class T2 , class L2 , class A2 >
struct same_size_impl< boost::numeric::ublas::matrix< T , L , A > , boost::numeric::ublas::matrix< T2 , L2 , A2 > >
{
    static bool same_size( const boost::numeric::ublas::matrix< T , L , A > &m1 ,
                           const boost::numeric::ublas::matrix< T2 , L2 , A2 > &m2 )
    {
        return ( ( m1.size1() == m2.size1() ) && ( m1.size2() == m2.size2() ) );
    }
};

template< class T , class L , class A , class T2 , class L2 , class A2 >
struct resize_impl< boost::numeric::ublas::matrix< T , L , A > , boost::numeric::ublas::matrix< T2 , L2 , A2 > >
{
    static void resize( boost::numeric::ublas::matrix< T , L , A > &m1 ,
                        const boost::numeric::ublas::matrix< T2 , L2 , A2 > &m2 )
    {
        m1.resize( m2.size1() , m2.size2() );
    }
};

// same size and resize specialization for matrix-vector resizing
template< class T , class L , class A , class T_V , class A_V >
struct same_size_impl< boost::numeric::ublas::matrix< T , L , A > , boost::numeric::ublas::vector< T_V , A_V > >
{
    static bool same_size( const boost::numeric::ublas::matrix< T , L , A > &m ,
                           const boost::numeric::ublas::vector< T_V , A_V > &v )
    {
        return ( ( m.size1() == v.size() ) && ( m.size2() == v.size() ) );
    }
};

template< class T , class L , class A , class T_V , class A_V >
struct resize_impl< boost::numeric::ublas::matrix< T , L , A > , boost::numeric::ublas::vector< T_V , A_V > >
{
    static void resize( boost::numeric::ublas::matrix< T , L , A > &m ,
                        const boost::numeric::ublas::vector< T_V , A_V > &v )
    {
        m.resize( v.size() , v.size() );
    }
};

// specialization for ublas::permutation_matrix
// same size and resize specialization for matrix-vector resizing
template< class T , class A , class T_V , class A_V >
struct same_size_impl< boost::numeric::ublas::permutation_matrix< T , A > , boost::numeric::ublas::vector< T_V , A_V > >
{
    static bool same_size( const boost::numeric::ublas::permutation_matrix< T , A > &m ,
                           const boost::numeric::ublas::vector< T_V , A_V > &v )
    {
        return ( m.size() == v.size() ); // && ( m.size2() == v.size() ) );
    }
};

template< class T , class A , class T_V , class A_V >
struct resize_impl< boost::numeric::ublas::vector< T_V , A_V > , boost::numeric::ublas::permutation_matrix< T , A > >
{
    static void resize( const boost::numeric::ublas::vector< T_V , A_V > &v,
                        boost::numeric::ublas::permutation_matrix< T , A > &m )
    {
        m.resize( v.size() , v.size() );
    }
};

template< class T , class A >
struct state_wrapper< boost::numeric::ublas::permutation_matrix< T , A > > // with resizing
{
    typedef boost::numeric::ublas::permutation_matrix< T , A > state_type;
    typedef state_wrapper< state_type > state_wrapper_type;

    state_type m_v;

    state_wrapper() : m_v( 1 ) // permutation matrix constructor requires a size, choose 1 as default
    { }

};

} } }

//// all specializations done, ready to include state_wrapper
//
//#include <boost/numeric/odeint/util/state_wrapper.hpp>
//
//namespace boost {
//namespace numeric {
//namespace odeint {
//
///* specialization for permutation matrices wrapper because we need to change the construction */
//template< class T , class A >
//struct state_wrapper< boost::numeric::ublas::permutation_matrix< T , A > , true > // with resizing
//{
//    typedef boost::numeric::ublas::permutation_matrix< T , A > state_type;
//    typedef state_wrapper< state_type > state_wrapper_type;
//    //typedef typename V::value_type value_type;
//    typedef boost::true_type is_resizeable;
//
//    state_type m_v;
//
//    state_wrapper() : m_v( 1 ) // permutation matrix constructor requires a size, choose 1 as default
//    { }
//
//    template< class T_V , class A_V >
//    bool same_size( const boost::numeric::ublas::vector< T_V , A_V > &x )
//    {
//        return boost::numeric::odeint::same_size( m_v , x );
//    }
//
//    template< class T_V , class A_V >
//    bool resize( const boost::numeric::ublas::vector< T_V , A_V > &x )
//    {
//        //standard resizing done like for std::vector
//        if( !same_size( x ) )
//        {
//            boost::numeric::odeint::resize( m_v , x );
//            return true;
//        } else
//            return false;
//    }
//};
//
//}
//}
//}

/*
 * preparing ublas::matrix for boost::range, such that ublas::matrix can be used in all steppers with the range algebra
 */

namespace boost
{
template< class T , class L , class A >
struct range_mutable_iterator< boost::numeric::ublas::matrix< T , L , A > >
{
    typedef typename boost::numeric::ublas::matrix< T , L , A >::array_type::iterator type;
};

template< class T , class L , class A >
struct range_const_iterator< boost::numeric::ublas::matrix< T , L , A > >
{
    typedef typename boost::numeric::ublas::matrix< T , L , A >::array_type::const_iterator type;
};

} // namespace boost

namespace boost { namespace numeric { namespace ublas {

template< class T , class L , class A >
inline typename matrix< T , L , A >::array_type::iterator
range_begin( matrix< T , L , A > &x )
{
    return x.data().begin();
}

template< class T , class L , class A >
inline typename matrix< T , L , A >::array_type::const_iterator
range_begin( const matrix< T , L , A > &x )
{
    return x.data().begin();
}

template< class T , class L , class A >
inline typename matrix< T , L , A >::array_type::iterator
range_end( matrix< T , L , A > &x )
{
    return x.data().end();
}

template< class T , class L , class A >
inline typename matrix< T , L , A >::array_type::const_iterator
range_end( const matrix< T , L , A > &x )
{
    return x.data().end();
}

} } } // namespace boost::numeric::ublas

#endif // BOOST_NUMERIC_ODEINT_UTIL_UBLAS_WRAPPER_HPP_INCLUDED


#define BOOST_TEST_MODULE factorial header only test
#include <boost/test/included/unit_test.hpp>
#include "../factorial.cpp"

BOOST_AUTO_TEST_CASE(Factorials_for_zero) {
    BOOST_TEST( Factorial(0) == 1 );
}

BOOST_AUTO_TEST_CASE(Factorials_for_positive_numbers) {
    BOOST_CHECK( Factorial(1) == 1 );
    BOOST_CHECK( Factorial(2) == 2 );
    BOOST_CHECK( Factorial(3) == 6 );
    BOOST_CHECK( Factorial(10) == 3628800 );
}


// Copyright 2014, Max Planck Society.
// Distributed under the BSD 3-Clause license.
// (See accompanying file LICENSE.txt or copy at
// http://opensource.org/licenses/BSD-3-Clause)

#ifndef BOOST_UBLAS_MATRIX_HELPER_GRASSMANN_AVERAGES_PCA_HPP__
#define BOOST_UBLAS_MATRIX_HELPER_GRASSMANN_AVERAGES_PCA_HPP__

/*!@file
 * Contains utility classes around uBlas matrices(mainly an iterator on matrix rows).
 */

#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <boost/iterator/iterator_adaptor.hpp>

namespace grassmann_averages_pca
{
  namespace details
  {
    namespace ublas_helpers
    {

      /*!@brief Iterator on rows of a matrix.
       *
       * This iterator is an adaptor that iterates over the rows of an ublas matrix. The returned element
       * is a matrix proxy that provides an ublas vector semantic.
       * @author Raffi Enficiaud
       */
      template <class matrix_t>
      class row_iter :
        public boost::iterator_facade<
          row_iter<matrix_t>                            // Derived
        , boost::numeric::ublas::matrix_row<matrix_t>   // Value
        , std::random_access_iterator_tag               // CategoryOrTraversal
        , boost::numeric::ublas::matrix_row<matrix_t>   // reference
        >
      {
      private:
        typedef row_iter<matrix_t> this_type;

        // this is a nice technic for SFNIAE, taken from the examples of boost.iterator.
        struct enabler {};

        size_t index;
        matrix_t *matrix;

        typedef boost::numeric::ublas::matrix_row<matrix_t> return_t;

      public:

        //! Default constructor
        row_iter() : index(std::numeric_limits<size_t>::max()), matrix(0)
        {}

        /*! Constructs an iterator on the nth rows of the given matrix
         *
         * @param[in] matrix_ the matrix from which the rows will be extracted
         * @param[in] index_ the index of the row of the matrix on which the iterator starts.
         *
         * @pre the provided index is lower than the total number of rows of the matrix.
         */
        row_iter(matrix_t &matrix_, size_t index_) : index(index_), matrix(&matrix_)
        {
          // below the <= is correct since it should be possible to give an index one passed the end
          assert(index_ <= matrix->size1());
        }

        /*! Constructor from an iterator
         *
         * This constructor is selected when the row_iter is instanciated from a row_iter on another type, and
         * type are convertible from the other matrix type to the current type (example non-const to const). Otherwise
         * the SFNIAE does reveal this constructor in the set of available constructor for this class.
         */
        template <class other_matrix_t>
        row_iter(
          row_iter<other_matrix_t> const& other,
          typename boost::enable_if<
            boost::is_convertible<typename other_matrix_t::iterator1, typename matrix_t::iterator1>,
            enabler>::type = enabler())
          :
          index(other.index), matrix(other.matrix)
        {}

      private:
        friend class boost::iterator_core_access;

        //!@name boost::iterator_facade interface
        //!@{

        void increment()
        {
          assert(matrix);
          assert(index < matrix->size1());
          index++;
        }

        bool equal(this_type const& other) const
        {
          assert(matrix == other.matrix);
          return this->index == other.index;
        }

        return_t dereference() const
        {
          assert(matrix);
          return return_t(*matrix, index);
        }

        typename this_type::difference_type distance_to(this_type const& r) const
        {
          assert((matrix != 0) && (r.matrix == matrix));
          return typename this_type::difference_type(r.index) - typename this_type::difference_type(index); // sign promotion
        }

        void advance(typename this_type::difference_type n)
        {
          if(n < 0)
          {
            assert((-n) <= static_cast<typename this_type::difference_type>(index));
            index -= n;
          }
          else
          {
            assert(n + index <= matrix->size1());
            index += n;
          }

        }

        //!@}

      };

    }
  }
}

#endif


//==============================================================================
//         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 boost.simd.arithmetic toolbox - fma/scalar Mode"

//////////////////////////////////////////////////////////////////////////////
// unit test behavior of boost.simd.arithmetic components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created by jt the 01/12/2010
///
#include <nt2/arithmetic/include/functions/fma.hpp>
#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>
#include <nt2/sdk/unit/tests/ulp.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/include/constants/inf.hpp>
#include <nt2/include/constants/minf.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/constants/mone.hpp>
#include <nt2/include/constants/zero.hpp>
#include <nt2/include/constants/two.hpp>
#include <nt2/include/constants/nan.hpp>
#include <nt2/include/constants/minf.hpp>

NT2_TEST_CASE_TPL ( fma_real__3_0, BOOST_SIMD_REAL_TYPES)
{

  using nt2::fma;
  using nt2::tag::fma_;
  typedef std::complex<T> cT;
  typedef typename boost::dispatch::meta::call<fma_(cT,cT,cT)>::type r_t;
  typedef typename nt2::meta::scalar_of<r_t>::type sr_t;

  // return type conformity test
  NT2_TEST_TYPE_IS( typename boost::dispatch::meta::call<fma_(cT,cT,cT)>::type, cT );

  // specific values tests
  NT2_TEST_ULP_EQUAL(fma(cT(nt2::Inf<T>()), cT(nt2::Inf<T>()), cT(nt2::Inf<T>())), cT(nt2::Inf<T>()), 0);
  NT2_TEST_EQUAL(fma(cT(nt2::Minf<T>()), cT(nt2::Minf<T>()), cT(nt2::Minf<T>())), cT(nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(cT(nt2::Mone<T>()), cT(nt2::Mone<T>()), cT(nt2::Mone<T>())), cT(nt2::Zero<T>()));
  NT2_TEST_EQUAL(fma(cT(nt2::Nan<T>()), cT(nt2::Nan<T>()), cT(nt2::Nan<T>())), cT(nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(cT(nt2::One<T>()), cT(nt2::One<T>()), cT(nt2::One<T>())), cT(nt2::Two<T>()));
  NT2_TEST_EQUAL(fma(cT(nt2::Zero<T>()), cT(nt2::Zero<T>()), cT(nt2::Zero<T>())), cT(nt2::Zero<T>()));
} // end of test for floating_

NT2_TEST_CASE_TPL ( fma_various,  BOOST_SIMD_REAL_TYPES)
{

  using nt2::fma;
  using nt2::tag::fma_;
  typedef std::complex<T> cT;
  typedef typename nt2::meta::as_imaginary<T>::type iT;

  std::cout << "0\n";
  NT2_TEST_EQUAL(fma(T(2), T(3), T(4)), T(10));
  NT2_TEST_EQUAL(fma(cT(2), cT(3), cT(4)), cT(10));
  NT2_TEST_EQUAL(    cT(2)*cT(3)+cT(4), cT(10));
  std::cout << "1\n";
  NT2_TEST_EQUAL(fma(cT(2), cT(3), iT(4)), cT(6, 4));
  NT2_TEST_EQUAL(fma(cT(2), cT(3), cT(0, 4)), cT(6, 4));
  NT2_TEST_EQUAL(    cT(2)*cT(3)+cT(0, 4), cT(6, 4));
  std::cout << "2\n";
  NT2_TEST_EQUAL(fma(cT(2), iT(3), cT(4)), cT(4, 6));
  NT2_TEST_EQUAL(fma(cT(2), cT(0, 3), cT(4)), cT(4, 6));
  NT2_TEST_EQUAL((cT(2)*cT(0, 3)+cT(4)), cT(4, 6));
  std::cout << "3\n";
  NT2_TEST_EQUAL(fma(iT(2), cT(3), cT(4)), cT(4, 6));
  NT2_TEST_EQUAL(fma(cT(0, 2), cT(3), cT(4)), cT(4, 6));
  NT2_TEST_EQUAL((cT(0, 2)* cT(3)+cT(4)), cT(4, 6));
  std::cout << "4\n";
  NT2_TEST_EQUAL(fma(cT(2), iT(3), iT(4)), cT(0, 10));
  NT2_TEST_EQUAL(fma(cT(2), cT(0, 3), cT(0, 4)), cT(0, 10));
  NT2_TEST_EQUAL((cT(2)* cT(0, 3)+ cT(0, 4)), cT(0, 10));
  std::cout << "5\n";
  NT2_TEST_EQUAL(fma(iT(2), iT(3), cT(4, 5)), cT(-2, 5));
  NT2_TEST_EQUAL(fma(cT(0, 2), cT(0, 3), cT(4, 5)), cT(-2, 5));
  NT2_TEST_EQUAL((cT(0, 2)* cT(0, 3)+ cT(4, 5)), cT(-2, 5));
  std::cout << "6\n";
  NT2_TEST_EQUAL(fma(iT(2), cT(3, 5), iT(4)), cT(-10, 10));
  NT2_TEST_EQUAL(fma(cT(0, 2), cT(3, 5), cT(0, 4)), cT(-10, 10));
  NT2_TEST_EQUAL((cT(0, 2)* cT(3, 5)+ cT(0, 4)), cT(-10, 10));
  std::cout << "7\n";
  NT2_TEST_EQUAL(fma(iT(2), iT(3),iT(4)), cT(-6, 4));
  NT2_TEST_EQUAL(fma(cT(0, 2), cT(0, 3), cT(0, 4)), cT(-6, 4));
  NT2_TEST_EQUAL((cT(0, 2)*cT(0, 3)+cT(0, 4)), cT(-6, 4));
  std::cout << "8\n";
  NT2_TEST_EQUAL(fma(T(2), cT(5, 3),cT(6, 4)), cT(16, 10));
  NT2_TEST_EQUAL(fma(cT(2), cT(5, 3), cT(6, 4)), cT(16, 10));
  NT2_TEST_EQUAL((cT(2)*cT(5, 3)+cT(6, 4)), cT(16, 10));
  std::cout << "9\n";
  NT2_TEST_EQUAL(fma(T(2), cT(5, 3),cT(6, 4)), cT(16, 10));
  NT2_TEST_EQUAL(fma(cT(2), cT(5, 3), cT(6, 4)), cT(16, 10));
  NT2_TEST_EQUAL((cT(2)*cT(5, 3)+cT(6, 4)), cT(16, 10));
  std::cout << "10\n";
  NT2_TEST_EQUAL(fma(cT(2, 3), cT(5, 3),T(6)), cT(7, 21));
  NT2_TEST_EQUAL(fma(cT(2, 3), cT(5, 3), cT(6)), cT(7, 21));
  NT2_TEST_EQUAL((cT(2, 3)*cT(5, 3)+cT(6)), cT(7, 21));
  std::cout << "11\n";
  NT2_TEST_EQUAL(fma(cT(2, 3), T(5),T(6)), cT(16, 15));
  NT2_TEST_EQUAL(fma(cT(2, 3), cT(5), cT(6)), cT(16, 15));
  NT2_TEST_EQUAL((cT(2, 3)*cT(5)+cT(6)), cT(16, 15));
  std::cout << "12\n";
  NT2_TEST_EQUAL(fma(T(2), cT(5, 3),T(6)), cT(16, 6));
  NT2_TEST_EQUAL(fma(cT(2), cT(5, 3), cT(6)), cT(16, 6));
  NT2_TEST_EQUAL((cT(2)*cT(5, 3)+cT(6)), cT(16, 6));
  std::cout << "13\n";
  NT2_TEST_EQUAL(fma(T(2), T(5),cT(6, 2)), cT(16, 2));
  NT2_TEST_EQUAL(fma(cT(2), cT(5), cT(6, 2)), cT(16, 2));
  NT2_TEST_EQUAL((cT(2)*cT(5)+cT(6, 2)), cT(16, 2));
  std::cout << "14\n";
  NT2_TEST_EQUAL(fma(T(2), iT(5),cT(6, 2)), cT(6, 12));
  NT2_TEST_EQUAL(fma(cT(2), cT(0, 5), cT(6, 2)), cT(6, 12));
  NT2_TEST_EQUAL((cT(2)*cT(0, 5)+cT(6, 2)), cT(6, 12));
  std::cout << "15\n";
  NT2_TEST_EQUAL(fma(T(2), cT(2, 5),iT(2)), cT(4, 12));
  NT2_TEST_EQUAL(fma(cT(2), cT(2, 5), cT(0, 2)), cT(4, 12));
  NT2_TEST_EQUAL((cT(2)*cT(2, 5)+cT(0, 2)), cT(4, 12));
  std::cout << "16\n";
  NT2_TEST_EQUAL(fma(cT(2, 5), iT(5),T(2)), cT(-23, 10));
  NT2_TEST_EQUAL(fma(cT(2, 5), cT(0, 5), cT(2)), cT(-23, 10));
  NT2_TEST_EQUAL((cT(2, 5)*cT(0, 5)+cT(2)), cT(-23, 10));
  std::cout << "17\n";
  NT2_TEST_EQUAL(fma(iT(5), cT(2, 5),T(2)), cT(-23, 10));
  NT2_TEST_EQUAL(fma(cT(0, 5), cT(2, 5), cT(2)), cT(-23, 10));
  NT2_TEST_EQUAL((cT(0, 5)*cT(2, 5)+cT(2)), cT(-23, 10));
  std::cout << "18\n";
  NT2_TEST_EQUAL(fma(cT(2, 5), T(3),iT(2)), cT(6, 17));
  NT2_TEST_EQUAL(fma(cT(2, 5), cT(3, 0), cT(0, 2)), cT(6, 17));
  NT2_TEST_EQUAL((cT(2, 5)*cT(3, 0)+cT(0, 2)), cT(6, 17));
  std::cout << "19\n";
  NT2_TEST_EQUAL(fma(iT(5), T(3),cT(6, 2)), cT(6, 17));
  NT2_TEST_EQUAL(fma(cT(0, 5), cT(3), cT(6, 2)), cT(6, 17));
  NT2_TEST_EQUAL((cT(0, 5)*cT(3, 0)+cT(6, 2)), cT(6, 17));

} // end of test for floating_

NT2_TEST_CASE_TPL ( fma_various_invalid, (float))//BOOST_SIMD_REAL_TYPES)
{

  using nt2::fma;
  using nt2::tag::fma_;
  typedef std::complex<T> cT;
  typedef typename nt2::meta::as_imaginary<T>::type iT;

  // specific values tests

  std::cout << "0 ccc \n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(3), cT(4)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(3), cT(4)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(cT(2), cT(3), cT(4)), cT(10));
  NT2_TEST_EQUAL(fma(cT(2, 3), cT(3, 1), cT(2, 4)), cT(5, 15));

  NT2_TEST_EQUAL(fma(cT(0, nt2::Inf<T>()), cT(0), cT(3, 4)), cT(3, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(cT(0),cT(0, nt2::Inf<T>()), cT(4)), cT(4, nt2::Nan<T>()));

  NT2_TEST_EQUAL(fma(cT(1, nt2::Inf<T>()), cT(0), cT(3, nt2::Minf<T>())), cT(3, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(cT(0),cT(1, nt2::Inf<T>()), cT(4)), cT(4, nt2::Nan<T>()));

  NT2_TEST_EQUAL(fma(nt2::Inf<T>(), T(3), T(4)), nt2::Inf<T>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(3), cT(nt2::Minf<T>())), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(1),nt2::Inf<cT>(), cT(nt2::Minf<T>())), cT(nt2::Nan<T>(), 0));
  NT2_TEST_EQUAL(fma(cT(1),cT(0, nt2::Inf<T>()), cT(nt2::Minf<T>())), cT(nt2::Minf<T>(), nt2::Inf<T>()));

  NT2_TEST_EQUAL(   nt2::multiplies(nt2::Inf<cT>(), cT(3))+cT(4), nt2::Inf<cT>());

  std::cout << "1 cci\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(3), iT(0)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(cT(2), cT(3), cT(0, 4)), cT(6, 4));
  NT2_TEST_EQUAL(    nt2::plus(nt2::multiplies(nt2::Inf<cT>(), cT(3)), iT(0)), nt2::Inf<cT>());

  std::cout << "2 cic \n";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(), T(0), cT(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), iT(0), cT(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0), cT(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(nt2::Inf<cT>(), iT(0)), cT(4)), nt2::Nan<cT>());
  std::cout << "3 icc\n";
  NT2_TEST_EQUAL(fma(iT(0), nt2::Inf<cT>(), cT(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(0), nt2::Inf<cT>(), cT(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(iT(0), nt2::Inf<cT>()), cT(4)), nt2::Nan<cT>());

  std::cout << "4 cii\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), iT(0), cT(0, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), iT(1), iT(4)), cT(0, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0, 1), iT(4)), cT(0, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0), cT(0, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(cT(0), cT(0), nt2::Inf<cT>()),  nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0), nt2::Inf<cT>()),  nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Minf<cT>(), cT(1), nt2::Inf<cT>()),  nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(1), nt2::Inf<cT>()),  nt2::Nan<cT>());
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(nt2::Inf<cT>(), cT(0)), cT(0, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(nt2::Inf<cT>(), iT(0)), cT(0, 4)), cT(nt2::Nan<T>(), 4));

  std::cout << "5 iic\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0), cT(4, 5)), cT(nt2::Nan<T>(), 5));
  NT2_TEST_EQUAL(fma(cT(0), nt2::Inf<cT>(), cT(4, 5)), cT(nt2::Nan<T>(), 5));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(nt2::Inf<cT>(), cT(0)), cT(4, 5)), cT(nt2::Nan<T>(), 5));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(nt2::Inf<cT>(), iT(0)), cT(4, 5)), cT(nt2::Nan<T>(), 5));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(0), cT(4, 4)), cT(4, nt2::Nan<T>()));

  std::cout << "6 ici\n";
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), cT(0), iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(cT(0), iT(nt2::Inf<T>()), iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(0), cT(3, 4)), cT(3, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(iT(0), iT(nt2::Inf<T>()), cT(3, 4)), cT(3, nt2::Nan<T>()));

  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(0), iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma( iT(0),iT(nt2::Inf<T>()),iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(1), iT(4)), cT(nt2::Minf<T>(), 4));
  NT2_TEST_EQUAL(fma( iT(1),iT(nt2::Inf<T>()),iT(4)), cT(nt2::Minf<T>(), 4));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(cT(0,nt2::Inf<T>()), cT(0)), cT(0, 4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(iT(nt2::Inf<T>()), cT(0)), cT(0, 4)), cT(0, nt2::Nan<T>()));

  std::cout << "7 iii\n";
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(3),iT(4)), cT(nt2::Minf<T>(), 4));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(0),iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(iT(nt2::Inf<T>()), iT(0)), iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(iT(nt2::Inf<T>()), iT(3)), iT(4)), cT(nt2::Minf<T>(), 4));

  std::cout << "8\n acc";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(), cT(0),cT(6, 4)),     cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(), iT(0), cT(6, 4)),    cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(), cT(0, 3),cT(6, 4)),  cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(), iT(3), cT(6, 4)),    cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(T(0),          nt2::Inf<cT>(),      cT(6, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(T(0),          iT(nt2::Inf<T>()),   cT(6, 4)), cT(6, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  cT(1), cT( 3, 4)), cT(nt2::Inf<T>(), 4));
  NT2_TEST_EQUAL(fma(T(1), cT(nt2::Inf<T>()),  cT(4, 4)), cT(nt2::Inf<T>(), 4));

  std::cout << "9 cac\n";
  NT2_TEST_EQUAL(fma( cT(0)                ,nt2::Inf<T>(),cT(6, 4)),     cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( iT(0)                ,nt2::Inf<T>(),cT(6, 4)),    cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( iT(0)                ,nt2::Inf<cT>(),cT(6, 4)),    cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( cT(0, 3)             ,nt2::Inf<T>(),cT(6, 4)),  cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma( iT(3)                ,nt2::Inf<T>(),cT(6, 4)),    cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma( nt2::Inf<cT>(),       T(0),         cT(6, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( iT(nt2::Inf<T>()),    T(0),         cT(6, 4)), cT(6, nt2::Nan<T>()));

  std::cout << "10 cca\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(3), T(4)),                     nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(cT(3),                     nt2::Inf<cT>(), T(4)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(cT(4),                     nt2::Inf<cT>(), cT(3)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), T(4), cT(3)),                     nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0), T(4)),                     nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(0),                     nt2::Inf<cT>(), T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(0),                     nt2::Inf<cT>(), cT(3)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), T(4), cT(3)),                     nt2::Inf<cT>());

  std::cout << "11 caa\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), T(3),           T(4)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(cT(3, 4),        nt2::Inf<T>(), T(4)), cT(nt2::Inf<T>(), nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(cT(4),           nt2::Inf<T>(), T(3)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(),  T(0),          T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(0),           nt2::Inf<T>(), T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(),  T(4),          T(3)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(cT(0, nt2::Inf<T>()), T(4),     T(3)), cT(3, nt2::Inf<T>()));

  std::cout << "12 aca\n";
  NT2_TEST_EQUAL(fma(T(3),         nt2::Inf<cT>(),   T(4)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),cT(3, 4),         T(4)), cT(nt2::Inf<T>(), nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),cT(4),            T(3)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(T(0),         nt2::Inf<cT>(),   T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),cT(0),            T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(T(4),         nt2::Inf<cT>(),   T(3)), nt2::Inf<cT>());
  NT2_TEST_EQUAL(fma(T(4), cT(0, nt2::Inf<T>()), T(3)), cT(3, nt2::Inf<T>()));

  std::cout << "13 aac\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  T(0), cT(6, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(T(0), nt2::Inf<T>(),  cT(6, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  T(1), cT(6, 4)), cT(nt2::Inf<T>(), 4));
  NT2_TEST_EQUAL(fma(T(1), nt2::Inf<T>(),  cT(6, 4)), cT(nt2::Inf<T>(), 4));

  std::cout << "14\n aic";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(0), cT(6, 4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(T(0), iT(nt2::Inf<T>()),  cT(6, 4)), cT(6, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(1), cT(6, 4)), cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(T(1), iT(nt2::Inf<T>()),  cT(6, 4)), cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(0), cT(6)), cT(nt2::Nan<T>(), 0));
  NT2_TEST_EQUAL(fma(T(0), iT(nt2::Inf<T>()),  cT(6)), cT(6, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(1), cT(6)), cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(T(1), iT(nt2::Inf<T>()),  cT(6)), cT(6, nt2::Inf<T>()));

  std::cout << "15 aci\n";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  cT(0), iT(4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(T(0), cT(nt2::Inf<T>()),  iT(4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  cT(1), iT(4)), cT(nt2::Inf<T>(), 4));
  NT2_TEST_EQUAL(fma(T(1), cT(nt2::Inf<T>()),  iT(4)), cT(nt2::Inf<T>(), 4));

  std::cout << "16 cia \n";
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), iT(0), T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(nt2::Inf<cT>(), cT(0), T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(0), iT(nt2::Inf<T>()), T(4)), cT(4, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(cT(0), cT(0, nt2::Inf<T>()), T(4)),cT(4, nt2::Nan<T>()));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(nt2::Inf<cT>(), iT(0)), T(4)), nt2::Nan<cT>());

  std::cout << "17 ica \n";
  NT2_TEST_EQUAL(fma(iT(0), nt2::Inf<cT>(), T(4)), nt2::Nan<cT>());
  NT2_TEST_EQUAL(fma(cT(0), nt2::Inf<cT>(), T(4)), nt2::Nan<cT>());

  std::cout << "18 cai \n";
  NT2_TEST_EQUAL(fma( cT(0),              nt2::Inf<T>(), iT(4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( cT(nt2::Inf<T>()),  T(0),          iT(4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( cT(1),              nt2::Inf<T>(), iT(4)), cT(nt2::Inf<T>(), 4));
  NT2_TEST_EQUAL(fma( cT(nt2::Inf<T>()),  T(1),          iT(4)), cT(nt2::Inf<T>(), 4));

  std::cout << "19 iac \n";
  NT2_TEST_EQUAL(fma( iT(0),              nt2::Inf<T>(), cT(6, 4)),   cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma( iT(nt2::Inf<T>()),  T(0),          cT(6, 4)), cT(6, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma( iT(1),   nt2::Inf<T>(), cT(6, 4)), cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma( iT(nt2::Inf<T>()),  T(1),          cT(6, 4)), cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma( iT(0),              nt2::Inf<T>(), cT(6)),      cT(nt2::Nan<T>(), 0));
  NT2_TEST_EQUAL(fma( iT(nt2::Inf<T>()),  T(0),          cT(6)), cT(6, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma( iT(1),              nt2::Inf<T>(), cT(6)),      cT(6, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma( iT(nt2::Inf<T>()),  T(1),          cT(6)), cT(6, nt2::Inf<T>()));

  std::cout << "20 aai \n";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  T(0), iT(4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(T(0), nt2::Inf<T>(),  iT(4)), cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  T(1), iT(4)), cT(nt2::Inf<T>(), 4));
  NT2_TEST_EQUAL(fma(T(1), nt2::Inf<T>(),  iT(4)), cT(nt2::Inf<T>(), 4));

  std::cout << "21 aia \n";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(0), T(4)),    cT(nt2::Nan<T>(), 0));
  NT2_TEST_EQUAL(fma(T(0), iT(nt2::Inf<T>()),  T(4)), cT(4, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(1), T(4)),    cT(4, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(T(1), iT(nt2::Inf<T>()),  T(4)), cT(4, nt2::Inf<T>()));

  std::cout << "22 iaa \n";
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()),  T(0), T(4)),    cT(4, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(iT(0), nt2::Inf<T>(),  T(4)),       cT(nt2::Nan<T>(), 0));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()),  T(1), T(4)),    cT(4, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(iT(1), T(nt2::Inf<T>()),  T(4)),    cT(4, nt2::Inf<T>()));

  std::cout << "23 aii \n";
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(0), iT(4)),    cT(nt2::Nan<T>(), 4));
  NT2_TEST_EQUAL(fma(T(0), iT(nt2::Inf<T>()),  iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(nt2::Inf<T>(),  iT(1), iT(4)),    cT(0, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(T(1), iT(nt2::Inf<T>()),  iT(4)), cT(0, nt2::Inf<T>()));

  std::cout << "24 iia \n";
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(3),T(4)), cT(nt2::Minf<T>(), 0));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), iT(0),T(4)), cT(4, nt2::Nan<T>()));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(iT(nt2::Inf<T>()), iT(0)), T(4)), cT(4, nt2::Nan<T>()));
  NT2_TEST_EQUAL(nt2::plus(nt2::multiplies(iT(nt2::Inf<T>()), iT(3)), T(4)), cT(nt2::Minf<T>(), 0));

  std::cout << "25 iai \n";
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), T(3),iT(4)), cT(0, nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(iT(nt2::Inf<T>()), T(0),iT(4)), cT(0, nt2::Nan<T>()));
  NT2_TEST_EQUAL(fma(iT(3), nt2::Inf<T>(),iT(4)),     cT(0,  nt2::Inf<T>()));
  NT2_TEST_EQUAL(fma(iT(0), nt2::Inf<T>(),iT(4)),     cT(nt2::Nan<T>(), 4));
} // end of test for floating_


//------------------------------------------------------------------------------
// \file ToBytes_test.cpp
//------------------------------------------------------------------------------
#include "Utilities/ToBytes.h"

#include <boost/test/unit_test.hpp>
#include <cstddef> // std::byte
#include <cstdio> // printf
#include <iostream>
#include <limits>
#include <string>

using Utilities::ToBytes;

BOOST_AUTO_TEST_SUITE(Utilities)
BOOST_AUTO_TEST_SUITE(ToBytes_tests)

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ReinterpretCastAndHexadecimalPrintExamples)
{
  std::cout << "\n ReinterpretCastAndHexadecimalPrintExamples begins \n";

  constexpr unsigned short x_0 {15213};
  constexpr short x_1 {15213};
  constexpr short y {-15213};

  auto x = reinterpret_cast<const std::byte*>(&x_0);
  auto xa = reinterpret_cast<const unsigned char*>(&x_0);

  //std::cout << std::to_integer(x[0]) << '\n'; // didn't work
  //std::cout << std::to_integer(*x) << '\n'; // didn't work
  // std::cout << x << '\n'; // worked

  //std::cout << xa[0] << '\n'; // m
  //std::cout << xa[1] << '\n'; // ;
  //std::cout << xa[2] << '\n';
  //std::cout << xa[3] << '\n';
  //printf("%x \n", xa); // 178892be
  //printf("%01x \n", xa[0]);
  //printf("%01x \n", xa[1]);
  //printf("%01x \n", xa[2]);
  //printf("%001x \n", xa[3]);
  //printf("%001x \n", xa[4]);

  BOOST_TEST_REQUIRE(sizeof(unsigned short) == 2);
  BOOST_TEST_REQUIRE(sizeof(short) == 2);

  BOOST_TEST(true);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ToBytesWorks)
{
  constexpr unsigned short x_0 {15213};
  constexpr short x_1 {15213};
  constexpr short y {-15213};

  const ToBytes to_bytes_x_0 {x_0};

  std::cout << "\n Print 15213 with increasing addresses \n";
  to_bytes_x_0.increasing_addresses_print(); // WORKS
  //to_bytes_x_0.decreasing_addresses_print(); // WORKS
  std::cout << "\n END OF Print 15213 with increasing addresses \n";

  ToBytes to_bytes_x_1 {x_1};

  to_bytes_x_1.increasing_addresses_print(); // WORKS 93
  to_bytes_x_1.decreasing_addresses_print(); // WORKS c4

  const ToBytes to_bytes_y {y};

  to_bytes_y.increasing_addresses_print(); // WORKS c4
  to_bytes_y.decreasing_addresses_print(); // WORKS 93
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(IncreasingAddressesHexWorks)
{
  constexpr unsigned short x_0 {15213};
  constexpr short x_1 {15213};
  constexpr short y {-15213};

  const ToBytes to_bytes_x_0 {x_0};

  ToBytes to_bytes_x_1 {x_1};

  const ToBytes to_bytes_y {y};

  const std::string x_0_str {to_bytes_x_0.increasing_addresses_hex()};
  BOOST_TEST(x_0_str == "6d3b");

  const std::string x_1_str {to_bytes_x_1.increasing_addresses_hex()};
  BOOST_TEST(x_1_str == "6d3b");

  const std::string y_str {to_bytes_y.increasing_addresses_hex()};
  BOOST_TEST(y_str == "93c4");
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(IncreasingAddressesHexWorksByInduction)
{
  {
    BOOST_TEST(sizeof(unsigned int) == 4);
    const unsigned int x {0};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "0000");
  }
  {
    const unsigned int x {1};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "1000");
  }
  {
    const unsigned int x {2};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "2000");
  }
  {
    const unsigned int x {15};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "f000");
  }
  {
    const unsigned int x {16};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "10000");
  }
  {
    const unsigned int x {17};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "11000");
  }
  {
    const unsigned int x {std::numeric_limits<unsigned int>::max() - 1};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "feffffff");
  }
  {
    const unsigned int x {std::numeric_limits<unsigned int>::max()};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "ffffffff");
  }
  {
    const unsigned int x {std::numeric_limits<unsigned int>::min()};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.increasing_addresses_hex() == "0000");
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(DecreasingAddressesHexWorksByInduction)
{
  {
    BOOST_TEST(sizeof(unsigned int) == 4);
    const unsigned int x {0};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "0000");
  }
  {
    const unsigned int x {1};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "0001");
  }
  {
    const unsigned int x {2};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "0002");
  }
  {
    const unsigned int x {15};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "000f");
  }
  {
    const unsigned int x {16};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "00010");
  }
  {
    const unsigned int x {17};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "00011");
  }
  {
    const unsigned int x {std::numeric_limits<unsigned int>::max() - 1};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "fffffffe");
  }
  {
    const unsigned int x {std::numeric_limits<unsigned int>::max()};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "ffffffff");
  }
  {
    const unsigned int x {std::numeric_limits<unsigned int>::min()};
    const ToBytes to_bytes_x {x};
    BOOST_TEST(to_bytes_x.decreasing_addresses_hex() == "0000");
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(DecreasingAddressesHexWorks)
{
  constexpr unsigned short x_0 {15213};
  constexpr short x_1 {15213};
  constexpr short y {-15213};

  const ToBytes to_bytes_x_0 {x_0};

  ToBytes to_bytes_x_1 {x_1};

  const ToBytes to_bytes_y {y};

  const std::string x_0_str {to_bytes_x_0.decreasing_addresses_hex()};
  BOOST_TEST(x_0_str == "3b6d");

  const std::string x_1_str {to_bytes_x_1.decreasing_addresses_hex()};
  BOOST_TEST(x_1_str == "3b6d");

  const std::string y_str {to_bytes_y.decreasing_addresses_hex()};
  BOOST_TEST(y_str == "c493");
}

BOOST_AUTO_TEST_SUITE(RepresentingStrings_tests)

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(StringToByteGetsPointer)
{
  const std::string input {"12345"};
  const ToBytes input_in_bytes {input};

  //BOOST_TEST(input_in_bytes.decreasing_addresses_hex() ==
  //  "0000040ad14000353433323100000005007ffdc68e6e10 ");

  const ToBytes input_as_char_in_bytes {input.data()};

  //BOOST_TEST(input_as_char_in_bytes.decreasing_addresses_hex() ==
  //  "007ffd70befdb0 ");

  //const ToBytes r_input {"12345"};

  BOOST_TEST(true);
}

BOOST_AUTO_TEST_SUITE_END() // RepresentingStrings_tests

BOOST_AUTO_TEST_SUITE_END() // ToBytes_tests
BOOST_AUTO_TEST_SUITE_END() // Utilities


//  (C) Copyright Raffi Enficiaud 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)

//  See http://www.boost.org/libs/test for the library home page.

//[example_code
#define BOOST_TEST_MODULE boost_test_sequence
#include <boost/test/included/unit_test.hpp>
#include <vector>

BOOST_AUTO_TEST_CASE( test_collections_vectors )
{
  std::vector<int> a{1,2,3}, c{1,5,3,4};
  std::vector<long> b{1,5,3};

  // the following does not compile
  //BOOST_TEST(a == b);
  //BOOST_TEST(a <= b);

  // stl defaults to lexicographical comparison
  BOOST_TEST(a < c);
  BOOST_TEST(a >= c);
  BOOST_TEST(a != c);
}
//]


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

#define BOOST_TEST_MAIN

#include <limits>

#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>

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

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

namespace tudat
{
namespace unit_tests
{

using namespace basic_astrodynamics;

//! Test the functionality of the time conversion functions.
BOOST_AUTO_TEST_SUITE( test_Time_Conversions )

//! Unit test for Julian day to seconds conversion function.
BOOST_AUTO_TEST_CASE( testJulianDayToSecondsConversions )
{
    // Test conversion from Julian day to seconds since epoch at 0 MJD.
    {
        // Set reference epoch and Julian day for tests.
        const double referenceEpoch = JULIAN_DAY_AT_0_MJD;
        const double julianDay = JULIAN_DAY_AT_0_MJD + 1.0e6 / 86400.0;

        // Set expected seconds since epoch result.
        const double expectedSecondsSinceEpoch = 1.0e6;

        // Compute seconds since epoch given Julian day and reference epoch.
        const double computedSecondsSinceEpoch = convertJulianDayToSecondsSinceEpoch(
                    julianDay, referenceEpoch );

        // Test that computed result matches expected result.
        // Test is run at reduced tolerance, because the final digits of the seconds were lost
        // when converting to Julian day.
        BOOST_CHECK_CLOSE_FRACTION( computedSecondsSinceEpoch, expectedSecondsSinceEpoch,
                                    1.0e-11 );
    }

    // Test conversion from Julian day to seconds since J2000 epoch.
    {
        // Set reference epoch and Julian day for tests.
        const double referenceEpoch = JULIAN_DAY_ON_J2000;
        const double julianDay = JULIAN_DAY_ON_J2000 + 0.5;

        // Set expected seconds since epoch result.
        double expectedSecondsSinceEpoch
                = physical_constants::JULIAN_DAY / 2.0;

        // Compute seconds since epoch given Julian day and reference epoch.
        const double computedSecondsSinceEpoch = convertJulianDayToSecondsSinceEpoch(
                    julianDay, referenceEpoch );

        // Test that computed result matches expected result.
        // Test is run at reduced tolerance, because the final digits of the seconds were lost
        // when converting to Julian day.
        BOOST_CHECK_CLOSE_FRACTION( computedSecondsSinceEpoch, expectedSecondsSinceEpoch,
                                    std::numeric_limits< double >::epsilon( ) );
    }
}

//! Unit test for seconds to Julian day conversion function.
BOOST_AUTO_TEST_CASE( testSecondsSinceEpochToJulianDayConversions )
{
    // Test conversion from seconds since epoch to Julian day.

    // Set reference epoch and seconds since epoch for tests.
    const double referenceEpoch = JULIAN_DAY_AT_0_MJD;
    const double secondsSinceEpoch = 1.0e6;

    // Set expected Julian day result.
    const double expectedJulianDay = JULIAN_DAY_AT_0_MJD + 1.0e6 / 86400.0;

    // Compute Julian day with seconds since reference epoch specified.
    const double computedJulianDay = convertSecondsSinceEpochToJulianDay(
                secondsSinceEpoch, referenceEpoch );

    // Test that computed result matches expected result.
    BOOST_CHECK_CLOSE_FRACTION( computedJulianDay, expectedJulianDay,
                                std::numeric_limits< double >::epsilon( ) );
}

//! Unit test for calendar date to Julian day conversion function.
BOOST_AUTO_TEST_CASE( testConversionCalendarDateToJulianDay )
{
    // Compute the Julian day of the calendar date: January 1st, 2000, at 12h0m0s.
    {
        //Use the function to compute the Julian day.
        const double computedJulianDay = convertCalendarDateToJulianDay ( 2000, 1, 1, 12, 0, 0 );

        //Known Julian day at this calendar date.
        const double expectedJulianDay = basic_astrodynamics::JULIAN_DAY_ON_J2000;

        // Test that computed result matches expected result.
        BOOST_CHECK_CLOSE_FRACTION( computedJulianDay, expectedJulianDay,
                                std::numeric_limits< double >::epsilon( ) );
    }

    //Compute the Julian day of the calendar date: November 17th, 1858, At 0h0m0s.
    {
        //Use the function to compute the Julian day.
        const double computedJulianDay = convertCalendarDateToJulianDay( 1858, 11, 17, 0, 0, 0 );

        //Known Julian day at this calendar date
        const double expectedJulianDay = basic_astrodynamics::JULIAN_DAY_AT_0_MJD;

        // Test that computed result matches expected result.
        BOOST_CHECK_CLOSE_FRACTION( computedJulianDay, expectedJulianDay,
                                std::numeric_limits< double >::epsilon( ) );
    }

    //Test conversion wrapper against boost result.
    {
        const int year = 1749;
        const int month = 3;
        const int day = 30;

        BOOST_CHECK_CLOSE_FRACTION( boost::gregorian::date( year, month, day ).julian_day( ) - 0.5,
                                    convertCalendarDateToJulianDay( year, month, day, 0, 0, 0.0 ),
                                    std::numeric_limits< double >::epsilon( ) );
        const int hour = 4;
        BOOST_CHECK_CLOSE_FRACTION( boost::gregorian::date( year, month, day ).julian_day( ) - 0.5 +
                                    static_cast< double >( hour ) / 24.0,
                                    convertCalendarDateToJulianDay( year, month, day, hour, 0, 0.0 ),
                                    std::numeric_limits< double >::epsilon( ) );

        const int minute = 36;
        BOOST_CHECK_CLOSE_FRACTION( boost::gregorian::date( year, month, day ).julian_day( ) - 0.5 +
                                    static_cast< double >( hour ) / 24.0 + static_cast< double >( minute ) / ( 24.0 * 60.0 ),
                                    convertCalendarDateToJulianDay( year, month, day, hour, minute, 0.0 ),
                                    std::numeric_limits< double >::epsilon( ) );

        const double second = 21.36474854836359;
        BOOST_CHECK_CLOSE_FRACTION( boost::gregorian::date( year, month, day ).julian_day( ) - 0.5 +
                                    static_cast< double >( hour ) / 24.0 + static_cast< double >( minute ) / ( 24.0 * 60.0 ) +
                                    second / ( 24.0 * 60.0 * 60.0 ),
                                    convertCalendarDateToJulianDay( year, month, day, hour, minute, second ),
                                    std::numeric_limits< double >::epsilon( ) );

    }
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat


#define BOOST_TEST_MAIN

#include <boost/format.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/make_shared.hpp>

#include "Tudat/Basics/testMacros.h"

#include "Tudat/External/SpiceInterface/spiceInterface.h"
#include "Tudat/InputOutput/basicInputOutput.h"

#include "Tudat/Astrodynamics/Ephemerides/frameManager.h"
#include "Tudat/Astrodynamics/Ephemerides/constantEphemeris.h"

namespace tudat
{
namespace unit_tests
{

using namespace tudat::ephemerides;
using namespace tudat::spice_interface;

BOOST_AUTO_TEST_SUITE( test_frame_manager )

BOOST_AUTO_TEST_CASE( test_FrameManager )
{

    std::string kernelsPath = input_output::getSpiceKernelPath( );

    //Load spice kernels.
    spice_interface::loadSpiceKernelInTudat( kernelsPath + "naif0009.tls");
    spice_interface::loadSpiceKernelInTudat( kernelsPath + "pck00009.tpc");
    spice_interface::loadSpiceKernelInTudat( kernelsPath + "de-403-masses.tpc");
    spice_interface::loadSpiceKernelInTudat( kernelsPath + "de421.bsp");

    std::map< std::string, boost::shared_ptr< Ephemeris > > ephemerisList;

    basic_mathematics::Vector6d barycentricSunState = getBodyCartesianStateAtEpoch( "Sun", getBaseFrameName( ), "ECLIPJ2000", "NONE", 0.0 );
    ephemerisList[ "Sun" ] = boost::make_shared< ConstantEphemeris >( barycentricSunState, getBaseFrameName( ), "ECLIPJ2000" );

    basic_mathematics::Vector6d sunCentricEarthState = getBodyCartesianStateAtEpoch( "Earth", "Sun", "ECLIPJ2000", "NONE", 0.0 );
    ephemerisList[ "Earth" ] = boost::make_shared< ConstantEphemeris >( sunCentricEarthState, "Sun", "ECLIPJ2000" );

    basic_mathematics::Vector6d earthCentricMoonState = getBodyCartesianStateAtEpoch( "Moon", "Earth", "ECLIPJ2000", "NONE", 0.0 );
    ephemerisList[ "Moon" ] = boost::make_shared< ConstantEphemeris >( earthCentricMoonState, "Earth", "ECLIPJ2000" );

    basic_mathematics::Vector6d earthCentricLageosState = basic_mathematics::Vector6d::Zero( );
    earthCentricLageosState( 1 ) = 2.5E6;
    earthCentricLageosState( 2 ) = 4.0E6;
    ephemerisList[ "LAGEOS" ] = boost::make_shared< ConstantEphemeris >( earthCentricLageosState, "Earth", "ECLIPJ2000" );

    basic_mathematics::Vector6d moonCentricLroState = basic_mathematics::Vector6d::Zero( );
    moonCentricLroState( 0 ) = 1.0E6;
    moonCentricLroState( 1 ) = 2.0E6;

    ephemerisList[ "LRO" ] = boost::make_shared< ConstantEphemeris >( moonCentricLroState, "Moon", "ECLIPJ2000" );

    basic_mathematics::Vector6d sunCentricMarsState = getBodyCartesianStateAtEpoch( "Mars", "Sun", "ECLIPJ2000", "NONE", 0.0 );
    ephemerisList[ "Mars" ] = boost::make_shared< ConstantEphemeris >( sunCentricMarsState, "Sun", "ECLIPJ2000" );

    basic_mathematics::Vector6d marsCentricPhobosState = basic_mathematics::Vector6d::Zero( );
    marsCentricPhobosState( 0 ) = 2.3E5;
    marsCentricPhobosState( 1 ) = 2.9E4;
    marsCentricPhobosState( 2 ) = 600;

    ephemerisList[ "Phobos" ] = boost::make_shared< ConstantEphemeris >( marsCentricPhobosState, "Mars", "ECLIPJ2000" );

    boost::shared_ptr< ReferenceFrameManager > frameManager = boost::make_shared< ReferenceFrameManager >( ephemerisList );

    std::map< std::string, int > expectedFrameLevel;
    expectedFrameLevel[ "Sun" ] = 0;
    expectedFrameLevel[ "Earth" ] = 1;
    expectedFrameLevel[ "Mars" ] = 1;
    expectedFrameLevel[ "LAGEOS" ] = 2;
    expectedFrameLevel[ "Moon" ] = 2;
    expectedFrameLevel[ "Phobos" ] = 2;
    expectedFrameLevel[ "LRO" ] = 3;

    for( std::map< std::string, int >::iterator it = expectedFrameLevel.begin( ); it != expectedFrameLevel.end( ); it++ )
    {
        if( frameManager->getFrameLevel( it->first ).first != it->second )
        {
            throw std::runtime_error(
                        "Error when identifying frame level of " + it->first + " found " +
                        boost::lexical_cast< std::string >( frameManager->getFrameLevel( it->first ).first ) + " expected" +
                        boost::lexical_cast< std::string >( it->second ) );
        }
    }

    std::vector< std::string > frames;
    frames.push_back( "Earth" );
    frames.push_back( "Mars" );
    std::pair< std::string, int > commonFrame = frameManager->getNearestCommonFrame( frames );
    BOOST_CHECK_EQUAL( commonFrame.first, "Sun" );
    BOOST_CHECK_EQUAL( commonFrame.second, 0 );

    frames.clear( );
    frames.push_back( "Moon" );
    frames.push_back( "Sun" );

    commonFrame = frameManager->getNearestCommonFrame( frames );

    BOOST_CHECK_EQUAL( commonFrame.first, "Sun" );
    BOOST_CHECK_EQUAL( commonFrame.second, 0 );

    frames.clear( );
    frames.push_back( "Earth" );
    frames.push_back( "LRO" );

    commonFrame = frameManager->getNearestCommonFrame( frames );

    BOOST_CHECK_EQUAL( commonFrame.first, "Earth" );
    BOOST_CHECK_EQUAL( commonFrame.second, 1 );

    basic_mathematics::Vector6d testState = frameManager->getEphemeris< >( "Moon", "LAGEOS" )->getCartesianStateFromEphemeris( 0.0 );
    basic_mathematics::Vector6d expectedState = earthCentricLageosState - earthCentricMoonState;
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( testState, expectedState, std::numeric_limits< double >::epsilon( ) );

    testState = frameManager->getEphemeris( "Phobos", "Sun" )->getCartesianStateFromEphemeris( 0.0 );
    expectedState = sunCentricMarsState + marsCentricPhobosState;
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( testState, ( -1.0 * expectedState ), std::numeric_limits< double >::epsilon( ) );

    testState = frameManager->getEphemeris( "Sun", "Phobos" )->getCartesianStateFromEphemeris( 0.0 );
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( testState, expectedState, std::numeric_limits< double >::epsilon( ) );

    testState = frameManager->getEphemeris( "Sun", "Earth" )->getCartesianStateFromEphemeris( 0.0 );
    expectedState = sunCentricEarthState;
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( testState, expectedState, std::numeric_limits< double >::epsilon( ) );

    testState = frameManager->getEphemeris( getBaseFrameName( ), "Earth" )->getCartesianStateFromEphemeris( 0.0 );
    expectedState = barycentricSunState + sunCentricEarthState;
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( testState, expectedState, std::numeric_limits< double >::epsilon( ) );

    testState = frameManager->getEphemeris( "Earth", getBaseFrameName( ) )->getCartesianStateFromEphemeris( 0.0 );
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( testState, ( -1.0 * expectedState ), std::numeric_limits< double >::epsilon( ) );

}

BOOST_AUTO_TEST_SUITE_END( )

}

}


//////////////////////////////////////////////////////////////////////////////
///   Copyright 2003 and onward LASMEA UMR 6602 CNRS/U.B.P Clermont-Ferrand
///   Copyright 2009 and onward 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 bitwise toolbox - hi/scalar Mode"

//////////////////////////////////////////////////////////////////////////////
// Test behavior of bitwise components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created  by jt the 18/02/2011
/// modified by jt the 16/03/2011
#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/sdk/constant/real.hpp>
#include <nt2/sdk/constant/infinites.hpp>
#include <nt2/include/functions/ulpdist.hpp>
#include <nt2/toolbox/bitwise/include/hi.hpp>
// specific includes for arity 1 tests
#include<nt2/sdk/meta/downgrade.hpp>

NT2_TEST_CASE_TPL ( hi_real__1,  NT2_REAL_TYPES)
{

  using nt2::hi;
  using nt2::tag::hi_;
  typedef typename nt2::meta::as_integer<T,unsigned>::type ir_t;
  typedef typename nt2::meta::as_integer<T>::type iT;
  typedef typename nt2::meta::call<hi_(T)>::type r_t;
  typedef typename nt2::meta::upgrade<T>::type u_t;
  typedef typename nt2::meta::downgrade<ir_t>::type wished_r_t;

  // return type conformity test
  NT2_TEST( (boost::is_same < r_t, wished_r_t >::value) );
  std::cout << std::endl;
  double ulpd;
  ulpd=0.0;

  // specific values tests
  NT2_TEST_EQUAL(hi(nt2::Nan<T>()), nt2::Mone<r_t>());
  NT2_TEST_EQUAL(hi(nt2::Zero<T>()), nt2::Zero<r_t>());
} // end of test for real_

NT2_TEST_CASE_TPL ( hi_int64__1,  (int64_t)(uint64_t))
{

  using nt2::hi;
  using nt2::tag::hi_;
  typedef typename nt2::meta::as_integer<T,unsigned>::type ir_t;
  typedef typename nt2::meta::as_integer<T>::type iT;
  typedef typename nt2::meta::call<hi_(T)>::type r_t;
  typedef typename nt2::meta::upgrade<T>::type u_t;
  typedef typename nt2::meta::downgrade<ir_t>::type wished_r_t;

  // return type conformity test
  NT2_TEST( (boost::is_same < r_t, wished_r_t >::value) );
  std::cout << std::endl;
  double ulpd;
  ulpd=0.0;

  // specific values tests
  NT2_TEST_EQUAL(hi(nt2::One<T>()), nt2::Zero<r_t>());
  NT2_TEST_EQUAL(hi(nt2::Zero<T>()), nt2::Zero<r_t>());
} // end of test for int64_

NT2_TEST_CASE_TPL ( hi_int32__1,  (int32_t)(uint32_t))
{

  using nt2::hi;
  using nt2::tag::hi_;
  typedef typename nt2::meta::as_integer<T,unsigned>::type ir_t;
  typedef typename nt2::meta::as_integer<T>::type iT;
  typedef typename nt2::meta::call<hi_(T)>::type r_t;
  typedef typename nt2::meta::upgrade<T>::type u_t;
  typedef typename nt2::meta::downgrade<ir_t>::type wished_r_t;

  // return type conformity test
  NT2_TEST( (boost::is_same < r_t, wished_r_t >::value) );
  std::cout << std::endl;
  double ulpd;
  ulpd=0.0;

  // specific values tests
  NT2_TEST_EQUAL(hi(nt2::One<T>()), nt2::Zero<r_t>());
  NT2_TEST_EQUAL(hi(nt2::Zero<T>()), nt2::Zero<r_t>());
} // end of test for int32_

NT2_TEST_CASE_TPL ( hi_int16__1,  (int16_t)(uint16_t))
{

  using nt2::hi;
  using nt2::tag::hi_;
  typedef typename nt2::meta::as_integer<T,unsigned>::type ir_t;
  typedef typename nt2::meta::as_integer<T>::type iT;
  typedef typename nt2::meta::call<hi_(T)>::type r_t;
  typedef typename nt2::meta::upgrade<T>::type u_t;
  typedef typename nt2::meta::downgrade<ir_t>::type wished_r_t;

  // return type conformity test
  NT2_TEST( (boost::is_same < r_t, wished_r_t >::value) );
  std::cout << std::endl;
  double ulpd;
  ulpd=0.0;

  // specific values tests
  NT2_TEST_EQUAL(hi(nt2::One<T>()), nt2::Zero<r_t>());
  NT2_TEST_EQUAL(hi(nt2::Zero<T>()), nt2::Zero<r_t>());
} // end of test for int16_


/*
The library Boost.NumericConversion can be used to convert numbers of one
type to numbers of a different type. In C++, such a conversion can also
take place implicitly as shown in the following example.
*/

//#include <iostream>
//
//int main()
//{
//  int i = 0x10000;
//  short s = i;
//  std::cout << s << std::endl;
//}

/*
The example is compiled without any error since the type conversion from
int to short takes place automatically. Even though the application can be
executed, the result of the conversion cannot be predicted but rather
depends on the actual compiler and its implementation. The number 0x10000
in the variable i is too big to be stored in a variable of type short. Per
the C++ standard, the result of this operation is "implementation defined".
Compiled with Visual C++ 2008, the application displays 0. The value of s
certainly differs from the value in i.
*/

/*
To avoid these kind of errors while converting numbers, the cast operator
boost::numeric_cast can be used.
*/

#include <boost/numeric/conversion/cast.hpp>
#include <iostream>

int main()
{
  try
  {
    int i = -0x10000;
    short s = boost::numeric_cast<short>(i);
    std::cout << s << std::endl;
  }
  catch (boost::numeric::bad_numeric_cast &e)
  {
    std::cerr << e.what() << std::endl;
  }
}

/*
boost::numeric_cast is used exactly like the known C++ cast operators. The
correct header file must certainly be included though; in this case
boost/numeric/conversion/cast.hpp.

boost::numeric_cast executes the same conversion than C++ does implicitly.
However, boost::numeric_cast actually verifies whether or not the
conversion can take place without changing the value of the number to be
converted. Given the example application, a conversion would not take
place. Instead, an exception of type boost::numeric::bad_numeric_cast is
thrown since 0x10000 is too big to be placed in a variable of type short.
*/

/*
Strictly speaking, an exception of type boost::numeric::positive_overflow is
thrown. This type specifies a so-called overflow - in this case for
positive numbers. There also exists a type boost::numeric::negative_overflow
which specifies an overflow for negative numbers instead.
*/

//#include <boost/numeric/conversion/cast.hpp>
//#include <iostream>
//
//int main()
//{
//  try
//  {
//    int i = -0x10000;
//    short s = boost::numeric_cast<short>(i);
//    std::cout << s << std::endl;
//  }
//  catch (boost::numeric::negative_overflow &e)
//  {
//    std::cerr << e.what() << std::endl;
//  }
//}

/*
Boost.NumericConversion defines additional exception types, all derived
from boost::numeric::bad_numeric_cast. Since boost::numeric::bad_numeric_cast
is derived from std::bad_cast itself, a catch handler can also catch
exceptions of this type.
*/