#ifndef BOOST_SAFE_FLOAT_LITERALS_HPP
#define BOOST_SAFE_FLOAT_LITERALS_HPP

#include <boost/safe_float.hpp>

namespace boost
{
namespace safe_float
{
namespace literals
{
namespace detail
{
#define HEX_PARSE_ERROR "Not a valid hex floating point number literal"
#define DEC_PARSE_ERROR "Not a valid dec floating point number literal"
#define VALUE_ERROR "Floating point number isn't a positive power of 0.5"

template<char... digits>
struct bigint;

template<typename MANTISSA, int EXPONENT>
struct number {
    using mantissa = MANTISSA;
    static constexpr int exponent = EXPONENT;
};

template<typename T>
struct is_number : std::false_type {};

template<typename M, int E>
struct is_number<number<M, E>> : std::true_type {};

template<int MIN, int MAX>
struct min_max_pow {
    static constexpr int min = MIN;
    static constexpr int max = MAX;
};

template<typename BI, int EXP>
struct shift_left_helper;

template<char... digits, int EXP>
struct shift_left_helper<bigint<digits...>, EXP> {
    using type = typename shift_left_helper<bigint<digits..., 0>, EXP-1>::type;
};

template<char... digits>
struct shift_left_helper<bigint<digits...>, 0> {
    using type = bigint<digits...>;
};

template<typename BI, int EXP>
struct shift_right_helper;

template<char... digits, int EXP>
struct shift_right_helper<bigint<digits...>, EXP> {
    using type = typename shift_right_helper<bigint<0, digits...>, EXP-1>::type;
};

template<char... digits>
struct shift_right_helper<bigint<digits...>, 0> {
    using type = bigint<digits...>;
};

template<char... digits>
struct bigint {
    template<char next>
    using append = bigint<digits..., next>;

    template<int EXP>
    using shift_left = typename shift_left_helper<bigint, EXP>::type;

    template<int EXP>
    using shift_right = typename shift_right_helper<bigint, EXP>::type;

