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

#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <limits>

#include <boost/type_index.hpp>

#include <fmp.hpp>
#include <fmp/incubation.hpp>
#include <fmp/operator.hpp>
#include <fmp/monoid.hpp>
#include <fmp/foldmap.hpp>
#include <fmp/values.hpp>
#include <fmp/utils.hpp>
#include <fmp/maybe.hpp>
#include <fmp/functor.hpp>

#include "sample.hpp"

void test_quote() {
  using q0 = fmp::quote<int>;
  std::cout << "Quote::type: " << T_name<q0::type>() << std::endl;
  std::cout << "Unquote: " << T_name<q0::unquote>() << std::endl;
}

void test_derived() {
  using q0 = fmp::quote<int>;
  using d0 = fmp::derived<q0>;

  std::cout << "derived: " << T_name<d0::type>() << std::endl;
}

void test_value() {
  using namespace fmp;
  using val0 = fmp::val<int, 0>;
  static_assert(val0() == 0, "val0() == 0");
  std::cout << "val::value: " << val0::value << std::endl;

  using has_val0 = has_value<int>;
  using has_val1 = has_value<val0>;
  std::cout << "has_val0:" << has_val0() << std::endl;
  std::cout << "has_val1:" << has_val1() << std::endl;

  using b0 = fmp::boolean<std::true_type>;
  std::cout << "b0:" << b0() << std::endl;
  std::cout << "b(false):" << fmp::boolean<std::false_type>() << std::endl;

#if defined(__cpp_template_auto)
  using at1 = atval<0u>;
  using at0 = atval<0>;
  std::cout << "at1: " << T_name<at1>() << std::endl;
  std::cout << "at0: " << T_name<at0>() << std::endl;
#endif /* __cpp_template_auto */

}

void test_unity() {
  using namespace fmp;
#if 0
  using et0 = fmp::all;
  //using e0 = unity<int>; // ::type instantiation causes assertion error

  std::cout << "---Unity---" << std::endl;
  std::cout << "unity::type:" << T_name<unity<et0>::type>() << std::endl;
  std::cout << "unity_t:" << T_name<unity_t<et0>>() << std::endl;
#endif
};

void test_unite() {
  using namespace fmp;
  using et0 = fmp::all<std::true_type>;
  //using et1 = fmp::et<int>::type;

  std::cout << "---Unite---" << std::endl;
#if 0
  std::cout << "has_unite:" << has_unite<et0>::value << std::endl;
  std::cout << "unite<true, false>: "
            << T_name<unite_t<et0, std::true_type, std::false_type>>()
            << std::endl;
#endif
}

void test_monoid_et() {
  using et0 = fmp::all<std::true_type>;
  using ett0 = fmp::monoid_trait<fmp::all>;
  using et_u = fmp::unity_t<fmp::all>;
  using et_unite = fmp::unite_t<et0, et_u>;
  std::cout << "MONOID et---" << std::endl;
  std::cout << "et<true_type>=" << T_name<et0>() << std::endl;
  std::cout << "monoid_trait<et>=" << T_name<ett0>() << std::endl;
  std::cout << "monoid_trait<et>::unity=" << T_name<et_u>() << std::endl;
  std::cout << "unite<et0, unite>=" << T_name<et_unite>() << std::endl;
#if 0
  std::cout << "Unity: " << T_name<et0::unity>() << std::endl;
  std::cout << "et<true, false>:" << T_name<et0::unite_t<std::true_type, std::false_type>>() << std::endl;
  std::cout << "et<false, false>:" << T_name<et0::unite_t<std::false_type, std::false_type>>() << std::endl;
  std::cout << "et<false, true>:" << T_name<et0::unite_t<std::false_type, std::true_type>>() << std::endl;
  std::cout << "et<true, true>:" << T_name<et0::unite_t<std::true_type, std::true_type>>() << std::endl;
//  std::cout << "et<true>:" << T_name<et0::unite_t<std::true_type>>() << std::endl;
//  std::cout << "et<false>:" << T_name<et0::unite_t<std::false_type>>() << std::endl;
#endif
}

void test_monoid_uel() {
#if 0
  using op0 = fmp::uel;
  std::cout << "MONOID uel---" << std::endl;
  std::cout << "Unity: " << T_name<op0::unity>() << std::endl;
  std::cout << "uel<true, false>:" << T_name<op0::unite_t<std::true_type, std::false_type>>() << std::endl;
  std::cout << "uel<false, false>:" << T_name<op0::unite_t<std::false_type, std::false_type>>() << std::endl;
  std::cout << "uel<false, true>:" << T_name<op0::unite_t<std::false_type, std::true_type>>() << std::endl;
  std::cout << "uel<true, true>:" << T_name<op0::unite_t<std::true_type, std::true_type>>() << std::endl;
//  std::cout << "uel<true>:" << T_name<op0::unite_t<std::true_type>>() << std::endl;
//  std::cout << "uel<false>:" << T_name<op0::unite_t<std::false_type>>() << std::endl;
#endif
}

template <typename... A>
struct noarg;

template <>
struct noarg<> {
  constexpr static int value = 43;
  using type = std::true_type;
};

void test_curry() {
  using fmp::curry;
  using c0 = curry<std::is_same, int>;
  using c1 = c0::apply<int>;
  using c1t = c0::apply_t<int>;
  using c2 = c0::currying<long>;

  using n0 = curry<noarg>;

  std::cout << "c0 curried params:" << c0::value << std::endl;
  std::cout << "c1:" << T_name<c1t>() << std::endl;
  std::cout << "curry<is_same, int>::apply<int>:" << c1() << std::endl;
  std::cout << "c0::currying<long>: " << c2::apply<>() << std::endl;

  std::cout << "n0::value: " << n0::apply<>::value << std::endl;
}

void test_lt() {
  using int0 = fmp::val<int, 0>;
  using int1 = fmp::val<int, 1>;
  using op = fmp::lt<int0, int1>;
  using op_i = fmp::lt<fmp::type_size<fmp::infinity_lower>, fmp::type_size<char>>;
  using op_i0 = fmp::lt<fmp::type_size<fmp::infinity_lower>, fmp::type_size<fmp::infinity_lower>>;
  using op_i1= fmp::lt<fmp::type_size<long>, fmp::type_size<fmp::infinity_lower>>;
  using op_i2= fmp::lt<fmp::type_size<fmp::infinity_lower>, fmp::type_size<fmp::infinity_upper>>;
  std::cout << "LT: 0 < 1: " << T_name<op::type>() << std::endl;
  std::cout << "LT: 0 < 0: " << T_name<fmp::lt<int0, int0>::type>() << std::endl;
  std::cout << "LT: 1 < 0: " << T_name<fmp::lt<int1, int0>::type>() << std::endl;
  std::cout << "op_i: " << T_name<op_i::type>() << std::endl;
  std::cout << "op_i0: " << T_name<op_i0::type>() << std::endl;
  std::cout << "op_i1: " << T_name<op_i1::type>() << std::endl;
  std::cout << "op_i2: " << T_name<op_i2::type>() << std::endl;
}

void test_eq() {
  using int0 = fmp::val<int, 0>;
  using int1 = fmp::val<int, 1>;
  using op = fmp::eq<int0, int1>;
  using namespace fmp;
  std::cout << "EQ: 0 op 1: " << T_name<op::type>() << std::endl;
  std::cout << "EQ: 0 op 0: " << T_name<fmp::eq<int0, int0>>() << std::endl;
  std::cout << "EQ: 1 op 0: " << T_name<fmp::eq<int1, int0>::type>() << std::endl;
  std::cout << "gte: " << T_name<neg<gte<val<int, 0>, val<int, 0>>::type>>() << std::endl;
}

void test_gt() {
  using int0 = fmp::val<int, 0>;
  using int1 = fmp::val<int, 1>;
  using op = fmp::gt<int0, int1>;
  using op_i = fmp::gt<fmp::type_size<fmp::infinity_lower>, fmp::type_size<char>>;
  using op_i0 = fmp::gt<fmp::type_size<fmp::infinity_lower>, fmp::type_size<fmp::infinity_lower>>;
  using op_i1= fmp::gt<fmp::type_size<long>, fmp::type_size<fmp::infinity_lower>>;

  std::cout << "GT: 0 op 1: " << T_name<op::type>() << std::endl;
  std::cout << "GT: 0 op 0: " << T_name<fmp::gt<int0, int0>::type>() << std::endl;
  std::cout << "GT: 1 op 0: " << T_name<fmp::gt<int1, int0>::type>() << std::endl;
  std::cout << "op_i: " << T_name<op_i::type>() << std::endl;
  std::cout << "op_i0: " << T_name<op_i0::type>() << std::endl;
  std::cout << "op_i1: " << T_name<op_i1::type>() << std::endl;
}

void test_compare() {
  using int0 = fmp::val<int, 0>;
  using int1 = fmp::val<int, 1>;
  using op = fmp::compare<int0, int1>;

  std::cout << "CMP: 0 op 1: " << T_name<op::type>() << std::endl;
  std::cout << "CMP: 0 op 0: " << T_name<fmp::compare<int0, int0>::type>() << std::endl;
  std::cout << "CMP: 1 op 0: " << T_name<fmp::compare<int1, int0>::type>() << std::endl;
}

void test_max() {
#if 0
  using int0 = fmp::val<int, 0>;
  using maxop = fmp::max<fmp::type_size>;
  using max0 = maxop::unite_t<char, int>;
  using max1 = maxop::unite_t<int0, int0>;
//  using max2 = maxop::unite_t<char>;
  std::cout << "max0: " << T_name<max0::type>() << std::endl;
  std::cout << "max1: " << T_name<max1::type>() << std::endl;
//  std::cout << "max2: " << T_name<max2::type>() << std::endl;
#endif
}

void test_min() {
  using int0 = fmp::val<int, 0>;
#if 0
  using minop = fmp::min<fmp::type_size>;
  using min0 = minop::unite_t<char, int>;
  using min1 = minop::unite_t<int0, int0>;
//  using min2 = minop::unite_t<char>;
  using gt0 = fmp::gt<fmp::type_size<char>, fmp::type_size<fmp::infinity_upper>>;
  std::cout << "gt0: " << T_name<gt0::type>() << std::endl;
  std::cout << "min0: " << T_name<min0::type>() << std::endl;
  std::cout << "min1: " << T_name<min1::type>() << std::endl;
//  std::cout << "min2: " << T_name<min2::type>() << std::endl;
#endif
}

void test_foldl() {
  using namespace fmp;
//  using fold0 = foldl<cons, nil_type, int, long long>;

//  std::cout << "foldl0:" << T_name<fold0::type>() << std::endl;
}

void test_foldr() {
  using namespace fmp;
  using f0 = foldr_t<curry<cons>, nil_type, sequence<int, long>>;
//  using fold0 = foldr<cons, nil_type, int, long long>;

  std::cout << "fold(f0): " << T_name<f0>() << std::endl;
}

