//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef QTL_REGION_CLASSIFIER_HPP_
#define QTL_REGION_CLASSIFIER_HPP_

#include "qtl_allele.h"
#include "clotho/utility/random_generator.hpp"
#include "clotho/classifiers/region_classifier.hpp"

#include <boost/random/poisson_distribution.hpp>
#include <set>
#include <cmath>

#include "clotho/recombination/recombination_rate_parameter.hpp"

namespace clotho {
namespace utility {

template < class URNG >
class random_generator< URNG, clotho::classifiers::region_classifier< qtl_allele > > :
    public recombination_rate_parameter< typename qtl_allele::real_type >
{
public:
    typedef typename qtl_allele::real_type                         real_type;
    typedef recombination_rate_parameter< real_type >              base_type;
    typedef clotho::classifiers::region_classifier< qtl_allele >   result_type;
    typedef random_generator< URNG, result_type > self_type;

    typedef boost::random::uniform_01< real_type >                              uniform_type;   // key distribution
    typedef boost::random::poisson_distribution< unsigned int, real_type >      dist_type;      // region distribution

    random_generator( URNG & rng, boost::property_tree::ptree & config ) :
        base_type( config )
        , m_rng( &rng )
        , m_dist( base_type::DEFAULT_RECOMB_RATE )
        , m_bSkip(false)
    {
        initialize();
    }

    random_generator( URNG & rng, real_type  r = base_type::DEFAULT_RECOMB_RATE ) :
        base_type( r )
        , m_rng( &rng )
        , m_dist( base_type::DEFAULT_RECOMB_RATE )
        , m_bSkip( false )
    {
        initialize();
    }

    result_type operator()() {
        typename result_type::param_type p;
        unsigned int n = ((m_bSkip) ? 0 : m_dist(*m_rng) );

#ifdef USE_FAST_GENERATOR
        generate_ordered_list( p, n );
#else
        method1( p, n );
#endif  // USE_GEN_ORDERED_LIST

        return result_type(p);
    }

protected:

    void method1(typename result_type::param_type & p, unsigned int n) {
        if( n == 0 ) return;

        p.reserve( n );

        std::set< real_type > positions;
        while( positions.size() < n ) {
            positions.insert( m_uniform( *m_rng ) );
        }

        qtl_allele::trait_weights coeff;
        for( std::set< real_type >::iterator it = positions.begin(); it != positions.end(); ++it ) {
            p.push_back( qtl_allele( *it, DEFAULT_SELECTION, DEFAULT_DOMINANCE, DEFAULT_NEUTRAL, 0, coeff) );
        }
    }

    // Linear generation of ordered random allele locations
    // @article{Bentley:1980:GSL:355900.355907,
    //  author = {Bentley, Jon Louis and Saxe, James B.},
    //  title = {Generating Sorted Lists of Random Numbers},
    //  journal = {ACM Trans. Math. Softw.},
    //  issue_date = {Sept. 1980},
    //  volume = {6},
    //  number = {3},
    //  month = sep,
    //  year = {1980},
    //  issn = {0098-3500},
    //  pages = {359--364},
    //  numpages = {6},
    //  url = {http://doi.acm.org/10.1145/355900.355907},
    //  doi = {10.1145/355900.355907},
    //  acmid = {355907},
    //  publisher = {ACM},
    //  address = {New York, NY, USA},
    //  }
    void generate_ordered_list( typename result_type::param_type & p, unsigned int N ) {
        if( N == 0 ) return;

        p.reserve( N );

        real_type curmax = 0.0;
        qtl_allele::trait_weights coeff;
        while( N ) {
            // generates list in reverse order
            // hence taking the complement
            curmax += (log( m_uniform( *m_rng ) ) / (real_type)(N));
            p.push_back( qtl_allele( (1.0 - exp(curmax)), DEFAULT_SELECTION, DEFAULT_DOMINANCE, DEFAULT_NEUTRAL, 0, coeff) );
            --N;
        }
    }

    void initialize(  ) {
        m_bSkip = (m_rho <= 0.0);

        if( !m_bSkip ) {
            typename dist_type::param_type p( m_rho );
            m_dist.param( p );
        }
    }

    URNG        * m_rng;
    uniform_type    m_uniform;
    dist_type       m_dist;
    bool        m_bSkip;
};

}   // namespace utility {
}   // namespace clotho {

#endif  // QTL_REGION_CLASSIFIER_HPP_


// test_nc_chi_squared.cpp

// Copyright John Maddock 2008.

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

#include <pch.hpp>

#ifdef _MSC_VER
#pragma warning (disable:4127 4512)
#endif

#if !defined(TEST_FLOAT) && !defined(TEST_DOUBLE) && !defined(TEST_LDOUBLE) && !defined(TEST_REAL_CONCEPT)
#  define TEST_FLOAT
#  define TEST_DOUBLE
#  define TEST_LDOUBLE
#  define TEST_REAL_CONCEPT
#endif

#include <boost/math/concepts/real_concept.hpp> // for real_concept
#include <boost/math/distributions/non_central_chi_squared.hpp> // for chi_squared_distribution
#include <boost/math/special_functions/cbrt.hpp> // for chi_squared_distribution
#include <boost/test/test_exec_monitor.hpp> // for test_main
#include <boost/test/results_collector.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp> // for BOOST_CHECK_CLOSE

#include "functor.hpp"
#include "handle_test_result.hpp"
#include "test_nccs_hooks.hpp"

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

#define BOOST_CHECK_CLOSE_EX(a, b, prec, i) \
   {\
      unsigned int failures = boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed;\
      BOOST_CHECK_CLOSE(a, b, prec); \
      if(failures != boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed)\
      {\
         std::cerr << "Failure was at row " << i << std::endl;\
         std::cerr << std::setprecision(35); \
         std::cerr << "{ " << data[i][0] << " , " << data[i][1] << " , " << data[i][2];\
         std::cerr << " , " << data[i][3] << " , " << data[i][4] << " } " << std::endl;\
      }\
   }

#define BOOST_CHECK_EX(a, i) \
   {\
      unsigned int failures = boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed;\
      BOOST_CHECK(a); \
      if(failures != boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed)\
      {\
         std::cerr << "Failure was at row " << i << std::endl;\
         std::cerr << std::setprecision(35); \
         std::cerr << "{ " << data[i][0] << " , " << data[i][1] << " , " << data[i][2];\
         std::cerr << " , " << data[i][3] << " , " << data[i][4] << " } " << std::endl;\
      }\
   }

void expected_results()
{
   //
   // Define the max and mean errors expected for
   // various compilers and platforms.
   //
   const char* largest_type;
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
   if(boost::math::policies::digits<double, boost::math::policies::policy<> >() == boost::math::policies::digits<long double, boost::math::policies::policy<> >())
   {
      largest_type = "(long\\s+)?double|real_concept";
   }
   else
   {
      largest_type = "long double|real_concept";
   }
#else
   largest_type = "(long\\s+)?double|real_concept";
#endif

   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "Mac OS",                          // platform
      largest_type,                     // test type(s)
      "[^|]*medium[^|]*",                   // test data group
      "[^|]*", 550, 100);                  // test function
   //
   // Catch all cases come last:
   //
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*medium[^|]*",                   // test data group
      "[^|]*", 350, 100);                  // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*large[^|]*",                   // test data group
      "[^|]*", 17000, 3000);                  // test function

   //
   // Allow some long double error to creep into
   // the double results:
   //
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "double",                         // test type(s)
      "[^|]*",                   // test data group
      "[^|]*", 3, 2);                  // test function

   //
   // Finish off by printing out the compiler/stdlib/platform names,
   // we do this to make it easier to mark up expected error rates.
   //
   std::cout << "Tests run with " << BOOST_COMPILER << ", "
      << BOOST_STDLIB << ", " << BOOST_PLATFORM << std::endl;
}

template <class RealType>
RealType naive_pdf(RealType v, RealType lam, RealType x)
{
   // Formula direct from
   // http://mathworld.wolfram.com/NoncentralChi-SquaredDistribution.html
   // with no simplification:
   RealType sum, term, prefix(1);
   RealType eps = boost::math::tools::epsilon<RealType>();
   term = sum = pdf(boost::math::chi_squared_distribution<RealType>(v), x);
   for(int i = 1;; ++i)
   {
      prefix *= lam / (2 * i);
      term = prefix * pdf(boost::math::chi_squared_distribution<RealType>(v + 2 * i), x);
      sum += term;
      if(term / sum < eps)
         break;
   }
   return sum * exp(-lam/2);
}

template <class RealType>
void test_spot(
     RealType df,    // Degrees of freedom
     RealType ncp,   // non-centrality param
     RealType cs,    // Chi Square statistic
     RealType P,     // CDF
     RealType Q,     // Complement of CDF
     RealType tol)   // Test tolerance
{
   boost::math::non_central_chi_squared_distribution<RealType> dist(df, ncp);
   BOOST_CHECK_CLOSE(
      cdf(dist, cs), P, tol);
   try{
      BOOST_CHECK_CLOSE(
         pdf(dist, cs), naive_pdf(dist.degrees_of_freedom(), ncp, cs), tol * 150);
   }
   catch(const std::overflow_error&)
   {}
   if((P < 0.99) && (Q < 0.99))
   {
      //
      // We can only check this if P is not too close to 1,
      // so that we can guarentee Q is reasonably free of error:
      //
      BOOST_CHECK_CLOSE(
         cdf(complement(dist, cs)), Q, tol);
      BOOST_CHECK_CLOSE(
            quantile(dist, P), cs, tol * 10);
      BOOST_CHECK_CLOSE(
            quantile(complement(dist, Q)), cs, tol * 10);
      BOOST_CHECK_CLOSE(
         dist.find_degrees_of_freedom(ncp, cs, P), df, tol * 10);
      BOOST_CHECK_CLOSE(
         dist.find_degrees_of_freedom(boost::math::complement(ncp, cs, Q)), df, tol * 10);
      BOOST_CHECK_CLOSE(
         dist.find_non_centrality(df, cs, P), ncp, tol * 10);
      BOOST_CHECK_CLOSE(
         dist.find_non_centrality(boost::math::complement(df, cs, Q)), ncp, tol * 10);
   }
}

