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

#include <cmath>
#include <tuple>

typedef std::tuple<float, double, long double> test_types;

#include <triumf/constants/codata_2002.hpp>

// Wien displacement law constant
// (0.0028977685 ± 5.1e-09) m K
BOOST_AUTO_TEST_CASE_TEMPLATE(Wien_displacement_law_constant, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::Wien_displacement_law_constant<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::Wien_displacement_law_constant<
                 T>::value() == static_cast<T>(0.0028977685));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::Wien_displacement_law_constant<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::Wien_displacement_law_constant<
                 T>::uncertainty() == static_cast<T>(5.1e-09));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::Wien_displacement_law_constant<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::Wien_displacement_law_constant<
          T>::precision()));
}

// atomic unit of 1st hyperpolarizablity
// (3.20636151e-53 ± 2.8e-60) C^3 m^3 J^-2
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_1st_hyperpolarizablity, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_1st_hyperpolarizablity<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_1st_hyperpolarizablity<
          T>::value() == static_cast<T>(3.20636151e-53));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_1st_hyperpolarizablity<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_1st_hyperpolarizablity<
          T>::uncertainty() == static_cast<T>(2.8e-60));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_1st_hyperpolarizablity<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_1st_hyperpolarizablity<
          T>::precision()));
}

// atomic unit of 2nd hyperpolarizablity
// (6.2353808e-65 ± 1.1e-71) C^4 m^4 J^-3
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_2nd_hyperpolarizablity, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_2nd_hyperpolarizablity<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_2nd_hyperpolarizablity<
          T>::value() == static_cast<T>(6.2353808e-65));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_2nd_hyperpolarizablity<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_2nd_hyperpolarizablity<
          T>::uncertainty() == static_cast<T>(1.1e-71));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_2nd_hyperpolarizablity<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_2nd_hyperpolarizablity<
          T>::precision()));
}

// atomic unit of electric dipole moment
// (8.47835309e-30 ± 7.3e-37) C m
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_electric_dipole_moment, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_dipole_moment<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_electric_dipole_moment<
          T>::value() == static_cast<T>(8.47835309e-30));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_dipole_moment<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_electric_dipole_moment<
          T>::uncertainty() == static_cast<T>(7.3e-37));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_dipole_moment<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_electric_dipole_moment<
          T>::precision()));
}

// atomic unit of electric polarizablity
// (1.648777274e-41 ± 1.6e-49) C^2 m^2 J^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_electric_polarizablity, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_polarizablity<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_electric_polarizablity<
          T>::value() == static_cast<T>(1.648777274e-41));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_polarizablity<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_electric_polarizablity<
          T>::uncertainty() == static_cast<T>(1.6e-49));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_polarizablity<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_electric_polarizablity<
          T>::precision()));
}

// atomic unit of electric quadrupole moment
// (4.48655124e-40 ± 3.9e-47) C m^2
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_electric_quadrupole_moment, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_quadrupole_moment<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_electric_quadrupole_moment<
          T>::value() == static_cast<T>(4.48655124e-40));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_quadrupole_moment<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::atomic_unit_of_electric_quadrupole_moment<
          T>::uncertainty() == static_cast<T>(3.9e-47));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_electric_quadrupole_moment<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_electric_quadrupole_moment<
          T>::precision()));
}

// atomic unit of magn. dipole moment
// (1.8548019e-23 ± 1.6e-30) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_magn_dipole_moment, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_magn_dipole_moment<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::atomic_unit_of_magn_dipole_moment<
                 T>::value() == static_cast<T>(1.8548019e-23));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_magn_dipole_moment<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::atomic_unit_of_magn_dipole_moment<
                 T>::uncertainty() == static_cast<T>(1.6e-30));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_magn_dipole_moment<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_magn_dipole_moment<
          T>::precision()));
}

// atomic unit of magn. flux density
// (235051.742 ± 0.02) T
BOOST_AUTO_TEST_CASE_TEMPLATE(atomic_unit_of_magn_flux_density, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_magn_flux_density<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::atomic_unit_of_magn_flux_density<
                 T>::value() == static_cast<T>(235051.742));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_magn_flux_density<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::atomic_unit_of_magn_flux_density<
                 T>::uncertainty() == static_cast<T>(0.02));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::atomic_unit_of_magn_flux_density<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::atomic_unit_of_magn_flux_density<
          T>::precision()));
}

// deuteron magn. moment
// (4.33073482e-27 ± 3.8e-34) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(deuteron_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_magn_moment<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::deuteron_magn_moment<T>::value() ==
             static_cast<T>(4.33073482e-27));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_magn_moment<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::deuteron_magn_moment<T>::uncertainty() ==
      static_cast<T>(3.8e-34));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_magn_moment<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::deuteron_magn_moment<T>::precision()));
}

// deuteron magn. moment to Bohr magneton ratio
// (0.0004669754567 ± 5e-12)
BOOST_AUTO_TEST_CASE_TEMPLATE(deuteron_magn_moment_to_Bohr_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_Bohr_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 deuteron_magn_moment_to_Bohr_magneton_ratio<T>::value() ==
             static_cast<T>(0.0004669754567));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_Bohr_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_Bohr_magneton_ratio<T>::uncertainty() ==
      static_cast<T>(5e-12));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
}

// deuteron magn. moment to nuclear magneton ratio
// (0.8574382329 ± 9.2e-09)
BOOST_AUTO_TEST_CASE_TEMPLATE(deuteron_magn_moment_to_nuclear_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 deuteron_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
             static_cast<T>(0.8574382329));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty() ==
      static_cast<T>(9.2e-09));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          deuteron_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
}

// deuteron-electron magn. moment ratio
// (-0.0004664345548 ± 5e-12)
BOOST_AUTO_TEST_CASE_TEMPLATE(deuteron_electron_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_electron_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::deuteron_electron_magn_moment_ratio<
          T>::value() == static_cast<T>(-0.0004664345548));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_electron_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::deuteron_electron_magn_moment_ratio<
          T>::uncertainty() == static_cast<T>(5e-12));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_electron_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::deuteron_electron_magn_moment_ratio<
          T>::precision()));
}

// deuteron-proton magn. moment ratio
// (0.3070122084 ± 4.5e-09)
BOOST_AUTO_TEST_CASE_TEMPLATE(deuteron_proton_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_proton_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::deuteron_proton_magn_moment_ratio<
                 T>::value() == static_cast<T>(0.3070122084));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_proton_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::deuteron_proton_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(4.5e-09));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_proton_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::deuteron_proton_magn_moment_ratio<
          T>::precision()));
}

// deuteron-neutron magn. moment ratio
// (-0.44820652 ± 1.1e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(deuteron_neutron_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_neutron_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::deuteron_neutron_magn_moment_ratio<
                 T>::value() == static_cast<T>(-0.44820652));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_neutron_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::deuteron_neutron_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(1.1e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::deuteron_neutron_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::deuteron_neutron_magn_moment_ratio<
          T>::precision()));
}

// electron gyromagn. ratio
// (176085974000.0 ± 15000.0) s^-1 T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_gyromagn_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_gyromagn_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::electron_gyromagn_ratio<T>::value() ==
      static_cast<T>(176085974000.0));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::electron_gyromagn_ratio<
                    T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::electron_gyromagn_ratio<
                 T>::uncertainty() == static_cast<T>(15000.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_gyromagn_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_gyromagn_ratio<T>::precision()));
}

// electron gyromagn. ratio over 2 pi
// (28024.9532 ± 0.0024) MHz T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_gyromagn_ratio_over_2_pi, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_gyromagn_ratio_over_2_pi<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::electron_gyromagn_ratio_over_2_pi<
                 T>::value() == static_cast<T>(28024.9532));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_gyromagn_ratio_over_2_pi<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::electron_gyromagn_ratio_over_2_pi<
                 T>::uncertainty() == static_cast<T>(0.0024));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_gyromagn_ratio_over_2_pi<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_gyromagn_ratio_over_2_pi<
          T>::precision()));
}

// electron magn. moment
// (-9.28476412e-24 ± 8e-31) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_magn_moment<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::electron_magn_moment<T>::value() ==
             static_cast<T>(-9.28476412e-24));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_magn_moment<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::electron_magn_moment<T>::uncertainty() ==
      static_cast<T>(8e-31));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_magn_moment<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_magn_moment<T>::precision()));
}

// electron magn. moment to Bohr magneton ratio
// (-1.0011596521859 ± 3.8e-12)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_magn_moment_to_Bohr_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_magn_moment_to_Bohr_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 electron_magn_moment_to_Bohr_magneton_ratio<T>::value() ==
             static_cast<T>(-1.0011596521859));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_magn_moment_to_Bohr_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          electron_magn_moment_to_Bohr_magneton_ratio<T>::uncertainty() ==
      static_cast<T>(3.8e-12));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          electron_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
}