void test_cons() {
  using namespace fmp;

  using c0 = unity_t<cons>;
  using c1 = cons<int, nil_type>;
  using ac0 = curry<cons, int>;
  using c1_0 = apply_t<ac0, empty<cons>::type>;
  //using c2_0 = detail::monoid_unite_impl<cons>::template apply<cons<char, double>, c1>;
  using c2 = unite_t<c1, cons<char, cons<float, nil_type> > >;
  using car_0t = car_t<c1>;

  std::cout << "unity<cons>: " << T_name<c0>() << std::endl;
  std::cout << "cons<c1>: " << T_name<c1::type>() << std::endl;
  std::cout << "cons<c1>==cons?: " << is_cons_v<c0> << std::endl;
  std::cout << "cons<c1_0>: " << T_name<c1_0::type>() << std::endl;
  std::cout << "cons<c2>: " << T_name<c2>() << std::endl;
  std::cout << "car<c1>:=" << T_name<car<c1>>() << std::endl;
  std::cout << "car_t<c1>:=" << T_name<car_t<c1>>() << std::endl;
};

void test_list() {
  using l0 = fmp::list_t<char, int, float, double>;

  std::cout << "list<>: " << T_name<l0>() << std::endl;
}

void apply_sample() {
  using namespace fmp;
  using c0 = curry<std::is_same>;
  using a0 = apply<c0, int>::type;
  using a1 = apply_t<a0, char>;

  using t0 = has_apply<a1>;
  using e0 = apply<a1>; // cause assertion error if instantiate

  std::cout << "a0:" << T_name<a0>() << std::endl;
  std::cout << "a1:" << T_name<a1>() << std::endl;
  std::cout << "t0:" << T_name<t0>() << std::endl;
}

void compose_sample() {
  using namespace fmp;
  using f0 = curry<car>;
  using g0 = curry<cons>;
  using f1 = curry<std::add_const>;
  using f2 = curry<id>;

  using c0 = compose<f0, g0>;
  using r0 = apply_t<c0, int>;
  using r1 = apply_t<r0, int>;
  using c2 = compose<curry<id>, f0, g0>;
  using r2 = apply_t<c2, int, char>;

  //using ac0 = typename compose<f2, f1>::template apply<int>::type;
  //using ac0 = typename detail::compose_apply_impl<f2, apply_t<f1, int>>::type;
  using ac0 = apply_t<compose<f2, f1>, int>;

  std::cout << "hasapply:" << T_name<f0::template apply<cons<int, char>>>()
            << std::endl;
  std::cout << "f0 apply:" << T_name<apply_t<f0, cons<int, char>> >() << std::endl;
  std::cout << "car<cons2<int, char>>: "
            << T_name<car_t<cons<int, char>>>()<< std::endl;
  std::cout << "compose r0:" << T_name<apply_t<r0, nil_type>>() << std::endl;
  std::cout << "compose r1:" << T_name<apply_t<f0, cons<int, int>>>() << std::endl;
  std::cout << "compose c2:" << T_name<c2>() << std::endl;
  std::cout << "compose r2:" << T_name<r2>() << std::endl;
  std::cout << "compose ac0:" << T_name<ac0>() << std::endl;
  std::cout << "compose c0:" << T_name<r1>() << std::endl;
}

void test_valtype() {
  using namespace fmp;
  using vt0 = valtype<int>;
  using v0 = valtype<int>::template let<0>;
  using v1 = vt0::let<1>;
  using v2 = vt0::let<2>;

  std::cout << "--valtype--" << std::endl;
  std::cout << "v0: " << T_name<v0>() << std::endl;
  std::cout << "v1: " << T_name<v1>() << std::endl;
  std::cout << "v2: " << T_name<v2>() << std::endl;
}

void test_sequence() {
  using s0 = fmp::sequence<int, char>;
  using s1 = fmp::sequence<float, double>;
  using su = fmp::unity_t<fmp::sequence>;
  using sunite = fmp::unite_t<s0, s1>;

  using r0 = fmp::append_t<s0, s1>;
  std::cout << "--sequence--" << std::endl;
  std::cout << "r0:" << T_name<r0>() << std::endl;
  std::cout << "head<r0>: " << T_name<fmp::head_t<r0>>() << std::endl;
  std::cout << "unity<sequence>=" << T_name<su>() << std::endl;
  std::cout << "unite<s0, s1>=" << T_name<sunite>() << std::endl;
}

void test_flip() {
  using namespace fmp;

  std::cout << "flip: " << std::endl;
  using fl0 = curry<flip, curry<cons>>;
  using fl1 = flipf<cons, nil_type>;
  using snc0 = apply_t<fl0, nil_type, int>;

  using snc0 = apply_t<fl0, nil_type, int>;
  using snc1 = apply_t<fl1, int>;

  std::cout << "fl0: " << T_name<fl0>() << std::endl;
  std::cout << "snc0: " << T_name<snc0>()<< std::endl;
  std::cout << "snc1: " << T_name<snc1>() << std::endl;
}

void test_curried() {
  using namespace fmp;

  std::cout << "CURRIED-----" << std::endl;
  using c0 = curry<id, int>;
  using r0 = is_curried<c0>;

  std::cout << "fl0: " << T_name<r0::type>() << std::endl;
  std::cout << "is_curried_v<c0>: " << is_curried_v<c0> << std::endl;
  std::cout << "is_curried_v<int>: " << is_curried_v<int> << std::endl;
  std::cout << "is_curried_v<cons<int,nil>>: " << is_curried_v<cons<int,nil_type>> << std::endl;
}

void test_endo() {
  using namespace fmp;

  std::cout << "ENDO-----" << std::endl;
  using e0 = endo<curry<all>>;
  using ue0 = unite_t<endo<curry<get>>, e0>;

  std::cout << "unity<endo>:" << T_name<unity_t<endo>>() << std::endl;
  std::cout << "endo:" << T_name<e0>() << std::endl;
  std::cout << "apply:" << T_name<apply_t<e0, std::true_type>>() << std::endl;
  std::cout << "unite:" << T_name<apply_t<ue0, std::true_type>>() << std::endl;
}

void test_getmf() {
  using namespace fmp;

  using c0 = cons<int, char>;
  using r0 = get_mf<int>::type;
  using r1 = get_mf<c0>::template type<float, double>;

  std::cout << "-- GetMF-- " << std::endl;
  std::cout << "r0(int): " << T_name<r0>() << std::endl;
  std::cout << "r1(cons): " << T_name<r1>() << std::endl;
}

void test_mconcat() {
  using namespace fmp;

  std::cout << "## test_mconcat() ##" << std::endl;
  using e0 = compose<curry<id>, curry<unite>>;
  using u0 = unite_t<all<std::true_type>, all<std::false_type>>;
  using r0 = apply_t<e0, all<std::true_type>, all<std::false_type>>;
  using sq = sequence<all<std::true_type>, all<std::true_type>>;
  using f0 = foldr_t<e0, unity_t<all>, sq>;

  using mc0 = mconcat_t<all, sq>;
  using cc = curry<foldr, curry<unite>, unity_t<all>>;
  using mdet = monoid_trait<all>::concat;

  std::cout << "u0:" << T_name<u0::get>() << std::endl;
  std::cout << "e0:" << T_name<r0>() << std::endl;
  std::cout << "fold(f0): " << T_name<f0::get>() << std::endl;
  std::cout << "cc: " << T_name<cc>() << std::endl;
  std::cout << "mdet: " << T_name<apply<mdet, sq>::type>() << std::endl;
  std::cout << "mconcat: " << T_name<mc0>() << std::endl;
}

void test_map() {
  using namespace fmp;

  std::cout << "## test_map() ##" << std::endl;
  using c0 = list_t<int, char, double>;
  using s0 = sequence<int, char, double>;
  using p0 = curry<std::is_same, int>;
  using cr0 = map<p0, c0>;
  using sr0 = map<p0, s0>;

  std::cout << "c0: " << T_name<c0>() << std::endl;
  std::cout << "cr0: " << T_name<cr0::type>() << std::endl;
  std::cout << "sr0: " << T_name<sr0::type>() << std::endl;
}

void test_maybe() {
  using namespace fmp;

  std::cout << "## test_maybe() ##" << std::endl;

  using j0 = just_t<all<std::true_type>>;
  using j1 = just_t<all<std::false_type>>;
  using n0 = nothing_t;

  using p0 = is_just_t<n0>;
  using p1 = is_nothing_t<j0>;

  using fj0 = from_just_t<j0>;
  using fm0 = from_maybe_t<j0, std::nullptr_t>;
  using fm1 = from_maybe_t<n0, std::nullptr_t>;
  using unit0 = unity_t<maybe>;
  using um0 = unite_t<j1, j1>;
  using cp0 = compose<curry<just>, curry<all>>;
  using amp0 = map_t<cp0,
                     sequence<std::true_type, std::true_type, std::true_type>>;
  using mcc0 = mconcat_t<maybe, amp0>;

  std::cout << "j0: " << T_name<j0>() << std::endl;
  std::cout << "n0: " << T_name<n0>() << std::endl;

  std::cout << "is_just<T>: " << T_name<is_just_t<j0>>() << std::endl;
  std::cout << "is_nothing<T>: " << T_name<is_nothing_t<n0>>() << std::endl;

  std::cout << "from_just<T>: " << T_name<from_just_t<j0>>() << std::endl;
  std::cout << "from_maybe<T>: " << T_name<fm0>() << std::endl;
  std::cout << "from_maybe<nothing>: " << T_name<fm1>() << std::endl;
  std::cout << "unity<>: " << T_name<unit0>() << std::endl;
  std::cout << "unite<A,B>: " << T_name<get_t<um0>>() << std::endl;
  std::cout << "all map: "<< T_name<amp0>() << std::endl;
  std::cout << "mconcat<maybe, map<...>>: " << T_name<from_maybe_t<mcc0, nothing>>() << std::endl;

}

void test_fmap()
{
  using namespace fmp;
  std::cout << "## " << __func__ << "() ##" << std::endl;

  using c0 = list_t<int, char, double>;
  using p0 = curry<std::is_same, int>;
  using cr0 = fmap_t<p0, c0>;

  using mp0 = fmap_t<curry<std::add_const>, just_t<int>>;
  using mp1 = fmap_t<curry<std::add_const>, nothing_t>;

  std::cout << "cr0: " << T_name<cr0>() << std::endl;

  std::cout << "fmap<just>: "<< T_name<mp0>() << std::endl;
  std::cout << "fmap<nothing>: "<< T_name<mp1>() << std::endl;
}

void test_add()
{
  using namespace fmp;
  std::cout << "## " << __func__ << "() ##" << std::endl;

  using vt = valtype<int>;
  using v1 = vt::let<1>;
  using v10 = vt::let<10>;
  using r11 = add<v1, v10>;

  std::cout << "add: " << T_name<r11::type>() << std::endl;
}