template <class RealType> // Any floating-point type RealType.
void test_spots(RealType)
{
   RealType tolerance = (std::max)(
      boost::math::tools::epsilon<RealType>(),
      (RealType)boost::math::tools::epsilon<double>() * 5) * 150;
   //
   // At float precision we need to up the tolerance, since
   // the input values are rounded off to inexact quantities
   // the results get thrown off by a noticeable amount.
   //
   if(boost::math::tools::digits<RealType>() < 50)
      tolerance *= 50;
   if(boost::is_floating_point<RealType>::value != 1)
      tolerance *= 20; // real_concept special functions are less accurate

   cout << "Tolerance = " << tolerance << "%." << endl;

   using boost::math::chi_squared_distribution;
   using  ::boost::math::chi_squared;
   using  ::boost::math::cdf;
   using  ::boost::math::pdf;
   //
   // Test against the data from Table 6 of:
   //
   // "Self-Validating Computations of Probabilities for Selected
   // Central and Noncentral Univariate Probability Functions."
   // Morgan C. Wang; William J. Kennedy
   // Journal of the American Statistical Association,
   // Vol. 89, No. 427. (Sep., 1994), pp. 878-887.
   //
   test_spot(
      static_cast<RealType>(1),   // degrees of freedom
      static_cast<RealType>(6),   // non centrality
      static_cast<RealType>(0.00393),   // Chi Squared statistic
      static_cast<RealType>(0.2498463724258039e-2),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.2498463724258039e-2),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(5),   // degrees of freedom
      static_cast<RealType>(1),   // non centrality
      static_cast<RealType>(9.23636),   // Chi Squared statistic
      static_cast<RealType>(0.8272918751175548),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.8272918751175548),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(11),   // degrees of freedom
      static_cast<RealType>(21),   // non centrality
      static_cast<RealType>(24.72497),   // Chi Squared statistic
      static_cast<RealType>(0.2539481822183126),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.2539481822183126),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(31),   // degrees of freedom
      static_cast<RealType>(6),   // non centrality
      static_cast<RealType>(44.98534),   // Chi Squared statistic
      static_cast<RealType>(0.8125198785064969),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.8125198785064969),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(51),   // degrees of freedom
      static_cast<RealType>(1),   // non centrality
      static_cast<RealType>(38.56038),   // Chi Squared statistic
      static_cast<RealType>(0.8519497361859118e-1),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.8519497361859118e-1),           // Q = 1 - P
      tolerance * 2);
   test_spot(
      static_cast<RealType>(100),   // degrees of freedom
      static_cast<RealType>(16),   // non centrality
      static_cast<RealType>(82.35814),   // Chi Squared statistic
      static_cast<RealType>(0.1184348822747824e-1),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.1184348822747824e-1),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(300),   // degrees of freedom
      static_cast<RealType>(16),   // non centrality
      static_cast<RealType>(331.78852),   // Chi Squared statistic
      static_cast<RealType>(0.7355956710306709),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.7355956710306709),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(500),   // degrees of freedom
      static_cast<RealType>(21),   // non centrality
      static_cast<RealType>(459.92612),   // Chi Squared statistic
      static_cast<RealType>(0.2797023600800060e-1),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.2797023600800060e-1),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(1),   // degrees of freedom
      static_cast<RealType>(1),   // non centrality
      static_cast<RealType>(0.00016),   // Chi Squared statistic
      static_cast<RealType>(0.6121428929881423e-2),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.6121428929881423e-2),           // Q = 1 - P
      tolerance);
   test_spot(
      static_cast<RealType>(1),   // degrees of freedom
      static_cast<RealType>(1),   // non centrality
      static_cast<RealType>(0.00393),   // Chi Squared statistic
      static_cast<RealType>(0.3033814229753780e-1),       // Probability of result (CDF), P
      static_cast<RealType>(1-0.3033814229753780e-1),           // Q = 1 - P
      tolerance);

   RealType tol2 = boost::math::tools::epsilon<RealType>() * 5 * 100; // 5 eps as a percentage
   boost::math::non_central_chi_squared_distribution<RealType> dist(static_cast<RealType>(8), static_cast<RealType>(12));
   RealType x = 7;
   using namespace std; // ADL of std names.
   // mean:
   BOOST_CHECK_CLOSE(
      mean(dist)
      , static_cast<RealType>(8+12), tol2);
   // variance:
   BOOST_CHECK_CLOSE(
      variance(dist)
      , static_cast<RealType>(64), tol2);
   // std deviation:
   BOOST_CHECK_CLOSE(
      standard_deviation(dist)
      , static_cast<RealType>(8), tol2);
   // hazard:
   BOOST_CHECK_CLOSE(
      hazard(dist, x)
      , pdf(dist, x) / cdf(complement(dist, x)), tol2);
   // cumulative hazard:
   BOOST_CHECK_CLOSE(
      chf(dist, x)
      , -log(cdf(complement(dist, x))), tol2);
   // coefficient_of_variation:
   BOOST_CHECK_CLOSE(
      coefficient_of_variation(dist)
      , standard_deviation(dist) / mean(dist), tol2);
   // mode:
   BOOST_CHECK_CLOSE(
      mode(dist)
      , static_cast<RealType>(17.184201184730857030170788677340294070728990862663L), sqrt(tolerance * 500));
   BOOST_CHECK_CLOSE(
      median(dist),
      quantile(
      boost::math::non_central_chi_squared_distribution<RealType>(
         static_cast<RealType>(8),
         static_cast<RealType>(12)),
      static_cast<RealType>(0.5)), static_cast<RealType>(tol2));
   // skewness:
   BOOST_CHECK_CLOSE(
      skewness(dist)
      , static_cast<RealType>(0.6875), tol2);
   // kurtosis:
   BOOST_CHECK_CLOSE(
      kurtosis(dist)
      , static_cast<RealType>(3.65625), tol2);
   // kurtosis excess:
   BOOST_CHECK_CLOSE(
      kurtosis_excess(dist)
      , static_cast<RealType>(0.65625), tol2);
} // template <class RealType>void test_spots(RealType)

template <class T>
T nccs_cdf(T df, T nc, T x)
{
   return cdf(boost::math::non_central_chi_squared_distribution<T>(df, nc), x);
}

template <class T>
T nccs_ccdf(T df, T nc, T x)
{
   return cdf(complement(boost::math::non_central_chi_squared_distribution<T>(df, nc), x));
}

template <typename T>
void do_test_nc_chi_squared(T& data, const char* type_name, const char* test)
{
   typedef typename T::value_type row_type;
   typedef typename row_type::value_type value_type;

   std::cout << "Testing: " << test << std::endl;

   value_type (*fp1)(value_type, value_type, value_type) = nccs_cdf;
   boost::math::tools::test_result<value_type> result;

   result = boost::math::tools::test(
      data,
      bind_func(fp1, 0, 1, 2),
      extract_result(3));
   handle_test_result(result, data[result.worst()], result.worst(),
      type_name, "CDF", test);

   fp1 = nccs_ccdf;
   result = boost::math::tools::test(
      data,
      bind_func(fp1, 0, 1, 2),
      extract_result(4));
   handle_test_result(result, data[result.worst()], result.worst(),
      type_name, "CCDF", test);

#ifdef TEST_OTHER
   fp1 = other::nccs_cdf;
   result = boost::math::tools::test(
      data,
      bind_func(fp1, 0, 1, 2),
      extract_result(3));
   handle_test_result(result, data[result.worst()], result.worst(),
      type_name, "other::CDF", test);
#endif

   std::cout << std::endl;

}

template <typename T>
void quantile_sanity_check(T& data, const char* type_name, const char* test)
{
   typedef typename T::value_type row_type;
   typedef typename row_type::value_type value_type;

   //
   // Tests with type real_concept take rather too long to run, so
   // for now we'll disable them:
   //
   if(!boost::is_floating_point<value_type>::value)
      return;

   std::cout << "Testing: " << type_name << " quantile sanity check, with tests " << test << std::endl;

   //
   // These sanity checks test for a round trip accuracy of one half
   // of the bits in T, unless T is type float, in which case we check
   // for just one decimal digit.  The problem here is the sensitivity
   // of the functions, not their accuracy.  This test data was generated
   // for the forward functions, which means that when it is used as
   // the input to the inverses then it is necessarily inexact.  This rounding
   // of the input is what makes the data unsuitable for use as an accuracy check,
   // and also demonstrates that you can't in general round-trip these functions.
   // It is however a useful sanity check.
   //
   value_type precision = static_cast<value_type>(ldexp(1.0, 1-boost::math::policies::digits<value_type, boost::math::policies::policy<> >()/2)) * 100;
   if(boost::math::policies::digits<value_type, boost::math::policies::policy<> >() < 50)
      precision = 1;   // 1% or two decimal digits, all we can hope for when the input is truncated to float

   for(unsigned i = 0; i < data.size(); ++i)
   {
      if(data[i][3] == 0)
      {
         BOOST_CHECK(0 == quantile(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), data[i][3]));
      }
      else if(data[i][3] < 0.9999f)
      {
         value_type p = quantile(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), data[i][3]);
         value_type pt = data[i][2];
         BOOST_CHECK_CLOSE_EX(pt, p, precision, i);
      }
      if(data[i][4] == 0)
      {
         BOOST_CHECK(0 == quantile(complement(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), data[i][3])));
      }
      else if(data[i][4] < 0.9999f)
      {
         value_type p = quantile(complement(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), data[i][4]));
         value_type pt = data[i][2];
         BOOST_CHECK_CLOSE_EX(pt, p, precision, i);
      }
      if(boost::math::tools::digits<value_type>() > 50)
      {
         //
         // Sanity check mode, the accuracy of
         // the mode is at *best* the square root of the accuracy of the PDF:
         //
         try{
            value_type m = mode(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]));
            value_type p = pdf(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), m);
            BOOST_CHECK_EX(pdf(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), m * (1 + sqrt(precision) * 50)) <= p, i);
            BOOST_CHECK_EX(pdf(boost::math::non_central_chi_squared_distribution<value_type>(data[i][0], data[i][1]), m * (1 - sqrt(precision)) * 50) <= p, i);
         }
         catch(const boost::math::evaluation_error& ) {}
         //
         // Sanity check degrees-of-freedom finder, don't bother at float
         // precision though as there's not enough data in the probability
         // values to get back to the correct degrees of freedom or
         // non-cenrality parameter:
         //
         try{
            if((data[i][3] < 0.99) && (data[i][3] != 0))
            {
               BOOST_CHECK_CLOSE_EX(
                  boost::math::non_central_chi_squared_distribution<value_type>::find_degrees_of_freedom(data[i][1], data[i][2], data[i][3]),
                  data[i][0], precision, i);
               BOOST_CHECK_CLOSE_EX(
                  boost::math::non_central_chi_squared_distribution<value_type>::find_non_centrality(data[i][0], data[i][2], data[i][3]),
                  data[i][1], precision, i);
            }
            if((data[i][4] < 0.99) && (data[i][4] != 0))
            {
               BOOST_CHECK_CLOSE_EX(
                  boost::math::non_central_chi_squared_distribution<value_type>::find_degrees_of_freedom(boost::math::complement(data[i][1], data[i][2], data[i][4])),
                  data[i][0], precision, i);
               BOOST_CHECK_CLOSE_EX(
                  boost::math::non_central_chi_squared_distribution<value_type>::find_non_centrality(boost::math::complement(data[i][0], data[i][2], data[i][4])),
                  data[i][1], precision, i);
            }
         }
         catch(const std::exception& e)
         {
            BOOST_ERROR(e.what());
         }
      }
   }
}

template <typename T>
void test_accuracy(T, const char* type_name)
{
#include "nccs.ipp"
    do_test_nc_chi_squared(nccs, type_name, "Non Central Chi Squared, medium parameters");
    quantile_sanity_check(nccs, type_name, "Non Central Chi Squared, medium parameters");

#include "nccs_big.ipp"
    do_test_nc_chi_squared(nccs_big, type_name, "Non Central Chi Squared, large parameters");
    quantile_sanity_check(nccs_big, type_name, "Non Central Chi Squared, large parameters");
}

int test_main(int, char* [])
{
   BOOST_MATH_CONTROL_FP;
   // Basic sanity-check spot values.
   expected_results();
   // (Parameter value, arbitrarily zero, only communicates the floating point type).
#ifdef TEST_FLOAT
   test_spots(0.0F); // Test float.
#endif
#ifdef TEST_DOUBLE
   test_spots(0.0); // Test double.
#endif
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#ifdef TEST_LDOUBLE
   test_spots(0.0L); // Test long double.
#endif
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
#ifdef TEST_REAL_CONCEPT
   test_spots(boost::math::concepts::real_concept(0.)); // Test real concept.
#endif
#endif
#endif

#ifdef TEST_FLOAT
   test_accuracy(0.0F, "float"); // Test float.
#endif
#ifdef TEST_DOUBLE
   test_accuracy(0.0, "double"); // Test double.
#endif
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#ifdef TEST_LDOUBLE
   test_accuracy(0.0L, "long double"); // Test long double.
#endif
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
#ifdef TEST_REAL_CONCEPT
   test_accuracy(boost::math::concepts::real_concept(0.), "real_concept"); // Test real concept.
#endif
#endif
#endif
   return 0;
} // int test_main(int, char* [])


/**
 * @file
 * @brief Shows how the classes in the namespace lf::io can be used.
 * @author Raffael Casagrande
 * @date   2018-09-02 02:44:15
 * @copyright MIT License
 */

#include <lf/io/io.h>
#include <lf/mesh/hybrid2d/hybrid2d.h>
#include <lf/mesh/utils/utils.h>
#include <boost/filesystem.hpp>
#include "lf/mesh/utils/lambda_mesh_data_set.h"