// electron magn. moment to nuclear magneton ratio
// (-1838.28197107 ± 8.5e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_magn_moment_to_nuclear_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 electron_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
             static_cast<T>(-1838.28197107));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          electron_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty() ==
      static_cast<T>(8.5e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          electron_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
}

// electron magn. moment anomaly
// (0.0011596521859 ± 3.8e-12)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_magn_moment_anomaly, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_magn_moment_anomaly<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::electron_magn_moment_anomaly<
                 T>::value() == static_cast<T>(0.0011596521859));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_magn_moment_anomaly<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::electron_magn_moment_anomaly<
                 T>::uncertainty() == static_cast<T>(3.8e-12));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_magn_moment_anomaly<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_magn_moment_anomaly<
          T>::precision()));
}

// electron to shielded proton magn. moment ratio
// (-658.2275956 ± 7.1e-06)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_to_shielded_proton_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_to_shielded_proton_magn_moment_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 electron_to_shielded_proton_magn_moment_ratio<T>::value() ==
             static_cast<T>(-658.2275956));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_to_shielded_proton_magn_moment_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          electron_to_shielded_proton_magn_moment_ratio<T>::uncertainty() ==
      static_cast<T>(7.1e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_to_shielded_proton_magn_moment_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          electron_to_shielded_proton_magn_moment_ratio<T>::precision()));
}

// electron to shielded helion magn. moment ratio
// (864.058255 ± 1e-05)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_to_shielded_helion_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_to_shielded_helion_magn_moment_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 electron_to_shielded_helion_magn_moment_ratio<T>::value() ==
             static_cast<T>(864.058255));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_to_shielded_helion_magn_moment_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          electron_to_shielded_helion_magn_moment_ratio<T>::uncertainty() ==
      static_cast<T>(1e-05));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          electron_to_shielded_helion_magn_moment_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          electron_to_shielded_helion_magn_moment_ratio<T>::precision()));
}

// electron-deuteron magn. moment ratio
// (-2143.923493 ± 2.3e-05)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_deuteron_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_deuteron_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::electron_deuteron_magn_moment_ratio<
          T>::value() == static_cast<T>(-2143.923493));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_deuteron_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::electron_deuteron_magn_moment_ratio<
          T>::uncertainty() == static_cast<T>(2.3e-05));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_deuteron_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_deuteron_magn_moment_ratio<
          T>::precision()));
}

// electron-muon magn. moment ratio
// (206.7669894 ± 5.4e-06)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_muon_magn_moment_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_muon_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::electron_muon_magn_moment_ratio<
                 T>::value() == static_cast<T>(206.7669894));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_muon_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::electron_muon_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(5.4e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_muon_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_muon_magn_moment_ratio<
          T>::precision()));
}

// electron-neutron magn. moment ratio
// (960.9205 ± 0.00023)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_neutron_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_neutron_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::electron_neutron_magn_moment_ratio<
                 T>::value() == static_cast<T>(960.9205));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_neutron_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::electron_neutron_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(0.00023));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_neutron_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_neutron_magn_moment_ratio<
          T>::precision()));
}

// electron-proton magn. moment ratio
// (-658.2106862 ± 6.6e-06)
BOOST_AUTO_TEST_CASE_TEMPLATE(electron_proton_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_proton_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::electron_proton_magn_moment_ratio<
                 T>::value() == static_cast<T>(-658.2106862));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_proton_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::electron_proton_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(6.6e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::electron_proton_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::electron_proton_magn_moment_ratio<
          T>::precision()));
}

// magn. constant
// (1.2566370614e-06 ± 0.0) N A^-2
BOOST_AUTO_TEST_CASE_TEMPLATE(magn_constant, T, test_types) {
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::magn_constant<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::magn_constant<T>::value() ==
             static_cast<T>(1.2566370614e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::magn_constant<T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::magn_constant<T>::uncertainty() ==
             static_cast<T>(0.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::magn_constant<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::magn_constant<T>::precision()));
}

// magn. flux quantum
// (2.06783372e-15 ± 1.8e-22) Wb
BOOST_AUTO_TEST_CASE_TEMPLATE(magn_flux_quantum, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::magn_flux_quantum<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::magn_flux_quantum<T>::value() ==
             static_cast<T>(2.06783372e-15));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::magn_flux_quantum<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::magn_flux_quantum<T>::uncertainty() ==
      static_cast<T>(1.8e-22));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::magn_flux_quantum<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::magn_flux_quantum<T>::precision()));
}

// muon magn. moment
// (-4.49044799e-26 ± 4e-33) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(muon_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_magn_moment<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::muon_magn_moment<T>::value() ==
             static_cast<T>(-4.49044799e-26));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_magn_moment<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::muon_magn_moment<T>::uncertainty() ==
      static_cast<T>(4e-33));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_magn_moment<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::muon_magn_moment<T>::precision()));
}

// muon magn. moment to Bohr magneton ratio
// (-0.00484197045 ± 1.3e-10)
BOOST_AUTO_TEST_CASE_TEMPLATE(muon_magn_moment_to_Bohr_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_magn_moment_to_Bohr_magneton_ratio<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::muon_magn_moment_to_Bohr_magneton_ratio<
          T>::value() == static_cast<T>(-0.00484197045));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_magn_moment_to_Bohr_magneton_ratio<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::muon_magn_moment_to_Bohr_magneton_ratio<
          T>::uncertainty() == static_cast<T>(1.3e-10));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_magn_moment_to_Bohr_magneton_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::muon_magn_moment_to_Bohr_magneton_ratio<
          T>::precision()));
}

// muon magn. moment to nuclear magneton ratio
// (-8.89059698 ± 2.3e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(muon_magn_moment_to_nuclear_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          muon_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 muon_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
             static_cast<T>(-8.89059698));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          muon_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 muon_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty() ==
             static_cast<T>(2.3e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          muon_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          muon_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
}

// muon-proton magn. moment ratio
// (-3.183345118 ± 8.9e-08)
BOOST_AUTO_TEST_CASE_TEMPLATE(muon_proton_magn_moment_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_proton_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::muon_proton_magn_moment_ratio<
                 T>::value() == static_cast<T>(-3.183345118));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_proton_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::muon_proton_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(8.9e-08));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::muon_proton_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::muon_proton_magn_moment_ratio<
          T>::precision()));
}

// neutron gyromagn. ratio
// (183247183.0 ± 46.0) s^-1 T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_gyromagn_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_gyromagn_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::neutron_gyromagn_ratio<T>::value() ==
      static_cast<T>(183247183.0));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::neutron_gyromagn_ratio<
                    T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_gyromagn_ratio<
                 T>::uncertainty() == static_cast<T>(46.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_gyromagn_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::neutron_gyromagn_ratio<T>::precision()));
}

// neutron gyromagn. ratio over 2 pi
// (29.164695 ± 7.3e-06) MHz T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_gyromagn_ratio_over_2_pi, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_gyromagn_ratio_over_2_pi<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_gyromagn_ratio_over_2_pi<
                 T>::value() == static_cast<T>(29.164695));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_gyromagn_ratio_over_2_pi<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_gyromagn_ratio_over_2_pi<
                 T>::uncertainty() == static_cast<T>(7.3e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_gyromagn_ratio_over_2_pi<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::neutron_gyromagn_ratio_over_2_pi<
          T>::precision()));
}

// neutron magn. moment
// (-9.6623645e-27 ± 2.4e-33) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_magn_moment<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_magn_moment<T>::value() ==
             static_cast<T>(-9.6623645e-27));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_magn_moment<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::neutron_magn_moment<T>::uncertainty() ==
      static_cast<T>(2.4e-33));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_magn_moment<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::neutron_magn_moment<T>::precision()));
}

// neutron magn. moment to Bohr magneton ratio
// (-0.00104187563 ± 2.5e-10)
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_magn_moment_to_Bohr_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_Bohr_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 neutron_magn_moment_to_Bohr_magneton_ratio<T>::value() ==
             static_cast<T>(-0.00104187563));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_Bohr_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 neutron_magn_moment_to_Bohr_magneton_ratio<T>::uncertainty() ==
             static_cast<T>(2.5e-10));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
}

// neutron magn. moment to nuclear magneton ratio
// (-1.91304273 ± 4.5e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_magn_moment_to_nuclear_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 neutron_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
             static_cast<T>(-1.91304273));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty() ==
      static_cast<T>(4.5e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          neutron_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
}