void test_div()
{
  using namespace fmp;
  std::cout << "## " << __func__ << "() ##" << std::endl;

  using vt = valtype<int>;
  using v1 = vt::let<12>;
  using v2 = vt::let<6>;
  using r0 = fmp::div_t<v1, v2>;

  std::cout << "div: " << T_name<r0>() << std::endl;
}

void test_eval()
{
  using namespace fmp;
  std::cout << "## " << __func__ << "() ##" << std::endl;

  using c0 = list_t<int, char, double>;
  using p0 = curry<std::is_same, int>;
  using cr0 = fmap<p0, c0>;

  using e0 = evalcL_t<int, 0>;
  using e1 = cr0::type;
  using e1_1 = evalcL_t<cr0, 2>;
  using e1_2 = evalL_t<cr0, val<int, 2>>;

  std::cout << "e0: " << T_name<e0>() << std::endl;
  std::cout << "e1: " << T_name<e1>() << std::endl;
  std::cout << "eval_t: " << T_name<eval_t<cr0>>() << std::endl;
  std::cout << "e1_0: " << T_name<e1_1>() << std::endl;
  std::cout << "e1_2: " << T_name<e1_2>() << std::endl;

}

int main(int , char**)
{
  std::cout << std::boolalpha;
  //test_derived();
  //test_quote();
  //test_order();
  //test_monoid();
  test_curry();
  test_monoid_et();
  //test_monoid_uel();
  //test_lt();
  //test_gt();
  //test_compare();
  //test_max();
  //test_min();
  //test_foldl();
  //apply_sample();
  test_valtype();
  test_unity();
  test_unite();

  test_cons();
  //test_flip();
  //test_curried();
  test_getmf();
  test_foldr();
  test_list();
  test_mconcat();
  test_map();
  test_sequence();
  compose_sample();
  test_endo();
  test_maybe();
  test_fmap();
  test_value();
  test_add();
  test_eq();
  test_eval();

  return 0;
}


#include "interval.h"

#include <possumwood_sdk/app.h>

#include <QAction>
#include <QApplication>
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QMainWindow>
#include <QStyle>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>

interval_ui::interval_ui() {
	m_widget = new QWidget(NULL);

	QHBoxLayout* layout = new QHBoxLayout(m_widget);
	layout->setContentsMargins(0, 0, 0, 0);

	m_slider = new QSlider();
	m_slider->setMinimum(0);
	m_slider->setMaximum(1000);
	m_slider->setOrientation(Qt::Horizontal);
	layout->addWidget(m_slider, 1);

	m_sliderConnection = QObject::connect(m_slider, &QSlider::valueChanged, [this](int value) -> void {
		float norm_val = (float)value / 1000.0f;
		assert(norm_val >= 0.0f && norm_val <= 1.0f);

		if(m_value.type() == possumwood::maths::Interval::kLinear) {
			m_value = m_value.min() + (m_value.max() - m_value.min()) * norm_val;
		}
		else if(m_value.type() == possumwood::maths::Interval::kLog) {
			assert(m_value.min() > 0.0f);

			const float min = log10(m_value.min());
			const float max = log10(m_value.max());

			norm_val = min + norm_val * (max - min);
			norm_val = powf(10.0f, norm_val);

			m_value = norm_val;
		}
		else
			assert(false);

		callValueChangedCallbacks();
	});

	m_detailsButton = new QToolButton();
	m_detailsButton->setIcon(QIcon::fromTheme("preferences-other"));
	layout->addWidget(m_detailsButton);

	m_buttonConnection = QObject::connect(m_detailsButton, &QToolButton::released, [this]() -> void {
		possumwood::maths::Interval current;
		get(current);

		IntervalDialog* dialog = new IntervalDialog(m_widget, current);
		if(dialog->exec() == QDialog::Accepted) {
			// apply the settings
			dialog->updateInterval(current);

			set(current);

			callValueChangedCallbacks();
		}

		dialog->deleteLater();
	});
}

interval_ui::~interval_ui() {
	QObject::disconnect(m_sliderConnection);
}

void interval_ui::get(possumwood::maths::Interval& value) const {
	value = m_value;
}

void interval_ui::set(const possumwood::maths::Interval& value) {
	m_value = value;

	const bool bs = m_slider->blockSignals(true);

	if(m_value.max() == m_value.min())
		m_slider->setValue(500);

	else if(m_value.type() == possumwood::maths::Interval::kLinear) {
		float val = (m_value.value() - m_value.min()) / (m_value.max() - m_value.min());
		val = std::min(std::max(0.0f, val), 1.0f);

		m_slider->setValue(val * 1000.0f);
	}
	else if(m_value.type() == possumwood::maths::Interval::kLog) {
		assert(m_value.min() > 0.0f);

		const float min = log10(m_value.min());
		const float max = log10(m_value.max());

		float val = (log10(m_value.value()) - min) / (max - min);
		val = std::min(std::max(0.0f, val), 1.0f);

		m_slider->setValue(val * 1000.0f);
	}
	else
		assert(false);

	m_slider->blockSignals(bs);

	m_slider->setTracking(m_value.inProgressUpdates());
}

QWidget* interval_ui::widget() {
	return m_widget;
}

void interval_ui::onFlagsChanged(unsigned flags) {
	m_slider->setDisabled(flags & kDisabled);
	m_detailsButton->setDisabled(flags & kDisabled);
}

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

IntervalDialog::IntervalDialog(QWidget* parent, const possumwood::maths::Interval& current) : QDialog(parent) {
	setModal(true);
	setWindowTitle("Interval properties");

	QVBoxLayout* mainLayout = new QVBoxLayout(this);
	QFrame* frame = new QFrame();
	frame->setFrameStyle(QFrame::Panel | QFrame::Sunken);
	mainLayout->addWidget(frame, 1);

	QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
	mainLayout->addWidget(buttons, 0);

	connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
	connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);

	QFormLayout* layout = new QFormLayout(frame);

	m_type = new QComboBox();
	m_type->addItem("Linear");
	m_type->addItem("Logarithmic");
	layout->addRow("Interval type", m_type);
	if(current.type() == possumwood::maths::Interval::kLinear)
		m_type->setCurrentIndex(0);
	else if(current.type() == possumwood::maths::Interval::kLog)
		m_type->setCurrentIndex(1);
	else
		assert(false);

	m_min = new QDoubleSpinBox();
	m_min->setRange(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
	m_min->setValue(current.min());
	layout->addRow("Minimum value", m_min);

	m_max = new QDoubleSpinBox();
	m_max->setRange(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
	m_max->setValue(current.max());
	layout->addRow("Maximum value", m_max);

	m_update = new QCheckBox();
	m_update->setChecked(current.inProgressUpdates());
	layout->addRow("Update while dragging", m_update);
}

void IntervalDialog::updateInterval(possumwood::maths::Interval& i) {
	if(m_type->currentIndex() == 0)
		i.setType(possumwood::maths::Interval::kLinear);
	else if(m_type->currentIndex() == 1)
		i.setType(possumwood::maths::Interval::kLog);
	else
		assert(false);

	const float current = i.value();

	i.setMin(m_min->value());
	i.setMax(m_max->value());
	i.setInProgressUpdates(m_update->isChecked());

	i.setValue(current);
}


/**
 * @file tests/main_tests/kfn_test.cpp
 * @author Atharva Khandait
 * @author Heet Sankesara
 *
 * Test mlpackMain() of kfn_main.cpp.
 *
 * mlpack is free software; you may redistribute it and/or modify it under the
 * terms of the 3-clause BSD license.  You should have received a copy of the
 * 3-clause BSD license along with mlpack.  If not, see
 * http://www.opensource.org/licenses/BSD-3-Clause for more information.
 */
#include <string>

#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "K-FurthestNeighborsSearch";

#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include "test_helper.hpp"
#include <mlpack/methods/neighbor_search/kfn_main.cpp>

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

using namespace mlpack;

struct KFNTestFixture
{
 public:
  KFNTestFixture()
  {
    // Cache in the options for this program.
    CLI::RestoreSettings(testName);
  }

  ~KFNTestFixture()
  {
    // Clear the settings.
    bindings::tests::CleanMemory();
    CLI::ClearSettings();
  }
};

BOOST_FIXTURE_TEST_SUITE(KFNMainTest, KFNTestFixture);

/*
 * Check that we can't provide reference and query matrices
 * with different dimensions.
 */
BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Now we specify an invalid dimension(2) for the query data.
  // Note that the number of points in query and reference matrices
  // are allowed to be different
  arma::mat queryData;
  queryData.randu(2, 90); // 90 points in 2 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("query", std::move(queryData));
  SetInputParam("k", (int) 10);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't specify an invalid k when only reference
 * matrix is given.
 */
BOOST_AUTO_TEST_CASE(KFNInvalidKTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k > number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 101);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);

  delete CLI::GetParam<KFNModel*>("output_model");
  CLI::GetParam<KFNModel*>("output_model") = NULL;

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["k"].wasPassed = false;

  // SetInputParam("reference", referenceData);
  // SetInputParam("k", (int) 0); // Invalid.

  // BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);

  // CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  // CLI::GetSingleton().Parameters()["k"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("k", (int) -1); // Invalid.

  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't specify an invalid k when both reference
 * and query matrices are given.
 */