int main() {
  // Find path to the smiley mesh
  boost::filesystem::path here = __FILE__;
  auto smiley_path = here.parent_path() / "smiley.msh";

  // load the smiley mesh
  auto mesh_factory = std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
  lf::io::GmshReader reader(std::move(mesh_factory), smiley_path.string());

  // print all physical entities:
  std::cout << "Physical Entities in Gmsh File " << std::endl;
  std::cout
      << "---------------------------------------------------------------\n";
  for (lf::base::dim_t codim = 0; codim <= 2; ++codim) {
    for (auto& pair : reader.PhysicalEntities(codim)) {
      std::cout << "codim = " << static_cast<int>(codim) << ": " << pair.first
                << " <=> " << pair.second << std::endl;
    }
  }
  std::cout << std::endl << std::endl;

  // count the number of elements in the eyes:
  int num_eye_elements = 0;
  auto mesh = reader.mesh();
  auto physical_entity_nr_eyes = reader.PhysicalEntityName2Nr("eyes");
  for (auto e : mesh->Entities(0)) {
    if (reader.IsPhysicalEntity(*e, physical_entity_nr_eyes)) {
      ++num_eye_elements;
    }
  }
  std::cout << "Number of eye elements : " << num_eye_elements << std::endl;

  // count the number of edges that form the mouth
  int num_mouth_edges = 0;
  auto physical_entity_nr_mouth = reader.PhysicalEntityName2Nr("mouth");
  for (auto e : mesh->Entities(1)) {
    if (reader.IsPhysicalEntity(*e, physical_entity_nr_mouth)) {
      ++num_mouth_edges;
    }
  }
  std::cout << "Number of mouth edges : " << num_mouth_edges << std::endl;

  // count the total number of elements in the face (including eyes)
  int num_face_elements = 0;
  auto physical_entity_nr_face = reader.PhysicalEntityName2Nr("face");
  for (auto e : mesh->Entities(0)) {
    if (reader.IsPhysicalEntity(*e, physical_entity_nr_face)) {
      ++num_face_elements;
    }
  }
  std::cout << "Number of face elements : " << num_face_elements << std::endl;

  // Start vtk output:
  lf::io::VtkWriter vtk_writer(mesh, "smiley.vtk");

  // write a cell-based function that takes the value 1 on the eyes and 0
  // everywhere else
  vtk_writer.WriteCellData(
      "eyes", *lf::mesh::utils::make_LambdaMeshDataSet([&](const auto& e) {
        return static_cast<int>(
            reader.IsPhysicalEntity(e, physical_entity_nr_eyes));
      }));

  // write nodal data that takes the value 2 on the eyes and 1 on the mouth,
  // zero everywhere else.
  auto mds = lf::mesh::utils::make_CodimMeshDataSet<int>(mesh, 2, 0);
  // mark the eyes
  for (auto e : mesh->Entities(0)) {
    if (reader.IsPhysicalEntity(*e, physical_entity_nr_eyes)) {
      for (auto node : e->SubEntities(2)) {
        mds->operator()(*node) = 2;
      }
    }
  }
  // mark the mouth
  for (auto e : mesh->Entities(1)) {
    if (reader.IsPhysicalEntity(*e, physical_entity_nr_mouth)) {
      for (auto node : e->SubEntities(1)) {
        mds->operator()(*node) = 1;
      }
    }
  }
  vtk_writer.WritePointData("smile", *mds);

  // write a node based, vector valued function that points to the nose:
  auto origin = Eigen::MatrixXd::Zero(0, 1);
  vtk_writer.WritePointData(
      "nose_vec", *lf::mesh::utils::make_LambdaMeshDataSet([&](const auto& n) {
        return Eigen::Vector2d(-n.Geometry()->Global(origin));
      }));
}


//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// 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)
//=======================================================================

/*
  This file implements the function

  template <class VertexAndEdgeListGraph, class DistanceMatrix,
            class P, class T, class R>
  bool
  johnson_all_pairs_shortest_paths
    (VertexAndEdgeListGraph& g,
     DistanceMatrix& D,
     const bgl_named_params<P, T, R>& params)
 */

#ifndef BOOST_GRAPH_JOHNSON_HPP
#define BOOST_GRAPH_JOHNSON_HPP

#include <boost/graph/graph_traits.hpp>
#include <boost/property_map.hpp>
#include <boost/graph/bellman_ford_shortest_paths.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/pending/ct_if.hpp>
#include <boost/type_traits/same_traits.hpp>

namespace boost {

  /*template <class VertexAndEdgeListGraph, class DistanceMatrix,
            class VertexID, class Weight, typename BinaryPredicate,
            typename BinaryFunction, typename Infinity, class DistanceZero>
  bool
  johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g1,
               DistanceMatrix& D,
               VertexID id1, Weight w1, const BinaryPredicate& compare,
               const BinaryFunction& combine, const Infinity& inf,
               DistanceZero zero)
  {
    typedef graph_traits<VertexAndEdgeListGraph> Traits1;
    typedef typename property_traits<Weight>::value_type DT;
    function_requires< BasicMatrixConcept<DistanceMatrix,
      typename Traits1::vertices_size_type, DT> >();

    typedef typename Traits1::directed_category DirCat;
    bool is_undirected = is_same<DirCat, undirected_tag>::value;

    typedef adjacency_list<vecS, vecS, directedS,
      property< vertex_distance_t, DT>,
      property< edge_weight_t, DT,
      property< edge_weight2_t, DT > > > Graph2;
    typedef graph_traits<Graph2> Traits2;

    Graph2 g2(num_vertices(g1) + 1);
    typename property_map<Graph2, edge_weight_t>::type
      w = get(edge_weight, g2);
    typename property_map<Graph2, edge_weight2_t>::type
      w_hat = get(edge_weight2, g2);
    typename property_map<Graph2, vertex_distance_t>::type
      d = get(vertex_distance, g2);
    typedef typename property_map<Graph2, vertex_index_t>::type VertexID2;
    VertexID2 id2 = get(vertex_index, g2);

    // Construct g2 where V[g2] = V[g1] U {s}
    //   and  E[g2] = E[g1] U {(s,v)| v in V[g1]}
    std::vector<typename Traits1::vertex_descriptor>
      verts1(num_vertices(g1) + 1);
    typename Traits2::vertex_descriptor s = *vertices(g2).first;
    {
      typename Traits1::vertex_iterator v, v_end;
      int i = 1;
      for (tie(v, v_end) = vertices(g1); v != v_end; ++v, ++i) {
        typename Traits2::edge_descriptor e; bool z;
        tie(e, z) = add_edge(s, get(id1, *v) + 1, g2);
        put(w, e, zero);
        verts1[i] = *v;
      }
      typename Traits1::edge_iterator e, e_end;
      for (tie(e, e_end) = edges(g1); e != e_end; ++e) {
        typename Traits2::edge_descriptor e2; bool z;
        tie(e2, z) = add_edge(get(id1, source(*e, g1)) + 1,
                              get(id1, target(*e, g1)) + 1, g2);
        put(w, e2, get(w1, *e));
        if (is_undirected) {
          tie(e2, z) = add_edge(get(id1, target(*e, g1)) + 1,
                                get(id1, source(*e, g1)) + 1, g2);
          put(w, e2, get(w1, *e));
        }
      }
    }
    typename Traits2::vertex_iterator v, v_end, u, u_end;
    typename Traits2::edge_iterator e, e_end;
    std::vector<DT> h_vec(num_vertices(g2));
    typedef typename std::vector<DT>::iterator iter_t;
    iterator_property_map<iter_t,VertexID2,DT,DT&> h(h_vec.begin(), id2);

    for (tie(v, v_end) = vertices(g2); v != v_end; ++v)
      d[*v] = inf;

    put(d, s, zero);
    // Using the non-named parameter versions of bellman_ford and
    // dijkstra for portability reasons.
    dummy_property_map pred; bellman_visitor<> bvis;
    if (bellman_ford_shortest_paths
        (g2, num_vertices(g2), w, pred, d, combine, compare, bvis)) {
      for (tie(v, v_end) = vertices(g2); v != v_end; ++v)
        put(h, *v, get(d, *v));
      // Reweight the edges to remove negatives
      for (tie(e, e_end) = edges(g2); e != e_end; ++e) {
        typename Traits2::vertex_descriptor a = source(*e, g2),
          b = target(*e, g2);
        put(w_hat, *e, get(w, *e) + get(h, a) - get(h, b));
      }
      for (tie(u, u_end) = vertices(g2); u != u_end; ++u) {
        dijkstra_visitor<> dvis;
        dijkstra_shortest_paths
          (g2, *u, pred, d, w_hat, id2, compare, combine, inf, zero,dvis);
        for (tie(v, v_end) = vertices(g2); v != v_end; ++v) {
          if (*u != s && *v != s) {
            typename Traits1::vertex_descriptor u1, v1;
            u1 = verts1[id2[*u]]; v1 = verts1[id2[*v]];
            D[id2[*u]-1][id2[*v]-1] = get(d, *v) + get(h, *v) - get(h, *u);
          }
        }
      }
      return true;
    } else
      return false;
  }*/

  namespace detail {
    template <class VertexAndEdgeListGraph, class VertexIDMap,
      class WeightMap, typename DistanceZero>
    struct single_source_vertex_graph {
      VertexAndEdgeListGraph& _g;
      VertexIDMap _id;
      WeightMap _w;
      DistanceZero _zero;
      single_source_vertex_graph(VertexAndEdgeListGraph& g,
        VertexIDMap id, WeightMap w, DistanceZero zero)
        : _g(g), _id(id), _w(w), _zero(zero) {}
    };
    template <class Vertex, class Weight>
    struct ssv_graph_edge
        : std::pair<Vertex,Vertex> {
      Weight _w;
      ssv_graph_edge() {}
      ssv_graph_edge(Vertex s, Vertex t, Weight w) :
        std::pair<Vertex,Vertex>(s,t), _w(w) {}
      //ssv_graph_edge(const ssv_graph_edge& e): _w(e._w) {}
    };
    template <class VertexAndEdgeListGraph, class EdgeIter,
      class VertexIDMap, class WeightMap, class Edge, typename DistanceZero>
    class ssv_edge_iter :
      public iterator_facade<
        ssv_edge_iter<VertexAndEdgeListGraph,EdgeIter,
          VertexIDMap,WeightMap,Edge,DistanceZero>,
        Edge,
        forward_traversal_tag,
        Edge>
    {
      typedef typename property_traits<VertexIDMap>::value_type src_iter;
      bool _iter_source;
      EdgeIter _ei, _eiend;
      src_iter _si,_siend;
      VertexAndEdgeListGraph *_g;
      VertexIDMap _id;
      WeightMap _w;
      DistanceZero _zero;
    public:
      ssv_edge_iter() {}
      ssv_edge_iter(bool iter_source, src_iter si, src_iter siend,
        EdgeIter ei, EdgeIter eiend, VertexAndEdgeListGraph& g,
        VertexIDMap id, WeightMap w, DistanceZero zero)
        : _iter_source(iter_source), _si(si), _siend(siend),
        _ei(ei), _eiend(ei), _g(&g), _id(id), _w(w), _zero(zero) {}
      ssv_edge_iter(const ssv_edge_iter& sei)
          : _iter_source(sei._iter_source), _si(sei._si), _siend(sei._siend),
          _ei(sei._ei), _eiend(sei._eiend), _g(sei._g), _id(sei._id),
          _w(sei._w), _zero(sei._zero) {}

    private:
      friend class boost::iterator_core_access;
      inline void increment() {
          if (_iter_source) {
              ++_si;
              if ( _si == _siend) { _iter_source = false; }
          } else if (_ei != _eiend) {
              ++_ei;
          }
      }
      inline Edge dereference() const {
          if (_iter_source) { return Edge(0,_si,_zero); }
          else { return Edge(_id[source(*_ei,*_g)]+1,_id[target(*_ei,*_g)]+1,_w[*_ei]); }
      }
      inline bool equal(const ssv_edge_iter& other) const {
          return (_iter_source == other._iter_source &&
                 _si == other._si && _ei == other._ei);
      }
    };
    template <class VertexAndEdgeListGraph, class VertexIDMap,
      class WeightMap, typename DistanceZero>
    struct ssv_graph_help {
      typedef VertexAndEdgeListGraph native_graph;
      typedef graph_traits<VertexAndEdgeListGraph> native_traits;
      typedef typename native_traits::edge_iterator native_edge_iterator;
      typedef detail::ssv_graph_edge<
        typename property_traits<VertexIDMap>::value_type,
        typename property_traits<WeightMap>::value_type > edge;
      typedef typename ssv_edge_iter<native_graph, native_edge_iterator,
          VertexIDMap, WeightMap, edge, DistanceZero> edge_iterator;
      typedef std::pair<edge_iterator, edge_iterator> edges_ret_type;
      typedef typename native_traits::edges_size_type num_edges_ret_type;
    };
    template <class Vertex, class Weight>
    class ssv_edge_weight_map {};
  }