// neutron to shielded proton magn. moment ratio
// (-0.68499694 ± 1.6e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_to_shielded_proton_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_to_shielded_proton_magn_moment_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 neutron_to_shielded_proton_magn_moment_ratio<T>::value() ==
             static_cast<T>(-0.68499694));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_to_shielded_proton_magn_moment_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          neutron_to_shielded_proton_magn_moment_ratio<T>::uncertainty() ==
      static_cast<T>(1.6e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          neutron_to_shielded_proton_magn_moment_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          neutron_to_shielded_proton_magn_moment_ratio<T>::precision()));
}

// neutron-electron magn. moment ratio
// (0.00104066882 ± 2.5e-10)
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_electron_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_electron_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_electron_magn_moment_ratio<
                 T>::value() == static_cast<T>(0.00104066882));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_electron_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_electron_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(2.5e-10));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_electron_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::neutron_electron_magn_moment_ratio<
          T>::precision()));
}

// neutron-proton magn. moment ratio
// (-0.68497934 ± 1.6e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(neutron_proton_magn_moment_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_proton_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_proton_magn_moment_ratio<
                 T>::value() == static_cast<T>(-0.68497934));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_proton_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::neutron_proton_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(1.6e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::neutron_proton_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::neutron_proton_magn_moment_ratio<
          T>::precision()));
}

// proton gyromagn. ratio
// (267522205.0 ± 23.0) s^-1 T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_gyromagn_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_gyromagn_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::proton_gyromagn_ratio<T>::value() ==
      static_cast<T>(267522205.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_gyromagn_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::proton_gyromagn_ratio<T>::uncertainty() ==
      static_cast<T>(23.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_gyromagn_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::proton_gyromagn_ratio<T>::precision()));
}

// proton gyromagn. ratio over 2 pi
// (42.5774813 ± 3.7e-06) MHz T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_gyromagn_ratio_over_2_pi, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_gyromagn_ratio_over_2_pi<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::proton_gyromagn_ratio_over_2_pi<
                 T>::value() == static_cast<T>(42.5774813));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_gyromagn_ratio_over_2_pi<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::proton_gyromagn_ratio_over_2_pi<
                 T>::uncertainty() == static_cast<T>(3.7e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_gyromagn_ratio_over_2_pi<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::proton_gyromagn_ratio_over_2_pi<
          T>::precision()));
}

// proton magn. moment
// (1.41060671e-26 ± 1.2e-33) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_moment<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::proton_magn_moment<T>::value() ==
             static_cast<T>(1.41060671e-26));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_moment<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::proton_magn_moment<T>::uncertainty() ==
      static_cast<T>(1.2e-33));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_moment<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::proton_magn_moment<T>::precision()));
}

// proton magn. moment to Bohr magneton ratio
// (0.001521032206 ± 1.5e-11)
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_magn_moment_to_Bohr_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_moment_to_Bohr_magneton_ratio<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::proton_magn_moment_to_Bohr_magneton_ratio<
          T>::value() == static_cast<T>(0.001521032206));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_moment_to_Bohr_magneton_ratio<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::proton_magn_moment_to_Bohr_magneton_ratio<
          T>::uncertainty() == static_cast<T>(1.5e-11));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_moment_to_Bohr_magneton_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::proton_magn_moment_to_Bohr_magneton_ratio<
          T>::precision()));
}

// proton magn. moment to nuclear magneton ratio
// (2.792847351 ± 2.8e-08)
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_magn_moment_to_nuclear_magneton_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          proton_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 proton_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
             static_cast<T>(2.792847351));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          proton_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          proton_magn_moment_to_nuclear_magneton_ratio<T>::uncertainty() ==
      static_cast<T>(2.8e-08));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          proton_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          proton_magn_moment_to_nuclear_magneton_ratio<T>::precision()));
}

// proton magn. shielding correction
// (2.5689e-05 ± 1.5e-08)
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_magn_shielding_correction, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_shielding_correction<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::proton_magn_shielding_correction<
                 T>::value() == static_cast<T>(2.5689e-05));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_shielding_correction<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::proton_magn_shielding_correction<
                 T>::uncertainty() == static_cast<T>(1.5e-08));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_magn_shielding_correction<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::proton_magn_shielding_correction<
          T>::precision()));
}

// proton-neutron magn. moment ratio
// (-1.45989805 ± 3.4e-07)
BOOST_AUTO_TEST_CASE_TEMPLATE(proton_neutron_magn_moment_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_neutron_magn_moment_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::proton_neutron_magn_moment_ratio<
                 T>::value() == static_cast<T>(-1.45989805));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_neutron_magn_moment_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::proton_neutron_magn_moment_ratio<
                 T>::uncertainty() == static_cast<T>(3.4e-07));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::proton_neutron_magn_moment_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::proton_neutron_magn_moment_ratio<
          T>::precision()));
}

// shielded helion gyromagn. ratio
// (203789470.0 ± 18.0) s^-1 T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(shielded_helion_gyromagn_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::shielded_helion_gyromagn_ratio<
                 T>::value() == static_cast<T>(203789470.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::shielded_helion_gyromagn_ratio<
                 T>::uncertainty() == static_cast<T>(18.0));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio<
          T>::precision()));
}

// shielded helion gyromagn. ratio over 2 pi
// (32.4341015 ± 2.8e-06) MHz T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(shielded_helion_gyromagn_ratio_over_2_pi, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio_over_2_pi<
          T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio_over_2_pi<
          T>::value() == static_cast<T>(32.4341015));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio_over_2_pi<
          T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio_over_2_pi<
          T>::uncertainty() == static_cast<T>(2.8e-06));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio_over_2_pi<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::shielded_helion_gyromagn_ratio_over_2_pi<
          T>::precision()));
}

// shielded helion magn. moment
// (-1.074553024e-26 ± 9.3e-34) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(shielded_helion_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_helion_magn_moment<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::shielded_helion_magn_moment<T>::value() ==
      static_cast<T>(-1.074553024e-26));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::shielded_helion_magn_moment<
                    T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::shielded_helion_magn_moment<
                 T>::uncertainty() == static_cast<T>(9.3e-34));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::shielded_helion_magn_moment<
                    T>::precision()));
  BOOST_TEST(
      !std::signbit(triumf::constants::codata_2002::shielded_helion_magn_moment<
                    T>::precision()));
}

// shielded helion magn. moment to Bohr magneton ratio
// (-0.001158671474 ± 1.4e-11)
BOOST_AUTO_TEST_CASE_TEMPLATE(
    shielded_helion_magn_moment_to_Bohr_magneton_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_magn_moment_to_Bohr_magneton_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          shielded_helion_magn_moment_to_Bohr_magneton_ratio<T>::value() ==
      static_cast<T>(-0.001158671474));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_helion_magn_moment_to_Bohr_magneton_ratio<
                            T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 shielded_helion_magn_moment_to_Bohr_magneton_ratio<
                     T>::uncertainty() == static_cast<T>(1.4e-11));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          shielded_helion_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
}

// shielded helion magn. moment to nuclear magneton ratio
// (-2.127497723 ± 2.5e-08)
BOOST_AUTO_TEST_CASE_TEMPLATE(
    shielded_helion_magn_moment_to_nuclear_magneton_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          shielded_helion_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
      static_cast<T>(-2.127497723));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_helion_magn_moment_to_nuclear_magneton_ratio<
                            T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 shielded_helion_magn_moment_to_nuclear_magneton_ratio<
                     T>::uncertainty() == static_cast<T>(2.5e-08));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_helion_magn_moment_to_nuclear_magneton_ratio<
                            T>::precision()));
  BOOST_TEST(
      !std::signbit(triumf::constants::codata_2002::
                        shielded_helion_magn_moment_to_nuclear_magneton_ratio<
                            T>::precision()));
}

// shielded helion to proton magn. moment ratio
// (-0.761766562 ± 1.2e-08)
BOOST_AUTO_TEST_CASE_TEMPLATE(shielded_helion_to_proton_magn_moment_ratio, T,
                              test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_to_proton_magn_moment_ratio<T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::
                 shielded_helion_to_proton_magn_moment_ratio<T>::value() ==
             static_cast<T>(-0.761766562));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_to_proton_magn_moment_ratio<T>::uncertainty()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          shielded_helion_to_proton_magn_moment_ratio<T>::uncertainty() ==
      static_cast<T>(1.2e-08));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_to_proton_magn_moment_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          shielded_helion_to_proton_magn_moment_ratio<T>::precision()));
}

// shielded helion to shielded proton magn. moment ratio
// (-0.7617861313 ± 3.3e-09)
BOOST_AUTO_TEST_CASE_TEMPLATE(
    shielded_helion_to_shielded_proton_magn_moment_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_helion_to_shielded_proton_magn_moment_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          shielded_helion_to_shielded_proton_magn_moment_ratio<T>::value() ==
      static_cast<T>(-0.7617861313));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_helion_to_shielded_proton_magn_moment_ratio<
                            T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 shielded_helion_to_shielded_proton_magn_moment_ratio<
                     T>::uncertainty() == static_cast<T>(3.3e-09));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_helion_to_shielded_proton_magn_moment_ratio<
                            T>::precision()));
  BOOST_TEST(
      !std::signbit(triumf::constants::codata_2002::
                        shielded_helion_to_shielded_proton_magn_moment_ratio<
                            T>::precision()));
}