BOOST_AUTO_TEST_CASE(KFNInvalidKQueryDataTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  arma::mat queryData;
  queryData.randu(3, 90); // 90 points in 3 dimensions.

  // Random input, some k > number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("query", std::move(queryData));
  SetInputParam("k", (int) 101);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Check that we can't specify a negative leaf size.
 */
BOOST_AUTO_TEST_CASE(KFNLeafSizeTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, negative leaf size.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("leaf_size", (int) -1); // Invalid.

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't pass both input_model and reference matrix.
 */
BOOST_AUTO_TEST_CASE(KFNRefModelTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("k", (int) 10);

  mlpackMain();

  // Input pre-trained model.
  SetInputParam("input_model",
      std::move(CLI::GetParam<KFNModel*>("output_model")));

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't pass an invalid tree type.
 */
BOOST_AUTO_TEST_CASE(KFNInvalidTreeTypeTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("k", (int) 10);
  SetInputParam("tree_type", (string) "min-rp"); // Invalid.

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't pass an invalid algorithm.
 */
BOOST_AUTO_TEST_CASE(KFNInvalidAlgoTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("k", (int) 10);
  SetInputParam("algorithm", (string) "triple_tree"); // Invalid.

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't pass an invalid value of epsilon.
 */
BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);
  SetInputParam("epsilon", (double) -1); // Invalid.

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["epsilon"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("epsilon", (double) 2); // Invalid.

  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["epsilon"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("epsilon", (double) 1); // Invalid.

  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Check that we can't pass an invalid value of percentage.
 */
BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);
  SetInputParam("percentage", (double) -1); // Invalid.

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["percentage"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("percentage", (double) 0); // Invalid.

  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["epsilon"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("percentage", (double) 2); // Invalid.

  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Make sure that dimensions of the neighbors and distances
 * matrices are correct given a value of k.
 */
BOOST_AUTO_TEST_CASE(KFNOutputDimensionTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("k", (int) 10);

  mlpackMain();

  // Check the neighbors matrix has 4 points for each input point.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::Mat<size_t>>
      ("neighbors").n_rows, 10);
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::Mat<size_t>>
      ("neighbors").n_cols, 100);

  // Check the distances matrix has 4 points for each input point.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("distances").n_rows, 10);
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("distances").n_cols, 100);
}

/**
 * Ensure that saved model can be used again.
 */
BOOST_AUTO_TEST_CASE(KFNModelReuseTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  arma::mat queryData;
  queryData.randu(3, 90); // 90 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("query", queryData);
  SetInputParam("k", (int) 10);

  mlpackMain();

  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  distances = std::move(CLI::GetParam<arma::mat>("distances"));

  // bindings::tests::CleanMemory();

  // Reset passed parameters.
  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["query"].wasPassed = false;

  // Input saved model, pass the same query and keep k unchanged.
  SetInputParam("input_model",
      std::move(CLI::GetParam<KFNModel*>("output_model")));
  SetInputParam("query", queryData);

  mlpackMain();

  // Check that initial output matrices and the output matrices using
  // saved model are equal.
  CheckMatrices(neighbors, CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  CheckMatrices(distances, CLI::GetParam<arma::mat>("distances"));
}

/*
 * Ensure that changing the value of epsilon gives us different
 * approximate KFN results.
 */
BOOST_AUTO_TEST_CASE(KFNDifferentEpsilonTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 1000); // 1000 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);
  SetInputParam("epsilon", (double) 0.2);

  mlpackMain();

  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  distances = std::move(CLI::GetParam<arma::mat>("distances"));

  bindings::tests::CleanMemory();

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["epsilon"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("epsilon", (double) 0.8);

  mlpackMain();

  CheckMatricesNotEqual(neighbors,
      CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  CheckMatricesNotEqual(distances,
      CLI::GetParam<arma::mat>("distances"));
}

/*
 * Ensure that changing the value of percentage gives us different
 * approximate KFN results.
 */
BOOST_AUTO_TEST_CASE(KFNDifferentPercentageTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 1000); // 1000 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);
  SetInputParam("percentage", (double) 0.2);

  mlpackMain();

  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  distances = std::move(CLI::GetParam<arma::mat>("distances"));

  bindings::tests::CleanMemory();

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["percentage"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("percentage", (double) 0.8);

  mlpackMain();

  CheckMatricesNotEqual(neighbors,
      CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  CheckMatricesNotEqual(distances,
      CLI::GetParam<arma::mat>("distances"));
}

/*
 * Ensure that we get different results on running twice in greedy
 * search mode when random_basis is specified.
 */
BOOST_AUTO_TEST_CASE(KFNRandomBasisTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 1000); // 1000 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);
  CLI::SetPassed("random_basis");

  mlpackMain();

  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  distances = std::move(CLI::GetParam<arma::mat>("distances"));
  BOOST_REQUIRE_EQUAL(CLI::GetParam<KFNModel*>("output_model")->RandomBasis(),
      true);

  bindings::tests::CleanMemory();

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["random_basis"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));

  mlpackMain();

  CheckMatrices(neighbors, CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  CheckMatrices(distances, CLI::GetParam<arma::mat>("distances"));
  BOOST_REQUIRE_EQUAL(CLI::GetParam<KFNModel*>("output_model")->RandomBasis(),
      false);
}

/*
 * Ensure that the program runs successfully when we pass true_neighbors
 * and/or true_distances and fails when those matrices have the wrong shape.
 */
BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);

  mlpackMain();

  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
  distances = std::move(CLI::GetParam<arma::mat>("distances"));

  delete CLI::GetParam<KFNModel*>("output_model");
  CLI::GetParam<KFNModel*>("output_model") = NULL;

  SetInputParam("reference", referenceData);
  SetInputParam("true_neighbors", neighbors);
  SetInputParam("true_distances", distances);
  SetInputParam("epsilon", (double) 0.5);

  BOOST_REQUIRE_NO_THROW(mlpackMain());

  // True output matrices have incorrect shape.
  arma::Mat<size_t> dummyNeighbors;
  arma::mat dummyDistances;
  dummyNeighbors.randu(20, 100);
  dummyDistances.randu(20, 100);

  delete CLI::GetParam<KFNModel*>("output_model");
  CLI::GetParam<KFNModel*>("output_model") = NULL;

  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
  CLI::GetSingleton().Parameters()["true_neighbors"].wasPassed = false;
  CLI::GetSingleton().Parameters()["true_distances"].wasPassed = false;

  SetInputParam("reference", std::move(referenceData));
  SetInputParam("true_neighbors", std::move(dummyNeighbors));
  SetInputParam("true_distances", std::move(dummyDistances));

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/*
 * Ensure that different search algorithms give same result.
 * We do not consider greedy because it is an approximate algorithm.
 */
BOOST_AUTO_TEST_CASE(KFNAllAlgorithmsTest)
{
  string algorithms[] = {"dual_tree", "naive", "single_tree"};
  const int nofalgorithms = 3;

  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  arma::mat queryData;
  queryData.randu(3, 90); // 90 points in 3 dimensions.

  // Keep some k <= number of reference points same over all.
  SetInputParam("k", (int) 10);

  arma::Mat<size_t> neighborsCompare;
  arma::mat distancesCompare;

  arma::Mat<size_t> neighbors;
  arma::mat distances;

  // Looping over all the algorithms and storing their outputs.
  for (int i = 0; i < nofalgorithms; i++)
  {
    // Same random inputs, different algorithms.
    SetInputParam("reference", referenceData);
    SetInputParam("query", queryData);
    SetInputParam("algorithm", algorithms[i]);

    mlpackMain();

    if (i == 0)
    {
      neighborsCompare = std::move
          (CLI::GetParam<arma::Mat<size_t>>("neighbors"));
      distancesCompare = std::move(CLI::GetParam<arma::mat>("distances"));
    }
    else
    {
      neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
      distances = std::move(CLI::GetParam<arma::mat>("distances"));

      CheckMatrices(neighborsCompare, neighbors);
      CheckMatrices(distancesCompare, distances);
    }

    delete CLI::GetParam<KFNModel*>("output_model");
    CLI::GetParam<KFNModel*>("output_model") = NULL;

    // Reset passed parameters.
    CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
    CLI::GetSingleton().Parameters()["query"].wasPassed = false;
    CLI::GetSingleton().Parameters()["algorithm"].wasPassed = false;
  }
}

/*
 * Ensure that different tree types give same result.
 */
BOOST_AUTO_TEST_CASE(KFNAllTreeTypesTest)
{
  string treetypes[] = {"kd", "vp", "rp", "max-rp", "ub", "cover", "r",
      "r-star", "x", "ball", "hilbert-r", "r-plus", "r-plus-plus",
      "oct"};
  const int noftreetypes = 14;

  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  arma::mat queryData;
  queryData.randu(3, 90); // 90 points in 3 dimensions.

  // Keep some k <= number of reference points same over all.
  SetInputParam("k", (int) 10);

  arma::Mat<size_t> neighborsCompare;
  arma::mat distancesCompare;

  arma::Mat<size_t> neighbors;
  arma::mat distances;

  // Looping over all the algorithms and storing their outputs.
  for (int i = 0; i < noftreetypes; i++)
  {
    // Same random inputs, different algorithms.
    SetInputParam("reference", referenceData);
    SetInputParam("query", queryData);
    SetInputParam("tree_type", treetypes[i]);

    mlpackMain();

    if (i == 0)
    {
      neighborsCompare = std::move(
          CLI::GetParam<arma::Mat<size_t>>("neighbors"));
      distancesCompare = std::move(CLI::GetParam<arma::mat>("distances"));
    }
    else
    {
      neighbors = std::move(CLI::GetParam<arma::Mat<size_t>>("neighbors"));
      distances = std::move(CLI::GetParam<arma::mat>("distances"));

      CheckMatrices(neighborsCompare, neighbors);
      CheckMatrices(distancesCompare, distances);
    }

    delete CLI::GetParam<KFNModel*>("output_model");
    CLI::GetParam<KFNModel*>("output_model") = NULL;

    // Reset passed parameters.
    CLI::GetSingleton().Parameters()["reference"].wasPassed = false;
    CLI::GetSingleton().Parameters()["query"].wasPassed = false;
    CLI::GetSingleton().Parameters()["tree_type"].wasPassed = false;
  }
}

/**
  * Ensure that different leaf sizes give different results.
 */
BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes)
{
  arma::mat referenceData;
  referenceData.randu(3, 100); // 100 points in 3 dimensions.

  // Random input, some k <= number of reference points.
  SetInputParam("reference", referenceData);
  SetInputParam("k", (int) 10);
  SetInputParam("leaf_size", (int) 1);

  mlpackMain();

  BOOST_CHECK_EQUAL(CLI::GetParam<KFNModel*>("output_model")->LeafSize(),
      (int) 1);

  bindings::tests::CleanMemory();

  // Reset passed parameters.
  CLI::GetSingleton().Parameters()["reference"].wasPassed = false;

  // Input saved model, pass the same query and keep k unchanged.
  SetInputParam("reference", std::move(referenceData));
  SetInputParam("k", (int) 10);
  SetInputParam("leaf_size", (int) 10);

  mlpackMain();

  // Check that initial output matrices and the output matrices using
  // saved model are equal.
  BOOST_CHECK_EQUAL(CLI::GetParam<KFNModel*>("output_model")->LeafSize(),
      (int) 10);
}

BOOST_AUTO_TEST_SUITE_END();


#include <fstream>
#include <yaml-cpp/yaml.h>
#include <Eigen/Dense>
#include <qualisys/yaml_utils.h>

namespace qualisys {
namespace yaml_utils {

// Support for new yaml-cpp, taken from
// https://github.com/ros-planning/moveit_setup_assistant/commit/c9238ca#diff-1
#ifdef HAVE_NEW_YAMLCPP
// The >> operator disappeared in yaml-cpp 0.5, so this function is
// added to provide support for code written under the yaml-cpp 0.3 API.
template <typename T>
static void operator>>(const YAML::Node &node, T &i)
{
  i = node.as<T>();
}
#endif

// yaml-cpp 0.5 also changed how you load the YAML document.  This
// function hides the changes.
static void loadYaml(std::istream &in_stream, YAML::Node &doc_out)
{
#ifdef HAVE_NEW_YAMLCPP
  doc_out = YAML::Load(in_stream);
#else
  YAML::Parser parser(in_stream);
  parser.GetNextDocument(doc_out);
#endif
}

// Read SE3 pose from a file
bool loadPoseFromFile(
    const std::string &filename, Eigen::Affine3d &pose) {

  // Init pose to identity.
  // If exception occurs, pose will be returned as identity.
  pose = Eigen::Affine3d::Identity();

  // Open File
  std::ifstream fin(filename.c_str());
  if(!fin.is_open())
    return false;

  bool ret = false;

  try
  {
    YAML::Node doc;
    loadYaml(fin, doc);

    try
    {
      Eigen::Vector3d v;
      Eigen::Quaterniond q;
      doc["translation"]["x"] >> v(0);
      doc["translation"]["y"] >> v(1);
      doc["translation"]["z"] >> v(2);
      doc["rotation"]["x"] >> q.x();
      doc["rotation"]["y"] >> q.y();
      doc["rotation"]["z"] >> q.z();
      doc["rotation"]["w"] >> q.w();
      pose.translate(v);
      pose.rotate(q);
      ret = true;
    }
    catch(YAML::KeyNotFound &e)
    {
      ret = false;
    }
  }
  catch(YAML::ParserException &e)
  {
    ret = false;
  }
  fin.close();

  return ret;
}

// Save SE3 pose to a file
bool savePoseToFile(
    const Eigen::Affine3d &pose, const std::string &filename) {

  YAML::Emitter out;

  Eigen::Vector3d v(pose.translation());
  Eigen::Quaterniond q(pose.rotation());

  out << YAML::BeginMap;
  out << YAML::Key << "translation";
  out << YAML::Value << YAML::BeginMap << YAML::Key << "x" << YAML::Value
      << v.x() << YAML::Key << "y" << YAML::Value << v.y() << YAML::Key << "z"
      << YAML::Value << v.z() << YAML::EndMap;
  out << YAML::Key << "rotation";
  out << YAML::Value << YAML::BeginMap << YAML::Key << "x" << YAML::Value
      << q.x() << YAML::Key << "y" << YAML::Value << q.y() << YAML::Key << "z"
      << YAML::Value << q.z() << YAML::Key << "w" << YAML::Value << q.w()
      << YAML::EndMap;
  out << YAML::EndMap;

  // Open the file
  std::ofstream fout(filename.c_str(),
      std::ios_base::out | std::ios_base::trunc);
  if(!fout.is_open())
    return false;

  bool ret = true;

  fout << out.c_str() << std::endl;
  if(!fout.good())
    ret = false;

  fout.close();

  return ret;
}

} // End namespace yaml_utils
} // End namespace qualisys


//=======================================================================
// Copyright 2009 Trustees of Indiana University.
// Authors: Michael Hansen, Andrew Lumsdaine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <boost/graph/graph_archetypes.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/grid_graph.hpp>
#include <boost/concept/assert.hpp>

using namespace boost;

template < unsigned int Dims > void check()
{
    typedef grid_graph< Dims > Graph;
    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
    typedef typename graph_traits< Graph >::edge_descriptor Edge;

    BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
    BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >));
    BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >));
    BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
    BOOST_CONCEPT_ASSERT((AdjacencyGraphConcept< Graph >));
    BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph >));
    BOOST_CONCEPT_ASSERT(
        (ReadablePropertyGraphConcept< Graph, Vertex, vertex_index_t >));
    BOOST_CONCEPT_ASSERT(
        (ReadablePropertyGraphConcept< Graph, Edge, edge_index_t >));
}