  template <class VertexAndEdgeListGraph, class VertexIDMap,
    class WeightMap, typename DistanceZero>
  struct graph_traits< detail::single_source_vertex_graph<
      VertexAndEdgeListGraph, VertexIDMap, WeightMap, DistanceZero> > {
    typedef edge_list_graph_tag traversal_category;
    typedef directed_tag directed_category;
    typedef typename graph_traits<VertexAndEdgeListGraph>::edge_parallel_category
        edge_parallel_category;
    typedef typename graph_traits<VertexAndEdgeListGraph>::edges_size_type
        edges_size_type;
    typedef typename property_traits<VertexIDMap>::value_type vertex_descriptor;
    typedef detail::ssv_graph_edge<vertex_descriptor,
        typename property_traits<WeightMap>::value_type> edge_descriptor;
    typedef detail::ssv_graph_help<VertexAndEdgeListGraph,
      VertexIDMap, WeightMap, DistanceZero> helper;
    typedef typename helper::edge_iterator edge_iterator;
    static vertex_descriptor null_vertex() {
        return std::numeric_limits<vertex_descriptor>::max(); }
  };

  /*template <class Vertex, class Weight, class Graph>
  Vertex source(detail::ssv_graph_edge<Vertex,Weight> e, Graph&)
  { return e._s; }
  template <class Vertex, class Weight, class Graph>
  Vertex target(detail::ssv_graph_edge<Vertex,Weight> e, Graph&)
  { return e._t; }*/
  template <class VertexAndEdgeListGraph, class VertexIDMap,
    class WeightMap, typename DistanceZero>
  typename detail::ssv_graph_help<
    VertexAndEdgeListGraph,
    VertexIDMap, WeightMap, DistanceZero>::edges_ret_type
  edges(const detail::single_source_vertex_graph<
          VertexAndEdgeListGraph, VertexIDMap, WeightMap, DistanceZero>& g) {
    typedef detail::single_source_vertex_graph<
          VertexAndEdgeListGraph, VertexIDMap, WeightMap, DistanceZero> graph;
    typedef typename graph_traits<VertexAndEdgeListGraph>::edge_iterator native_ei;
    native_ei ei,eiend;
    tie(ei,eiend) = edges(g._g);
    return std::make_pair(
        graph_traits<graph>::edge_iterator(true, 1, num_vertices(g._g)+1,
            ei, eiend, g._g, g._id, g._w, g._zero),
        graph_traits<graph>::edge_iterator(false, num_vertices(g._g)+1,
            num_vertices(g._g)+1, eiend, eiend, g._g, g._id, g._w, g._zero));
  }
  template <class VertexAndEdgeListGraph, class VertexIDMap,
    class WeightMap, typename DistanceZero>
  typename detail::ssv_graph_help<
    VertexAndEdgeListGraph, VertexIDMap,
      WeightMap, DistanceZero>::num_edges_ret_type
  num_edges(const detail::single_source_vertex_graph<
              VertexAndEdgeListGraph, VertexIDMap, WeightMap, DistanceZero>& g) {
    return num_edges(g._g) + num_vertices(g._g);
  }

  template <class Vertex, class Weight>
  Weight get(const detail::ssv_edge_weight_map<Vertex,Weight>&,
    detail::ssv_graph_edge<Vertex,Weight>& e)
  { return e._w; }

  template <class Vertex, class Weight>
  struct property_traits<detail::ssv_edge_weight_map<Vertex,Weight> > {
    typedef readable_property_map_tag category;
    typedef Weight value_type;
    typedef detail::ssv_graph_edge<Vertex,Weight> key_type;
    typedef value_type reference;
  };

  template <class VertexAndEdgeListGraph, class DistanceMatrix,
            class VertexID, class Weight, typename BinaryPredicate,
            typename BinaryFunction, typename Infinity, class DistanceZero>
  bool
  johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g1,
               DistanceMatrix& D,
               VertexID id1, Weight w1, const BinaryPredicate& compare,
               const BinaryFunction& combine, const Infinity& inf,
               DistanceZero zero)
  {
    typedef detail::single_source_vertex_graph<VertexAndEdgeListGraph,
        VertexID,Weight,DistanceZero> graph_ssv;

    typedef typename property_traits<Weight>::value_type DT;

    graph_ssv gssv(g1, id1, w1, zero);

    std::vector<DT> d_vec(num_vertices(g1)+1, inf);
    std::vector<DT> h_vec(num_vertices(g1)+1);
    typedef typename std::vector<DT>::iterator iter_t;
    iterator_property_map<iter_t,identity_property_map,DT,DT&>
        d(d_vec.begin(), identity_property_map());
    iterator_property_map<iter_t,identity_property_map,DT,DT&>
        h(h_vec.begin(), identity_property_map());

    detail::ssv_edge_weight_map<graph_traits<graph_ssv>::vertex_descriptor,
        property_traits<Weight>::value_type> w2;

    dummy_property_map pred; bellman_visitor<> bvis;
    if (bellman_ford_shortest_paths
      (gssv, num_vertices(g1)+1, w2, pred, d, combine, compare, bvis))
    {
        return true;
    } else
      return false;
    /*typedef graph_traits<VertexAndEdgeListGraph> Traits1;
    typedef typename property_traits<Weight>::value_type DT;
    function_requires< BasicMatrixConcept<DistanceMatrix,
      typename Traits1::vertices_size_type, DT> >();

    typedef typename Traits1::directed_category DirCat;
    bool is_undirected = is_same<DirCat, undirected_tag>::value;

    typedef adjacency_list<vecS, vecS, directedS,
      property< vertex_distance_t, DT>,
      property< edge_weight_t, DT,
      property< edge_weight2_t, DT > > > Graph2;
    typedef graph_traits<Graph2> Traits2;

    Graph2 g2(num_vertices(g1) + 1);
    typename property_map<Graph2, edge_weight_t>::type
      w = get(edge_weight, g2);
    typename property_map<Graph2, edge_weight2_t>::type
      w_hat = get(edge_weight2, g2);
    typename property_map<Graph2, vertex_distance_t>::type
      d = get(vertex_distance, g2);
    typedef typename property_map<Graph2, vertex_index_t>::type VertexID2;
    VertexID2 id2 = get(vertex_index, g2);

    // Construct g2 where V[g2] = V[g1] U {s}
    //   and  E[g2] = E[g1] U {(s,v)| v in V[g1]}
    std::vector<typename Traits1::vertex_descriptor>
      verts1(num_vertices(g1) + 1);
    typename Traits2::vertex_descriptor s = *vertices(g2).first;
    {
      typename Traits1::vertex_iterator v, v_end;
      int i = 1;
      for (tie(v, v_end) = vertices(g1); v != v_end; ++v, ++i) {
        typename Traits2::edge_descriptor e; bool z;
        tie(e, z) = add_edge(s, get(id1, *v) + 1, g2);
        put(w, e, zero);
        verts1[i] = *v;
      }
      typename Traits1::edge_iterator e, e_end;
      for (tie(e, e_end) = edges(g1); e != e_end; ++e) {
        typename Traits2::edge_descriptor e2; bool z;
        tie(e2, z) = add_edge(get(id1, source(*e, g1)) + 1,
                              get(id1, target(*e, g1)) + 1, g2);
        put(w, e2, get(w1, *e));
        if (is_undirected) {
          tie(e2, z) = add_edge(get(id1, target(*e, g1)) + 1,
                                get(id1, source(*e, g1)) + 1, g2);
          put(w, e2, get(w1, *e));
        }
      }
    }
    typename Traits2::vertex_iterator v, v_end, u, u_end;
    typename Traits2::edge_iterator e, e_end;
    std::vector<DT> h_vec(num_vertices(g2));
    typedef typename std::vector<DT>::iterator iter_t;
    iterator_property_map<iter_t,VertexID2,DT,DT&> h(h_vec.begin(), id2);

    for (tie(v, v_end) = vertices(g2); v != v_end; ++v)
      d[*v] = inf;

    put(d, s, zero);
    // Using the non-named parameter versions of bellman_ford and
    // dijkstra for portability reasons.
    dummy_property_map pred; bellman_visitor<> bvis;
    if (bellman_ford_shortest_paths
        (g2, num_vertices(g2), w, pred, d, combine, compare, bvis)) {
      for (tie(v, v_end) = vertices(g2); v != v_end; ++v)
        put(h, *v, get(d, *v));
      // Reweight the edges to remove negatives
      for (tie(e, e_end) = edges(g2); e != e_end; ++e) {
        typename Traits2::vertex_descriptor a = source(*e, g2),
          b = target(*e, g2);
        put(w_hat, *e, get(w, *e) + get(h, a) - get(h, b));
      }
      for (tie(u, u_end) = vertices(g2); u != u_end; ++u) {
        dijkstra_visitor<> dvis;
        dijkstra_shortest_paths
          (g2, *u, pred, d, w_hat, id2, compare, combine, inf, zero,dvis);
        for (tie(v, v_end) = vertices(g2); v != v_end; ++v) {
          if (*u != s && *v != s) {
            typename Traits1::vertex_descriptor u1, v1;
            u1 = verts1[id2[*u]]; v1 = verts1[id2[*v]];
            D[id2[*u]-1][id2[*v]-1] = get(d, *v) + get(h, *v) - get(h, *u);
          }
        }
      }
      return true;
    } else
      return false;*/
  }

  template <class VertexAndEdgeListGraph, class DistanceMatrix,
            class VertexID, class Weight, class DistanceZero>
  bool
  johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g1,
               DistanceMatrix& D,
               VertexID id1, Weight w1, DistanceZero zero)
  {
    typedef typename property_traits<Weight>::value_type WT;
    return johnson_all_pairs_shortest_paths(g1, D, id1, w1,
                                            std::less<WT>(),
                                            closed_plus<WT>(),
                                            (std::numeric_limits<WT>::max)(),
                                            zero);
  }

  namespace detail {

    template <class VertexAndEdgeListGraph, class DistanceMatrix,
              class P, class T, class R, class Weight,
              class VertexID>
    bool
    johnson_dispatch(VertexAndEdgeListGraph& g,
                     DistanceMatrix& D,
                     const bgl_named_params<P, T, R>& params,
                     Weight w, VertexID id)
    {
      typedef typename property_traits<Weight>::value_type WT;

      return johnson_all_pairs_shortest_paths
        (g, D, id, w,
        choose_param(get_param(params, distance_compare_t()),
          std::less<WT>()),
        choose_param(get_param(params, distance_combine_t()),
          closed_plus<WT>()),
        choose_param(get_param(params, distance_inf_t()),
          std::numeric_limits<WT>::max BOOST_PREVENT_MACRO_SUBSTITUTION()),
         choose_param(get_param(params, distance_zero_t()), WT()) );
    }

  } // namespace detail

  template <class VertexAndEdgeListGraph, class DistanceMatrix,
            class P, class T, class R>
  bool
  johnson_all_pairs_shortest_paths
    (VertexAndEdgeListGraph& g,
     DistanceMatrix& D,
     const bgl_named_params<P, T, R>& params)
  {
    return detail::johnson_dispatch
      (g, D, params,
       choose_const_pmap(get_param(params, edge_weight), g, edge_weight),
       choose_const_pmap(get_param(params, vertex_index), g, vertex_index)
       );
  }

  template <class VertexAndEdgeListGraph, class DistanceMatrix>
  bool
  johnson_all_pairs_shortest_paths
    (VertexAndEdgeListGraph& g, DistanceMatrix& D)
  {
    bgl_named_params<int,int> params(1);
    return detail::johnson_dispatch
      (g, D, params, get(edge_weight, g), get(vertex_index, g));
  }

} // namespace boost

#endif // BOOST_GRAPH_JOHNSON_HPP


#include <NTL/ZZ_pX.h>

#include <cstdio>

NTL_CLIENT

double clean_data(double *t)
{
   double x, y, z;
   long i, ix, iy, n;

   x = t[0]; ix = 0;
   y = t[0]; iy = 0;

   for (i = 1; i < 5; i++) {
      if (t[i] < x) {
         x = t[i];
         ix = i;
      }
      if (t[i] > y) {
         y = t[i];
         iy = i;
      }
   }

   z = 0; n = 0;
   for (i = 0; i < 5; i++) {
      if (i != ix && i != iy) z+= t[i], n++;
   }

   z = z/n;

   return z;
}