// shielded proton magn. moment
// (1.41057047e-26 ± 1.2e-33) J T^-1
BOOST_AUTO_TEST_CASE_TEMPLATE(shielded_proton_magn_moment, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::shielded_proton_magn_moment<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::shielded_proton_magn_moment<T>::value() ==
      static_cast<T>(1.41057047e-26));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::shielded_proton_magn_moment<
                    T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::shielded_proton_magn_moment<
                 T>::uncertainty() == static_cast<T>(1.2e-33));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::shielded_proton_magn_moment<
                    T>::precision()));
  BOOST_TEST(
      !std::signbit(triumf::constants::codata_2002::shielded_proton_magn_moment<
                    T>::precision()));
}

// shielded proton magn. moment to Bohr magneton ratio
// (0.001520993132 ± 1.6e-11)
BOOST_AUTO_TEST_CASE_TEMPLATE(
    shielded_proton_magn_moment_to_Bohr_magneton_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_proton_magn_moment_to_Bohr_magneton_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          shielded_proton_magn_moment_to_Bohr_magneton_ratio<T>::value() ==
      static_cast<T>(0.001520993132));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_proton_magn_moment_to_Bohr_magneton_ratio<
                            T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 shielded_proton_magn_moment_to_Bohr_magneton_ratio<
                     T>::uncertainty() == static_cast<T>(1.6e-11));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_proton_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::
          shielded_proton_magn_moment_to_Bohr_magneton_ratio<T>::precision()));
}

// shielded proton magn. moment to nuclear magneton ratio
// (2.792775604 ± 3e-08)
BOOST_AUTO_TEST_CASE_TEMPLATE(
    shielded_proton_magn_moment_to_nuclear_magneton_ratio, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::
          shielded_proton_magn_moment_to_nuclear_magneton_ratio<T>::value()));
  BOOST_TEST(
      triumf::constants::codata_2002::
          shielded_proton_magn_moment_to_nuclear_magneton_ratio<T>::value() ==
      static_cast<T>(2.792775604));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_proton_magn_moment_to_nuclear_magneton_ratio<
                            T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::
                 shielded_proton_magn_moment_to_nuclear_magneton_ratio<
                     T>::uncertainty() == static_cast<T>(3e-08));
  BOOST_TEST(
      std::isfinite(triumf::constants::codata_2002::
                        shielded_proton_magn_moment_to_nuclear_magneton_ratio<
                            T>::precision()));
  BOOST_TEST(
      !std::signbit(triumf::constants::codata_2002::
                        shielded_proton_magn_moment_to_nuclear_magneton_ratio<
                            T>::precision()));
}

// {220} lattice spacing of silicon
// (1.920155965e-10 ± 7e-18) m
BOOST_AUTO_TEST_CASE_TEMPLATE(lattice_spacing_of_silicon_220, T, test_types) {
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::lattice_spacing_of_silicon_220<
          T>::value()));
  BOOST_TEST(triumf::constants::codata_2002::lattice_spacing_of_silicon_220<
                 T>::value() == static_cast<T>(1.920155965e-10));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::lattice_spacing_of_silicon_220<
          T>::uncertainty()));
  BOOST_TEST(triumf::constants::codata_2002::lattice_spacing_of_silicon_220<
                 T>::uncertainty() == static_cast<T>(7e-18));
  BOOST_TEST(std::isfinite(
      triumf::constants::codata_2002::lattice_spacing_of_silicon_220<
          T>::precision()));
  BOOST_TEST(!std::signbit(
      triumf::constants::codata_2002::lattice_spacing_of_silicon_220<
          T>::precision()));
}


#include <fstream>
#include <iostream>
#include <cstdlib>
#include <ctime>

#include <Eigen/Dense>

#include "roadnet.hpp"
#include "problem.hpp"

using namespace dubins_traffic;

int main( int argc, char *argv[] )
{
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " FILE" << std::endl;
        return 1;
    }

    std::string buf;
    std::ifstream infile( argv[1] );
    if (!infile.is_open()) {
        std::cerr << "Failed to open " << argv[1] << std::endl;
        return 1;
    }

    RoadNetwork rnd( infile );

    Eigen::Vector2i number_goals_bounds( 1, 2 );

    std::srand( std::time( 0 ) );
    Problem pinstance = Problem::random( rnd,
                                         number_goals_bounds );

    std::cout << pinstance << std::endl;

    return 0;
}


#pragma once

#include <deal.II/base/function_parser.h>
#include <deal.II/base/point.h>

#include "matrix/bc/impl/mls/diffusive_reflection.hpp"

namespace std {
template<>
class hash<dealii::Point<2>>
{
 public:
  std::size_t operator()(const dealii::Point<2>& x) const
  {
    std::size_t current = std::hash<double>()(x[0]);
    boost::hash_combine(current, std::hash<double>()(x[1]));

    return current;
  }

};
}  // std

namespace boltzmann {
namespace impl_mls {

class DiffusiveReflectionX : public boltzmann::impl::flux_worker
{
 public:
  DiffusiveReflectionX(const vec_t& hw, const vec_t& hx, double vt, const std::string& Tx)
      : hw_(hw),
        hx_(hx),
        vt_(vt),
        Tx_(1 /* output dim */)
  {
    std::map<std::string, double> constants;
    constants["pi"] = 3.14159265358979323846264338328;
    std::string variables = "x,y";
    Tx_.initialize(variables, Tx, constants);
  }

  virtual void apply(mat_t& out, const mat_t& in, const dealii::Point<2>& x) const;

 private:
  vec_t hw_;
  vec_t hx_;
  double vt_;
  dealii::FunctionParser<2> Tx_;
  mutable std::unordered_map<dealii::Point<2>, DiffusiveReflection> values_;
};

void DiffusiveReflectionX::apply(mat_t& out, const mat_t& in, const dealii::Point<2>& x) const
{
  auto it = values_.find(x);
  if (it != values_.end()) {
    it->second.apply(out, in);
  } else {
    double Tloc = Tx_.value(x);
    auto it = values_.emplace(std::make_pair(x, DiffusiveReflection(hw_, hx_, vt_, Tloc)));
    it.first->second.apply(out, in);
  }
}

}  // impl_mls
}  // boltzmann


/*-------------------------------------------------------------------

                  Copyright (c) 2006
         Nicola Beume <nicola.beume@tu-dortmund.de>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

---------------------------------------------------------------------

This program calculates the dominated hypervolume or S-metric of a
set of d-dimensional points (d>=3). Please refer to the following
publication for a description of the algorithm:

Nicola Beume and Guenter Rudolph.
Faster S-Metric Calculation by Considering Dominated Hypervolume
as Klee's Measure Problem.
In: B. Kovalerchuk (ed.): Proceedings of the Second IASTED
Conference on Computational Intelligence (CI 2006), pp. 231-236.
ACTA Press: Anaheim, 2006.

Extended version published as:
Technical Report of the Collaborative Research Centre 531
'Computational Intelligence', CI-216/06, ISSN 1433-3325.
University of Dortmund, July 2006.

-------------------------------------------------------------------*/

#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <bitset> // for calculation of trellis
#include <vector>
#include <Eigen/Dense>
using namespace std;

/* function invoked by main */
void stream(double regLow[], double regUp[], const vector<double*>& cubs, int lev, double cov);
bool cmp(double* a, double* b);
/* function invoked by stream */
/*
inline bool cmp(double* a, double* b);
inline bool covers(const double* cub, const double regLow[]);
inline bool partCovers(const double* cub, const double regUp[]);
inline int containsBoundary(const double* cub, const double regLow[], const int split);
inline double getMeasure(const double regLow[], const double regUp[]);
inline int isPile(const double* cub, const double regLow[], const double regUp[]);
inline double computeTrellis(const double regLow[], const double regUp[], const double trellis[]);
inline double getMedian(vector<double>& bounds);
*/

/* global variables */
static int dataNumber;
static int dimension;
static double dSqrtDataNumber;
static double volume;