int main(int, char*[])
{
    check< 0 >();
    check< 1 >();
    check< 2 >();
    check< 3 >();
    check< 4 >();

    return (0);
}


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 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
//==============================================================================
#ifndef BOOST_SIMD_SDK_SIMD_PACK_META_CARDINAL_OF_HPP_INCLUDED
#define BOOST_SIMD_SDK_SIMD_PACK_META_CARDINAL_OF_HPP_INCLUDED

#include <boost/simd/sdk/meta/cardinal_of.hpp>
#include <boost/simd/sdk/simd/pack/forward.hpp>
#include <boost/mpl/size_t.hpp>

namespace boost { namespace simd { namespace meta
{
  template< class Type
          , std::size_t Cardinal
          >
  struct cardinal_of< boost::simd::pack<Type, Cardinal> >
    : mpl::size_t<Cardinal>
  {
  };
} } }

#endif


#define BOOST_TEST_MODULE extension_store test
#include <boost/test/included/unit_test.hpp>
#include <iostream>

#include "extension_store.h"

BOOST_AUTO_TEST_CASE( all_tests ) {
	using namespace std;
	extension_store store;

	extension_store::extension_ptr extA( new extension_store::extension() );
	extA->range.a = 10;
	extA->range.b = 12;
	extA->add_row( closed_interval(5,10), 6 );
	extA->add_row( closed_interval(7,12), 8 );
	extA->add_row( closed_interval(7,10), 6 );
	store.add( extA );

	// Test basic overlap code.
	try {
		store.get_bounds( point(11,11), true );
		BOOST_FAIL( "Overlap check failed." );
	} catch( point_covered_exception &e ) {}

	extension_store::bounds b = store.get_bounds( point(20,11), true );
	closed_interval test_int(8,20);
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 13 && test_int.b == 20 ) ;

	b = store.get_bounds( point(5,11), true );
	test_int.a = 0; test_int.b = 10;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.b == 6 && test_int.a == 0 );

	// Add new extension that overlaps extA completely.
	extension_store::extension_ptr extB( new extension_store::extension() );
	extB->range.a = 10;
	extB->range.b = 12;
	extB->add_row( closed_interval(15,20), 16 );
	extB->add_row( closed_interval(18,25), 19 );
	extB->add_row( closed_interval(18,22), 29 );
	store.add( extB );

	b = store.get_bounds( point(14,11), true );
	test_int.a = 8; test_int.b = 20;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 13 && test_int.b == 17 );

	// Add an extension that overlaps extA on the top exactly.
	extension_store::extension_ptr extC( new extension_store::extension() );
	extC->range.a = 10;
	extC->range.b = 15;
	extC->add_row( closed_interval(30,40), 36 );
	extC->add_row( closed_interval(32,45), 39 );
	extC->add_row( closed_interval(33,46), 40 );
	extC->add_row( closed_interval(33,47), 40 );
	extC->add_row( closed_interval(35,50), 43 );
	extC->add_row( closed_interval(36,45), 44 );
	store.add( extC );

	b = store.get_bounds( point(27,11), true );
	test_int.a = 20; test_int.b = 35;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 26 && test_int.b == 31 );

	b = store.get_bounds( point(27,14), true );
	test_int.a = 20; test_int.b = 40;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 20 && test_int.b == 34);

	// Break top extension and add a further extension on the bottom.
	extension_store::extension_ptr extD( new extension_store::extension() );
	extD->range.a = 12;
	extD->range.b = 20;
	extD->add_row( closed_interval(1,2), 1 );
	extD->add_row( closed_interval(1,3), 2 );
	extD->add_row( closed_interval(1,3), 2 ); //
	extD->add_row( closed_interval(1,3), 2 );
	extD->add_row( closed_interval(1,4), 2 );
	extD->add_row( closed_interval(1,4), 2 ); //
	extD->add_row( closed_interval(1,4), 2 );
	extD->add_row( closed_interval(1,4), 2 );
	extD->add_row( closed_interval(1,4), 2 ); //
	store.add( extD );

	b = store.get_bounds( point(5,11), true );
	test_int.a = 0; test_int.b = 40;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 6 );

	b = store.get_bounds( point(5,12), true );
	test_int.a = 0; test_int.b = 40;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 3 && test_int.b == 6 );

	b = store.get_bounds( point(5,14), true );
	test_int.a = 0; test_int.b = 40;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 4 && test_int.b == 34 );

	b = store.get_bounds( point(5,18), true );
	test_int.a = 0; test_int.b = 40;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 5 && test_int.b == 40 );

	// Add overlap where top has overhang.
	extension_store::extension_ptr extE( new extension_store::extension() );
	extE->range.a = 6;
	extE->range.b = 11;
	extE->add_row( closed_interval(80,90), 85 );
	extE->add_row( closed_interval(80,90), 85 );
	extE->add_row( closed_interval(80,90), 85 );
	extE->add_row( closed_interval(80,90), 85 );//
	extE->add_row( closed_interval(82,92), 85 );
	extE->add_row( closed_interval(82,92), 85 );
	store.add( extE );

	b = store.get_bounds( point(60,8), true );
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 79 );

	b = store.get_bounds( point(60,10), true );
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 41 && test_int.b == 81 );

	// Need to test iteration.
	closed_interval bint(25,25);
	b = store.get_bounds( point(25,0), true );
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 100 );

	for( int i = 0; i < 6; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 79 );

	for( int i = 0; i < 4; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 21 && test_int.b == 29 );

	for( int i = 0; i < 2; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 23 && test_int.b == 32 );

	for( int i = 0; i < 100; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 100 );

	// Test reverse step.
	b = store.get_bounds( point(25,25), false );
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 100 );

	for( int i = 0; i < 5; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 5 && test_int.b == 100 );

	for( int i = 0; i < 6; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 4 && test_int.b == 34 );

	for( int i = 0; i < 13; ++i ) b.step(bint);
	test_int.a = 0; test_int.b = 100;
	test_int = b.clip(test_int);
	BOOST_CHECK( test_int.a == 0 && test_int.b == 100 );

	store.clear();
	extension_store::extension_ptr extF( new extension_store::extension() );
	extF->range.a = 10;
	extF->range.b = 20;
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	extF->add_row( closed_interval(5,10), 6 );
	store.add( extF );

	extension_store::extension_ptr extH( new extension_store::extension() );
	extH->range.a = 10;
	extH->range.b = 20;
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	extH->add_row( closed_interval(11,13), 11 );
	store.add( extH );

	extension_store::extension_ptr extG( new extension_store::extension() );
	extG->range.a = 13;
	extG->range.b = 16;
	extG->add_row( closed_interval(15,20), 17 );
	extG->add_row( closed_interval(15,20), 17 );
	extG->add_row( closed_interval(15,20), 17 );
	extG->add_row( closed_interval(15,20), 17 );
	store.add( extG );
	store.check();

}


//==============================================================================
//         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 accompnoneing file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <boost/simd/reduction/include/functions/none.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <boost/simd/sdk/simd/logical.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/simd/include/constants/true.hpp>
#include <boost/simd/include/constants/false.hpp>
#include <boost/simd/include/constants/inf.hpp>
#include <boost/simd/include/constants/nan.hpp>
#include <boost/simd/include/constants/minf.hpp>
#include <boost/simd/include/constants/mzero.hpp>

#include <nt2/sdk/unit/tests.hpp>
#include <nt2/sdk/unit/module.hpp>