void print_flag()
{

#if (defined(NTL_CRT_ALTCODE))
printf("CRT_ALTCODE ");
#else
printf("DEFAULT ");
#endif

printf("\n");

}

int main()
{

   SetSeed(ZZ(0));

   long n, k;

   n = 1024;
   k = 30*NTL_SP_NBITS;

   ZZ p;

   RandomLen(p, k);
   if (!IsOdd(p)) p++;

   ZZ_p::init(p);         // initialization

   ZZ_pX f, g, h, r1, r2, r3;

   random(g, n);    // g = random polynomial of degree < n
   random(h, n);    // h =             "   "
   random(f, n);    // f =             "   "

   SetCoeff(f, n);  // Sets coefficient of X^n to 1

   // For doing arithmetic mod f quickly, one must pre-compute
   // some information.

   ZZ_pXModulus F;
   build(F, f);

   PlainMul(r1, g, h);  // this uses classical arithmetic
   PlainRem(r1, r1, f);

   MulMod(r2, g, h, F);  // this uses the FFT

   MulMod(r3, g, h, f);  // uses FFT, but slower

   // compare the results...

   if (r1 != r2) {
      printf("999999999999999 ");
      print_flag();
      return 0;
   }
   else if (r1 != r3) {
      printf("999999999999999 ");
      print_flag();
      return 0;
   }

   double t;
   long i;
   long iter;

   ZZ_pX a, b, c;
   random(a, n);
   random(b, n);
   long da = deg(a);
   long db = deg(b);
   long dc = da + db;
   long l = NextPowerOfTwo(dc+1);

   FFTRep arep, brep, crep;
   ToFFTRep(arep, a, l, 0, da);
   ToFFTRep(brep, b, l, 0, db);

   mul(crep, arep, brep);

   ZZ_pXModRep modrep;
   FromFFTRep(modrep, crep);

   FromZZ_pXModRep(c, modrep, 0, dc);

   iter = 1;

   do {
     t = GetTime();
     for (i = 0; i < iter; i++) {
        FromZZ_pXModRep(c, modrep, 0, dc);
     }
     t = GetTime() - t;
     iter = 2*iter;
   } while(t < 1);

   iter = iter/2;

   iter = long((3/t)*iter) + 1;

   double tvec[5];
   long w;

   for (w = 0; w < 5; w++) {
     t = GetTime();
     for (i = 0; i < iter; i++) {
        FromZZ_pXModRep(c, modrep, 0, dc);
     }
     t = GetTime() - t;
     tvec[w] = t;
   }

   t = clean_data(tvec);

   t = floor((t/iter)*1e12);

   if (t < 0 || t >= 1e15)
      printf("999999999999999 ");
   else
      printf("%015.0f ", t);

   printf(" [%ld] ", iter);

   print_flag();

   return 0;
}


// Copyright (c) 2019 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.

#include <utilstrencodings.h>
#include <test/test_bitcoin.h>
#include <zelcash/NoteEncryption.hpp>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(convertbits_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(convertbits_deterministic)
{
    for (size_t i = 0; i < 256; i++) {
        std::vector<unsigned char> input(32, i);
        std::vector<unsigned char> data;
        std::vector<unsigned char> output;
        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, input.begin(), input.end());
        ConvertBits<5, 8, false>([&](unsigned char c) { output.push_back(c); }, data.begin(), data.end());
        BOOST_CHECK_EQUAL(data.size(), 52);
        BOOST_CHECK_EQUAL(output.size(), 32);
        BOOST_CHECK(input == output);
    }

    for (size_t i = 0; i < 256; i++) {
        std::vector<unsigned char> input(43, i);
        std::vector<unsigned char> data;
        std::vector<unsigned char> output;
        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, input.begin(), input.end());
        ConvertBits<5, 8, false>([&](unsigned char c) { output.push_back(c); }, data.begin(), data.end());
        BOOST_CHECK_EQUAL(data.size(), 69);
        BOOST_CHECK_EQUAL(output.size(), 43);
        BOOST_CHECK(input == output);
    }
}

BOOST_AUTO_TEST_CASE(convertbits_random)
{
    for (size_t i = 0; i < 1000; i++) {
        auto input = libzelcash::random_uint256();
        std::vector<unsigned char> data;
        std::vector<unsigned char> output;
        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, input.begin(), input.end());
        ConvertBits<5, 8, false>([&](unsigned char c) { output.push_back(c); }, data.begin(), data.end());
        BOOST_CHECK_EQUAL(data.size(), 52);
        BOOST_CHECK_EQUAL(output.size(), 32);
        BOOST_CHECK(input == uint256(output));
    }
}

BOOST_AUTO_TEST_SUITE_END()


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

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

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

/**
 * @file    testNavState.cpp
 * @brief   Unit tests for NavState
 * @author  Frank Dellaert
 * @date    July 2015
 */

#include <gtsam/navigation/NavState.h>
#include <gtsam/base/TestableAssertions.h>
#include <gtsam/base/numericalDerivative.h>

#include <boost/bind/bind.hpp>
#include <CppUnitLite/TestHarness.h>

using namespace std::placeholders;
using namespace std;
using namespace gtsam;

static const Rot3 kAttitude = Rot3::RzRyRx(0.1, 0.2, 0.3);
static const Point3 kPosition(1.0, 2.0, 3.0);
static const Pose3 kPose(kAttitude, kPosition);
static const Velocity3 kVelocity(0.4, 0.5, 0.6);
static const NavState kIdentity;
static const NavState kState1(kAttitude, kPosition, kVelocity);
static const Vector3 kOmegaCoriolis(0.02, 0.03, 0.04);
static const Vector3 kGravity(0, 0, 9.81);
static const Vector9 kZeroXi = Vector9::Zero();

/* ************************************************************************* */
TEST(NavState, Constructor) {
  std::function<NavState(const Rot3&, const Point3&, const Vector3&)> create =
      std::bind(&NavState::Create, std::placeholders::_1, std::placeholders::_2,
                std::placeholders::_3, boost::none, boost::none, boost::none);
  Matrix aH1, aH2, aH3;
  EXPECT(
      assert_equal(kState1,
          NavState::Create(kAttitude, kPosition, kVelocity, aH1, aH2, aH3)));
  EXPECT(
      assert_equal(
          numericalDerivative31(create, kAttitude, kPosition, kVelocity), aH1));
  EXPECT(
      assert_equal(
          numericalDerivative32(create, kAttitude, kPosition, kVelocity), aH2));
  EXPECT(
      assert_equal(
          numericalDerivative32(create, kAttitude, kPosition, kVelocity), aH2));
}

/* ************************************************************************* */
TEST(NavState, Constructor2) {
  std::function<NavState(const Pose3&, const Vector3&)> construct =
      std::bind(&NavState::FromPoseVelocity, std::placeholders::_1,
                std::placeholders::_2, boost::none, boost::none);
  Matrix aH1, aH2;
  EXPECT(
      assert_equal(kState1,
          NavState::FromPoseVelocity(kPose, kVelocity, aH1, aH2)));
  EXPECT(assert_equal(numericalDerivative21(construct, kPose, kVelocity), aH1));
  EXPECT(assert_equal(numericalDerivative22(construct, kPose, kVelocity), aH2));
}

/* ************************************************************************* */
TEST( NavState, Attitude) {
  Matrix39 aH, eH;
  Rot3 actual = kState1.attitude(aH);
  EXPECT(assert_equal(actual, kAttitude));
  eH = numericalDerivative11<Rot3, NavState>(
      std::bind(&NavState::attitude, std::placeholders::_1, boost::none), kState1);
  EXPECT(assert_equal((Matrix )eH, aH));
}

/* ************************************************************************* */
TEST( NavState, Position) {
  Matrix39 aH, eH;
  Point3 actual = kState1.position(aH);
  EXPECT(assert_equal(actual, kPosition));
  eH = numericalDerivative11<Point3, NavState>(
      std::bind(&NavState::position, std::placeholders::_1, boost::none),
      kState1);
  EXPECT(assert_equal((Matrix )eH, aH));
}

/* ************************************************************************* */
TEST( NavState, Velocity) {
  Matrix39 aH, eH;
  Velocity3 actual = kState1.velocity(aH);
  EXPECT(assert_equal(actual, kVelocity));
  eH = numericalDerivative11<Velocity3, NavState>(
      std::bind(&NavState::velocity, std::placeholders::_1, boost::none),
      kState1);
  EXPECT(assert_equal((Matrix )eH, aH));
}

/* ************************************************************************* */
TEST( NavState, BodyVelocity) {
  Matrix39 aH, eH;
  Velocity3 actual = kState1.bodyVelocity(aH);
  EXPECT(assert_equal<Velocity3>(actual, kAttitude.unrotate(kVelocity)));
  eH = numericalDerivative11<Velocity3, NavState>(
      std::bind(&NavState::bodyVelocity, std::placeholders::_1, boost::none),
      kState1);
  EXPECT(assert_equal((Matrix )eH, aH));
}

/* ************************************************************************* */
TEST( NavState, Manifold ) {
  // Check zero xi
  EXPECT(assert_equal(kIdentity, kIdentity.retract(kZeroXi)));
  EXPECT(assert_equal(kZeroXi, kIdentity.localCoordinates(kIdentity)));
  EXPECT(assert_equal(kState1, kState1.retract(kZeroXi)));
  EXPECT(assert_equal(kZeroXi, kState1.localCoordinates(kState1)));

  // Check definition of retract as operating on components separately
  Vector9 xi;
  xi << 0.1, 0.1, 0.1, 0.2, 0.3, 0.4, -0.1, -0.2, -0.3;
  Rot3 drot = Rot3::Expmap(xi.head<3>());
  Point3 dt = Point3(xi.segment<3>(3));
  Velocity3 dvel = Velocity3(-0.1, -0.2, -0.3);
  NavState state2 = NavState(kState1.attitude() * drot,
      kState1.position() + kState1.attitude() * dt,
      kState1.velocity() + kState1.attitude() * dvel);
  EXPECT(assert_equal(state2, kState1.retract(xi)));
  EXPECT(assert_equal(xi, kState1.localCoordinates(state2)));

  // roundtrip from state2 to state3 and back
  NavState state3 = state2.retract(xi);
  EXPECT(assert_equal(xi, state2.localCoordinates(state3)));

  // Check retract derivatives
  Matrix9 aH1, aH2;
  kState1.retract(xi, aH1, aH2);
  std::function<NavState(const NavState&, const Vector9&)> retract =
      std::bind(&NavState::retract, std::placeholders::_1,
                std::placeholders::_2, boost::none, boost::none);
  EXPECT(assert_equal(numericalDerivative21(retract, kState1, xi), aH1));
  EXPECT(assert_equal(numericalDerivative22(retract, kState1, xi), aH2));

  // Check retract derivatives on state 2
  const Vector9 xi2 = -3.0*xi;
  state2.retract(xi2, aH1, aH2);
  EXPECT(assert_equal(numericalDerivative21(retract, state2, xi2), aH1));
  EXPECT(assert_equal(numericalDerivative22(retract, state2, xi2), aH2));

  // Check localCoordinates derivatives
  std::function<Vector9(const NavState&, const NavState&)> local =
      std::bind(&NavState::localCoordinates, std::placeholders::_1,
                std::placeholders::_2, boost::none, boost::none);
  // from state1 to state2
  kState1.localCoordinates(state2, aH1, aH2);
  EXPECT(assert_equal(numericalDerivative21(local, kState1, state2), aH1));
  EXPECT(assert_equal(numericalDerivative22(local, kState1, state2), aH2));
  // from identity to state2
  kIdentity.localCoordinates(state2, aH1, aH2);
  EXPECT(assert_equal(numericalDerivative21(local, kIdentity, state2), aH1));
  EXPECT(assert_equal(numericalDerivative22(local, kIdentity, state2), aH2));
  // from state2 to identity
  state2.localCoordinates(kIdentity, aH1, aH2);
  EXPECT(assert_equal(numericalDerivative21(local, state2, kIdentity), aH1));
  EXPECT(assert_equal(numericalDerivative22(local, state2, kIdentity), aH2));
}