static double calculate(int dim, int dataNum, const Eigen::MatrixXd &xd, const Eigen::MatrixXd &xr) {
    /*
     * arguments are:
     * dimension of input data points
     * number of input data points
     * file name of input data
     * file name of reference point
     */

    int i,j;
    dimension = dim;
    dataNumber = dataNum;
    if (dimension < 3) {
        fprintf(stderr, "invalid argument\n");
        exit(1);
    }

    static vector<double*> pointsInitial(dataNumber);

    for (int i = 0; i < dataNumber; i++) {
        pointsInitial[i] = new double[dimension];
        for (int j = 0; j < dimension; j++) {
            pointsInitial[i][j] = xd(i, j);
        }
    }

    // read in reference point
    static double* refPoint = new double[dimension];
    for (int i = 0; i < dimension; i++) {
        refPoint[i] = xr(i);
    }

    // initialize volume
    volume = 0.0;
    // sqrt of dataNumber
    dSqrtDataNumber = sqrt((double)dataNumber);

    // initialize region
    double* regionLow = new double[dimension-1];
    double* regionUp = new double[dimension-1];
    for (j=0; j<dimension-1; j++)  {
        // determine minimal j coordinate
        double min = 10000000.0;
        for (i=0; i<dataNumber; i++) {
            if (pointsInitial[i][j] < min) {
                min = pointsInitial[i][j];
            }
        }
        regionLow[j] = min;
        regionUp[j] = refPoint[j];
    }

    // sort pointList according to d-th dimension
    sort(pointsInitial.begin(), pointsInitial.end(), cmp);

    // call stream initially
    stream(regionLow, regionUp, pointsInitial, 0, refPoint[dimension-1]);
    // return hypervolume
    return volume;
}

inline bool cmp(double* a, double* b) {
    return (a[dimension-1] < b[dimension-1]);
}

inline bool covers(const double* cub, const double regLow[]) {
    static int i;
    for (i=0; i<dimension-1; i++) {
        if (cub[i] > regLow[i]) {
            return false;
        }
    }
    return true;
}

inline bool partCovers(const double* cub, const double regUp[]) {
    static int i;
    for (i=0; i<dimension-1; i++) {
        if (cub[i] >= regUp[i]) {
            return false;
        }
    }
    return true;
}

inline int containsBoundary(const double* cub, const double regLow[], const int split) {
    // condition only checked for split>0
    if (regLow[split] >= cub[split]){
        // boundary in dimension split not contained in region, thus
        // boundary is no candidate for the splitting line
        return -1;
    }
    else {
        static int j;
        for (j=0; j<split; j++) { // check boundaries
            if (regLow[j] < cub[j]) {
                // boundary contained in region
                return 1;
            }
        }
    }
    // no boundary contained in region
    return 0;
}

inline double getMeasure(const double regLow[], const double regUp[]) {
    static double vol;
    static int i;
    vol = 1.0;
    for (i=0; i<dimension-1; i++) {
        vol *= (regUp[i] - regLow[i]);
    }
    return vol;
}

inline int isPile(const double* cub, const double regLow[], const double regUp[]) {
    static int pile;
    static int k;

    pile = dimension;
    // check all dimensions of the node
    for (k=0; k<dimension-1; k++) {
        // k-boundary of the node's region contained in the cuboid?
        if (cub[k] > regLow[k]) {
            if (pile != dimension) {
                // second dimension occured that is not completely covered
                // ==> cuboid is no pile
                return -1;
            }
            pile = k;
        }
    }
    // if pile == this.dimension then
    // cuboid completely covers region
    // case is not possible since covering cuboids have been removed before

    // region in only one dimenison not completly covered
    // ==> cuboid is a pile
    return pile;
}

inline double computeTrellis(const double regLow[], const double regUp[], const double trellis[]) {

    static int i,j;
    static double vol;
    static int numberSummands;
    static double summand;
    static bitset<16> bitvector;

    vol= 0.0;
    summand = 0.0;
    numberSummands = 0;

    // calculate number of summands
    static bitset<16> nSummands;
    for (i=0; i<dimension-1; i++) {
        nSummands[i] = 1;
    }
    numberSummands = nSummands.to_ulong();

    static double* valueTrellis = new double[dimension-1];
    static double* valueRegion = new double[dimension-1];
    for (i=0; i<dimension-1; i++) {
        valueTrellis[i] = trellis[i] - regUp[i];
    }
    for (i=0; i<dimension-1; i++) {
        valueRegion[i] = regUp[i] - regLow[i];
    }

    static double* dTemp = new double[numberSummands/2 + 1];

    // sum
    for (i=1; i<=numberSummands/2; i++) {

        // set bitvector length to fixed value 16
        // TODO Warning: dimension-1 <= 16 is assumed
        bitvector = (long)i;

        // construct summand
        // 0: take factor from region
        // 1: take factor from cuboid
        summand = 1.0;
        for (j=0; j<dimension-2; j++) {
            if (bitvector[j]) {
                summand *= valueTrellis[j];
            }
            else {
                summand *= valueRegion[j];
            }
        }
        summand *= valueRegion[dimension-2];

        // determine sign of summand
        vol -= summand;
        dTemp[i] =- summand;

        // add summand to sum
        // sign = (int) pow((double)-1, (double)counterOnes+1);
        // vol += (sign * summand);
    }

    bitvector = (long)i;
    summand = 1.0;
    for (j=0; j<dimension-1; j++) {
        if (bitvector[j]) {
            summand *= valueTrellis[j];
        }
        else {
            summand *= valueRegion[j];
        }
    }
    vol -= summand;

    for (i=1; i<=numberSummands/2; i++) {
        summand = dTemp[i];
        summand *= regUp[dimension-2] - trellis[dimension-2];
        summand /= valueRegion[dimension-2];
        vol -= summand;
    }

    //delete[] valueTrellis;
    //delete[] valueRegion;
    return vol;
}

// return median of the list of boundaries considered as a set
// TODO linear implementation
inline double getMedian(vector<double>& bounds) {
    // do not filter duplicates
    static unsigned int i;
    if (bounds.size()==1) {
        return bounds[0];
    }
    else if (bounds.size()==2) {
        return bounds[1];
    }
    vector<double>::iterator median;
    median = bounds.begin();
    for(i=0;i<=bounds.size()/2;i++){
        median++;
    }
    partial_sort(bounds.begin(),median,bounds.end());
    return bounds[bounds.size()/2];
}

// recursive calculation of hypervolume
inline void stream(double regionLow[], double regionUp[], const vector<double*>& points, int split, double cover) {

    //--- init --------------------------------------------------------------//

    static double coverOld;
    coverOld = cover;
    unsigned int coverIndex = 0;
    static int c;

    //--- cover -------------------------------------------------------------//

    // identify first covering cuboid
    double dMeasure = getMeasure(regionLow, regionUp);
    while (cover == coverOld && coverIndex < points.size()) {
        if ( covers(points[coverIndex], regionLow) ) {
            // new cover value
            cover = points[coverIndex][dimension-1];
            volume += dMeasure * (coverOld - cover);
        }
        else coverIndex++;
    }

    /* coverIndex shall be the index of the first point in points which
     * is ignored in the remaining process
     *
     * It may occur that that some points in front of coverIndex have the same
     * d-th coordinate as the point at coverIndex. This points must be discarded
     * and therefore the following for-loop checks for this points and reduces
     * coverIndex if necessary.
     */
    for (c=coverIndex; c>0; c--) {
        if (points[c-1][dimension-1] == cover) {
            coverIndex--;
        }
    }

    // abort if points is empty
    if (coverIndex == 0) {
        return;
    }
    // Note: in the remainder points is only considered to index coverIndex

    //--- allPiles  ---------------------------------------------------------//

    bool allPiles = true;
    unsigned int i;

    static int* piles = new int[coverIndex];
    for (i = 0; i<coverIndex; i++) {
        piles[i] = isPile(points[i], regionLow, regionUp);
        if (piles[i] == -1) {
            allPiles = false;
            //delete[] piles;
            break;
        }
    }

    /*
     * trellis[i] contains the values of the minimal i-coordinate of
     * the i-piles.
     * If there is no i-pile the default value is the upper bpund of the region.
     * The 1-dimensional KMP of the i-piles is: reg[1][i] - trellis[i]
     *
     */

    if (allPiles) { // sweep

        // initialize trellis with region's upper bound
        static double* trellis = new double[dimension-1];
        for (c=0; c<dimension-1; c++) {
            trellis[c] = regionUp[c];
        }

        double current = 0.0;
        double next = 0.0;
        i = 0;
        do { // while(next != coverNew)
            current = points[i][dimension-1];
            do { // while(next == current)
                if (points[i][piles[i]] < trellis[piles[i]]) {
                    trellis[piles[i]] = points[i][piles[i]];
                }
                i++; // index of next point
                if (i < coverIndex) {
                    next = points[i][dimension-1];
                }
                else {
                    next = cover;
                }

            } while(next == current);
            volume += computeTrellis(regionLow, regionUp, trellis) * (next - current);
        } while(next != cover);
    }

        //--- split -------------------------------------------------------------//
        // inner node of partition tree
    else{
        double bound = -1.0;
        vector<double> boundaries;
        vector<double> noBoundaries;

        do {
            for (i=0; i<coverIndex; i++) {
                int contained = containsBoundary(points[i], regionLow, split);
                if (contained == 1) {
                    boundaries.push_back(points[i][split]);
                } else if (contained == 0) {
                    noBoundaries.push_back(points[i][split]);
                }
            }

            if (boundaries.size() >  0) {
                bound = getMedian(boundaries);
                //bound = getRandom(boundaries);
            }
            else if (noBoundaries.size() >  dSqrtDataNumber) {
                bound = getMedian(noBoundaries);
                //bound = getRandom(noBoundaries);
            }
            else {
                split++;
            }
        } while (bound == -1.0);

        double dLast;
        vector<double*> pointsChild;
        pointsChild.reserve(coverIndex);

        // left child
        // reduce maxPoint
        dLast = regionUp[split];
        regionUp[split] = bound;
        for (i=0; i<coverIndex; i++) {
            if (partCovers(points[i], regionUp)) {
                pointsChild.push_back(points[i]);
            }
        }
        if (!pointsChild.empty()) {
            stream(regionLow, regionUp, pointsChild, split, cover);
        }

        // right child
        // increase minPoint
        pointsChild.clear();
        regionUp[split] = dLast;
        dLast = regionLow[split];
        regionLow[split] = bound;
        for (i=0; i<coverIndex; i++) {
            if (partCovers(points[i], regionUp)) {
                pointsChild.push_back(points[i]);
            }
        }
        if (!pointsChild.empty()) {
            stream(regionLow, regionUp, pointsChild, split, cover);
        }
        regionLow[split] = dLast;

    }// end inner node

} // end stream