    static constexpr size_t length = sizeof...(digits);
};

template<typename T, unsigned long long init = 0>
struct bigint_value;

template<char first, char... rest, unsigned long long init>
struct bigint_value<bigint<first, rest...>, init> {
    static constexpr unsigned long long value = bigint_value<bigint<rest...>, init*10 + first>::value;
};

template<unsigned long long init>
struct bigint_value<bigint<>, init> {
    static constexpr unsigned long long value = init;
};

template<typename BI, typename RES, bool carry>
struct halve_helper;

template<char first, char... digits, char... other, bool carry>
struct halve_helper<bigint<first, digits...>, bigint<other...>, carry> {
    using type = typename halve_helper<bigint<digits...>, bigint<other..., (carry ? 5 : 0) + first/2>, (first % 2 == 1)>::type;
};

template<char... other, bool carry>
struct halve_helper<bigint<>, bigint<other...>, carry> {
    using type = bigint<other...>;
};

template<typename BI, typename RES>
struct halve_helper_first;

template<char first, char... digits>
struct halve_helper_first<bigint<first, digits...>, bigint<>> {
    using type = typename halve_helper<bigint<digits...>, bigint<first/2>, (first % 2 == 1)>::type;
};

template<char...digits>
struct halve_helper_first<bigint<1, digits...>, bigint<>> {
    using type = typename halve_helper<bigint<digits...>, bigint<>, true>::type;
};

template<typename BI>
using halve = typename halve_helper_first<BI, bigint<>>::type;

template<typename BI, typename RES, bool carry>
struct double_helper;

template<char first, char... digits, char... other, bool carry>
struct double_helper<bigint<first, digits...>, bigint<other...>, carry> {
    using type = typename double_helper<bigint<digits...>, bigint<other..., (first*2 + (carry?1:0))%10>, (first >= 5)>::type;
};

template<char... other, bool carry>
struct double_helper<bigint<>, bigint<other...>, carry> {
    using type = bigint<other...>;
};

template<typename BI, typename RES>
struct double_helper_first;

template<char first, char... digits>
struct double_helper_first<bigint<first, digits...>, bigint<>> {
    using type = typename double_helper<bigint<digits...>, bigint<(first*2)%10>, (first >= 5)>::type;
};

template<char... digits>
struct double_helper_first<bigint<5, digits...>, bigint<>> {
    using type = typename double_helper<bigint<digits...>, bigint<>, true>::type;
};

template<typename BI>
using double_op = typename double_helper_first<BI, bigint<>>::type;

template<typename BI>
struct is_odd;

template<char first, char... digits>
struct is_odd<bigint<first, digits...>> {
    static constexpr bool value = is_odd<bigint<digits...>>::value;
};

template<char digit>
struct is_odd<bigint<digit>> {
    static constexpr bool value = (digit % 2 == 1);
};

template<typename BI>
struct ends_with_gt5;

template<char first, char... digits>
struct ends_with_gt5<bigint<first, digits...>> {
    static constexpr bool value = ends_with_gt5<bigint<digits...>>::value;
};

template<char digit>
struct ends_with_gt5<bigint<digit>> {
    static constexpr bool value = (digit >= 5);
};

// TODO Find a way to get min/max power of 2 with less template recursion
// It could speed up compilation and avoid error with long numbers

template<typename MANTISSA>
struct get_min_pow_int_helper {
    static constexpr int value = (is_odd<MANTISSA>::value ? 0 : get_min_pow_int_helper<halve<MANTISSA>>::value + 1);
};

template<>
struct get_min_pow_int_helper<bigint<1>> {
    static constexpr int value = 0;
};

template<typename MANTISSA>
constexpr int get_min_pow_int() {
    return get_min_pow_int_helper<MANTISSA>::value;
}

template<typename MANTISSA, typename enable = void>
struct get_max_pow_dec_helper {
    static constexpr int value = (ends_with_gt5<MANTISSA>::value ? -1 : get_max_pow_dec_helper<double_op<MANTISSA>>::value - 1);
};

template<char digit>
struct get_max_pow_dec_helper<bigint<digit>, std::enable_if_t<(digit >=5)>> {
    static constexpr int value = -1;
};

template<typename MANTISSA>
constexpr int get_max_pow_dec() {
    return get_max_pow_dec_helper<MANTISSA>::value;
}

template<typename MANTISSA>
struct get_max_pow_int_helper {
    static constexpr int value = 1 + get_max_pow_int_helper<halve<MANTISSA>>::value;
};

template<>
struct get_max_pow_int_helper<bigint<1>> {
    static constexpr int value = 0;
};

template<typename MANTISSA>
constexpr int get_max_pow_int() {
    return get_max_pow_int_helper<MANTISSA>::value;
}

// TODO Stop recursion after a while if the number isn't made of powers of 2
template<typename MANTISSA, unsigned MAX_STEPS, typename enable = void>
struct get_min_pow_dec_helper;

template<typename MANTISSA, unsigned MAX_STEPS>
struct get_min_pow_dec_helper<MANTISSA, MAX_STEPS, std::enable_if_t<(MANTISSA::length > 1 && MAX_STEPS > 0)>> {
    static constexpr int value = get_min_pow_dec_helper<double_op<MANTISSA>, MAX_STEPS-1>::value - 1;
};

template<char digit, unsigned MAX_STEPS>
struct get_min_pow_dec_helper<bigint<digit>, MAX_STEPS, std::enable_if_t<(digit == 5 && MAX_STEPS > 0)>> {
    static constexpr int value = -1;
};

template<char digit, unsigned MAX_STEPS>
struct get_min_pow_dec_helper<bigint<digit>, MAX_STEPS, std::enable_if_t<(digit != 5 && MAX_STEPS > 0)>> {
    static constexpr int value = get_min_pow_dec_helper<double_op<bigint<digit>>, MAX_STEPS-1>::value - 1;
};

// If template recursion goes too far, stop it, number is not made of power of 2
template<typename MANTISSA>
struct get_min_pow_dec_helper<MANTISSA, 0, void> {
    static constexpr int value = -10000; // Give a value that will indicates the number isn't representable
};

template<typename MANTISSA>
constexpr int get_min_pow_dec() {
    return get_min_pow_dec_helper<MANTISSA, 800>::value;
}

template<typename BI, typename RES, unsigned count>
struct extract_begin_helper;

template<char first, char... digits, char... other, unsigned count>
struct extract_begin_helper<bigint<first, digits...>, bigint<other...>, count> {
    using type = typename extract_begin_helper<bigint<digits...>, bigint<other..., first>, count-1>::type;
};

template<char first, char...digits, char...other>
struct extract_begin_helper<bigint<first, digits...>, bigint<other...>, 0> {
    using type = bigint<other...>;
};

template<char... other, unsigned count>
struct extract_begin_helper<bigint<>, bigint<other...>, count> {
    using type = bigint<other...>;
};

template<typename BI, unsigned count>
using extract_begin = typename extract_begin_helper<BI, bigint<>, count>::type;

template<typename BI, unsigned count>
struct extract_end_helper;

template<char first, char... digits, unsigned count>
struct extract_end_helper<bigint<first, digits...>, count> {
    using type = std::conditional_t<(bigint<first, digits...>::length > count),
    typename extract_end_helper<bigint<digits...>, count>::type,
    bigint<first, digits...>>;
};

template<unsigned count>
struct extract_end_helper<bigint<>, count> {
    using type = bigint<>;
};

template<typename BI, unsigned count>
using extract_end = typename extract_end_helper<BI, count>::type;

template<typename NUMBER, typename INVERTED>
struct inverse_helper;

template<char first, char... rest, char... other>
struct inverse_helper<bigint<first, rest...>, bigint<other...>>  {
    using type = typename inverse_helper<bigint<rest...>, bigint<first, other...>>::type;
};

template<char... other>
struct inverse_helper<bigint<>, bigint<other...>> {
    using type = bigint<other...>;
};

template<typename NUMBER>
using inverse = typename inverse_helper<NUMBER, bigint<>>::type;

// A struct to be used in static_assert
template<typename T>
struct always_false
{
    static constexpr bool value = false;
};

// A constexpr version of isxdigit working on ASCII
constexpr bool isxdigit(char c)
{
    return ((c >= '0' and c <= '9') or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F'));
}

// A constexpr version of isdigit working on ASCII
constexpr bool isdigit(char c)
{
    return (c >= '0' and c <= '9');
}

// constexpr function to get the represented value of a hex digit
constexpr int hexvalue(char xdigit)
{
    return (xdigit >= '0' and xdigit <= '9') ?
               xdigit - '0' :
               (xdigit >= 'a' and xdigit <= 'f') ? xdigit - 'a' + 10 :
                                                   (xdigit >= 'A' and xdigit <= 'F') ? xdigit - 'A' + 10 : 0;
}

// constexpr function to get the represented value of a digit
constexpr int decvalue(char digit)
{
    return (digit >= '0' and digit <= '9') ? digit - '0' : 0;
}

// constexpr function that count bit equal to 1
constexpr int count_bit(unsigned long long a)
{
    int count = 0;
    while (a != 0)
    {
        if (a & 0x1) count++;
        a >>= 1;
    }

    return count;
}

// A constexpr function that count the number of bit with value 0 before a bit with 1
constexpr int count_shift(unsigned long long a)
{
    int count = 0;
    while (a != 0)
    {
        if (a & 0x1) return count;
        count++;
        a >>= 1;
    }

    return count;
}

template<typename T>
constexpr T trivial_pow(T x, int e)
{
    return e < 0 ? 1 / trivial_pow(x, -e) : e == 0 ? 1 : x * trivial_pow(x, e - 1);
}

// A function to know is a literal begins with an hex prefix
template<char FIRST>
constexpr bool has_hex_prefix()
{
    return false;
}

template<char FIRST, char SECOND, char... REST>
constexpr bool has_hex_prefix()
{
    return FIRST == '0' and (SECOND == 'x' or SECOND == 'X');
}

/*
 * Hex parsing related functions (better understanding by reading from bottom to top)
 */

// Function used to validate the number and returning its value
template<typename RT, unsigned long long MANTISSA, int POW, bool SIGN, int EXPONENT>
constexpr RT validate_hex()
{
    // Is it a power of two ?
    static_assert(count_bit(MANTISSA) == 1, VALUE_ERROR);
    // Is the exponent negative (positive power of 0.5 means negative power of 2)
    static_assert(count_shift(MANTISSA) + POW + (SIGN ? EXPONENT : -EXPONENT) < 0, VALUE_ERROR);
    return static_cast<RT>(MANTISSA) * trivial_pow(2.0l, POW + (SIGN ? EXPONENT : -EXPONENT));
}

// Function used to parse the digit of the exponent
template<typename RT, unsigned long long MANTISSA, int POW, bool SIGN, int EXPONENT>
constexpr RT parse_hex_exponent()
{
    return validate_hex<RT, MANTISSA, POW, SIGN, EXPONENT>();
}

template<typename RT, unsigned long long MANTISSA, int POW, bool SIGN, int EXPONENT, char FIRST, char... REST>
constexpr RT parse_hex_exponent()
{
    static_assert(isdigit(FIRST), HEX_PARSE_ERROR);
    return parse_hex_exponent<RT, MANTISSA, POW, SIGN, EXPONENT * 10 + decvalue(FIRST), REST...>();
}

// This function parses the first character after the 'p'
template<typename RT, unsigned long long MANTISSA, int POW>
constexpr RT parse_hex_exponent_sign()
{
    static_assert(always_false<RT>::value, HEX_PARSE_ERROR);
    return RT{};
}

template<typename RT, unsigned long long MANTISSA, int POW, char FIRST, char... REST>
constexpr RT parse_hex_exponent_sign()
{
    static_assert(isxdigit(FIRST) or FIRST == '+' or FIRST == '-', HEX_PARSE_ERROR);
    if constexpr (isxdigit(FIRST))
        return parse_hex_exponent<RT, MANTISSA, POW, true, hexvalue(FIRST), REST...>();
    else
    {
        // If we have a sign, we need to make there is at least one other character after
        static_assert(sizeof...(REST) > 0, HEX_PARSE_ERROR);
        if constexpr (FIRST == '+')
            return parse_hex_exponent<RT, MANTISSA, POW, true, 0, REST...>();
        else
            return parse_hex_exponent<RT, MANTISSA, POW, false, 0, REST...>();
    }
}

// Function used to parse the characters of a hex float literal that appear after the period
template<typename RT, unsigned long long MANTISSA, int POW>
constexpr RT parse_hex_post_period()
{
    static_assert(always_false<RT>::value, HEX_PARSE_ERROR);
    return RT{};
}

template<typename RT, unsigned long long MANTISSA, int POW, char FIRST, char... REST>
constexpr RT parse_hex_post_period()
{
    static_assert(isxdigit(FIRST) or FIRST == 'p' or FIRST == 'P', HEX_PARSE_ERROR);
    if constexpr (isxdigit(FIRST))
        return parse_hex_post_period<RT, MANTISSA * 16 + hexvalue(FIRST), POW - 4, REST...>();
    else
        return parse_hex_exponent_sign<RT, MANTISSA, POW, REST...>();
}

// Function used to parse the characters of a hex float literal that appear before the period
template<typename RT, unsigned long long MANTISSA>
constexpr RT parse_hex_pre_period()
{
    // If they are no more characters and we're here it means that is not a good hex float literal
    static_assert(always_false<RT>::value, HEX_PARSE_ERROR);
    return RT{};
}

template<typename RT, unsigned long long MANTISSA, char FIRST, char... REST>
constexpr RT parse_hex_pre_period()
{
    static_assert(isxdigit(FIRST) or FIRST == '.' or FIRST == 'p' or FIRST == 'P', HEX_PARSE_ERROR);
    if constexpr (isxdigit(FIRST))
        return parse_hex_pre_period<RT, MANTISSA * 16 + hexvalue(FIRST), REST...>();
    else if constexpr (FIRST == '.')
        return parse_hex_post_period<RT, MANTISSA, 0, REST...>();
    else
        return parse_hex_exponent_sign<RT, MANTISSA, 0, REST...>();
}

template<typename RT, char FIRST, char SECOND, char... REST>
constexpr RT test_hex()
{
    // Discard 2 first char as they are the hex marker
    return parse_hex_pre_period<RT, 0, REST...>();
}

template<typename RT>
struct in_range_for_helper;

template<>
struct in_range_for_helper<float> {
    static constexpr bool calc(int min, int max) {
        return (max - min <= 23) && (max <  128) && (max > -127);
    }
};

template<>
struct in_range_for_helper<double> {
    static constexpr bool calc(int min, int max) {
        return (max - min <= 52) && (max <  1024) && (max > -1023);
    }
};

template<>
struct in_range_for_helper<long double> {
    static constexpr bool calc(int min, int max) {
        return (max - min <= 64) && (max <  16384) && (max > -16383);
    }
};

template<typename RT>
constexpr bool in_range_for(int min, int max) {
    return in_range_for_helper<RT>::calc(min, max);
}

template<typename MANTISSA, int EXPONENT>
constexpr auto get_min_max_pow() {
    // TODO Special cases when 0 or 0 dot something
    if constexpr(EXPONENT >= 0) // Only integer part
    {
        using shifted = typename MANTISSA::template shift_left<EXPONENT>;
        constexpr int min_pow = get_min_pow_int<shifted>();
        constexpr int max_pow = get_max_pow_int<shifted>();

        return min_max_pow<min_pow, max_pow>{};
    } else if constexpr(-EXPONENT >= MANTISSA::length) // Only decimal part
    {
        using shifted = typename MANTISSA::template shift_right<-EXPONENT-MANTISSA::length>;
        using inversed = inverse<shifted>;
        constexpr int min_pow = get_min_pow_dec<inversed>();
        constexpr int max_pow = get_max_pow_dec<inversed>();

        return min_max_pow<min_pow, max_pow>{};
    } else
    {
        using int_part = extract_begin<MANTISSA, MANTISSA::length+EXPONENT>;
        using dec_part = extract_end<MANTISSA, -EXPONENT>;
        constexpr int min_pow = get_min_pow_dec<inverse<dec_part>>();
        constexpr int max_pow = get_max_pow_int<int_part>();

        return min_max_pow<min_pow, max_pow>{};
    }
}

template<typename RT, typename MANTISSA, int EXPONENT>
constexpr bool is_representable() {
    // TODO Special cases when 0 or 0 dot something
    using min_max = decltype(get_min_max_pow<MANTISSA, EXPONENT>());
    return in_range_for<RT>(min_max::min, min_max::max);
}

// Validate value and returns it
template<typename RT, typename MANTISSA, int POW, bool SIGN, int EXPONENT>
constexpr RT validate_dec()
{
    static_assert(is_representable<RT, MANTISSA, POW + (SIGN ? EXPONENT : -EXPONENT)>(),
        "This number cannot be represented exactly");
    constexpr unsigned long long mantissa = bigint_value<MANTISSA>::value;
    constexpr RT value =
        (POW + (SIGN ? EXPONENT : -EXPONENT) < 0 ? mantissa / trivial_pow(10.0l, -POW - (SIGN ? EXPONENT : -EXPONENT)) :
                                                   mantissa * trivial_pow(10.0l, POW + (SIGN ? EXPONENT : -EXPONENT)));
    return value;
}

// This function parses the exponent past the first character
template<typename MANTISSA, int POW, bool SIGN, int EXPONENT>
constexpr auto parse_dec_exponent()
{
    return number<MANTISSA, POW + (SIGN ? EXPONENT : -EXPONENT)>{};
}

template<typename MANTISSA, int POW, bool SIGN, int EXPONENT, char FIRST, char... REST>
constexpr auto parse_dec_exponent()
{
    static_assert(isdigit(FIRST), DEC_PARSE_ERROR);
    return parse_dec_exponent<MANTISSA, POW, SIGN, EXPONENT * 10 + decvalue(FIRST), REST...>();
}

// This function parses the first character of the exponent
template<typename MANTISSA, int POW>
constexpr auto parse_dec_exponent_sign()
{
    static_assert(always_false<MANTISSA>::value, DEC_PARSE_ERROR);
    return int{};
}

template<typename MANTISSA, int POW, char FIRST, char... REST>
constexpr auto parse_dec_exponent_sign()
{
    static_assert(isdigit(FIRST) or ((FIRST == '+' or FIRST == '-') and sizeof...(REST) > 0), DEC_PARSE_ERROR);
    if constexpr (isdigit(FIRST))
        return parse_dec_exponent<MANTISSA, POW, true, decvalue(FIRST), REST...>();
    else if constexpr (FIRST == '+')
        return parse_dec_exponent<MANTISSA, POW, true, 0, REST...>();
    else
        return parse_dec_exponent<MANTISSA, POW, false, 0, REST...>();
}

// This function parses the characters that are after the period
template<typename MANTISSA, int POW>
constexpr auto parse_dec_post_period()
{
    return number<MANTISSA, POW>{};
}

template<typename MANTISSA, int POW, char FIRST, char... REST>
constexpr auto parse_dec_post_period()
{
    static_assert(isdigit(FIRST) or FIRST == 'e' or FIRST == 'E', DEC_PARSE_ERROR);
    if constexpr (isdigit(FIRST))
        return parse_dec_post_period<typename MANTISSA::template append<decvalue(FIRST)>, POW - 1, REST...>();
    else
        return parse_dec_exponent_sign<MANTISSA, POW, REST...>();
}

// This character parses the first characters before the period
template<typename MANTISSA>
constexpr auto parse_dec_pre_period()
{
    return validate_dec<MANTISSA, 0, true, 0>();
}

template<typename MANTISSA, char FIRST, char... REST>
constexpr auto parse_dec_pre_period()
{
    static_assert(isdigit(FIRST) or FIRST == '.' or FIRST == 'e' or FIRST == 'E', DEC_PARSE_ERROR);
    if constexpr (isdigit(FIRST))
        return parse_dec_pre_period<typename MANTISSA::template append<decvalue(FIRST)>, REST...>();
    else if constexpr (FIRST == '.')
        return parse_dec_post_period<MANTISSA, 0, REST...>();
    else
        return parse_dec_exponent_sign<MANTISSA, 0, REST...>();
}

template<char... STR>
constexpr auto test_dec()
{
    return parse_dec_pre_period<bigint<>, STR...>();
}

// Don't pollute global namespace
#undef HEX_PARSE_ERROR
#undef DEC_PARSE_ERROR
#undef VALUE_ERROR

template<char... STR>
constexpr auto parse_float_literal()
{
    if constexpr (has_hex_prefix<STR...>())
        return test_hex<double, STR...>();
    else
        return test_dec<STR...>();
}
} // namespace detail

template<char... STR>
boost::safe_float::safe_float<float> operator""_sf()
{
    using number = decltype(detail::parse_float_literal<STR...>());
    if constexpr(detail::is_number<number>::value) {
        using mantissa = typename number::mantissa;
        constexpr int exponent = number::exponent;

        static_assert(detail::is_representable<float, mantissa, exponent>(),
                      "This number cannot be represented exactly");

        constexpr unsigned long long mantissa_value = detail::bigint_value<mantissa>::value;
        constexpr float value =
            (exponent < 0 ? mantissa_value / detail::trivial_pow(10.0l, -exponent) :
             mantissa_value * detail::trivial_pow(10.0l, exponent));
        return boost::safe_float::safe_float<float>(value);
    }
}

template<char... STR>
boost::safe_float::safe_float<double> operator""_sd()
{
    using number = decltype(detail::parse_float_literal<STR...>());
    if constexpr(detail::is_number<number>::value) {
        using mantissa = typename number::mantissa;
        constexpr int exponent = number::exponent;

        static_assert(detail::is_representable<double, mantissa, exponent>(),
                      "This number cannot be represented exactly");

        constexpr unsigned long long mantissa_value = detail::bigint_value<mantissa>::value;
        constexpr double value =
            (exponent < 0 ? mantissa_value / detail::trivial_pow(10.0l, -exponent) :
             mantissa_value * detail::trivial_pow(10.0l, exponent));
        return boost::safe_float::safe_float<double>(value);
    }
    return boost::safe_float::safe_float<double>(0.0);
}

template<char... STR>
boost::safe_float::safe_float<long double> operator""_sld()
{
    using number = decltype(detail::parse_float_literal<STR...>());
    if constexpr(detail::is_number<number>::value) {
        using mantissa = typename number::mantissa;
        constexpr int exponent = number::exponent;

        static_assert(detail::is_representable<long double, mantissa, exponent>(),
                      "This number cannot be represented exactly");

        constexpr unsigned long long mantissa_value = detail::bigint_value<mantissa>::value;
        constexpr long double value =
            (exponent < 0 ? mantissa_value / detail::trivial_pow(10.0l, -exponent) :
             mantissa_value * detail::trivial_pow(10.0l, exponent));
        return boost::safe_float::safe_float<long double>(value);
    }
    return boost::safe_float::safe_float<long double>(0.0l);
}

} // namespace literals
} // namespace safe_float
} // namespace boost

#endif // BOOST_SAFE_FLOAT_LITERALS_HPP


// Boost.Geometry

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

// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP
#define BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP

#include <boost/geometry/algorithms/not_implemented.hpp>

#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>

#include <boost/geometry/util/math.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DISPATCH
namespace formula_dispatch
{

template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type>
struct eccentricity_sqr
    : not_implemented<Tag>
{};

template <typename ResultType, typename Geometry>
struct eccentricity_sqr<ResultType, Geometry, srs_sphere_tag>
{
    static inline ResultType apply(Geometry const& /*geometry*/)
    {
        return ResultType(0);
    }
};

template <typename ResultType, typename Geometry>
struct eccentricity_sqr<ResultType, Geometry, srs_spheroid_tag>
{
    static inline ResultType apply(Geometry const& geometry)
    {
        // 1 - (b / a)^2
        return ResultType(1) - math::sqr(ResultType(get_radius<2>(geometry))
                                       / ResultType(get_radius<0>(geometry)));
    }
};

} // namespace formula_dispatch
#endif // DOXYGEN_NO_DISPATCH

#ifndef DOXYGEN_NO_DETAIL
namespace formula
{

template <typename ResultType, typename Geometry>
ResultType eccentricity_sqr(Geometry const& geometry)
{
    return formula_dispatch::eccentricity_sqr<ResultType, Geometry>::apply(geometry);
}

} // namespace formula
#endif // DOXYGEN_NO_DETAIL

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP


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

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T.Lapreste

  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_DEFINITION_FABS_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_DEFINITION_FABS_HPP_INCLUDED

#include <boost/simd/config.hpp>
#include <boost/simd/function/definition/abs.hpp>
#include <boost/simd/detail/dispatch.hpp>

namespace boost { namespace simd
{
  namespace tag
  {
    using fabs_ = abs_;
  }