/* ************************************************************************* */
static const double dt = 2.0;
std::function<Vector9(const NavState&, const bool&)> coriolis =
    std::bind(&NavState::coriolis, std::placeholders::_1, dt, kOmegaCoriolis,
              std::placeholders::_2, boost::none);

TEST(NavState, Coriolis) {
  Matrix9 aH;

  // first-order
  kState1.coriolis(dt, kOmegaCoriolis, false, aH);
  EXPECT(assert_equal(numericalDerivative21(coriolis, kState1, false), aH));
  // second-order
  kState1.coriolis(dt, kOmegaCoriolis, true, aH);
  EXPECT(assert_equal(numericalDerivative21(coriolis, kState1, true), aH));
}

TEST(NavState, Coriolis2) {
  Matrix9 aH;
  NavState state2(Rot3::RzRyRx(M_PI / 12.0, M_PI / 6.0, M_PI / 4.0),
      Point3(5.0, 1.0, -50.0), Vector3(0.5, 0.0, 0.0));

  // first-order
  state2.coriolis(dt, kOmegaCoriolis, false, aH);
  EXPECT(assert_equal(numericalDerivative21(coriolis, state2, false), aH));
  // second-order
  state2.coriolis(dt, kOmegaCoriolis, true, aH);
  EXPECT(assert_equal(numericalDerivative21(coriolis, state2, true), aH));
}

TEST(NavState, Coriolis3) {
  /** Consider a massless planet with an attached nav frame at
   *  n_omega = [0 0 1]', and a body at position n_t = [1 0 0]', travelling with
   *  velocity n_v = [0 1 0]'. Orient the body so that it is not instantaneously
   *  aligned with the nav frame (i.e., nRb != I_3x3). Test that first and
   *  second order Coriolis corrections are as expected.
   */

  // Get true first and second order coriolis accelerations
  double dt = 2.0, dt2 = dt * dt;
  Vector3 n_omega(0.0, 0.0, 1.0), n_t(1.0, 0.0, 0.0), n_v(0.0, 1.0, 0.0);
  Vector3 n_aCorr1 = -2.0 * n_omega.cross(n_v),
          n_aCorr2 = -n_omega.cross(n_omega.cross(n_t));
  Rot3 nRb = Rot3(-1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0),
       bRn = nRb.inverse();

  // Get expected first and second order corrections in the nav frame
  Vector3 n_dP1e = 0.5 * dt2 * n_aCorr1,
          n_dP2e = 0.5 * dt2 * (n_aCorr1 + n_aCorr2),
          n_dV1e = dt * n_aCorr1,
          n_dV2e = dt * (n_aCorr1 + n_aCorr2);

  // Get expected first and second order corrections in the body frame
  Vector3 dRe = -dt * (bRn * n_omega),
          b_dP1e = bRn * n_dP1e, b_dP2e = bRn * n_dP2e,
          b_dV1e = bRn * n_dV1e, b_dV2e = bRn * n_dV2e;

  // Get actual first and scond order corrections in body frame
  NavState kState2(nRb, n_t, n_v);
  Vector9 dXi1a = kState2.coriolis(dt, n_omega, false),
          dXi2a = kState2.coriolis(dt, n_omega, true);
  Vector3 dRa = NavState::dR(dXi1a),
          b_dP1a = NavState::dP(dXi1a), b_dV1a = NavState::dV(dXi1a),
          b_dP2a = NavState::dP(dXi2a), b_dV2a = NavState::dV(dXi2a);

  EXPECT(assert_equal(dRe, dRa));
  EXPECT(assert_equal(b_dP1e, b_dP1a));
  EXPECT(assert_equal(b_dV1e, b_dV1a));
  EXPECT(assert_equal(b_dP2e, b_dP2a));
  EXPECT(assert_equal(b_dV2e, b_dV2a));

}

/* ************************************************************************* */
TEST(NavState, CorrectPIM) {
  Vector9 xi;
  xi << 0.1, 0.1, 0.1, 0.2, 0.3, 0.4, -0.1, -0.2, -0.3;
  double dt = 0.5;
  Matrix9 aH1, aH2;
  std::function<Vector9(const NavState&, const Vector9&)> correctPIM =
      std::bind(&NavState::correctPIM, std::placeholders::_1,
                std::placeholders::_2, dt, kGravity, kOmegaCoriolis, false,
                boost::none, boost::none);
  kState1.correctPIM(xi, dt, kGravity, kOmegaCoriolis, false, aH1, aH2);
  EXPECT(assert_equal(numericalDerivative21(correctPIM, kState1, xi), aH1));
  EXPECT(assert_equal(numericalDerivative22(correctPIM, kState1, xi), aH2));
}

/* ************************************************************************* */
TEST(NavState, Stream)
{
  NavState state;

  std::ostringstream os;
  os << state;

  string expected;
  expected = "R: [\n\t1, 0, 0;\n\t0, 1, 0;\n\t0, 0, 1\n]\np: 0 0 0\nv: 0 0 0";

  EXPECT(os.str() == expected);
}

/* ************************************************************************* */
int main() {
  TestResult tr;
  return TestRegistry::runAllTests(tr);
}
/* ************************************************************************* */


#ifndef pear_eigen_ext_hpp
#define pear_eigen_ext_hpp

#include <fstream>
#include <iostream>
#include <vector>

#include <Eigen/Core>

namespace pear {
template <typename T1, typename T2, typename T3>
T1 extract(const T2 &full, const T3 &ind) {
  int num_indices = ind.innerSize();
  T1 target(num_indices);
  for (int i = 0; i < num_indices; i++) {
    target[i] = full[ind[i]];
  }
  return target;
}

template <typename M> M load_csv(const std::string &path) {
  std::ifstream indata;
  indata.open(path);
  std::string line;
  std::vector<typename M::Scalar> values;
  uint64_t rows = 0;
  while (std::getline(indata, line)) {
    std::stringstream lineStream(line);
    std::string cell;
    while (std::getline(lineStream, cell, ',')) {
      values.push_back(std::stod(cell));
    }
    ++rows;
  }
  return Eigen::Map<
      const Eigen::Matrix<typename M::Scalar, M::RowsAtCompileTime,
                          M::ColsAtCompileTime, Eigen::RowMajor>>(
      values.data(), rows, values.size() / rows);
}

template <typename M> void write_csv(const std::string &path, M &matrix) {
  std::ofstream file(path.c_str());

  for (int i = 0; i < matrix.rows(); i++) {
    for (int j = 0; j < matrix.cols(); j++) {
      std::string str = std::to_string(matrix(i, j));
      if (j + 1 == matrix.cols()) {
        file << str;
      } else {
        file << str << ',';
      }
    }
    file << '\n';
  }
}

} // namespace pear

#endif


/**
 * Copyright (c) 2013 Jonan Cruz-Martin
 *
 * Distributed under the terms of the MIT license, see the accompanying
 * file COPYING or http://opensource.org/licenses/MIT.
 *
 * @file
 * @brief Implement calculation of the volume of a cell.
 */

#ifndef ALGORHITHMS_CELL_VOLUME_HPP
#define ALGORHITHMS_CELL_VOLUME_HPP

#include <boost/python.hpp>
using namespace boost::python;

#include "../points/cartesian.hpp"
#include "../points/cylindrical.hpp"
#include "../points/polar.hpp"
#include "../points/spherical.hpp"

#include "../cells/linear.hpp"
#include "../cells/triangular.hpp"
#include "../cells/quadrilateral.hpp"
#include "../cells/tetrahedral.hpp"

////////////
// Linear //
////////////

/**
 * Calculate the volume of a linear cartesian 1D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double LinearCartesian1D_Cell_volume(LinearCartesian1D_Cell cell);

/**
 * Calculate the volume of a linear cartesian 2D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double LinearCartesian2D_Cell_volume(LinearCartesian2D_Cell cell);

/**
 * Calculate the volume of a linear cartesian 3D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double LinearCartesian3D_Cell_volume(LinearCartesian3D_Cell cell);

/**
 * Calculate the volume of a linear cylindrical cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double LinearCylindrical3D_Cell_volume(LinearCylindrical3D_Cell cell);

/**
 * Calculate the volume of a linear polar cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double LinearPolar2D_Cell_volume(LinearPolar2D_Cell cell);

/**
 * Calculate the volume of a linear spherical cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double LinearSpherical3D_Cell_volume(LinearSpherical3D_Cell cell);

////////////////
// Triangular //
////////////////

/**
 * Calculate the volume of a triangular cartesian 2D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TriangularCartesian2D_Cell_volume(TriangularCartesian2D_Cell cell);

/**
 * Calculate the volume of a triangular cartesian 3D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TriangularCartesian3D_Cell_volume(TriangularCartesian3D_Cell cell);

/**
 * Calculate the volume of a triangular cylindrical cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TriangularCylindrical3D_Cell_volume(TriangularCylindrical3D_Cell cell);

/**
 * Calculate the volume of a triangular polar cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TriangularPolar2D_Cell_volume(TriangularPolar2D_Cell cell);

/**
 * Calculate the volume of a triangular spherical cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TriangularSpherical3D_Cell_volume(TriangularSpherical3D_Cell cell);

///////////////////
// Quadrilateral //
///////////////////

/**
 * Calculate the volume of a quadrilateral cartesian 2D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double QuadrilateralCartesian2D_Cell_volume(QuadrilateralCartesian2D_Cell cell);

/**
 * Calculate the volume of a quadrilateral cartesian 3D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double QuadrilateralCartesian3D_Cell_volume(QuadrilateralCartesian3D_Cell cell);

/**
 * Calculate the volume of a quadrilateral cylindrical cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double QuadrilateralCylindrical3D_Cell_volume(QuadrilateralCylindrical3D_Cell cell);

/**
 * Calculate the volume of a quadrilateral polar cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double QuadrilateralPolar2D_Cell_volume(QuadrilateralPolar2D_Cell cell);

/**
 * Calculate the volume of a quadrilateral sphericalº cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double QuadrilateralSpherical3D_Cell_volume(QuadrilateralSpherical3D_Cell cell);

/////////////////
// Tetrahedral //
/////////////////

/**
 * Calculate the volume of a tetrahedral cartesian 3D cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TetrahedralCartesian3D_Cell_volume(TetrahedralCartesian3D_Cell cell);

/**
 * Calculate the volume of a tetrahedral cylindrical cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TetrahedralCylindrical3D_Cell_volume(TetrahedralCylindrical3D_Cell cell);

/**
 * Calculate the volume of a tetrahedral sphericalº cell.
 *
 * @param cell Cell whose volume will be computed.
 * @return Real number in double precision which represents the volume of the cell.
 *
 * @since 0.1.0
 */
double TetrahedralSpherical3D_Cell_volume(TetrahedralSpherical3D_Cell cell);

#endif /* end of include guard: ALGORHITHMS_CELL_VOLUME_HPP */


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>

#include <opengm/utilities/metaprogramming.hxx>
#include <opengm/graphicalmodel/graphicalmodel.hxx>
#include <opengm/graphicalmodel/graphicalmodel_hdf5.hxx>
#include <opengm/operations/multiplier.hxx>
#include <opengm/operations/adder.hxx>
#include <opengm/functions/explicit_function.hxx>
#include <opengm/functions/potts.hxx>
#include <opengm/functions/pottsn.hxx>
#include <opengm/functions/pottsg.hxx>
#include <opengm/functions/truncated_absolute_difference.hxx>
#include <opengm/functions/truncated_squared_difference.hxx>

#include <boost/shared_ptr.hpp>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

struct ConverterDispatcher {
   virtual void exec(
      std::string sourceFileName,
      std::string destinationFileName,
      std::string inputModelName,
      std::string outputModelName,
      size_t maxCacheEntries,
      bool verbose
      ) = 0;
};