// ----------------
// Python interface
// ----------------

namespace py = pybind11;

PYBIND11_MODULE(hypervolume, m)
{
    m.doc() = "pybind11 hv plugin";

    m.def("calculate", &calculate);
}


// Copyright (C) 2014 Massachusetts Institute of Technology, Lincoln Laboratory
// License: Boost Software License   See LICENSE.txt for the full license.
// Authors: Davis E. King (davis@dlib.net)

#include <dlib/matrix.h>
#include <mitie/named_entity_extractor.h>
#include <string>

using namespace dlib;
using namespace std;
using namespace mitie;

#define ARG_4_DEFAULT ""

string classname;
named_entity_extractor ner;
bool did_init = false;

void mex_function (
    const std::vector<std::string>& tokens,
    std::vector<matrix<double,1> >& entities,
    std::vector<std::string>& labels,
    const std::string& model_filename
)
{
    if (!did_init)
    {
        if (model_filename == "")
            throw dlib::error("You need to give a MITIE ner model file as the second argument the first time you call this function.");

        dlib::deserialize(model_filename) >> classname >> ner;
        did_init = true;
    }

    std::vector<pair<unsigned long, unsigned long> > chunks;
    std::vector<unsigned long> chunk_tags;
    // Now detect all the entities in the tokens.  The output of this function is a set of
    // "chunks" of tokens, each a named entity.
    ner(tokens, chunks, chunk_tags);

    const std::vector<string> tagstr = ner.get_tag_name_strings();
    entities.clear();
    labels.clear();
    // copy the entities into the output variables
    for (unsigned int i = 0; i < chunks.size(); ++i)
    {
        labels.push_back(tagstr[chunk_tags[i]]);
        const unsigned long length = chunks[i].second-chunks[i].first;
        entities.push_back(linspace(chunks[i].first+1, chunks[i].second, length));
    }
}

#include "mex_wrapper.cpp"


/**
 * @file dbscan.hpp
 * @author Ryan Curtin
 *
 * An implementation of the DBSCAN clustering method, which is flexible enough
 * to support other algorithms for finding nearest neighbors.
 *
 * 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.
 */
#ifndef MLPACK_METHODS_DBSCAN_DBSCAN_HPP
#define MLPACK_METHODS_DBSCAN_DBSCAN_HPP

#include <mlpack/core.hpp>
#include <mlpack/methods/range_search/range_search.hpp>
#include "random_point_selection.hpp"
#include <boost/dynamic_bitset.hpp>

namespace mlpack {
namespace dbscan {

/**
 * DBSCAN (Density-Based Spatial Clustering of Applications with Noise) is a
 * clustering technique described in the following paper:
 *
 * @code
 * @inproceedings{ester1996density,
 *   title={A density-based algorithm for discovering clusters in large spatial
 *       databases with noise.},
 *   author={Ester, M. and Kriegel, H.-P. and Sander, J. and Xu, X.},
 *   booktitle={Proceedings of the Second International Conference on Knowledge
 *       Discovery and Data Mining (KDD '96)},
 *   pages={226--231},
 *   year={1996}
 * }
 * @endcode
 *
 * The DBSCAN algorithm iteratively clusters points using range searches with a
 * specified radius parameter.  This implementation allows configuration of the
 * range search technique used and the point selection strategy by means of
 * template parameters.
 *
 * @tparam RangeSearchType Class to use for range searching.
 * @tparam PointSelectionPolicy Strategy for selecting next point to cluster
 *      with.
 */
template<typename RangeSearchType = range::RangeSearch<>,
         typename PointSelectionPolicy = RandomPointSelection>
class DBSCAN
{
 public:
  /**
   * Construct the DBSCAN object with the given parameters.
   *
   * @param epsilon Size of range query.
   * @param minPoints Minimum number of points for each cluster.
   * @param rangeSearch Optional instantiated RangeSearch object.
   * @param pointSelector OptionL instantiated PointSelectionPolicy object.
   */
  DBSCAN(const double epsilon,
         const size_t minPoints,
         RangeSearchType rangeSearch = RangeSearchType(),
         PointSelectionPolicy pointSelector = PointSelectionPolicy());

  /**
   * Performs DBSCAN clustering on the data, returning number of clusters
   * and also the centroid of each cluster.
   *
   * @tparam MatType Type of matrix (arma::mat or arma::sp_mat).
   * @param data Dataset to cluster.
   * @param centroids Matrix in which centroids are stored.
   */
  template<typename MatType>
  size_t Cluster(const MatType& data,
                 arma::mat& centroids);

  /**
   * Performs DBSCAN clustering on the data, returning number of clusters
   * and also the list of cluster assignments.
   *
   * @tparam MatType Type of matrix (arma::mat or arma::sp_mat).
   * @param data Dataset to cluster.
   * @param assignments Vector to store cluster assignments.
   */
  template<typename MatType>
  size_t Cluster(const MatType& data,
                 arma::Row<size_t>& assignments);

  /**
   * Performs DBSCAN clustering on the data, returning number of clusters,
   * the centroid of each cluster and also the list of cluster assignments.
   * If assignments[i] == assignments.n_elem - 1, then the point is considered
   * "noise".
   *
   * @tparam MatType Type of matrix (arma::mat or arma::sp_mat).
   * @param data Dataset to cluster.
   * @param assignments Vector to store cluster assignments.
   * @param centroids Matrix in which centroids are stored.
   */
  template<typename MatType>
  size_t Cluster(const MatType& data,
                 arma::Row<size_t>& assignments,
                 arma::mat& centroids);

 private:
  //! Maximum distance between two points to be part of same cluster.
  double epsilon;

  //! Minimum number of points to be in the epsilon-neighborhood (including
  //! itself) for the point to be a core-point.
  size_t minPoints;

  //! Instantiated range search policy.
  RangeSearchType rangeSearch;

  //! Instantiated point selection policy.
  PointSelectionPolicy pointSelector;

  /**
   * This function processes the point at index. It  marks the point as visited,
   * checks if the given point is core or non-core.  If it is a core point, it
   * expands the cluster, otherwise it returns.
   *
   * @tparam MatType Type of matrix (arma::mat or arma::sp_mat).
   * @param data Dataset to cluster.
   * @param unvisited Remembers if a point has been visited.
   * @param index Index of point to be visited now.
   * @param assignments Vector to store cluster assignments.
   * @param currentCluster Index of cluster which will be  assigned to points in
   *     current cluster.
   * @param neighbors Matrix containing list of neighbors for each point which
   *     fall in its epsilon-neighborhood.
   * @param distances Matrix containing list of distances for each point which
   *     fall in its epsilon-neighborhood.
   * @param topLevel If true, then current point is the first point in the
   *     current cluster, helps in detecting noise.
   */
  template<typename MatType>
  size_t ProcessPoint(const MatType& data,
                      boost::dynamic_bitset<>& unvisited,
                      const size_t index,
                      arma::Row<size_t>& assignments,
                      const size_t currentCluster,
                      const std::vector<std::vector<size_t>>& neighbors,
                      const std::vector<std::vector<double>>& distances,
                      const bool topLevel = true);
};

} // namespace dbscan
} // namespace mlpack