  BOOST_DISPATCH_CALLABLE_DEFINITION(tag::fabs_,fabs);
} }

#endif


// Copyright 2003-2008 Jan Gaspar.
// Copyright 2013 Paul A. Bristow.   Added some Quickbook snippet markers.

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

//[circular_buffer_sum_example_1

/*`This example shows several functions, including summing all valid values.
*/

   #include <boost/circular_buffer.hpp>
   #include <numeric>
   #include <assert.h>

   int main(int /*argc*/, char* /*argv*/[])
   {
      // Create a circular buffer of capacity 3.
      boost::circular_buffer<int> cb(3);
      assert(cb.capacity() == 3);
      // Check is empty.
      assert(cb.size() == 0);
      assert(cb.empty());

      // Insert some elements into the circular buffer.
      cb.push_back(1);
      cb.push_back(2);

      // Assertions to check push_backs have expected effect.
      assert(cb[0] == 1);
      assert(cb[1] == 2);
      assert(!cb.full());
      assert(cb.size() == 2);
      assert(cb.capacity() == 3);

      // Insert some other elements.
      cb.push_back(3);
      cb.push_back(4);

      // Evaluate the sum of all elements.
      int sum = std::accumulate(cb.begin(), cb.end(), 0);

      // Assertions to check state.
      assert(sum == 9);
      assert(cb[0] == 2);
      assert(cb[1] == 3);
      assert(cb[2] == 4);
      assert(*cb.begin() == 2);
      assert(cb.front() == 2);
      assert(cb.back() == 4);
      assert(cb.full());
      assert(cb.size() == 3);
      assert(cb.capacity() == 3);

      return 0;
   }

   //] [/circular_buffer_sum_example_1]

   /*
   There is no output from this example.
   */


//
// Created by Denis Wagner on 1/14/19.
//

#ifndef PONG_BALL_HPP
#define PONG_BALL_HPP

#include <Node.hpp>
#include <SFML/Graphics/CircleShape.hpp>
#include <boost/math/constants/constants.hpp>
#include <random>
#include "Paddle.hpp"

class PlayfieldView;

class Ball : public Node {
    PlayfieldView* playfieldView;

    const float     ballRadius   = 10;
    const float     ballSpeed    = 15;
    sf::CircleShape circle;
    int             waitCounter;

    std::mt19937_64                        rng;
    std::uniform_real_distribution<double> randomAngle{ 0, 360 };
    std::normal_distribution<double>       randomOffsetAngle{ 0, 10 };

    sf::Vector2f wallDirectionVector{ 1, 0 };
    sf::Vector2f paddleDirectionVector{ 0, 1 };
    sf::Vector2f moveVector{ ballSpeed, 0 };
    bool         collisionTop    = false;
    bool         collisionBottom = false;
    bool         collisionLeft   = false;
    bool         collisionRight  = false;

    std::shared_ptr<Paddle> leftPaddle;
    std::shared_ptr<Paddle> rightPaddle;

public:
    virtual void init() override;
    virtual void draw( sf::RenderWindow& window ) override;
    float getBallRadius();
    const sf::Vector2f& getPosition();
    const sf::Vector2f& getMoveVector();
};

#endif //PONG_BALL_HPP


#include <boost/numeric/odeint/stepper/modified_midpoint.hpp>


/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/
#define _USE_MATH_DEFINES
#include "mitkHummelProtocolEvaluation.h"

#include <boost/serialization/array_wrapper.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/tail_quantile.hpp>
#include <boost/math/distributions/normal.hpp>
#include <algorithm>

bool mitk::HummelProtocolEvaluation::Evaluate15cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector<HummelProtocolDistanceError> &Results)
{
  if (m != mitk::HummelProtocolEvaluation::standard) { MITK_WARN << "15 cm distances are only evaluated for standard volumes, aborting!"; return false; }

  MITK_INFO << "########### 15 cm distance errors #############";

  //convert measurements to matrix
  std::array<std::array<mitk::Point3D, 10> ,9>  matrix = ParseMatrixStandardVolume(p);

  //these are the variables for the results:
  std::vector<double> distances;
  std::vector<std::string> descriptions;

  //evaluation of rows
  int distanceCounter = 0;
  for (int row = 0; row < 9; row++) //rows
    for (int distance = 0; distance < 7; distance++)
    {
      distanceCounter++;
      mitk::Point3D point1 = p->GetPoint(row * 10 + distance);
      mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 3);
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 4);
      descriptions.push_back(description.str());
    }

  //evaluation of columns
  for (int column = 0; column < 10; column++)
    for (int row = 0; row < 6; row++)
    {
      distanceCounter++;
      mitk::Point3D point1 = matrix[row][column];
      mitk::Point3D point2 = matrix[row + 3][column];
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 4) << "/" << (column + 1);
      descriptions.push_back(description.str());
    }

  //compute all errors
  for (std::size_t i = 0; i < distances.size(); ++i)
  {
    HummelProtocolDistanceError currentError;
    currentError.distanceError = fabs(distances.at(i) - (double)150.0);
    currentError.description = descriptions.at(i);
    Results.push_back(currentError);
    MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError;
  }

  //compute statistics
  std::vector<HummelProtocolDistanceError> statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results);
  for (auto currentError : statistics)
  {
    Results.push_back(currentError);
    MITK_INFO << currentError.description << " : " << currentError.distanceError;
  }

  return true;
}

bool mitk::HummelProtocolEvaluation::Evaluate30cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector<HummelProtocolDistanceError> &Results)
{
  if (m != mitk::HummelProtocolEvaluation::standard) { MITK_WARN << "30 cm distances are only evaluated for standard volumes, aborting!"; return false; }
  MITK_INFO << "########### 30 cm distance errors #############";

  //convert measurements to matrix
  std::array<std::array<mitk::Point3D, 10> ,9>  matrix = ParseMatrixStandardVolume(p);

  //these are the variables for the results:
  std::vector<double> distances;
  std::vector<std::string> descriptions;

  //evaluation of rows
  int distanceCounter = 0;
  for (int row = 0; row < 9; row++) //rows
    for (int distance = 0; distance < 4; distance++)
    {
      distanceCounter++;
      mitk::Point3D point1 = p->GetPoint(row * 10 + distance);
      mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 6);
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 7);
      descriptions.push_back(description.str());
    }

  //evaluation of columns
  for (int column = 0; column < 10; column++)
    for (int row = 0; row < 3; row++)
    {
      distanceCounter++;
      mitk::Point3D point1 = matrix[row][column];
      mitk::Point3D point2 = matrix[row + 6][column];
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 7) << "/" << (column + 1);
      descriptions.push_back(description.str());
    }

  //compute all errors
  for (std::size_t i = 0; i < distances.size(); ++i)
  {
    HummelProtocolDistanceError currentError;
    currentError.distanceError = fabs(distances.at(i) - (double)300.0);
    currentError.description = descriptions.at(i);
    Results.push_back(currentError);
    MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError;
  }

  //compute statistics
  std::vector<HummelProtocolDistanceError> statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results);
  for (auto currentError : statistics)
  {
    Results.push_back(currentError);
    MITK_INFO << currentError.description << " : " << currentError.distanceError;
  }

  return true;
}