template<class ValueType, class OperationType>
struct ConcreteConverterDispatcher : ConverterDispatcher {
   virtual void exec(
      std::string sourceFileName,
      std::string destinationFileName,
      std::string inputModelName,
      std::string outputModelName,
      size_t maxCacheEntries,
      bool verbose
   ) {
      typedef size_t LabelType;
      typedef size_t IndexType;
      typedef opengm::GraphicalModel<
         ValueType,
         OperationType,
         typename opengm::meta::TypeListGenerator< opengm::ExplicitFunction<ValueType> >::type,
         opengm::DiscreteSpace<IndexType, LabelType>,
         false
      > GmType;
      typedef opengm::ExplicitFunction<ValueType> ExplicitFunctionType;
      typedef typename GmType::FunctionIdentifier FunctionIdentifier;

      hid_t file = marray::hdf5::openFile(sourceFileName,
         marray::hdf5::READ_ONLY,
         marray::hdf5::DEFAULT_HDF5_VERSION);

      marray::Marray<ValueType> in;
      marray::hdf5::load(file, inputModelName, in);

      size_t numberOfVariables = static_cast<IndexType>(in(0));
      size_t numberOfFactors = static_cast<IndexType>(in(1));
      GmType gm(opengm::DiscreteSpace<IndexType, LabelType >(&in(2), &in(2+numberOfVariables) ));
      //std::vector<size_t> stateSpaceDimension(&in(2), &in(2+numberOfVariables));
      //GmType gm(stateSpaceDimension.begin(), stateSpaceDimension.end());

      std::vector<std::pair<ExplicitFunctionType, FunctionIdentifier> > cache;

      size_t p = 2+numberOfVariables-1;
      for(size_t j=0; j<numberOfFactors; ++j) {
         ++p;
         size_t numberOfVariablesOfFactor = static_cast<IndexType>(in(p));
         std::vector<IndexType> variableIndicesOfFactor(numberOfVariablesOfFactor);
         std::vector<LabelType> variableDimensionsOfFactor(numberOfVariablesOfFactor);
         size_t tableSize = 1;
         for(size_t k=0; k<numberOfVariablesOfFactor; ++k) {
            ++p;
            variableIndicesOfFactor[k] = static_cast<IndexType>(in(p));
            variableDimensionsOfFactor[k] = gm.numberOfLabels(variableIndicesOfFactor[k]);
            tableSize *= gm.numberOfLabels(variableIndicesOfFactor[k]);
            //variableDimensionsOfFactor[k] = stateSpaceDimension[variableIndicesOfFactor[k]];
            //tableSize *= stateSpaceDimension[variableIndicesOfFactor[k]];
         }
         ExplicitFunctionType ef(variableDimensionsOfFactor.begin(),variableDimensionsOfFactor.end());
         for(size_t k=0; k<tableSize; ++k) {
            ++p;
            ef(k) = in(p);
         }

         // Optionally try to be a bit smarter here and
         // match pairwise or higher factors that were already encountered
         // (usually corresponding to a regularizer)
         if (numberOfVariablesOfFactor >= 2) {
            // linear scan (perhaps replace by some tree structured thing some time...) of the cache
            bool found=false;
            for (size_t ci=0; ci<cache.size(); ++ci) {
               if (cache[ci].first.size() == ef.size()) {
                  if (std::equal(cache[ci].first.begin(), cache[ci].first.end(), ef.begin())) {
                     found = true;
                     gm.addFactor(cache[ci].second, variableIndicesOfFactor.begin(), variableIndicesOfFactor.end());
                     break;
                  }
               }
            }
            if (found) {
               if (verbose)
                  std::cout << "H";
               continue;
            } else {
               if (verbose)
                  std::cout << ".";
            }
         }
         FunctionIdentifier fi = gm.addFunction(ef);
         if(numberOfVariablesOfFactor >= 2 && cache.size() < maxCacheEntries) {
            // keep cache reasonably small
            cache.push_back(std::make_pair(ef, fi));
         }
         gm.addFactor(fi, variableIndicesOfFactor.begin(), variableIndicesOfFactor.end());
      }
      OPENGM_ASSERT(p == in.size()-1);
      opengm::hdf5::save(gm, destinationFileName, outputModelName);
      marray::hdf5::closeFile(file);
      if (verbose)
         std::cout << std::endl
         << "Done, converted " << numberOfFactors << " factors in "
         << numberOfVariables << " variables"
         << " using " << cache.size() << " cache entries for aggregation."
         << std::endl;
   }
};

int main(int argc, char** argv) {
   po::options_description desc("OpenGM legacy HDF5 model file converter");
   desc.add_options()
      ("help,h", "output help message")
      ("verbose,v", "verbose operation")
      ("input", po::value<std::string>(), "source model file (in old HDF5 format) to process")
      ("output", po::value<std::string>(), "target model file to write result to (in new HDF5 format)")
      ("additive,a", "assume additive (log-domain/energy-like) potentials (default)")
      ("multiplicative,m", "assume multiplicative (probability) potentials")
      ("compress,c", po::value<size_t>()->default_value(10), "cache N pairwise/higher-order potentials to match and aggregate (e.g. regularizer terms)")
      ("inputmodelname", po::value<std::string>()->default_value("model"), "name of input model within file")
      ("outputmodelname", po::value<std::string>()->default_value("model"), "name of output model within file")
      ("type", po::value<std::string>()->default_value("double"), "type code (value type of input)")
      ;

   po::variables_map vm;
   po::positional_options_description posopt;
   posopt.add("input", 1);
   posopt.add("output", 1);

   try {
      po::store(po::command_line_parser(argc, argv).
         options(desc).positional(posopt).run(), vm);
      po::notify(vm);
   } catch (po::unknown_option &e) {
      std::cerr << e.what() << std::endl;
      std::cerr << desc << std::endl;
      return 1;
   }
   bool minargs = (vm.count("input") > 0) && (vm.count("output") > 0);

   if (!minargs || vm.count("help")) {
      std::cerr << desc << std::endl;
      return 1;
   }
   const bool verbose = vm.count("verbose") > 0;

   const std::string sourceFileName(vm["input"].as<std::string>());
   const std::string destinationFileName(vm["output"].as<std::string>());

   const std::string inputModelName(vm["inputmodelname"].as<std::string>());
   const std::string outputModelName(vm["outputmodelname"].as<std::string>());
   const size_t maxCacheEntries(vm["compress"].as<size_t>());

   const bool multiplicative = vm.count("multiplicative");
   const bool additive = vm.count("additive");
   if (multiplicative && additive) {
      std::cerr << "Error: conflicting options." << std::endl;
      std::cerr << desc << std::endl;
      return 1;
   }

   typedef boost::shared_ptr<ConverterDispatcher> ptr;
   std::map<std::pair<std::string, bool>, ptr > typemap;
   typemap[std::make_pair("double",false)] = ptr(new ConcreteConverterDispatcher<double, opengm::Adder>());
   typemap[std::make_pair("float",false)] = ptr(new ConcreteConverterDispatcher<float, opengm::Adder>());
   typemap[std::make_pair("int",false)] = ptr(new ConcreteConverterDispatcher<int, opengm::Adder>());
   typemap[std::make_pair("double",true)] = ptr(new ConcreteConverterDispatcher<double, opengm::Multiplier>());
   typemap[std::make_pair("float",true)] = ptr(new ConcreteConverterDispatcher<float, opengm::Multiplier>());
   typemap[std::make_pair("int",true)] = ptr(new ConcreteConverterDispatcher<int, opengm::Multiplier>());

   ptr selected = typemap[std::make_pair(vm["type"].as<std::string>(), multiplicative)];
   if (selected)
      selected->exec(sourceFileName, destinationFileName, inputModelName, outputModelName, maxCacheEntries, verbose);
   else {
      std::cerr << "Error: type " << vm["type"].as<std::string>() << " unsupported." << std::endl;
      return 1;
   }

   return 0;
}


/**
 * @file cosmo_test.cpp
 *
 * @author Samuel Farrens
 *
 * Unit tests for the methods of the Cosmo class.
 *
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE MasterTestSuite
#include <boost/test/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
#include <limits>
#include "../../src/cosmo.hpp"
#include "../../src/exceptions.hpp"

using namespace boost::unit_test;
Cosmo cosmo;

BOOST_AUTO_TEST_SUITE (Master_test_suite)

/**
 * Unit test for Cosmo::set_up.
 */
BOOST_AUTO_TEST_CASE( set_up )
{
  BOOST_CHECK_THROW( cosmo.set_up(1.1, 0.7), BadArgumentException );
  BOOST_CHECK_THROW( cosmo.set_up(-0.1, 0.7), BadArgumentException );
  BOOST_CHECK_THROW( cosmo.set_up(0.3, 1.1), BadArgumentException );
  BOOST_CHECK_THROW( cosmo.set_up(0.3, -0.1), BadArgumentException );
  BOOST_CHECK_THROW( cosmo.set_up(0.5, 0.4), DomainException );
}

/**
 * Unit test for Cosmo::angdidis.
 */
BOOST_AUTO_TEST_CASE( angdidis )
{
  BOOST_CHECK( cosmo.angdidis(0.0) == 0.0 );
  BOOST_CHECK( std::abs(cosmo.angdidis(1.0) - 0.375)
	       <= std::numeric_limits<double>::epsilon() );
}

/**
 * Unit test for Cosmo::angdidis2.
 */
BOOST_AUTO_TEST_CASE( angdidis2 )
{
  BOOST_CHECK( std::abs(cosmo.angdidis2(0.0, 1.0) - 0.375)
	       <= std::numeric_limits<double>::epsilon() );
  BOOST_CHECK_THROW( cosmo.angdidis2(1.0, 0.0), BadArgumentException );
}

/**
 * Unit test for Cosmo::comdis.
 */
BOOST_AUTO_TEST_CASE( comdis )
{
  BOOST_CHECK( cosmo.comdis(0.0) == 0.0 );
  BOOST_CHECK_THROW( cosmo.comdis(-1.0), BadArgumentException );
}

/**
 * Unit test for Cosmo::comvol.
 */
BOOST_AUTO_TEST_CASE( comvol )
{
  BOOST_CHECK( cosmo.comvol(0.0) == 0.0 );
}

/**
 * Unit test for Cosmo::dcomdisdz.
 */
BOOST_AUTO_TEST_CASE( dcomdisdz )
{
  BOOST_CHECK( cosmo.dcomdisdz(0.0) == 1.0 );
}

/**
 * Unit test for Cosmo::dcomvoldz.
 */
BOOST_AUTO_TEST_CASE( dcomvoldz )
{
  BOOST_CHECK( cosmo.dcomvoldz(0.0) == 0.0 );
}

/**
 * Unit test for Cosmo::dlookbackdz.
 */
BOOST_AUTO_TEST_CASE( dlookbackdz )
{
  BOOST_CHECK( cosmo.dlookbackdz(0.0) == 1.0 );
  BOOST_CHECK_THROW( cosmo.dlookbackdz(-1.0), BadArgumentException );
}

/**
 * Unit test for Cosmo::doptdepthdz.
 */
BOOST_AUTO_TEST_CASE( doptdepthdz )
{
  BOOST_CHECK( cosmo.doptdepthdz(0.0) == 1.0 );
  BOOST_CHECK_THROW( cosmo.doptdepthdz(-1.0), BadArgumentException );
}

/**
 * Unit test for Cosmo::dpropmotdisdz.
 */
BOOST_AUTO_TEST_CASE( dpropmotdisdz )
{
  BOOST_CHECK( cosmo.dpropmotdisdz(0.0) == 1.0 );
}

/**
 * Unit test for Cosmo::intcomvol.
 */
BOOST_AUTO_TEST_CASE( intcomvol )
{
  BOOST_CHECK( cosmo.intcomvol(0.0) == 0.0 );
}

/**
 * Unit test for Cosmo::lookback.
 */
BOOST_AUTO_TEST_CASE( lookback )
{
  BOOST_CHECK( cosmo.lookback(0.0) == 0.0 );
}

/**
 * Unit test for Cosmo::lumdis.
 */
BOOST_AUTO_TEST_CASE( lumdis )
{
  BOOST_CHECK( cosmo.lumdis(0.0) == 0.0 );
}

/**
 * Unit test for Cosmo::optdepth.
 */
BOOST_AUTO_TEST_CASE( optdepth )
{
  BOOST_CHECK( cosmo.optdepth(0.0) == 0.0 );
}

BOOST_AUTO_TEST_SUITE_END ()

/**
 * Unit test for Cosmo::propmotdis.
 */
BOOST_AUTO_TEST_CASE( propmotdis )
{
  BOOST_CHECK( cosmo.propmotdis(0.0) == 0.0 );
  BOOST_CHECK_THROW( cosmo.propmotdis(-1.0), BadArgumentException );
}