NT2_TEST_CASE_TPL ( none, BOOST_SIMD_SIMD_TYPES)
{
  using boost::simd::none;
  using boost::simd::True;
  using boost::simd::False;
  using boost::simd::tag::none_;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION            ext_t;
  typedef native<T,ext_t>                         vT;
  typedef boost::simd::logical<T>                 lT;

  vT all_ok, none_ok, some_ok;
  for(std::size_t i=0;i<vT::static_size;++i)
  {
    none_ok[i] = T(0);
    some_ok[i] = all_ok[i] =T(1+i);
  }

  some_ok[vT::static_size/2] = T(0);

  NT2_TEST_EQUAL( none(all_ok) , False<lT>()  );
  NT2_TEST_EQUAL( none(some_ok), False<lT>()  );
  NT2_TEST_EQUAL( none(none_ok), True<lT>() );
}

NT2_TEST_CASE_TPL ( none_real, BOOST_SIMD_SIMD_REAL_TYPES)
{
  using boost::simd::none;
  using boost::simd::True;
  using boost::simd::Minf;
  using boost::simd::Inf;
  using boost::simd::Mzero;
  using boost::simd::Nan;
  using boost::simd::False;
  using boost::simd::tag::none_;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION            ext_t;
  typedef native<T,ext_t>                         vT;
  typedef boost::simd::logical<T>                 lT;

  NT2_TEST_EQUAL( none(Inf<vT>()) , False<lT>()  );
  NT2_TEST_EQUAL( none(Minf<vT>()), False<lT>() );
  NT2_TEST_EQUAL( none(Nan<vT>()) , False<lT>() );
  NT2_TEST_EQUAL( none(Mzero<vT>()), True<lT>() );
}


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

  Program:   Visualization Toolkit
  Module:    vtkBoostRandomSparseArraySource.cxx

-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

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

#include "vtkArrayCoordinateIterator.h"
#include "vtkBoostRandomSparseArraySource.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkSparseArray.h"

#include <boost/random.hpp>

// ----------------------------------------------------------------------

vtkCxxRevisionMacro(vtkBoostRandomSparseArraySource, "1.1");
vtkStandardNewMacro(vtkBoostRandomSparseArraySource);

// ----------------------------------------------------------------------

vtkBoostRandomSparseArraySource::vtkBoostRandomSparseArraySource() :
  Extents(2, 2),
  ElementProbabilitySeed(123),
  ElementProbability(0.5),
  ElementValueSeed(456),
  MinValue(0.0),
  MaxValue(1.0)
{
  this->SetNumberOfInputPorts(0);
  this->SetNumberOfOutputPorts(1);
}

// ----------------------------------------------------------------------

vtkBoostRandomSparseArraySource::~vtkBoostRandomSparseArraySource()
{
}

// ----------------------------------------------------------------------

void vtkBoostRandomSparseArraySource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "Extents: " << this->Extents << endl;
  os << indent << "ElementProbabilitySeed: " << this->ElementProbabilitySeed << endl;
  os << indent << "ElementProbability: " << this->ElementProbability << endl;
  os << indent << "ElementValueSeed: " << this->ElementValueSeed << endl;
  os << indent << "MinValue: " << this->MinValue << endl;
  os << indent << "MaxValue: " << this->MaxValue << endl;
}

void vtkBoostRandomSparseArraySource::SetExtents(const vtkArrayExtents& extents)
{
  if(extents == this->Extents)
    return;

  this->Extents = extents;
  this->Modified();
}

vtkArrayExtents vtkBoostRandomSparseArraySource::GetExtents()
{
  return this->Extents;
}

// ----------------------------------------------------------------------

int vtkBoostRandomSparseArraySource::RequestData(
  vtkInformation*,
  vtkInformationVector**,
  vtkInformationVector* outputVector)
{
  boost::mt19937 pattern_generator(static_cast<boost::uint32_t>(this->ElementProbabilitySeed));
  boost::bernoulli_distribution<> pattern_distribution(this->ElementProbability);
  boost::variate_generator<boost::mt19937&, boost::bernoulli_distribution<> > pattern(pattern_generator, pattern_distribution);

  boost::mt19937 value_generator(static_cast<boost::uint32_t>(this->ElementValueSeed));
  boost::uniform_real<> value_distribution(this->MinValue, this->MaxValue);
  boost::variate_generator<boost::mt19937&, boost::uniform_real<> > values(value_generator, value_distribution);

  vtkSparseArray<double>* const array = vtkSparseArray<double>::New();
  array->Resize(this->Extents);

  vtkSmartPointer<vtkArrayCoordinateIterator> iterator = vtkSmartPointer<vtkArrayCoordinateIterator>::New();
  iterator->SetExtents(this->Extents);
  while(iterator->HasNext())
    {
    vtkArrayCoordinates coordinates = iterator->Next();

    // Although it seems wasteful, we calculate a value for every element in the array
    // so the results stay consistent as the ElementProbability varies
    const double value = values();
    if(pattern())
      {
      array->AddValue(coordinates, value);
      }
    }

  vtkArrayData* const output = vtkArrayData::GetData(outputVector);
  output->SetArray(array);
  array->Delete();

  return 1;
}


/**
 * @file   TrajectoryAnalyzer.hpp
 * @author see AUTHORS
 * @brief  TrajectoryAnalyzer header file.
 */

#ifndef TRAJECTORYANALYZER_HPP
#define TRAJECTORYANALYZER_HPP

#include <memory>

#include <plog/Log.h>
#include <Eigen/Dense>

#include "Trajectory.hpp"
#include "ProteinSegment.hpp"
#include "ProteinSegmentEnsemble.hpp"

/*
* @class TrajectoryAnalyzer
*/
class TrajectoryAnalyzer {
public:
    /**
     * @param trajectory
     * @param protein_segments
     * @param temperature
     * @param ensemple_size
     */
    void analyze(Trajectory & trajectory,
                 std::vector<std::shared_ptr<ProteinSegment>> & protein_segments,
                 const double & temperature,
                 const int ensemble_size);

    /**
     * @param nma_covariance
     * @param protein_segments
     * @param temperature
     */
    void analyze(const Eigen::MatrixXd & nma_covariance,
                 std::vector<std::shared_ptr<ProteinSegment>> & protein_segments,
                 const double & temperature);

};

#endif

// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4


#include <ros/ros.h>
#include <geometry_msgs/Pose.h>
#include <geometry_msgs/PoseStamped.h>
#include "backtrack_behaviour/PreviousPosition.h"
#include <Eigen/Dense>

std::list<geometry_msgs::Pose> poses;

void callback(const geometry_msgs::Pose::ConstPtr& msg)
{
    if (poses.empty()) {
        poses.push_front(*msg);
        return;
    }
    // just add if it is far enough from the last position
    Eigen::Vector3d p1(msg->position.x, msg->position.y, msg->position.z);
    Eigen::Vector3d p2(poses.front().position.x, poses.front().position.y, poses.front().position.z);
    if ((p1 - p2).norm() < 0.1) {
        return;
    }
    poses.push_front(*msg);
    p2 = Eigen::Vector3d(poses.back().position.x, poses.back().position.y, poses.back().position.z);
    while (!poses.empty() && (p1 - p2).norm() > 2.0) {
        poses.pop_back();
        p2 = Eigen::Vector3d(poses.back().position.x, poses.back().position.y, poses.back().position.z);
    }
}

bool service_callback(backtrack_behaviour::PreviousPosition::Request& req,
                      backtrack_behaviour::PreviousPosition::Response& res)
{
    Eigen::Vector3d p1(poses.front().position.x, poses.front().position.y, poses.front().position.z);
    Eigen::Vector3d p2;
    for (std::list<geometry_msgs::Pose>::iterator i = poses.begin(); i != poses.end(); ++i) {
        p2 = Eigen::Vector3d(i->position.x, i->position.y, i->position.z);
        if ((p1 - p2).norm() > req.meters_back) {
            res.previous_pose.header.frame_id = "/map";
            res.previous_pose.pose = *i;
            return true;
        }
    }
    return false;
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "previous_positions_service");
	ros::NodeHandle n;
	ros::ServiceServer service = n.advertiseService("previous_position", &service_callback);
	ros::Subscriber sub = n.subscribe("/robot_pose", 1, &callback);

	//ros::spin();
	ros::Rate rate(10);
	while (n.ok()) {
	    rate.sleep();
	    ros::spinOnce();
	}

    return 0;
}


/* Copyright (c) 2017, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 *
 * All rights reserved.
 *
 * The Astrobee platform is licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

#include <ekf_bag/tracked_features.h>

#include <camera/camera_model.h>

#include <Eigen/Core>

namespace ekf_bag {

void TrackedOFFeatures::UpdateFeatures(const ff_msgs::Feature2dArray & of, float time) {
  std::map<int, ff_msgs::Feature2d > cur_features;
  for (unsigned int i = 0; i < of.feature_array.size(); i++) {
    cur_features.insert(std::pair<int, ff_msgs::Feature2d >(of.feature_array[i].id, of.feature_array[i]));
  }

  for (std::map<int, struct OFFeature>::iterator it = f_.begin(); it != f_.end(); it++) {
    int count = cur_features.count(it->first);
    if (count == 0) {
      it = f_.erase(it);
      it--;  // erase returns the next element, so we would skip it
    }
  }
  for (std::map<int, ff_msgs::Feature2d >::const_iterator it = cur_features.begin(); it != cur_features.end(); it++) {
    Eigen::Vector2d input(it->second.x, it->second.y);
    Eigen::Vector2d output;
    params_.Convert<camera::UNDISTORTED_C, camera::DISTORTED_C>(input, &output);
    struct OFFeature f = {it->second.id, time, static_cast<float>(output.x()), static_cast<float>(output.y())};
    auto t = f_.emplace(f.id, f);
    // if is already present
    t.first->second.x = output.x();
    t.first->second.y = output.y();
  }
}

void TrackedSMFeatures::UpdateFeatures(const ff_msgs::VisualLandmarks & vl, float time) {
  f_.clear();

  for (unsigned int i = 0; i < vl.landmarks.size(); i++) {
    auto & l = vl.landmarks[i];
    struct SMFeature f;
    f.pos.x() = l.x; f.pos.y() = l.y; f.pos.z() = l.z;
    Eigen::Vector2d input(l.u, l.v), output;
    params_.Convert<camera::UNDISTORTED_C, camera::DISTORTED_C>(input, &output);
    f.pixel.x() = output.x(); f.pixel.y() = output.y();
    f.time = time;
    f_.push_back(f);
  }
}

void TrackedSMFeatures::UpdatePose(const geometry_msgs::Pose & pose) {
  pose_transform_ = Eigen::Affine3d(
           Eigen::Translation3d(pose.position.x, pose.position.y, pose.position.z)) *
           Eigen::Affine3d(Eigen::Quaterniond(pose.orientation.w, pose.orientation.x,
                                              pose.orientation.y, pose.orientation.z));
}

Eigen::Vector2d TrackedSMFeatures::FeatureToCurrentPixel(const struct SMFeature & f) {
  Eigen::Vector3d rel = f.pos.cast<double>();
  camera::CameraModel c(body_to_camera_ * pose_transform_.inverse(), params_);
  Eigen::Vector2d output;
  params_.Convert<camera::UNDISTORTED_C, camera::DISTORTED_C>(c.ImageCoordinates(rel), &output);
  return output;
}

}  // namespace ekf_bag


/**
 * \ file GainColoredExpanderFilter.cpp
 */