bool mitk::HummelProtocolEvaluation::EvaluateAccumulatedDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector<HummelProtocolDistanceError> &Results)
{
  if (m != mitk::HummelProtocolEvaluation::standard) { MITK_WARN << "Accumulated distances are only evaluated for standard volumes, aborting!"; return false; }

  MITK_INFO << "########### accumulated distance errors #############";

  int distanceCounter = 0;

  //evaluation of rows
  for (int row = 0; row < 9; row++) //rows
    for (int distance = 0; distance < 9; distance++)
    {
      distanceCounter++;
      mitk::Point3D point1 = p->GetPoint(row * 10);
      mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 1);
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/1 to " << (row + 1) << "/" << (distance + 2);
      //compute error
      HummelProtocolDistanceError currentError;
      currentError.distanceError = fabs(point1.EuclideanDistanceTo(point2) - (double)(50.0*(distance+1)));
      currentError.description = description.str();
      Results.push_back(currentError);
      MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError;
    }

  //compute statistics
  std::vector<HummelProtocolDistanceError> statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results);
  for (auto currentError : statistics)
  {
    Results.push_back(currentError);
    MITK_INFO << currentError.description << " : " << currentError.distanceError;
  }

return true;
}

bool mitk::HummelProtocolEvaluation::Evaluate5cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector<HummelProtocolDistanceError> &Results)
{
MITK_INFO << "########### 5 cm distance errors #############";
std::vector<double> distances;
std::vector<std::string> descriptions;
switch (m)
{
case small:
  if (p->GetSize() != 12) {
  MITK_WARN << "Wrong number of points: " << p->GetSize() << " (expected 12), aborting";
  return false;
  }
  MITK_INFO << "Computing Hummel protocol distance errors for small measurement volumes (12 points)...";

  //row 1
  distances.push_back(p->GetPoint(0).EuclideanDistanceTo(p->GetPoint(1))); //0
  descriptions.push_back("Distance 4/4 to 4/5");
  distances.push_back(p->GetPoint(1).EuclideanDistanceTo(p->GetPoint(2))); //1
  descriptions.push_back("Distance 4/5 to 4/6");
  distances.push_back(p->GetPoint(2).EuclideanDistanceTo(p->GetPoint(3))); //2
  descriptions.push_back("Distance 4/6 to 4/7");
  //row 2
  distances.push_back(p->GetPoint(4).EuclideanDistanceTo(p->GetPoint(5))); //3
  descriptions.push_back("Distance 5/4 to 5/5");
  distances.push_back(p->GetPoint(5).EuclideanDistanceTo(p->GetPoint(6))); //4
  descriptions.push_back("Distance 5/5 to 5/6");
  distances.push_back(p->GetPoint(6).EuclideanDistanceTo(p->GetPoint(7))); //5
  descriptions.push_back("Distance 5/6 to 5/7");
  //row 3
  distances.push_back(p->GetPoint(8).EuclideanDistanceTo(p->GetPoint(9))); //6
  descriptions.push_back("Distance 6/4 to 6/5");
  distances.push_back(p->GetPoint(9).EuclideanDistanceTo(p->GetPoint(10))); //7
  descriptions.push_back("Distance 6/5 to 6/6");
  distances.push_back(p->GetPoint(10).EuclideanDistanceTo(p->GetPoint(11))); //8
  descriptions.push_back("Distance 6/6 to 6/7");
  //column 1
  distances.push_back(p->GetPoint(0).EuclideanDistanceTo(p->GetPoint(4))); //9
  descriptions.push_back("Distance 4/4 to 5/4");
  distances.push_back(p->GetPoint(4).EuclideanDistanceTo(p->GetPoint(8))); //10
  descriptions.push_back("Distance 5/4 to 6/4");
  //column 2
  distances.push_back(p->GetPoint(1).EuclideanDistanceTo(p->GetPoint(5))); //11
  descriptions.push_back("Distance 4/5 to 5/5");
  distances.push_back(p->GetPoint(5).EuclideanDistanceTo(p->GetPoint(9))); //12
  descriptions.push_back("Distance 5/5 to 6/5");
  //column 3
  distances.push_back(p->GetPoint(2).EuclideanDistanceTo(p->GetPoint(6))); //13
  descriptions.push_back("Distance 4/6 to 5/6");
  distances.push_back(p->GetPoint(6).EuclideanDistanceTo(p->GetPoint(10))); //14
  descriptions.push_back("Distance 5/6 to 6/6");
  //column 4
  distances.push_back(p->GetPoint(3).EuclideanDistanceTo(p->GetPoint(7))); //15
  descriptions.push_back("Distance 4/7 to 5/7");
  distances.push_back(p->GetPoint(7).EuclideanDistanceTo(p->GetPoint(11))); //16
  descriptions.push_back("Distance 5/7 to 6/7");

break;

case medium:
{
  if (p->GetSize() != 25) {
    MITK_WARN << "Wrong number of points (expected 25), aborting";
    return false;
  }
  MITK_INFO << "Computing Hummel protocol distance errors for medium measurement volumes (25 points)...";

  int distanceCounter = 0;

  //convert measurements to matrix
  std::array<std::array<mitk::Point3D, 5>, 5>  matrix = ParseMatrixMediumVolume(p);

  //evaluation of rows
  for (int row = 0; row < 5; row++) //rows
    for (int distance = 0; distance < 4; distance++)
    {
      distanceCounter++;
      mitk::Point3D point1 = p->GetPoint(row * 5 + distance);
      mitk::Point3D point2 = p->GetPoint(row * 5 + distance + 1);
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 2);
      descriptions.push_back(description.str());
    }

  //evaluation of columns
  for (int column = 0; column < 5; column++)
    for (int row = 0; row < 4; row++)
    {
      distanceCounter++;
      mitk::Point3D point1 = matrix[row][column];
      mitk::Point3D point2 = matrix[row + 1][column];
      MITK_INFO << "Point 1:" << point1 << "/Point 2:" << point2 << "/Distance:" << point1.EuclideanDistanceTo(point2);
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 2) << "/" << (column + 1);
      descriptions.push_back(description.str());
    }
  }
  break;

case standard:
{
  if (p->GetSize() != 90) {
    MITK_WARN << "Wrong number of points (expected 90), aborting";
    return false;
  }
  MITK_INFO << "Computing Hummel protocol distance errors for standard measurement volumes (90 points)...";

  int distanceCounter = 0;

  //convert measurements to matrix
  std::array<std::array<mitk::Point3D, 10>, 9>  matrix = ParseMatrixStandardVolume(p);

  //evaluation of rows
  for (int row = 0; row < 9; row++) //rows
    for (int distance = 0; distance < 9; distance++)
    {
      distanceCounter++;
      mitk::Point3D point1 = p->GetPoint(row * 10 + distance);
      mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 1);
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 2);
      descriptions.push_back(description.str());
    }

  //evaluation of columns
  for (int column = 0; column < 10; column++)
    for (int row = 0; row < 8; row++)
    {
      distanceCounter++;
      mitk::Point3D point1 = matrix[row][column];
      mitk::Point3D point2 = matrix[row + 1][column];
      distances.push_back(point1.EuclideanDistanceTo(point2));
      std::stringstream description;
      description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 2) << "/" << (column + 1);
      descriptions.push_back(description.str());
    }
  }
  break;

}

//compute all errors
for (std::size_t i = 0; i < distances.size(); ++i)
{
HummelProtocolDistanceError currentError;
currentError.distanceError = fabs(distances.at(i) - (double)50.0);
currentError.description = descriptions.at(i);
Results.push_back(currentError);
MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError;
}

//compute statistics
std::vector<HummelProtocolDistanceError> statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results);
for (auto currentError : statistics)
{
  Results.push_back(currentError);
  MITK_INFO << currentError.description << " : " << currentError.distanceError;
}

return true;
}

std::array<std::array<mitk::Point3D, 10>, 9> mitk::HummelProtocolEvaluation::ParseMatrixStandardVolume(mitk::PointSet::Pointer p)
{

  std::array<std::array<mitk::Point3D, 10> ,9> returnValue;

  if (p->GetSize() != 90)
  {
    MITK_WARN << "PointSet does not have the right size. Expected 90 got " << p->GetSize() << " ... aborting!";
    return returnValue;
  }
  for (int row = 0; row < 9; row++)
    for (int column = 0; column < 10; column++)
      returnValue[row][column] = p->GetPoint(row * 10 + column);
  return returnValue;
}

std::array<std::array<mitk::Point3D, 5>, 5> mitk::HummelProtocolEvaluation::ParseMatrixMediumVolume(mitk::PointSet::Pointer p)
{

  std::array<std::array<mitk::Point3D, 5>, 5> returnValue;

  if (p->GetSize() != 25)
  {
    MITK_WARN << "PointSet does not have the right size. Expected 25 got " << p->GetSize() << " ... aborting!";
    return returnValue;
  }
  for (int row = 0; row < 5; row++)
    for (int column = 0; column < 5; column++)
    {
      returnValue[row][column] = p->GetPoint(row * 5 + column);
      //MITK_INFO << "m " << row << "/" << column << ":" << p->GetPoint(row * 5 + column);
    }

  return returnValue;

}

std::vector<mitk::HummelProtocolEvaluation::HummelProtocolDistanceError> mitk::HummelProtocolEvaluation::ComputeStatistics(std::vector<mitk::HummelProtocolEvaluation::HummelProtocolDistanceError> values)
{
  std::vector<mitk::HummelProtocolEvaluation::HummelProtocolDistanceError> returnValue;

  //convert input values to boost / using boost accumulators for statistics
  boost::accumulators::accumulator_set<double, boost::accumulators::features<boost::accumulators::tag::mean,
                                                                             //boost::accumulators::tag::median,
                                                                             boost::accumulators::tag::variance,
                                                                             boost::accumulators::tag::max,
                                                                             boost::accumulators::tag::min
                                                                             //boost::accumulators::tag::tail<boost::accumulators::left>
                                                                          > > acc;
  for (mitk::HummelProtocolEvaluation::HummelProtocolDistanceError each : values)
  {
    acc(each.distanceError);
  }

  returnValue.push_back({ static_cast<double>(values.size()), "N" });
  returnValue.push_back({ boost::accumulators::mean(acc), "Mean" });
  //double quantile25th = boost::accumulators::quantile(acc, boost::accumulators::quantile_probability = 0.25);
  //returnValue.push_back({ boost::accumulators::median(acc), "Median" });
  //returnValue.push_back({ boost::accumulators::variance(acc), "Variance" });
  returnValue.push_back({ boost::accumulators::min(acc), "Min" });
  returnValue.push_back({ boost::accumulators::max(acc), "Max" });

  //don't get the boost stuff working correctly, so computing the quantiles, median and standard deviation by myself:
  std::vector<double> quantile;
  for (mitk::HummelProtocolEvaluation::HummelProtocolDistanceError each : values)
    {quantile.push_back(each.distanceError);}

  auto const Q1 = quantile.size() / 4;
  auto const Q2 = quantile.size() / 2;
  auto const Q3 = Q1 + Q2;

  std::sort(quantile.begin(),quantile.end());

  returnValue.push_back({ quantile[Q1], "Quartile 1" });
  returnValue.push_back({ quantile[Q2], "Median" });
  returnValue.push_back({ quantile[Q3], "Quartile 3" });

  double mean = boost::accumulators::mean(acc);
  double errorSum = 0;
  for (mitk::HummelProtocolEvaluation::HummelProtocolDistanceError each : values)
  {
    double error = pow((each.distanceError - mean),2);
    errorSum += error;
  }
  double variance = errorSum / values.size();
  double sampleVariance = errorSum / (values.size()-1);
  double standardDev = sqrt(variance);
  double sampleStandardDev = sqrt(sampleVariance);

  returnValue.push_back({ variance, "Variance" });
  returnValue.push_back({ sampleVariance, "Sample Variance" });
  returnValue.push_back({ standardDev, "Standard Deviation" });
  returnValue.push_back({ sampleStandardDev, "Sample Standard Deviation" });

  return returnValue;

}