/**
 * @file budgeted_maximum_coverage_result_check.hpp
 * @brief
 * @author Piotr Smulewicz
 * @version 1.0
 * @date 2014-10-09
 */
#ifndef PAAL_BUDGETED_MAXIMUM_COVERAGE_CHECK_HPP
#define PAAL_BUDGETED_MAXIMUM_COVERAGE_CHECK_HPP

#include "test_utils/test_result_check.hpp"

#include <boost/test/unit_test.hpp>

#include <vector>

template <typename Result, typename SetToElements, typename SetToWeight,
          typename SetToCost>
void budgeted_maximum_coverage_result_check(
    Result &result, SetToElements &sets_element, SetToWeight &weight,
    SetToCost &cost_of_set, const int elements, const int optimal,
    const int weight_solution, const double aproximation_ratio, int budget) {
    int weight_verification = 0, cost_verification = 0;
    std::vector<bool> is_covered(elements, false);
    for (auto const &set : result) {
        cost_verification += cost_of_set(set);
        for (auto element : sets_element[set]) {
            if (!is_covered.at(element)) {
                weight_verification += weight(element);
                is_covered[element] = true;
            }
        }
    }
    LOGLN("cost_verification: " << cost_verification);
    BOOST_CHECK(cost_verification <= budget);
    BOOST_CHECK_EQUAL(weight_verification, weight_solution);
    check_result(weight_solution, optimal, aproximation_ratio,
                 paal::utils::greater_equal());
}

#endif /* PAAL_BUDGETED_MAXIMUM_COVERAGE_CHECK_HPP */


// Author(s): Jeroen Keiren
// Copyright: see the accompanying file COPYING or copy at
// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
//
// 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 print_test.cpp
/// \brief Add your file description here.

#define BOOST_TEST_MODULE print_test
#include <boost/test/included/unit_test_framework.hpp>

#include "mcrl2/pbes/print.h"
#include "mcrl2/pbes/txt2pbes.h"

using namespace mcrl2;
using namespace mcrl2::pbes_system;

BOOST_AUTO_TEST_CASE(pbes_with_reals)
{
  std::string input(
    "pbes nu X(T: Real) =\n"
    "       (((true && val(true)) && val(1 > T)) && true) && ((false || val(!true)) || val(!(1 > T))) || X(1);\n"
    "\n"
    "init X(0);\n"
  );

  pbes p;
  p = txt2pbes(input);

  std::string output;
  output = pbes_system::pp(p);

  BOOST_CHECK(output.find("Real;") == std::string::npos);

}

BOOST_AUTO_TEST_CASE(pbes_print)
{
  std::string PBES =
    "pbes nu X = true; \n"
    "init X;           \n"
   ;

  pbes p;
  p = txt2pbes(PBES);
  pbes_system::pp(p);
}

BOOST_AUTO_TEST_CASE(pbes_val)
{
  std::string PBES =
    "pbes mu X(d: Pos) = val(d > 0); \n"
    "init X(1);                      \n"
   ;

  std::string expected_result =
    "pbes mu X(d: Pos) =\n"
    "       val(d > 0);\n"
    "\n"
    "init X(1);\n"
    ;

  pbes p;
  p = txt2pbes(PBES);
  std::string result = pbes_system::pp(p);
  BOOST_CHECK(result == expected_result);
}


//=======================================================================
// Copyright 2001 Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee,
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
#include <boost/config.hpp>
#include <iostream>
#include <boost/graph/copy.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/graph_utility.hpp>

template <typename Graph>
struct non_zero_degree {
  non_zero_degree() { } // has to have a default constructor!

  non_zero_degree(const Graph& g) : g(&g) { }

  bool operator()(typename boost::graph_traits<Graph>::vertex_descriptor v) const
  {
    return degree(v, *g) != 0;
  }
  const Graph* g;
};

int
main()
{
  using namespace boost;
  typedef adjacency_list < vecS, vecS, bidirectionalS,
    property < vertex_name_t, char > > graph_t;

  enum { a, b, c, d, e, f, g, N };
  graph_t G(N);
  property_map < graph_t, vertex_name_t >::type
    name_map = get(vertex_name, G);
  char name = 'a';
  graph_traits < graph_t >::vertex_iterator v, v_end;
  for (boost::tie(v, v_end) = vertices(G); v != v_end; ++v, ++name)
    name_map[*v] = name;

  typedef std::pair < int, int >E;
  E edges[] = { E(a, c), E(a, d), E(b, a), E(b, d), E(c, f),
    E(d, c), E(d, e), E(d, f), E(e, b), E(e, g), E(f, e), E(f, g)
  };
  for (int i = 0; i < 12; ++i)
    add_edge(edges[i].first, edges[i].second, G);

  print_graph(G, name_map);
  std::cout << std::endl;

  clear_vertex(b, G);
  clear_vertex(d, G);

  graph_t G_copy;
  copy_graph(make_filtered_graph(G, keep_all(), non_zero_degree<graph_t>(G)), G_copy);

  print_graph(G_copy, get(vertex_name, G_copy));

  return 0;
}


/*
 *  Copyright (c), 2020 Blue Brain Project - EPFL
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 *
 */
#include <algorithm>
#include <complex>

#undef H5GT_USE_BOOST
#define H5GT_USE_BOOST

#include <boost/multi_array.hpp>
#include <h5gt/H5DataSet.hpp>
#include <h5gt/H5DataSpace.hpp>
#include <h5gt/H5File.hpp>

typedef std::complex<double> complex_t;

int main() {
    boost::multi_array<complex_t, 4> multi_array(boost::extents[3][2][1][1]);
    std::fill_n(multi_array.origin(), multi_array.num_elements(), 1.0);
    multi_array[1][1][0][0] = complex_t{1.1, 1.2};

    h5gt::File file("multi_array_complex.h5", h5gt::File::Truncate);

    h5gt::DataSet dataset = file.createDataSet("multi_array", multi_array);
    return 0;
}


/*=============================================================================
    Copyright (c) 2001-2007 Joel de Guzman

    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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
//  A Calculator example demonstrating generation of AST
//
//  [ JDG April 28, 2002 ]
//
///////////////////////////////////////////////////////////////////////////////

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>

#include <iostream>
#include <vector>
#include <string>

using namespace boost::spirit;
using namespace boost::spirit::qi;
using namespace boost::spirit::ascii;
using namespace boost::spirit::arg_names;

///////////////////////////////////////////////////////////////////////////////
//  Our AST
///////////////////////////////////////////////////////////////////////////////
struct binary_op;
struct unary_op;
struct nil {};

struct expression_ast
{
    typedef
        boost::variant<
            nil // can't happen!
          , unsigned int
          , boost::recursive_wrapper<expression_ast>
          , boost::recursive_wrapper<binary_op>
          , boost::recursive_wrapper<unary_op>
        >
    type;

    expression_ast()
      : expr(nil()) {}

    template <typename Expr>
    expression_ast(Expr const& expr)
      : expr(expr) {}

    expression_ast& operator+=(expression_ast const& rhs);
    expression_ast& operator-=(expression_ast const& rhs);
    expression_ast& operator*=(expression_ast const& rhs);
    expression_ast& operator/=(expression_ast const& rhs);

    type expr;
};

struct binary_op
{
    binary_op(
        char op
      , expression_ast const& left
      , expression_ast const& right)
    : op(op), left(left), right(right) {}

    char op;
    expression_ast left;
    expression_ast right;
};

struct unary_op
{
    unary_op(
        char op
      , expression_ast const& subject)
    : op(op), subject(subject) {}

    char op;
    expression_ast subject;
};

expression_ast& expression_ast::operator+=(expression_ast const& rhs)
{
    expr = binary_op('+', expr, rhs);
    return *this;
}

expression_ast& expression_ast::operator-=(expression_ast const& rhs)
{
    expr = binary_op('-', expr, rhs);
    return *this;
}

expression_ast& expression_ast::operator*=(expression_ast const& rhs)
{
    expr = binary_op('*', expr, rhs);
    return *this;
}

expression_ast& expression_ast::operator/=(expression_ast const& rhs)
{
    expr = binary_op('/', expr, rhs);
    return *this;
}

// We should be using expression_ast::operator-. There's a bug
// in phoenix type deduction mechanism that prevents us from
// doing so. Phoenix will be switching to BOOST_TYPEOF. In the
// meantime, we will use a phoenix::function below:
struct negate_expr
{
    template <typename T>
    struct result { typedef T type; };

    expression_ast operator()(expression_ast const& expr) const
    {
        return expression_ast(unary_op('-', expr));
    }
};

boost::phoenix::function<negate_expr> neg;

///////////////////////////////////////////////////////////////////////////////
//  Our calculator grammar
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct calculator : grammar<Iterator, expression_ast(), space_type>
{
    calculator() : calculator::base_type(expression)
    {
        expression =
            term                            [_val = _1]
            >> *(   ('+' >> term            [_val += _1])
                |   ('-' >> term            [_val -= _1])
                )
            ;

        term =
            factor                          [_val = _1]
            >> *(   ('*' >> factor          [_val *= _1])
                |   ('/' >> factor          [_val /= _1])
                )
            ;

        factor =
            uint_                           [_val = _1]
            |   '(' >> expression           [_val = _1] >> ')'
            |   ('-' >> factor              [_val = neg(_1)])
            |   ('+' >> factor              [_val = _1])
            ;
    }

    rule<Iterator, expression_ast(), space_type> expression, term, factor;
};

///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Expression parser...\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Type an expression...or [q or Q] to quit\n\n";

    typedef std::string::const_iterator iterator_type;
    typedef calculator<iterator_type> calculator;

    calculator calc; // Our grammar

    std::string str;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        bool r = phrase_parse(iter, end, calc, space);

        if (r && iter == end)
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            std::cout << "-------------------------\n";
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \": " << rest << "\"\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}


/*=============================================================================
    Copyright (c) 2017 Paul Fultz II
    repeat_while.cpp
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#include <boost/hof/repeat_while.hpp>
#include <boost/hof/reveal.hpp>
#include "test.hpp"

// TODO: Test default construction, and static initialization

struct increment_constant
{
    template<class T>
    constexpr std::integral_constant<int, T::value + 1> operator()(T) const noexcept
    {
        return std::integral_constant<int, T::value + 1>();
    }
};

struct increment
{
    template<class T>
    constexpr T operator()(T x) const noexcept
    {
        return x + 1;
    }
};

struct not_6_constant
{
    template<class T>
    constexpr std::integral_constant<bool, (T::value != 6)>
    operator()(T) const noexcept
    {
        return std::integral_constant<bool, (T::value != 6)>();
    }
};

struct not_6
{
    template<class T>
    constexpr bool operator()(T x) const noexcept
    {
        return x != 6;
    }
};

struct not_limit
{
    template<class T>
    constexpr bool operator()(T x) const
    {
        return x != (BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH+4);
    }
};

#if BOOST_HOF_HAS_NOEXCEPT_DEDUCTION
BOOST_HOF_TEST_CASE()
{
    static_assert(noexcept(boost::hof::repeat_while(not_6())(increment())(1)), "noexcept repeat_while");
    static_assert(noexcept(boost::hof::repeat_while(not_6_constant())(increment_constant())(std::integral_constant<int, 1>())), "noexcept repeat_while");
}
#endif

BOOST_HOF_TEST_CASE()
{
    static_assert
    (
        std::is_same<
            std::integral_constant<int, 6>,
            decltype(boost::hof::repeat_while(not_6_constant())(increment_constant())(std::integral_constant<int, 1>()))
        >::value,
        "Error"
    );

    std::integral_constant<int, 6> x = boost::hof::repeat_while(not_6_constant())(increment_constant())(std::integral_constant<int, 1>());
    boost::hof::test::unused(x);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::repeat_while(not_6())(increment())(1) == 6);
    BOOST_HOF_TEST_CHECK(boost::hof::repeat_while(not_6())(increment())(1) == 6);
    BOOST_HOF_TEST_CHECK(boost::hof::reveal(boost::hof::repeat_while(not_6())(increment()))(1) == 6);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(boost::hof::repeat_while(not_limit())(increment())(1) == BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH+4);
#if BOOST_HOF_HAS_RELAXED_CONSTEXPR
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::repeat_while(not_limit())(increment())(1) == BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH+4);
#endif
}