// Include implementation.
#include "dbscan_impl.hpp"

#endif


#include <stan/math/prim/scal.hpp>
#include <boost/math/special_functions/owens_t.hpp>
#include <gtest/gtest.h>
#include <cmath>
#include <limits>

TEST(MathFunctions, owens_t) {
  double a = 1.0;
  double b = 2.0;
  EXPECT_FLOAT_EQ(stan::math::owens_t(a, b), boost::math::owens_t(a, b));
}

TEST(MathFunctions, owens_t_nan) {
  double nan = std::numeric_limits<double>::quiet_NaN();

  EXPECT_TRUE(std::isnan(stan::math::owens_t(1.0, nan)));
  EXPECT_TRUE(std::isnan(stan::math::owens_t(nan, 2.0)));
  EXPECT_TRUE(std::isnan(stan::math::owens_t(nan, nan)));
}


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

#include "test_utils/logger.hpp"
#include "iterative_rounding/log_visitor.hpp"

#include "paal/iterative_rounding/bounded_degree_min_spanning_tree/bounded_degree_mst.hpp"
#include "paal/utils/functors.hpp"

#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/range/counting_range.hpp>
#include <boost/test/unit_test.hpp>

using namespace paal;
using namespace paal::ir;

template <typename VertexList, typename EdgeProp>
using Graph = boost::adjacency_list<boost::vecS, VertexList, boost::undirectedS,
                                    boost::property<boost::vertex_index_t, int>,
                                    EdgeProp>;

using EdgeProp = boost::property<boost::edge_index_t, std::size_t,
                                 boost::property<boost::edge_weight_t, int>>;
using VectorGraph = Graph<boost::vecS, EdgeProp>;

using Edge = boost::graph_traits<VectorGraph>::edge_descriptor;
using ResultTree = std::set<Edge>;

template <typename Cost>
Edge add_edge_to_graph(VectorGraph &g, Cost &cost, int u, int v, double c) {
    bool b;
    Edge e;
    std::tie(e, b) = add_edge(u, v, g);
    assert(b);
    cost[e] = c;
    return e;
}

BOOST_AUTO_TEST_SUITE(bounded_degree_mst)
BOOST_AUTO_TEST_CASE(bounded_degree_mst_test) {
    // sample problem
    LOGLN("Sample problem:");
    VectorGraph g;
    auto costs = get(boost::edge_weight, g);

    ResultTree correct_bdmst;
    ResultTree result_tree;

    correct_bdmst.insert(add_edge_to_graph(g, costs, 1, 0, 173));
    correct_bdmst.insert(add_edge_to_graph(g, costs, 4, 2, 176));
                         add_edge_to_graph(g, costs, 2, 3, 176);
                         add_edge_to_graph(g, costs, 4, 3, 190);
    correct_bdmst.insert(add_edge_to_graph(g, costs, 3, 1, 37));
                         add_edge_to_graph(g, costs, 4, 1, 260);
    correct_bdmst.insert(add_edge_to_graph(g, costs, 5, 3, 105));
    correct_bdmst.insert(add_edge_to_graph(g, costs, 2, 1, 84));
                         add_edge_to_graph(g, costs, 5, 4, 243);
                         add_edge_to_graph(g, costs, 4, 0, 259);

    ON_LOG(auto indices = get(boost::vertex_index, g));

    std::vector<int> deg_bounds = {1, 3, 2, 2, 1, 1};
    auto bounds = paal::utils::make_array_to_functor(deg_bounds);

    bounded_degree_mst_iterative_rounding(g, bounds,
                    std::inserter(result_tree, result_tree.begin()),
                    bdmst_ir_components<>{}, lp::random_violated_separation_oracle{},
                    log_visitor{});

    ON_LOG(for (auto const & e : result_tree) {
        LOGLN("Edge (" << indices[source(e, g)] << ", " << indices[target(e, g)]
                       << ") "
                       << "in tree");
    })

    BOOST_CHECK_EQUAL(correct_bdmst.size(),result_tree.size());
    BOOST_CHECK(std::equal(correct_bdmst.begin(), correct_bdmst.end(), result_tree.begin()));
}

BOOST_AUTO_TEST_CASE(bounded_degree_mst_test_parameters) {
    // sample problem
    LOGLN("Sample problem:");
    VectorGraph g;

    ResultTree correct_bdmst;

    correct_bdmst.insert(add_edge(1, 0, 0, g).first);
                         add_edge(2, 1, 1, g);
    correct_bdmst.insert(add_edge(0, 2, 2, g).first);

    std::vector<double> costs = { 173, 176, 37 };
    auto cost = boost::make_iterator_property_map(costs.begin(),
                                                  get(boost::edge_index, g));

    auto bounds = [&](int) { return 2; };

    {
        ResultTree result_tree;
        bounded_degree_mst_iterative_rounding(g, bounds, boost::weight_map(cost),
                    std::inserter(result_tree, result_tree.begin()),
                    bdmst_ir_components<>{}, paal::lp::random_violated_separation_oracle{},
                    log_visitor{});

        BOOST_CHECK_EQUAL(correct_bdmst.size(),result_tree.size());
        BOOST_CHECK(std::equal(correct_bdmst.begin(), correct_bdmst.end(), result_tree.begin()));
    }
    {
        ResultTree result_tree;
        auto bdmst(make_bounded_degree_mst(g, bounds, boost::weight_map(cost),
                    std::inserter(result_tree, result_tree.begin())));
        solve_iterative_rounding(bdmst, bdmst_ir_components<>{}, log_visitor{});

        BOOST_CHECK_EQUAL(correct_bdmst.size(),result_tree.size());
        BOOST_CHECK(std::equal(correct_bdmst.begin(), correct_bdmst.end(), result_tree.begin()));
    }
}

BOOST_AUTO_TEST_CASE(bounded_degree_mst_list) {
    // boost::listS instead of boost::vecS for vertex storage
    using ListGraph =
        Graph<boost::listS, boost::property<boost::edge_weight_t, double>>;
    using EdgeT = boost::graph_traits<ListGraph>::edge_descriptor;

    std::vector<std::pair<int, int>> edges = { { 1, 0 }, { 4, 2 }, { 2, 3 },
                                               { 4, 3 }, { 3, 1 }, { 4, 1 },
                                               { 5, 3 }, { 2, 1 }, { 5, 4 },
                                               { 4, 0 } };
    std::vector<double> costs = { 173, 176, 176, 190, 37, 260, 105, 84, 243,
                                  259 };
    ListGraph g(edges.begin(), edges.end(), costs.begin(), 6);

    auto index = get(boost::vertex_index, g);
    int idx = 0;
    for (auto v : boost::make_iterator_range(vertices(g))) {
        put(index, v, idx);
        ++idx;
    }

    std::vector<int> deg_bounds = {1, 3, 2, 2, 1, 1};
    auto bounds = paal::utils::make_array_to_functor(deg_bounds);

    std::vector<EdgeT> result_tree;
    bounded_degree_mst_iterative_rounding(g, bounds,
                    std::inserter(result_tree, result_tree.begin()));
    BOOST_CHECK_EQUAL(result_tree.size(), 5u);
}

BOOST_AUTO_TEST_CASE(bounded_degree_mst_invalid_test) {
    // invalid problem (disconnected graph)
    LOGLN("Invalid problem (disconnected graph):");
    VectorGraph g;
    auto costs = get(boost::edge_weight, g);

    std::vector<Edge> result_tree;

    add_edge_to_graph(g, costs, 0, 1, 1);
    add_edge_to_graph(g, costs, 0, 2, 16);
    add_edge_to_graph(g, costs, 0, 3, 76);
    add_edge_to_graph(g, costs, 1, 2, 90);
    add_edge_to_graph(g, costs, 1, 3, 37);
    add_edge_to_graph(g, costs, 4, 5, 20);
    add_edge_to_graph(g, costs, 4, 6, 15);
    add_edge_to_graph(g, costs, 5, 6, 4);

    auto bounds = [&](int) { return 6; };

    auto bdmst(make_bounded_degree_mst(g, bounds, std::back_inserter(result_tree)));
    auto invalid = bdmst.check_input_validity();

    BOOST_CHECK(invalid);
    LOGLN(*invalid);
}