#ifndef PYTHONIC_INCLUDE_NUMPY_FLOOR_HPP
#define PYTHONIC_INCLUDE_NUMPY_FLOOR_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"
#include <boost/simd/function/floor.hpp>

namespace pythonic
{

  namespace numpy
  {
#define NUMPY_NARY_FUNC_NAME floor
#define NUMPY_NARY_FUNC_SYM boost::simd::floor
#include "pythonic/include/types/numpy_nary_expr.hpp"
  }
}

#endif


// std includes
#include <iostream>
#include <vector>
#include <random>
// thirdparties includes
#include <Eigen/Dense>
// lib includes
#include "m0sh/uniform.h"
#include "m0sh/structured_sub.h"

using TypeScalar = double;
// Space
const unsigned int DIM = 3;
using TypeVector = Eigen::Matrix<TypeScalar, DIM, 1>;
template<typename ...Args>
using TypeRef = Eigen::Ref<Args...>;
// Mesh
template<typename ...Args>
using TypeContainer = std::vector<Args...>;
using TypeStructured = m0sh::Structured<TypeVector, TypeRef, TypeContainer>;
using TypeMesh = m0sh::Uniform<TypeVector, TypeRef, TypeContainer>;
using TypeSub = m0sh::StructuredSub<TypeVector, TypeRef, TypeContainer>;
// Data
// // Uniform mesh
const std::size_t n = 100;
const double length = 1.0;
const double origin = 0.5;
// //
const std::size_t nSub = 10;
const TypeContainer<int> offSub = {0, 0, 0};

void print(const std::shared_ptr<TypeSub>& sMesh, std::uniform_int_distribution<int>& uniform, std::default_random_engine& e) {
    TypeContainer<int> ijk;
    TypeVector x;
    std::size_t index;
    // Print info
    ijk = {uniform(e), uniform(e), uniform(e)};
    x = sMesh->positionPoint(ijk);
    index = sMesh->indexPoint(ijk);
    std::cout << "i: " << ijk[0] << " j: " << ijk[1] << " k: " << ijk[2] << "\nindex: " << index << "\nx: " << x.transpose() << std::endl;
    ijk = sMesh->ijkPoint(x);
    std::cout << "xReverse: " << " i: " << ijk[0] << " j: " << ijk[1] << " k: " << ijk[2] << std::endl;
    ijk = sMesh->ijkPoint(index);
    std::cout << "indexReverse: " << " i: " << ijk[0] << " j: " << ijk[1] << " k: " << ijk[2] << std::endl;
    std::cout << std::endl;
}

int main () {
    std::shared_ptr<TypeMesh> sMesh = std::make_shared<TypeMesh>(TypeContainer<std::size_t>(DIM, n), TypeContainer<double>(DIM, length), TypeVector::Constant(origin), TypeContainer<bool>(DIM, false));
    std::shared_ptr<TypeSub> sSubMesh = std::make_shared<TypeSub>(TypeContainer<std::size_t>(DIM, nSub), offSub, sMesh);
    // Random setup
    std::random_device r;
    std::default_random_engine e(r());
    std::uniform_int_distribution<int> uniform(-int(nSub), 2*nSub-1);
    // Print
    print(sSubMesh, uniform, e);
    print(sSubMesh, uniform, e);
    print(sSubMesh, uniform, e);
}


#include <string>

#include <boost/ut.hpp>
#include <rapidcheck.h>

#include <dot.hpp>
#include <gcounter.hpp>

#include "version_vector_utility.hpp"

auto main() -> int
{
    using namespace boost::ut;
    using namespace crdt;

    "basic by one"_test = [] {
        gcounter<std::string> A;
        gcounter<std::string> B;

        A.apply(A.inc("A"));
        B.apply(B.inc("B"));

        expect(A.read() == B.read());
        expect(A != B);

        A.apply(A.inc("A"));

        expect(A.read() == (B.read() + 1));
    };

    "basic by many"_test = [] {
        gcounter<std::string> A;
        gcounter<std::string> B;

        std::uint32_t steps = 3;

        A.apply(A.inc("A", steps));
        B.apply(B.inc("B", steps));

        expect(A.read() == B.read());
        expect(A != B);

        A.apply(A.inc("A", steps));

        expect(A.read() == (B.read() + steps));
    };

    assert(rc::check("associative", [] (map<int> dots1, map<int> dots2, map<int> dots3) {
        auto counter1 = gcounter(build_vector(std::move(dots1)));
        auto counter2 = gcounter(build_vector(std::move(dots2)));
        auto counter3 = gcounter(build_vector(std::move(dots3)));

        auto v1_snapshot = counter1;

        counter1.merge(counter2);
        counter1.merge(counter3);

        counter2.merge(counter3);
        v1_snapshot.merge(counter2);

        RC_ASSERT(counter1 == v1_snapshot);
    }));

    assert(rc::check("commutative", [](map<int> dots1, map<int> dots2) {
        auto counter1 = gcounter(build_vector(std::move(dots1)));
        auto counter2 = gcounter(build_vector(std::move(dots2)));

        auto v1_snapshot(counter1);

        counter1.merge(counter2);

        counter2.merge(v1_snapshot);

        RC_ASSERT(counter1 == counter2);
    }));

    assert(rc::check("idempotent", [](map<int> dots) {
        auto counter = gcounter(build_vector(std::move(dots)));
        auto counter_snapshot = gcounter(build_vector(std::move(dots)));

        counter.merge(counter_snapshot);

        RC_ASSERT(counter == counter_snapshot);
    }));
}


/*    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
 *      120203    B. Tong Minh      Copied Euler unit test.
 *      120207    K. Kumar          Adapted to use modified benchmark functions in Tudat Core.
 *      120213    K. Kumar          Modified getCurrentInterval() to getIndependentVariable();
 *                                  transferred to Boost unit test framework.
 *      121106    K. Kumar          Rewrote unit tests to use direct benchmark data instead of
 *                                  using performance tests.
 *      130109    K. Kumar          Migrated to Tudat Core.
 *
 *    References
 *      Burden, R.L., Faires, J.D. Numerical Analysis, 7th Edition, Books/Cole, 2001.
 *      The MathWorks, Inc. Symbolic Math Toolbox, 2012.
 *
 *    Notes
 *
 */

#define BOOST_TEST_MAIN

#include <string>

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

#include <Eigen/Core>

#include "Tudat/InputOutput/basicInputOutput.h"
#include "Tudat/InputOutput/matrixTextFileReader.h"

#include "Tudat/Mathematics/NumericalIntegrators/euler.h"
#include "Tudat/Mathematics/NumericalIntegrators/numericalIntegrator.h"
#include "Tudat/Mathematics/NumericalIntegrators/reinitializableNumericalIntegrator.h"
#include "Tudat/Mathematics/NumericalIntegrators/UnitTests/numericalIntegratorTests.h"
#include "Tudat/Mathematics/NumericalIntegrators/UnitTests/numericalIntegratorTestFunctions.h"