#include <ATK/Dynamic/GainColoredExpanderFilter.h>

#include <ATK/Core/InPointerFilter.h>
#include <ATK/Core/OutPointerFilter.h>
#include <ATK/Core/Utilities.h>

#include <gtest/gtest.h>

#include <boost/math/constants/constants.hpp>

constexpr gsl::index PROCESSSIZE = 64;

TEST(GainColoredExpanderFilter, softness_test)
{
  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter;
  filter.set_softness(0.5);
  ASSERT_EQ(filter.get_softness(), 0.5);
}

TEST(GainColoredExpanderFilter, softness_range_test)
{
  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter;
  ASSERT_THROW(filter.set_softness(-0.000001), ATK::RuntimeError);
}

TEST(GainColoredExpanderFilter, color_test)
{
  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter;
  filter.set_color(0.5);
  ASSERT_EQ(filter.get_color(), 0.5);
}

TEST(GainColoredExpanderFilter, quality_test)
{
  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter;
  filter.set_quality(0.5);
  ASSERT_EQ(filter.get_quality(), 0.5);
}

TEST(GainColoredExpanderFilter, quality_range_test)
{
  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter;
  ASSERT_THROW(filter.set_quality(0), ATK::RuntimeError);
}

TEST(GainColoredExpanderFilter, const_1_test)
{
  std::array<double, PROCESSSIZE> data;
  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<double> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<double, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(10);

  ATK::OutPointerFilter<double> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    ASSERT_NEAR(1, outdata[i], 0.1);
  }
}

TEST(GainColoredExpanderFilter, const_0_test)
{
  std::array<double, PROCESSSIZE> data;
  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 0;
  }

  ATK::InPointerFilter<double> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<double, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);

  ATK::OutPointerFilter<double> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    ASSERT_NEAR(outdata[i], 0, 0.001);
  }
}

TEST(GainColoredExpanderFilter, const_1_threshold_2_ratio_2_test)
{
  std::array<double, PROCESSSIZE> data;
  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<double> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<double, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(2);
  filter.set_ratio(2);
  filter.set_softness(1);

  ATK::OutPointerFilter<double> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    ASSERT_NEAR(0.700553358, outdata[i], 0.1);
  }
}

TEST(GainColoredExpanderFilter, const_1_threshold_2_ratio_4_test)
{
  std::array<double, PROCESSSIZE> data;
  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = 1;
  }

  ATK::InPointerFilter<double> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<double, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(2);
  filter.set_ratio(4);
  filter.set_softness(1);

  ATK::OutPointerFilter<double> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    ASSERT_NEAR(0.343814075, outdata[i], 0.1);
  }
}

TEST(GainColoredExpanderFilter, always_more_1_test)
{
  std::array<double, PROCESSSIZE> data;
  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = i/1024.;
  }

  ATK::InPointerFilter<double> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<double, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(1);
  filter.set_quality(.1);
  filter.set_color(.1);

  ATK::OutPointerFilter<double> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(gsl::index i = 1; i < PROCESSSIZE; ++i)
  {
    ASSERT_GE(outdata[i], 1 - 10 * std::numeric_limits<float>::epsilon());
  }
}

TEST(GainColoredExpanderFilter, always_less_1_test)
{
  std::array<double, PROCESSSIZE> data;
  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    data[i] = i/1024.;
  }

  ATK::InPointerFilter<double> generator(data.data(), 1, PROCESSSIZE, false);
  generator.set_output_sampling_rate(48000);

  std::array<double, PROCESSSIZE> outdata;

  ATK::GainFilter<ATK::GainColoredExpanderFilter<double>> filter(1);
  filter.set_input_sampling_rate(48000);
  filter.set_input_port(0, &generator, 0);
  filter.set_threshold(1);
  filter.set_quality(.1);
  filter.set_color(-.1);

  ATK::OutPointerFilter<double> output(outdata.data(), 1, PROCESSSIZE, false);
  output.set_input_sampling_rate(48000);
  output.set_input_port(0, &filter, 0);

  output.process(PROCESSSIZE);

  for(gsl::index i = 0; i < PROCESSSIZE; ++i)
  {
    ASSERT_LE(outdata[i], 1 + 10 * std::numeric_limits<float>::epsilon());
  }
}


//=============================================================================
//
//  CLASS NewtonSolver
//
//=============================================================================

#ifndef COMISO_NEWTONSOLVER_HH
#define COMISO_NEWTONSOLVER_HH

//== COMPILE-TIME PACKAGE REQUIREMENTS ========================================
#include <CoMISo/Config/config.hh>

//== INCLUDES =================================================================

#include <CoMISo/Config/CoMISoDefines.hh>
#include <CoMISo/Utils/StopWatch.hh>
#include "NProblemInterface.hh"
#include "NProblemGmmInterface.hh"

//#include <Base/Debug/DebTime.hh>

#if COMISO_SUITESPARSE_AVAILABLE
  #include <Eigen/UmfPackSupport>
  #include <Eigen/CholmodSupport>
#endif

// ToDo: why is Metis not working yet?
//#if COMISO_METIS_AVAILABLE
//  #include <Eigen/MetisSupport>
//#endif

//== FORWARDDECLARATIONS ======================================================

//== NAMESPACES ===============================================================

namespace COMISO {

//== CLASS DEFINITION =========================================================

/** \class NewtonSolver NewtonSolver.hh <ACG/.../NewtonSolver.hh>

    Brief Description.

    A more elaborate description follows.
*/
class COMISODLLEXPORT NewtonSolver
{
public:

  enum LinearSolver {LS_EigenLU, LS_Umfpack, LS_MUMPS};

  typedef Eigen::VectorXd             VectorD;
  typedef Eigen::SparseMatrix<double> SMatrixD;
  typedef Eigen::Triplet<double>      Triplet;

  /// Default constructor
  NewtonSolver(const double _eps = 1e-6, const double _eps_line_search = 1e-9, const int _max_iters = 200, const double _alpha_ls=0.2, const double _beta_ls = 0.6)
    : eps_(_eps), eps_ls_(_eps_line_search), max_iters_(_max_iters), alpha_ls_(_alpha_ls), beta_ls_(_beta_ls), solver_type_(LS_EigenLU), constant_hessian_structure_(false)
  {
//#if COMISO_SUITESPARSE_AVAILABLE
//    solver_type_ = LS_Umfpack;
//#endif
  }

  // solve without linear constraints
  int solve(NProblemInterface* _problem)
  {
    SMatrixD A(0,_problem->n_unknowns());
    VectorD b(VectorD::Index(0));
    return solve(_problem, A, b);
  }

  // solve with linear constraints
  // Warning: so far only feasible starting points with (_A*_problem->initial_x() == b) are supported!
  // Extension to infeasible starting points is planned
  int solve(NProblemInterface* _problem, const SMatrixD& _A, const VectorD& _b);

  // select internal linear solver
  void set_linearsolver(LinearSolver _st)
  {
    solver_type_ = _st;
  }

protected:

  bool factorize(NProblemInterface* _problem, const SMatrixD& _A,
    const VectorD& _b, const VectorD& _x, double& _regularize_hessian,
    double& _regularize_constraints, const bool _first_factorization);

  double backtracking_line_search(NProblemInterface* _problem, VectorD& _x,
    VectorD& _g, VectorD& _dx, double& _newton_decrement, double& _fx,
    const double _t_start = 1.0);

  void analyze_pattern(SMatrixD& _KKT);

  bool numerical_factorization(SMatrixD& _KKT);

  void solve_kkt_system(const VectorD& _rhs, VectorD& _dx);

  // deprecated function!
  // solve
  int solve(NProblemGmmInterface* _problem);

  // deprecated function!
  // solve specifying parameters
  int solve(NProblemGmmInterface* _problem, int _max_iter, double _eps)
  {
    max_iters_ = _max_iter;
    eps_ = _eps;
    return solve(_problem);
  }

  // deprecated function!
  bool& constant_hessian_structure() { return constant_hessian_structure_; }

protected:
  double* P(std::vector<double>& _v)
  {
    if( !_v.empty())
      return ((double*)&_v[0]);
    else
      return 0;
  }

private:

  double eps_;
  double eps_ls_;
  int    max_iters_;
  double alpha_ls_;
  double beta_ls_;

  VectorD x_ls_;

  LinearSolver solver_type_;

  // cache KKT Matrix
  SMatrixD KKT_;

  // Sparse LU decomposition
  Eigen::SparseLU<SMatrixD> lu_solver_;

#if COMISO_SUITESPARSE_AVAILABLE
  Eigen::UmfPackLU<SMatrixD> umfpack_solver_;
#endif

  // deprecated
  bool   constant_hessian_structure_;
};

//=============================================================================
} // namespace COMISO
//=============================================================================
#endif // ACG_NEWTONSOLVER_HH defined
//=============================================================================


// This file is part of LatNet Builder.
//
// Copyright (C) 2012-2021  The LatNet Builder author's, supervised by Pierre L'Ecuyer, Universite de Montreal.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "netbuilder/NetConstructionTraits.h"

#include "latbuilder/SeqCombiner.h"
#include "latbuilder/Traversal.h"

#include <boost/dynamic_bitset.hpp>
#include <vector>
#include <list>

#include "latbuilder/TextStream.h"

namespace NetBuilder {

    const std::string NetConstructionTraits<NetConstruction::SOBOL>::name = "Sobol";

    typedef typename NetConstructionTraits<NetConstruction::SOBOL>::GenValue GenValue;

    typedef typename NetConstructionTraits<NetConstruction::SOBOL>::SizeParameter SizeParameter;

    bool NetConstructionTraits<NetConstruction::SOBOL>::checkGenValue(const GenValue& genValue, const SizeParameter& sizeParameter)
    {
        auto dimension = genValue.first;

        if (dimension==0)
        {
            return (genValue.second.size()==1 && genValue.second.front()==0);
        }

        unsigned int degree = nthPrimitivePolynomialDegree(dimension);

        if (genValue.second.size() != degree){
            return false;
        }

        for(unsigned int j = 0; j < degree; ++j)
        {
              if (!(genValue.second[j] % 2 == 1)){ //each direction number is odd
                  return false;
              }
              if (!(genValue.second[j]< (unsigned int) (2<<j))){ // each direction number is small enough
                  return false;
              }
        }
        return true;
    }

    unsigned int NetConstructionTraits<NetConstruction::SOBOL>::nRows(const SizeParameter& param) { return (unsigned int) param; }

    unsigned int NetConstructionTraits<NetConstruction::SOBOL>::nCols(const SizeParameter& param) { return (unsigned int) param; }

    static const std::array<unsigned int,21200> degrees =
    {{
        #include "../data/primitive_polynomials_degrees.csv"
    }};