BOOST_AUTO_TEST_CASE(bounded_degree_mst_infeasible_test) {
    // infeasible problem
    LOGLN("Infeasible problem:");
    VectorGraph g;
    auto costs = get(boost::edge_weight, g);

    std::vector<Edge> result_tree;

    add_edge_to_graph(g, costs, 0, 3, 5);
    add_edge_to_graph(g, costs, 3, 5, 15);
    add_edge_to_graph(g, costs, 5, 4, 7);
    add_edge_to_graph(g, costs, 5, 1, 2);
    add_edge_to_graph(g, costs, 1, 2, 78);
    add_edge_to_graph(g, costs, 5, 9, 56);
    add_edge_to_graph(g, costs, 8, 9, 13);
    add_edge_to_graph(g, costs, 9, 7, 6);
    add_edge_to_graph(g, costs, 5, 6, 1);

    std::vector<int> deg_bounds = {1, 2, 1, 2, 1, 3, 1, 1, 1, 3};
    auto bounds = paal::utils::make_array_to_functor(deg_bounds);

    auto bdmst(make_bounded_degree_mst(g, bounds, std::back_inserter(result_tree)));
    auto invalid = bdmst.check_input_validity();

    BOOST_CHECK(!invalid);

    auto result = solve_iterative_rounding(bdmst, bdmst_ir_components<>{});

    BOOST_CHECK(result.first == lp::INFEASIBLE);
}
BOOST_AUTO_TEST_SUITE_END()


#include <Columns/ColumnArray.h>
#include <Columns/IColumn.h>
#include <DataTypes/DataTypeArray.h>
#include <DataTypes/DataTypesNumber.h>
#include <DataTypes/IDataType.h>
#include <DataTypes/getLeastSupertype.h>
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionHelpers.h>

#include <Eigen/Core>

namespace DB
{
namespace ErrorCodes
{
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
    extern const int LOGICAL_ERROR;
}

template <const int N>
struct LpNorm
{
    static inline String name = "L" + std::to_string(N);
    template <typename T>
    static void compute(const std::vector<Eigen::VectorX<T>> & vec, PaddedPODArray<T> & array)
    {
        array.reserve(vec.size());
        for (const auto & v : vec)
        {
            array.push_back(v.template lpNorm<N>());
        }
    }
};

struct LinfNorm : LpNorm<Eigen::Infinity>
{
    static inline String name = "Linf";
};

template <class Kernel>
class FunctionArrayNorm : public IFunction
{
public:
    static inline auto name = "array" + Kernel::name + "Norm";
    String getName() const override { return name; }
    static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionArrayNorm<Kernel>>(); }
    size_t getNumberOfArguments() const override { return 1; }
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
    bool useDefaultImplementationForConstants() const override { return true; }

    DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
    {
        DataTypes types;
        for (const auto & argument : arguments)
        {
            const auto * array_type = checkAndGetDataType<DataTypeArray>(argument.type.get());
            if (!array_type)
                throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument of function {} must be array.", getName());

            types.push_back(array_type->getNestedType());
        }
        const auto & common_type = getLeastSupertype(types);
        switch (common_type->getTypeId())
        {
            case TypeIndex::UInt8:
            case TypeIndex::UInt16:
            case TypeIndex::UInt32:
            case TypeIndex::Int8:
            case TypeIndex::Int16:
            case TypeIndex::Int32:
            case TypeIndex::Float32:
                return std::make_shared<DataTypeFloat32>();
            case TypeIndex::UInt64:
            case TypeIndex::Int64:
            case TypeIndex::Float64:
                return std::make_shared<DataTypeFloat64>();
            default:
                throw Exception(
                    ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
                    "Arguments of function {} has nested type {}. "
                    "Support: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, Float32, Float64.",
                    getName(), common_type->getName());
        }
    }

    ColumnPtr
    executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t /*input_rows_count*/) const override
    {
        DataTypePtr type = typeid_cast<const DataTypeArray *>(arguments[0].type.get())->getNestedType();
        ColumnPtr column = arguments[0].column->convertToFullColumnIfConst();
        const auto * arr = assert_cast<const ColumnArray *>(column.get());

        auto result = result_type->createColumn();
        switch (result_type->getTypeId())
        {
            case TypeIndex::Float32:
                executeWithType<Float32>(*arr, type, result);
                break;
            case TypeIndex::Float64:
                executeWithType<Float64>(*arr, type, result);
                break;
            default:
                throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected result type.");
        }
        return result;
    }

private:
    template <typename MatrixType>
    void executeWithType(const ColumnArray & array, const DataTypePtr & type, MutableColumnPtr & column) const
    {
        std::vector<Eigen::VectorX<MatrixType>> vec;
        columnToVectors(array, type, vec);
        auto & data = assert_cast<ColumnVector<MatrixType> &>(*column).getData();
        Kernel::compute(vec, data);
    }

    template <typename MatrixType>
    void columnToVectors(const ColumnArray & array, const DataTypePtr & nested_type, std::vector<Eigen::VectorX<MatrixType>> & vec) const
    {
        switch (nested_type->getTypeId())
        {
            case TypeIndex::UInt8:
                fillVectors<MatrixType, UInt8>(vec, array);
                break;
            case TypeIndex::UInt16:
                fillVectors<MatrixType, UInt16>(vec, array);
                break;
            case TypeIndex::UInt32:
                fillVectors<MatrixType, UInt32>(vec, array);
                break;
            case TypeIndex::UInt64:
                fillVectors<MatrixType, UInt64>(vec, array);
                break;
            case TypeIndex::Int8:
                fillVectors<MatrixType, Int8>(vec, array);
                break;
            case TypeIndex::Int16:
                fillVectors<MatrixType, Int16>(vec, array);
                break;
            case TypeIndex::Int32:
                fillVectors<MatrixType, Int32>(vec, array);
                break;
            case TypeIndex::Int64:
                fillVectors<MatrixType, Int64>(vec, array);
                break;
            case TypeIndex::Float32:
                fillVectors<MatrixType, Float32>(vec, array);
                break;
            case TypeIndex::Float64:
                fillVectors<MatrixType, Float64>(vec, array);
                break;
            default:
                throw Exception(
                    ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
                    "Arguments of function {} has nested type {}. "
                    "Support: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, Float32, Float64.",
                    getName(), nested_type->getName());
        }
    }

    template <typename MatrixType, typename DataType>
    requires std::is_same_v<MatrixType, DataType>
    void fillVectors(std::vector<Eigen::VectorX<MatrixType>> & vec, const ColumnArray & array) const
    {
        const auto & data = typeid_cast<const ColumnVector<DataType> &>(array.getData()).getData();
        const auto & offsets = array.getOffsets();
        vec.reserve(offsets.size());
        ColumnArray::Offset prev = 0;
        for (auto off : offsets)
        {
            vec.emplace_back(Eigen::Map<const Eigen::VectorX<MatrixType>>(data.data() + prev, off - prev));
            prev = off;
        }
    }

    template <typename MatrixType, typename DataType>
    void fillVectors(std::vector<Eigen::VectorX<MatrixType>> & vec, const ColumnArray & array) const
    {
        const auto & data = typeid_cast<const ColumnVector<DataType> &>(array.getData()).getData();
        const auto & offsets = array.getOffsets();
        vec.reserve(offsets.size());

        ColumnArray::Offset prev = 0;
        for (auto off : offsets)
        {
            Eigen::VectorX<MatrixType> mat(off - prev);
            for (ColumnArray::Offset row = 0; row + prev < off; ++row)
            {
                mat[row] = static_cast<MatrixType>(data[prev + row]);
            }
            prev = off;
            vec.emplace_back(mat);
        }
    }
};

void registerFunctionArrayNorm(FunctionFactory & factory)
{
    factory.registerFunction<FunctionArrayNorm<LpNorm<1>>>();
    factory.registerFunction<FunctionArrayNorm<LpNorm<2>>>();
    factory.registerFunction<FunctionArrayNorm<LinfNorm>>();
}

}


#include "variables_chordal_initialization.h"
#include "srrg_solver/solver_core/variable_impl.cpp"
#include <Eigen/SVD>

namespace srrg2_hipe {
  using namespace srrg2_core;
  using namespace srrg2_solver;

  void VariableSE3ChordalInitializationRotation::applyPerturbation(const Vector9f& perturbation) {
    Matrix3f M = Matrix3f::Identity();
    M.row(0)   = perturbation.block<3, 1>(0, 0).transpose();
    M.row(1)   = perturbation.block<3, 1>(3, 0).transpose();
    M.row(2)   = perturbation.block<3, 1>(6, 0).transpose();
    _estimate.linear() += M;
    const Matrix3f& R = _estimate.linear();
    Eigen::JacobiSVD<Matrix3f> svd(R, Eigen::ComputeFullU | Eigen::ComputeFullV);
    float det_uv = (svd.matrixU() * svd.matrixV().transpose()).determinant();
    Vector3f singular_values(1.f, 1.f, det_uv);
    _estimate.linear() = svd.matrixU() * singular_values.asDiagonal() * svd.matrixV().transpose();
  }

  void
  VariableSE3ChordalInitializationTranslation::applyPerturbation(const Vector3f& perturbation) {
    _estimate.translation() += perturbation;
  }
} // namespace srrg2_hipe