namespace tudat
{
namespace unit_tests
{

using numerical_integrators::EulerIntegratorXd;
using numerical_integrators::NumericalIntegratorXdPointer;
using numerical_integrators::ReinitializableNumericalIntegratorXdPointer;

using numerical_integrator_test_functions::computeNonAutonomousModelStateDerivative;

BOOST_AUTO_TEST_SUITE( test_euler_integrator )

//! Test Euler integrator using benchmark data from (The MathWorks, 2012).
BOOST_AUTO_TEST_CASE( testEulerIntegratorUsingMatlabData )
{
    using namespace numerical_integrator_tests;

    // Read in benchmark data (generated using Symbolic Math Toolbox in Matlab
    // (The MathWorks, 2012)). This data is generated using the EULER1 numerical integrator.
    const std::string pathToForwardIntegrationOutputFile = input_output::getTudatRootPath( )
            + "/Mathematics/NumericalIntegrators/UnitTests/matlabOutputEulerForwards.txt";
    const std::string pathToBackwardIntegrationOutputFile = input_output::getTudatRootPath( )
            + "/Mathematics/NumericalIntegrators/UnitTests/matlabOutputEulerBackwards.txt";
    const std::string pathToDiscreteEventIntegrationOutputFile = input_output::getTudatRootPath( )
            + "/Mathematics/NumericalIntegrators/UnitTests/matlabOutputEulerDiscreteEvent.txt";

    // Store benchmark data in matrix.
    const Eigen::MatrixXd matlabForwardIntegrationData =
            input_output::readMatrixFromFile( pathToForwardIntegrationOutputFile, "," );
    const Eigen::MatrixXd matlabBackwardIntegrationData =
            input_output::readMatrixFromFile( pathToBackwardIntegrationOutputFile, "," );
    const Eigen::MatrixXd matlabDiscreteEventIntegrationData =
            input_output::readMatrixFromFile( pathToDiscreteEventIntegrationOutputFile, "," );

    // Case 1: Execute integrateTo() to integrate one step forward in time.
    {
        // Declare integrator with all necessary settings.
        NumericalIntegratorXdPointer integrator
                = boost::make_shared< EulerIntegratorXd >(
                    &computeNonAutonomousModelStateDerivative,
                    matlabForwardIntegrationData( FIRST_ROW, TIME_COLUMN_INDEX ),
                    ( Eigen::VectorXd( 1 )
                      << matlabForwardIntegrationData( FIRST_ROW,
                                                       STATE_COLUMN_INDEX ) ).finished( ) );

        executeOneIntegrateToStep( matlabForwardIntegrationData, 1.0e-15, integrator );
    }

    // Case 2: Execute performIntegrationStep() to perform multiple integration steps until final
    //         time.
    {
        // Declare integrator with all necessary settings.
        NumericalIntegratorXdPointer integrator
                = boost::make_shared< EulerIntegratorXd >(
                    &computeNonAutonomousModelStateDerivative,
                    matlabForwardIntegrationData( FIRST_ROW, TIME_COLUMN_INDEX ),
                    ( Eigen::VectorXd( 1 )
                      << matlabForwardIntegrationData( FIRST_ROW,
                                                       STATE_COLUMN_INDEX ) ).finished( ) );

        performIntegrationStepToSpecifiedTime( matlabForwardIntegrationData,
                                               1.0e-15,  1.0e-14, integrator );
    }

    // Case 3: Execute performIntegrationStep() to perform multiple integration steps until initial
    //         time (backwards).
    {
        // Declare integrator with all necessary settings.
        NumericalIntegratorXdPointer integrator
                = boost::make_shared< EulerIntegratorXd >(
                    &computeNonAutonomousModelStateDerivative,
                    matlabBackwardIntegrationData( FIRST_ROW, TIME_COLUMN_INDEX ),
                    ( Eigen::VectorXd( 1 )
                      << matlabBackwardIntegrationData( FIRST_ROW,
                                                        STATE_COLUMN_INDEX ) ).finished( ) );

        performIntegrationStepToSpecifiedTime( matlabBackwardIntegrationData,
                                               1.0e-15, 1.0e-14, integrator );
    }

    // Case 4: Execute integrateTo() to integrate to specified time in one step.
    {
        // Declare integrator with all necessary settings.
        NumericalIntegratorXdPointer integrator
                = boost::make_shared< EulerIntegratorXd >(
                    &computeNonAutonomousModelStateDerivative,
                    matlabForwardIntegrationData( FIRST_ROW, TIME_COLUMN_INDEX ),
                    ( Eigen::VectorXd( 1 )
                      << matlabForwardIntegrationData( FIRST_ROW,
                                                       STATE_COLUMN_INDEX ) ).finished( ) );

        executeIntegrateToToSpecifiedTime( matlabForwardIntegrationData, 1.0e-14, integrator,
                                           matlabForwardIntegrationData(
                                               matlabForwardIntegrationData.rows( ) - 1,
                                               TIME_COLUMN_INDEX ) );
    }

    // Case 5: Execute performIntegrationstep() to integrate to specified time in multiple steps,
    //         including discrete events.
    {
        // Declare integrator with all necessary settings.
        ReinitializableNumericalIntegratorXdPointer integrator
                = boost::make_shared< EulerIntegratorXd >(
                    &computeNonAutonomousModelStateDerivative,
                    matlabDiscreteEventIntegrationData( FIRST_ROW, TIME_COLUMN_INDEX ),
                    ( Eigen::VectorXd( 1 )
                      << matlabDiscreteEventIntegrationData( FIRST_ROW,
                                                             STATE_COLUMN_INDEX ) ).finished( ) );

        performIntegrationStepToSpecifiedTimeWithEvents( matlabDiscreteEventIntegrationData,
                                                         1.0e-15, 1.0e-13, integrator );
    }
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat


#include <frovedis.hpp>
#include <frovedis/ml/model_selection/k_fold.hpp>
#include <boost/program_options.hpp>

using namespace frovedis;

int main(int argc, char* argv[]) {
  use_frovedis use(argc, argv);
  using namespace boost::program_options;

  options_description opt("option");
  opt.add_options()
      ("help,h", "produce help message")
      ("input-data,i" , value<std::string>(), "input rowmajor matrix data.")
      ("input-labels,l" , value<std::string>(), "input label data.")
      ("nsplits" , value<int>(), "[default = 5]")
      ("verbose", "set loglevel to DEBUG")
      ("verbose2", "set loglevel to TRACE");

  variables_map argmap;
  store(command_line_parser(argc,argv).options(opt).allow_unregistered().
        run(), argmap);
  notify(argmap);

  int nsplits = 5;
  std::string data_p, data_l;

  if(argmap.count("input-data")){
    data_p = argmap["input-data"].as<std::string>();
  }else {
    std::cerr << "input-data is not specified" << std::endl;
    std::cerr << opt << std::endl;
    exit(1);
  }
  if(argmap.count("input-labels")){
    data_l = argmap["input-labels"].as<std::string>();
  }else {
    std::cerr << "input-labels is not specified" << std::endl;
    std::cerr << opt << std::endl;
    exit(1);
  }
  if(argmap.count("nsplits")){
    nsplits = argmap["nsplits"].as<int>();
  }
  try {
    auto mat = make_rowmajor_matrix_load<double>(data_p); // for dense data
    auto label = make_dvector_loadline<double>(data_l);

    // frovedis::k_fold demo for logistic regression
    k_fold<rowmajor_matrix<double>,double> kf(nsplits);
    kf.fit(mat, label);

    std::cout << "*** debug print of all splits *** \n";
    kf.debug_print(5);

    for(size_t i = 0; i < nsplits; ++i) {
      std::cout << "\n*** debug print of " << std::to_string(i)
                << "th fold for train/test data ***\n";
      auto train_test_split = kf[i];
      std::cout << "--------------------\n";
      std::cout << "TRAIN: \n";
      std::cout << "--------------------\n";
      train_test_split.first.debug_print(5);
      std::cout << "--------------------\n";
      std::cout << "TEST: \n";
      std::cout << "--------------------\n";
      train_test_split.second.debug_print(5);
      std::cout << "--------------------\n";
    }
  }
  catch (std::exception& e) {
    REPORT_ERROR(USER_ERROR, "exception caught: " + std::string(e.what()) + "\n");
  }

  return 0;
}


/// \file
/// Maintainer: Felice Serena
///

#include "statistical_outlier_removal.h"
#include "spatial/statistical_outlier_detection.h"
#include "spatial/uniform_grid.h"
#include <boost/log/trivial.hpp>

namespace MouseTrack {

StatisticalOutlierRemoval::StatisticalOutlierRemoval(double alpha, int k)
    : _k(k), _alpha(alpha) {
  // empty
}

PointCloud StatisticalOutlierRemoval::
operator()(const PointCloud &inCloud) const {
  auto bb_min = inCloud.charMin();
  auto bb_max = inCloud.charMax();
  auto bb_size = bb_max - bb_min;

  // division arbitrary, heuristic for better choice?
  BOOST_LOG_TRIVIAL(debug) << "grid maxR: " << bb_size.maxCoeff()
                           << ", grid cell size: " << bb_size.minCoeff() / 50.0;
  UniformGrid3d ug(bb_size.maxCoeff(), bb_size.minCoeff() / 50.0);

  typedef UniformGrid3d::PointList PointList;
  PointList pts(3, inCloud.size());
  for (size_t i = 0; i < inCloud.size(); ++i) {
    auto p = inCloud[i];
    pts(0, i) = p.x();
    pts(1, i) = p.x();
    pts(2, i) = p.x();
  }
  ug.compute(pts);
  auto outliers =
      statisticalOutlierDetection<PointList, Precision>(pts, &ug, alpha(), k());

  PointCloud outCloud;
  outCloud.resize(inCloud.size() - outliers.size(), inCloud.labelsDim());
  size_t next_insert = 0;
  size_t o = 0;
  for (size_t i = 0; i < inCloud.size(); ++i) {
    if (o < outliers.size() && outliers[o] == i) {
      // skip
      ++o;
      continue;
    }
    outCloud[next_insert] = inCloud[i];
    ++next_insert;
  }
  BOOST_LOG_TRIVIAL(debug) << "Removed " << outliers.size()
                           << " outliers from point cloud.";
  return outCloud;
}

// setter/getter

void StatisticalOutlierRemoval::k(int _new) { _k = _new; }

int StatisticalOutlierRemoval::k() const { return _k; }

void StatisticalOutlierRemoval::alpha(double _new) { _alpha = _new; }

double StatisticalOutlierRemoval::alpha() const { return _alpha; }

} // namespace MouseTrack


/*
@copyright Louis Dionne 2015
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/assert.hpp>
#include <boost/hana/functional/placeholder.hpp>

#include <utility>
namespace hana = boost::hana;
using hana::_;

struct extra_t { virtual ~extra_t() { } };
extra_t extra{};

constexpr struct { } invalid{};

template <typename ...> using bool_t = bool;
constexpr bool valid_call(...) { return false; }
template <typename F, typename ...Args>
constexpr auto valid_call(F&& f, Args&& ...args)
    -> bool_t<decltype(std::forward<F>(f)(std::forward<Args>(args)...))>
{ return true; }

#define BOOST_HANA_TEST_BINARY_OP(op, x, y)                                 \
    static_assert((_ op _)(x, y) == (x op y), "");                          \
    BOOST_HANA_RUNTIME_CHECK((_ op _)(x, y, extra) == (x op y));            \
    BOOST_HANA_RUNTIME_CHECK((_ op _)(x, y, extra, extra) == (x op y));     \
    static_assert(!valid_call(_ op _), "");                                 \
    static_assert(!valid_call(_ op _, invalid), "");                        \
    static_assert(!valid_call(_ op _, invalid, invalid), "");               \
                                                                            \
    static_assert((_ op y)(x) == (x op y), "");                             \
    BOOST_HANA_RUNTIME_CHECK((_ op y)(x, extra) == (x op y));               \
    BOOST_HANA_RUNTIME_CHECK((_ op y)(x, extra, extra) == (x op y));        \
    static_assert(!valid_call(_ op y), "");                                 \
    static_assert(!valid_call(_ op y, invalid), "");                        \
                                                                            \
    static_assert((x op _)(y) == (x op y), "");                             \
    BOOST_HANA_RUNTIME_CHECK((x op _)(y, extra) == (x op y));               \
    BOOST_HANA_RUNTIME_CHECK((x op _)(y, extra, extra) == (x op y));        \
    static_assert(!valid_call(x op _), "");                                 \
    static_assert(!valid_call(x op _, invalid), "");                        \
    static_assert(!valid_call(x op _, invalid), "");                        \
/**/

#define BOOST_HANA_TEST_UNARY_OP(op, x)                                     \
    static_assert((op _)(x) == (op x), "");                                 \
    BOOST_HANA_RUNTIME_CHECK((op _)(x, extra) == (op x));                   \
    BOOST_HANA_RUNTIME_CHECK((op _)(x, extra, extra) == (op x));            \
    static_assert(!valid_call(op _), "");                                   \
    static_assert(!valid_call(op _, invalid), "");                          \
/**/

struct incr_t {
    template <typename X>
    constexpr auto operator()(X x) const -> decltype(x + 1)
    { return x + 1; }
};
constexpr incr_t incr{};

int main() {
    // Arithmetic
    BOOST_HANA_TEST_UNARY_OP(+, 1)
    BOOST_HANA_TEST_UNARY_OP(-, 1)
    BOOST_HANA_TEST_BINARY_OP(+, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(-, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(*, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(/, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(%, 6, 3)

    // Bitwise
    BOOST_HANA_TEST_UNARY_OP(~, 5)
    BOOST_HANA_TEST_BINARY_OP(&, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(|, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(^, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(<<, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(>>, 6, 3)

    // Comparison
    BOOST_HANA_TEST_BINARY_OP(==, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(!=, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(<, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(<=, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(>, 6, 3)
    BOOST_HANA_TEST_BINARY_OP(>=, 6, 3)

    // Logical
    BOOST_HANA_TEST_BINARY_OP(||, true, false)
    BOOST_HANA_TEST_BINARY_OP(&&, true, true)
    BOOST_HANA_TEST_UNARY_OP(!, true)

    // Member access
    constexpr int i = 4;
    constexpr int array[] = {0, 1, 2};
    BOOST_HANA_TEST_UNARY_OP(*, &i)

    static_assert(_[0](array) == array[0], "");
    BOOST_HANA_RUNTIME_CHECK(_[0](array, extra) == array[0]);
    BOOST_HANA_RUNTIME_CHECK(_[0](array, extra, extra) == array[0]);
    static_assert(_[1](array) == array[1], "");
    static_assert(_[1](array) == array[1], "");
    static_assert(_[2](array) == array[2], "");
    static_assert(!valid_call(_[invalid]), "");
    static_assert(!valid_call(_[invalid], array), "");
    static_assert(!valid_call(_[invalid], invalid), "");
    static_assert(!valid_call(_[0], invalid), "");

    // Call operator
    static_assert(_(1)(incr) == incr(1), "");
    BOOST_HANA_RUNTIME_CHECK(_(1)(incr, extra) == incr(1));
    BOOST_HANA_RUNTIME_CHECK(_(1)(incr, extra, extra) == incr(1));
    static_assert(_(2)(incr) == incr(2), "");
    static_assert(_(3)(incr) == incr(3), "");
    static_assert(!valid_call(_(invalid)), "");
    static_assert(!valid_call(_(invalid), incr), "");
    static_assert(!valid_call(_(invalid), invalid), "");
    static_assert(!valid_call(_(1), invalid), "");
}


#define BOOST_TEST_MODULE SpaceTest

#include <boost/test/unit_test.hpp>
#include <sdm/types.hpp>
#include <sdm/spaces.hpp>

BOOST_AUTO_TEST_CASE(DiscreteSpaceTest)
{
    sdm::DiscreteSpace<sdm::number> ds1({0, 1, 2, 3, 4}), ds2({0, 1, 2, 3, 4});

    BOOST_CHECK_EQUAL(ds1.getNumItems(), 5);
    BOOST_CHECK_EQUAL(ds1.getItem(0), 0);
    BOOST_CHECK_EQUAL(ds1.getItemIndex(0), 0);
    BOOST_ASSERT(ds1 == ds2);

    sdm::DiscreteSpace<std::string> ds3({"up", "down", "left", "right"}), ds4({"up", "down", "right"}), ds5 = ds3;

    BOOST_CHECK_EQUAL(ds3.getNumItems(), 4);
    BOOST_CHECK_EQUAL(ds3.getItem(0), "up");
    BOOST_CHECK_EQUAL(ds3.getItemIndex("up"), 0);

    BOOST_ASSERT(ds3 != ds4);
    BOOST_ASSERT(ds3 == ds5);
}

BOOST_AUTO_TEST_CASE(MultiDiscreteSpaceTest)
{
    std::vector<std::vector<sdm::number>> values = {{2, 4, 5, 7}, {1, 2, 3}};
    sdm::MultiDiscreteSpace<sdm::number> mds1(values);

    sdm::DiscreteSpace<std::string> ds1({"up", "down"}), ds2({"up", "down", "left", "right"});
    sdm::MultiDiscreteSpace<std::string> mds2({ds1, ds2});

    BOOST_CHECK_EQUAL(mds1.getNumSpaces(), 2);
    BOOST_CHECK_EQUAL(mds1.getNumJointItems(), 12);
    BOOST_CHECK_EQUAL(mds1.getSpace(0)->getNumItems(), 4);
    BOOST_CHECK_EQUAL(mds1.getSpace(1)->getNumItems(), 3);

    BOOST_CHECK_EQUAL(mds2.getNumSpaces(), 2);
    BOOST_CHECK_EQUAL(mds2.getNumJointItems(), 8);
    BOOST_CHECK_EQUAL(mds2.getSpace(0)->getItem(0), "up");
}


#include <armadillo>
#include <boost/program_options.hpp>
#include <json.hpp>
#include <HSMM.hpp>
#include <ProMPs_emission.hpp>

using namespace arma;
using namespace hsmm;
using namespace robotics;
using namespace std;
namespace po = boost::program_options;

field<mat> fromMatToField(const mat& obs) {
    field<mat> ret(obs.n_cols);
    for(int i = 0; i < obs.n_cols; i++)
        ret(i) = obs.col(i);
    return ret;
}

int main(int argc, char *argv[]) {
    po::options_description desc("Options");
    desc.add_options()
        ("help,h", "Produce help message")
        ("input,i", po::value<string>(), "Path to the input obs")
        ("output,o", po::value<string>(), "Path to the json output params")
        ("commitid", po::value<string>(), "Git commit id of the experiment")
        ("labels", po::value<string>(), "Path to the provided labels")
        ("nfiles", po::value<int>()->default_value(1),
                "Number of files (sequences) to process");
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);
    if (vm.count("help")) {
        cout << desc << endl;
        return 0;
    }
    if (!vm.count("input") || !vm.count("output")) {
        cerr << "Error: You should provide input and output files" << endl;
        return 1;
    }
    string input_filename = vm["input"].as<string>();
    string output_filename = vm["output"].as<string>();
    field<field<mat>> seq_obs(1);
    field<Labels> seq_labels(1);
    int njoints;
    int nseq = vm["nfiles"].as<int>();
    seq_obs.set_size(nseq);
    seq_labels.set_size(nseq);
    for(int i = 0; i < seq_obs.n_elem; i++) {
        string name = input_filename;
        if (nseq != 1)
            name += string(".") + to_string(i);
        mat obs;
        obs.load(name, raw_ascii);
        njoints = obs.n_rows;
        int nobs = obs.n_cols;
        cout << "Time series shape: (" << njoints << ", " << nobs <<
            ")." << endl;
        seq_obs(i) = fromMatToField(obs);

        // Reading labels for different obs.
        if (!vm.count("labels"))
            continue;
        string labels_name = vm["labels"].as<string>();
        if (nseq != 1)
            labels_name += string(".") + to_string(i);
        mat labels_mat;
        labels_mat.load(labels_name);
        for(int j = 0; j < labels_mat.n_rows; j++)
            seq_labels(i).setLabel(labels_mat(j, 0), labels_mat(j, 1),
                    labels_mat(j, 2));
    }
    int min_duration = 35;
    int nstates = 5;
    int ndurations = 100;
    mat transition(nstates, nstates);
    transition.fill(1.0 / nstates );
    vec pi(nstates);
    pi.fill(1.0/nstates);
    mat durations(nstates, ndurations);
    durations.fill(1.0 / ndurations);
    int n_basis_functions = 4;

    // Setting a third order polynomial basis function for the ProMP
    int polynomial_order = n_basis_functions - 1;
    shared_ptr<ScalarBasisFun> kernel{ new ScalarPolyBasis(polynomial_order)};

    // Instantiating as many ProMPs as hidden states.
    vector<FullProMP> promps;
    for(int i = 0; i < nstates; i++) {
        vec mu_w(n_basis_functions * njoints, fill::randn);
        mat Sigma_w = 10 * eye<mat>(n_basis_functions * njoints,
                    n_basis_functions * njoints);
        mat Sigma_y = 0.01 * eye<mat>(njoints, njoints);

        ProMP promp(mu_w, Sigma_w, Sigma_y);
        FullProMP poly(kernel, promp, njoints);
        promps.push_back(poly);
    }

    // Creating the ProMP emission.
    shared_ptr<ProMPsEmission> ptr_emission(new ProMPsEmission(promps));

    // Creating a prior for Sigma_w.
    mat Phi = 0.01 * eye<mat>(n_basis_functions * njoints,
            n_basis_functions * njoints);
    NormalInverseWishart iw_prior(Phi, Phi.n_rows + 2);
    ptr_emission->set_Sigma_w_Prior(iw_prior);

    HSMM promp_hsmm(std::static_pointer_cast<AbstractEmission>(ptr_emission),
            transition, pi, durations, min_duration);

    // Saving the model in a json file.
    std::ofstream initial_params(output_filename);
    nlohmann::json initial_model = promp_hsmm.to_stream();
    if (vm.count("commitid"))
        initial_model["git_commit_id"] = vm["commitid"].as<string>();
    initial_params << std::setw(4) << initial_model << std::endl;
    initial_params.close();

    for(int i = 0; i < 10; i++) {

        // Reading the current parameters.
        std::ifstream current_params_stream(output_filename);
        nlohmann::json current_params;
        current_params_stream >> current_params;
        promp_hsmm.from_stream(current_params);
        bool convergence_reached = promp_hsmm.fit(seq_obs, seq_labels, 5, 1e-5);

        // Saving again the parameters after one training iteration.
        std::ofstream output_params(output_filename);
        current_params = promp_hsmm.to_stream();
        if (vm.count("commitid"))
            current_params["git_commit_id"] = vm["commitid"].as<string>();
        output_params << std::setw(4) << current_params << std::endl;
        output_params.close();

        if (convergence_reached)
            break;

    }
    return 0;
}


//////////////////////////////////////////////////////////////////////////////
// range_ex::example::nested_chain.cpp                        				//
//                                                                          //
//  (C) Copyright 2010 Erwann Rogard                                        //
//  Use, modification and distribution are subject to the                   //
//  Boost Software License, Version 1.0. (See accompanying file             //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)        //
//////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <iterator>
#include <vector>
#include <list>

#include <boost/typeof/typeof.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/algorithm/equal.hpp>

#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/statistics/detail/range_ex/chain/nest.hpp>
#include <boost/statistics/detail/range_ex/chain/chain2.hpp>
#include <libs/statistics/detail/range_ex/example/nest_chain.h>

void example_nest_chain(std::ostream& os)
{

	namespace range = boost::statistics::detail::range;

	typedef int val_;
    typedef std::vector<val_> vec_;
    typedef std::list<val_> list_;

	using namespace boost::assign;

    typedef boost::fusion::vector<vec_> seq1_;
    typedef boost::fusion::vector<vec_,list_,vec_> seq_;

    BOOST_MPL_ASSERT((
		range::impl::dont_nest<seq1_>
	));
	seq1_ seq1;
	seq_ seq;
    boost::fusion::at_c<0>(seq1) += 0,1,2,3,4,5,6,7,8,9;
    boost::fusion::at_c<0>(seq)  += 0,1,2,3,4,5,6,7,8,9;
    boost::fusion::at_c<1>(seq) = list_of(10)(11)(12)(13)(14)(15)(16)(17)(18)(19);
    boost::fusion::at_c<2>(seq) += 20, 21, 22, 23, 24, 25, 26, 27, 28, 29;

    {
		typedef range::result_of::nest_chain<seq1_>::type chained_;
    	chained_ chained = range::nest_chain( seq1 );
        vec_ vec;

    	boost::copy(
            boost::fusion::at_c<0>(seq), std::back_inserter(vec)
    	);
		std::copy(
    		boost::begin(chained),
        	boost::end(chained),
        	std::ostream_iterator<val_>(std::cout," ")
    	);
		BOOST_ASSERT(boost::equal(chained,vec));
	}
    os << std::endl;
    {
		typedef range::result_of::nest_chain<seq_>::type chained_;
    	chained_ chained = range::nest_chain( seq );
		vec_ vec;

    	boost::copy(
    		boost::fusion::at_c<2>(seq),
    		boost::copy(boost::fusion::at_c<1>(seq),
    			boost::copy(boost::fusion::at_c<0>(seq), std::back_inserter(vec))
        	)
    	);
		std::copy(
    		boost::begin(chained),
        	boost::end(chained),
        	std::ostream_iterator<val_>(std::cout," ")
    	);
		BOOST_ASSERT(boost::equal(chained,vec));
	}

	range::chain2(
    	boost::fusion::at_c<0>(seq)
    )(
    	boost::fusion::at_c<1>(seq)
    )(
    	boost::fusion::at_c<2>(seq)
    );

}


/*******************************************************************************
 * Copyright 2013-2014 Sebastian Niemann <niemann@sra.uni-hannover.de>.
 *
 * Licensed under the MIT License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/MIT
 *
 * Developers:
 *   Sebastian Niemann - Lead developer
 *   Daniel Kiechle - Unit testing
 ******************************************************************************/
#include <Expected.hpp>
using armadilloJava::Expected;

#include <iostream>
using std::cout;
using std::endl;

#include <algorithm>
using std::min;

#include <utility>
using std::pair;

#include <armadillo>
using arma::Row;
using arma::Col;
using arma::vec;

#include <InputClass.hpp>
using armadilloJava::InputClass;

#include <Input.hpp>
using armadilloJava::Input;

namespace armadilloJava {
  class ExpectedInPlaceGenColVecGenRowVec : public Expected {
    public:
      ExpectedInPlaceGenColVecGenRowVec() {
        cout << "Compute ExpectedInPlaceGenColVecGenRowVec(): " << endl;

          vector<vector<pair<string, void*>>> inputs = Input::getTestParameters({
            InputClass::GenColVec,
            InputClass::GenRowVec
          });

          for (vector<pair<string, void*>> input : inputs) {
            _fileSuffix = "";

            int n = 0;
            for (pair<string, void*> value : input) {
              switch (n) {
                case 0:
                  _fileSuffix += value.first;
                  _genColVec = *static_cast<Col<double>*>(value.second);
                  break;
                case 1:
                  _fileSuffix += "," + value.first;
                  _genRowVec = *static_cast<Row<double>*>(value.second);
                  break;
              }
              ++n;
            }

            cout << "Using input: " << _fileSuffix << endl;

            _copyOfGenColVec = _genColVec;
            _copyOfGenRowVec = _genRowVec;

            expectedColInPlaceEqual();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColInPlacePlus();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColInPlaceMinus();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColInPlaceTimes();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColInPlaceElemTimes();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColInPlaceElemDivide();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColSwap();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColCopy_size();

            _genColVec = _copyOfGenColVec;
            _genRowVec = _copyOfGenRowVec;
            expectedColCol();
          }

          cout << "done." << endl;
        }

    protected:
      Col<double> _genColVec;
      Col<double> _copyOfGenColVec;

      Row<double> _genRowVec;
      Row<double> _copyOfGenRowVec;

      void expectedColInPlaceEqual() {
    	if(_genColVec.n_rows != _genRowVec.n_rows || _genColVec.n_cols != _genRowVec.n_cols) {
          return;
        }
        cout << "- Compute expectedColInPlaceEqual() ... ";

        _genColVec = _genRowVec;
        save<double>("Col.inPlaceEqual", _genColVec);

        cout << "done." << endl;
      }

      void expectedColInPlacePlus() {
        if(_genColVec.n_rows != _genRowVec.n_rows || _genColVec.n_cols != _genRowVec.n_cols) {
          return;
        }

        cout << "- Compute expectedColInPlace() ... ";

        _genColVec += _genRowVec;
        save<double>("Col.inPlacePlus", _genColVec);

        cout << "done." << endl;
      }

      void expectedColInPlaceMinus() {
        if(_genColVec.n_rows != _genRowVec.n_rows || _genColVec.n_cols != _genRowVec.n_cols) {
          return;
        }

        cout << "- Compute expectedColInPlaceMinus() ... ";

        _genColVec -= _genRowVec;
        save<double>("Col.inPlaceMinus", _genColVec);

        cout << "done." << endl;
      }

      void expectedColInPlaceTimes() {
        if(_genColVec.n_cols != _genRowVec.n_rows) {
          return;
        }
        if(_genColVec.n_cols != _genRowVec.n_cols) {
          return;
        }

        cout << "- Compute expectedColInPlaceTimes() ... ";

        _genColVec *= _genRowVec;
        save<double>("Col.inPlaceTimes", _genColVec);

        cout << "done." << endl;
      }

      void expectedColInPlaceElemTimes() {
        if(_genColVec.n_rows != _genRowVec.n_rows || _genColVec.n_cols != _genRowVec.n_cols) {
          return;
        }

        cout << "- Compute expectedColInPlaceElemTimes() ... ";

        _genColVec %= _genRowVec;
        save<double>("Col.inPlaceElemTimes", _genColVec);

        cout << "done." << endl;
      }

      void expectedColInPlaceElemDivide() {
        if(_genColVec.n_rows != _genRowVec.n_rows || _genColVec.n_cols != _genRowVec.n_cols) {
          return;
        }

        cout << "- Compute expectedColInPlaceElemDivide() ... ";

        _genColVec /= _genRowVec;
        save<double>("Col.inPlaceElemDivide", _genColVec);

        cout << "done." << endl;
      }

      void expectedColSwap() {
        if(!_genRowVec.is_colvec()) {
          return;
        }
        if(!_genColVec.is_rowvec()) {
          return;
        }

        cout << "- Compute expectedColSwap() ... ";

        _genColVec.swap(_genRowVec);
        save<double>("Col.swap", _genColVec);

        cout << "done." << endl;
      }

      void expectedColCopy_size() {
        if(!_genRowVec.is_colvec()) {
          return;
        }
        cout << "- Compute expectedColCopy_size() ... ";

        _genColVec.copy_size(_genRowVec);
        save<double>("Col.copySize", _genColVec);

        cout << "done." << endl;
      }

      void expectedColCol() {
        if(!_genRowVec.is_colvec()) {
          return;
        }

        cout << "- Compute expectedColCol() ... ";

        _genColVec = vec(_genRowVec);
        save<double>("Col.col", _genColVec);

        cout << "done." << endl;
      }
  };
}


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

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  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_INBTRUE_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_INBTRUE_HPP_INCLUDED

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

 /*!

    @ingroup group-reduction
    Function object implementing inbtrue capabilities

    Returns the number of non @ref Zero elements of the input SIMD vector.

    @par Semantic:

    For every parameter of type T

    @code
    std::size_t r = inbtrue(x);
    @endcode

    is similar to:

    @code
    std::size_t r = sum(if_one_else_zero(x));
    @endcode

  **/
  const boost::dispatch::functor<tag::inbtrue_> inbtrue = {};
} }
#endif

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

#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 complex.exponential toolbox - acos/scalar Mode"

//////////////////////////////////////////////////////////////////////////////
// unit test behavior of exponential components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created by jt the 08/12/2010
///
#include <nt2/include/functions/acos.hpp>
#include <boost/type_traits/is_same.hpp>
#include <nt2/sdk/functor/meta/call.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/sdk/meta/as_floating.hpp>
#include <nt2/sdk/meta/as_signed.hpp>
#include <nt2/sdk/meta/upgrade.hpp>
#include <nt2/sdk/meta/downgrade.hpp>
#include <nt2/sdk/meta/scalar_of.hpp>
#include <boost/dispatch/meta/as_floating.hpp>
#include <boost/type_traits/common_type.hpp>
#include <nt2/sdk/unit/tests.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/memory/buffer.hpp>
#include <nt2/toolbox/constant/constant.hpp>
#include <boost/math/complex/acos.hpp>

NT2_TEST_CASE_TPL ( acos_real__1_0,  (double))//NT2_REAL_TYPES)
{

  using nt2::acos;
  using nt2::tag::acos_;
  typedef std::complex<T> cT;
  typedef typename nt2::meta::call<acos_(cT)>::type r_t;
  typedef typename nt2:: meta::as_complex<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_ULP_EQUAL(nt2::acos(cT(nt2::Zero<T>(),  nt2::Zero<T>())), cT(nt2::Pio_2<T>(), nt2::Zero<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan <T>(),  nt2::Zero<T>())), cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);

   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan  <T>(), nt2::One<T>())),  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan  <T>(), nt2::Inf<T>())),  cT(nt2::Nan <T>(), -nt2::Inf<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan  <T>(), nt2::Nan<T>())),  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Zero <T>(), nt2::Nan <T>())), cT(nt2::Pio_2<T>(), nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::One  <T>(), nt2::Nan <T>())), cT(nt2::Nan<T>(),  nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Inf  <T>(), nt2::Nan<T>())),  cT(nt2::Nan <T>(), nt2::Minf<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::One  <T>(), nt2::Inf <T>())), cT(nt2::Pio_2<T>(), -nt2::Inf<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Inf  <T>(), nt2::One <T>())), cT(nt2::Zero<T>(), nt2::Minf <T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Inf  <T>(), nt2::Inf<T>())),  cT(nt2::Pi<T>()/nt2::Four<T>(), nt2::Minf <T>()), 0.75);

   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Nan  <T>(), nt2::One<T>())),  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Nan  <T>(), nt2::Inf<T>())),  cT(nt2::Nan <T>(), -nt2::Inf<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Nan  <T>(), nt2::Nan<T>())),  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Zero <T>(), nt2::Nan <T>())), cT(nt2::Pio_2<T>(), nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::One  <T>(), nt2::Nan <T>())), cT(nt2::Nan<T>(),  nt2::Nan<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Inf  <T>(), nt2::Nan<T>())),  cT(nt2::Nan <T>(), nt2::Minf<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::One  <T>(), nt2::Inf <T>())), cT(nt2::Pio_2<T>(), nt2::Minf<T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Inf  <T>(), nt2::One <T>())), cT(nt2::Pi<T>(), -nt2::Inf <T>()), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Inf  <T>(), nt2::Inf<T>())),  cT(nt2::Three<T>()*nt2::Pi<T>()/nt2::Four<T>(), nt2::Minf <T>()), 0.75);

   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan  <T>(), nt2::One<T>())), boost::math::acos(cT(nt2::Nan  <T>(), nt2::One<T>())),  0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan  <T>(), nt2::Inf<T>())), boost::math::acos(cT(nt2::Nan  <T>(), nt2::Inf<T>())),  0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Nan  <T>(), nt2::Nan<T>())), boost::math::acos(cT(nt2::Nan  <T>(), nt2::Nan<T>())),  0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Zero <T>(), nt2::Nan <T>())),boost::math::acos(cT(nt2::Zero <T>(), nt2::Nan <T>())), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::One  <T>(), nt2::Nan <T>())),boost::math::acos(cT(nt2::One  <T>(), nt2::Nan <T>())), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Inf  <T>(), nt2::Nan<T>())), boost::math::acos(cT(nt2::Inf  <T>(), nt2::Nan<T>())),  0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::One  <T>(), nt2::Inf <T>())),boost::math::acos(cT(nt2::One  <T>(), nt2::Inf <T>())), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Inf  <T>(), nt2::One <T>())),boost::math::acos(cT(nt2::Inf  <T>(), nt2::One <T>())), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Inf  <T>(), nt2::Inf<T>())), boost::math::acos(cT(nt2::Inf  <T>(), nt2::Inf<T>())),  0.75);

   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Nan  <T>(), nt2::One<T>())), boost::math::acos(cT(-nt2::Nan  <T>(), nt2::One<T>())),    0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Nan  <T>(), nt2::Inf<T>())), boost::math::acos(cT(-nt2::Nan  <T>(), nt2::Inf<T>())),    0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Nan  <T>(), nt2::Nan<T>())), boost::math::acos(cT(-nt2::Nan  <T>(), nt2::Nan<T>())),    0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Zero <T>(), nt2::Nan <T>())),boost::math::acos(cT(-nt2::Zero <T>(), nt2::Nan <T>())),   0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::One  <T>(), nt2::Nan <T>())),boost::math::acos(cT(-nt2::One  <T>(), nt2::Nan <T>())),   0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Inf  <T>(), nt2::Nan<T>())), boost::math::acos(cT(-nt2::Inf  <T>(), nt2::Nan<T>())),    0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::One  <T>(), nt2::Inf <T>())),boost::math::acos(cT(-nt2::One  <T>(), nt2::Inf <T>())),   0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Inf  <T>(), nt2::One <T>())),boost::math::acos(cT(-nt2::Inf  <T>(), nt2::One <T>())),   0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(-nt2::Inf  <T>(), nt2::Inf<T>())), boost::math::acos(cT(-nt2::Inf  <T>(), nt2::Inf<T>())),    0.75);

   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::One  <T>(), nt2::One <T>())),   cT(0.904556894302381, -1.061275061905036), 2);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::One  <T>(), nt2::Mone <T>())),  cT(0.904556894302381,  1.061275061905036), 2);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Mone  <T>(), nt2::One <T>())),  cT(2.237035759287412, -1.061275061905036), 2);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(nt2::Mone  <T>(), nt2::Mone <T>())), cT(2.237035759287412,  1.061275061905036), 2);

   NT2_TEST_ULP_EQUAL(nt2::acos(cT(1, 1)),  boost::math::acos(cT(1, 1)), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(1, 10)),  boost::math::acos(cT(1, 10)), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(10, 10)),  boost::math::acos(cT(10, 10)), 0.75);
   NT2_TEST_ULP_EQUAL(nt2::acos(cT(10, 1)),  boost::math::acos(cT(10, 1)), 0.75);

 } // end of test for floating_