    static const std::array<unsigned long,21200> representations =
    {{
        #include "../data/primitive_polynomials_representations.csv"
    }};

    NetConstructionTraits<NetConstruction::SOBOL>::PrimitivePolynomial  NetConstructionTraits<NetConstruction::SOBOL>::nthPrimitivePolynomial(Dimension n)
    {
        // primitive polynomials are hard-coded because their computation is really complex.
        if (n>0 && n <= 21200)
        return std::pair<unsigned int,uInteger>(degrees[n-1],representations[n-1]);
        else{
            return std::pair<unsigned int,uInteger>(0,0);
        }
    }

    unsigned int  NetConstructionTraits<NetConstruction::SOBOL>::nthPrimitivePolynomialDegree(Dimension n)
    {
        // primitive polynomials are hard-coded because their computation is really complex.
        if (n>0 && n <= 21200)
        return degrees[n-1];
        else{
            return 0;
        }
    }

    void makeIteration(GeneratingMatrix& mat, std::list<boost::dynamic_bitset<>>& reg, const boost::dynamic_bitset<>& mask, unsigned int k)
    {
        assert(k <= mat.nCols() && k<= mat.nRows());
        boost::dynamic_bitset<> newDirNum = reg.front();
        newDirNum.resize(k);
        assert(reg.size()==mask.size());
        unsigned j = 0;
        for(boost::dynamic_bitset<> tmp : reg)
        {
            if (mask[j])
            {
                tmp.resize(k);
                tmp = tmp << (reg.size()-j);
                newDirNum ^= tmp;
            }
            ++j;
        }
        reg.pop_front();
        for(unsigned int i = 0; i < k; ++i)
        {
            mat(i, k-1) = newDirNum[k-i-1];
        }
        reg.push_back(std::move(newDirNum));
    }

    GeneratingMatrix*  NetConstructionTraits<NetConstruction::SOBOL>::createGeneratingMatrix(const GenValue& genValue, const SizeParameter& sizeParam, const Dimension& dimension_j, const unsigned int nRows)
    {
        unsigned int m  = nCols(sizeParam);
        unsigned int finalnRows = (nRows == 0)? m : nRows;
        Dimension coord = genValue.first;

        if (coord==0) // special case for the first dimension
        {
            GeneratingMatrix* tmp = new GeneratingMatrix(m,m);
            for(unsigned int k = 0; k<m; ++k){
            (*tmp)(k,k) = 1; // start with identity
            }
            return tmp;
        }

        // compute the vector defining the linear recurrence on the columns of the matrix
        PrimitivePolynomial p = nthPrimitivePolynomial(coord);
        auto degree = p.first;
        auto poly_rep = p.second;
        boost::dynamic_bitset<> mask(degree,(poly_rep << 1) + 1);
        unsigned int matrixSize = std::max(degree,m);
        GeneratingMatrix* tmp = new GeneratingMatrix(matrixSize, matrixSize);
        std::list<boost::dynamic_bitset<>> reg;
        unsigned int k = 1;
        for(auto dirNum : genValue.second)
        {
            reg.push_back(boost::dynamic_bitset<>(k,dirNum));
            for(unsigned int i = 0; i < k; ++i)
            {
                (*tmp)(i,k-1) = reg.back()[k-i-1];
            }
            ++k;
        }
        while (k<=matrixSize)
        {
            makeIteration(*tmp, reg, mask, k);
            ++k;
        }
        tmp->resize(finalnRows, m);
        return tmp;
    }

   NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::GenValueSpaceCoordSeq(Dimension coord):
    m_coord(coord),
    m_underlyingSeq(underlyingSeqs(coord))
    {};

    NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator::const_iterator(const GenValueSpaceCoordSeq& seq):
        m_coord(seq.coord()),
        m_underlyingIterator(seq.underlyingSeq().begin()),
        m_value(GenValue(m_coord, *m_underlyingIterator))
    {};

    NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator::const_iterator(const GenValueSpaceCoordSeq& seq, end_tag):
        m_coord(seq.coord()),
        m_underlyingIterator(seq.underlyingSeq().end())
    {};

    bool NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator::equal(const const_iterator& other) const
    {
        return m_underlyingIterator == other.m_underlyingIterator;
    }

    const NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator::value_type& NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator::dereference() const
    {
        return m_value;
    }

    void NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator::increment()
    {
        if (m_underlyingIterator != m_underlyingIterator.seq().end())
        {
            ++m_underlyingIterator;
            m_value = GenValue(m_coord, *m_underlyingIterator);
        }
    }

    NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::begin() const
    {
        return const_iterator(*this);
    }

    NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::const_iterator NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::end() const
    {
        return const_iterator(*this, typename const_iterator::end_tag{} );
    }

    Dimension NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::coord() const
    {
        return m_coord;
    }

    size_t  NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::size() const
    {
        return m_underlyingSeq.size();
    }

    const LatBuilder::SeqCombiner<std::vector<uInteger>,LatBuilder::CartesianProduct>& NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::underlyingSeq() const
    {
        return m_underlyingSeq;
    }

    std::vector<std::vector<uInteger>> NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq::underlyingSeqs(Dimension coord)
    {
        if (coord == 0)
        {
            return {{0}};
        }
        else
        {
            unsigned int size = nthPrimitivePolynomialDegree(coord);
            std::vector<uInteger> dirNums{1};
            dirNums.reserve( (1 << (size - 1))  - 1);

            std::vector<std::vector<uInteger>> seqs;
            seqs.reserve(size);
            seqs.push_back(dirNums);

            uInteger upperBound = 2;
            for(unsigned int i = 1; i < size; ++i)
            {
                upperBound = 2 * upperBound;
                for(uInteger k = dirNums.back() + 2; k < upperBound; k += 2)
                {
                    dirNums.push_back(k);
                }
                seqs.push_back(dirNums);
            }
            return seqs;
        }
    }

    typename NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceCoordSeq NetConstructionTraits<NetConstruction::SOBOL>::genValueSpaceCoord(Dimension coord, const SizeParameter& sizeParameter)
    {
        return GenValueSpaceCoordSeq(coord);
    }

    typename NetConstructionTraits<NetConstruction::SOBOL>::GenValueSpaceSeq NetConstructionTraits<NetConstruction::SOBOL>::genValueSpace(Dimension dimension, const SizeParameter& sizeParameter)
    {
        std::vector<GenValueSpaceCoordSeq> seqs;
        seqs.reserve(dimension);
        for(Dimension coord = 0; coord < dimension; ++coord)
        {
            seqs.push_back(genValueSpaceCoord(coord, sizeParameter));
        }
        return GenValueSpaceSeq(seqs);
    }

    std::string NetConstructionTraits<NetConstruction::SOBOL>::format(const std::vector<std::shared_ptr<GeneratingMatrix>>& genMatrices, const std::vector<std::shared_ptr<GenValue>>& genVals, const SizeParameter& sizeParameter, OutputStyle outputStyle, unsigned int interlacingFactor)
    {
        std::string res;
        std::string dimension = std::to_string(genVals.size()/interlacingFactor);
        unsigned int k = nCols(sizeParameter);

        if (outputStyle == OutputStyle::TERMINAL){
            res += "Sobol Digital Net - Direction numbers =\n";
            for (unsigned int coord = 0; coord < genVals.size(); coord++){
                res+="  ";
                for(const auto& dirNum : genVals[coord]->second)
                {
                    res+= std::to_string(dirNum);
                    res+= " ";
                }
                res.pop_back();
                res+="\n";
            }
        }

        else if (outputStyle == OutputStyle::SOBOLJK){
            res += "# Parameters for Sobol points, in JK format\n";
            res += dimension + "    # s = " + dimension + " dimensions\n";
            if (interlacingFactor > 1){
                res+= std::to_string(interlacingFactor) + "    # Interlacing factor" + "\n";
                res+= std::to_string(genVals.size()) + "    # Number of components = interlacing factor x dimension" + "\n";
            }
            res += std::to_string(k) + "    # k = " + std::to_string(k) + ",  n = 2^"+ std::to_string(k) + " = " + std::to_string((int)pow(2, k)) + " points\n";
            res +="#  d  a  m_{j,c}\n";
            for (unsigned int coord = 1; coord < genVals.size(); coord++){
                res+= std::to_string(coord +1) + "  ";
                PrimitivePolynomial p = nthPrimitivePolynomial(coord);
                auto degree = p.first;
                auto poly_rep = p.second;
                res+= std::to_string(degree) + "  ";
                res+= std::to_string(poly_rep) + "  ";
                for(const auto& dirNum : genVals[coord]->second)
                {
                    res+= std::to_string(dirNum);
                    res+= " ";
                }
                res.pop_back();
                res+="\n";

            }
            res.pop_back();
        }

        else if (outputStyle == OutputStyle::SOBOL){
            res += "# Initial direction numbers m_{j,c} for Sobol points\n";
            res += dimension + "    # s = " + dimension + " dimensions\n";
            if (interlacingFactor > 1){
                res+= std::to_string(interlacingFactor) + "    # Interlacing factor" + "\n";
                res+= std::to_string(genVals.size()) + "    # Number of components = interlacing factor x dimension" + "\n";
            }
            res += std::to_string(k) + "    # k = " + std::to_string(k) + ",  n = 2^"+ std::to_string(k) + " = " + std::to_string((int)pow(2, k)) + " points\n";
            res +="# m_{j,c}, starting from the second coordinate\n";
            for (unsigned int coord = 1; coord < genVals.size(); coord++){
                for(const auto& dirNum : genVals[coord]->second)
                {
                    res += std::to_string(dirNum);
                    res += " ";
                }
                res.pop_back();
                res+="\n";

            }
            res.pop_back();
        }
        return res;
    }
}


/*!
 * @file
 * Contains unit tests for the @ref Group typeclass.
 */

#include <boost/mpl11/group.hpp>

#include <boost/mpl11/core.hpp>
#include <boost/mpl11/integer.hpp>

#include "test_method_dispatch.hpp"

using namespace boost::mpl11;

///////////////////////////
// Test method dispatching
///////////////////////////
namespace boost { namespace mpl11 {
    template <>
    struct Group<Archetype<0>> : instantiate<Group>::with<Archetype<0>> {
        template <typename, typename> using minus_impl  = method_tag<minus>;
        template <typename>           using negate_impl = method_tag<negate>;
    };
}}

struct test_dispatching
    : method<minus, archetype<0>, archetype<0>>
    // , method<minus, archetype<0>, archetype<1>>
    // , method<minus, archetype<1>, archetype<0>>

    , method<negate, archetype<0>>
{ };

////////////////////////////////
// Test default implementations
////////////////////////////////
using Default = instantiate<Group>::with<Integer>;
static_assert(Default::minus_impl<int_<10>, int_<3>>::value == 10 - 3, "");
static_assert(Default::negate_impl<int_<10>>::value == -10, "");

int main() { }