#ifndef TVMTL_TVMINIMIZER_IRLS_HPP
#define TVMTL_TVMINIMIZER_IRLS_HPP

//System includes
#include <iostream>
#include <map>
#include <vector>
#include <chrono>

#ifdef TVMTL_TVMIN_DEBUG
    #include <string>
#endif

//Eigen includes
#include <Eigen/Sparse>
#include <Eigen/Core>
#include <unsupported/Eigen/Splines>

//CGAL includes For linear Interpolation
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Interpolation_traits_2.h>
#include <CGAL/natural_neighbor_coordinates_2.h>
#include <CGAL/interpolation_functions.h>

//vpp includes
#include <vpp/vpp.hh>

namespace tvmtl {

template <class FUNCTIONAL, class MANIFOLD, class DATA, enum PARALLEL PAR>
    class TV_Minimizer< IRLS, FUNCTIONAL, MANIFOLD, DATA, PAR > {

	public:
	    // Manifold typedefs
	    typedef typename MANIFOLD::scalar_type scalar_type;
	    typedef typename MANIFOLD::value_type value_type;
	    typedef typename MANIFOLD::tm_base_type tm_base_type;

	    // Functional typedefs
	    typedef typename FUNCTIONAL::gradient_type gradient_type;
	    typedef typename FUNCTIONAL::sparse_hessian_type hessian_type;
	    typedef typename FUNCTIONAL::tm_base_mat_type tm_base_mat_type;
	    typedef typename Eigen::SparseSelfAdjointView<hessian_type, Eigen::Upper> sa_hessian_type;

	    // Parameters from traits class
	    typedef algo_traits< MANIFOLD::MyType > AT;
	    static const int runtime = AT::max_runtime;

	    typedef double newton_error_type;

	    // Constructor
	    TV_Minimizer(FUNCTIONAL& func, DATA& dat):
		func_(func),
		data_(dat)
	    {
		max_runtime_=AT::max_runtime;
		max_irls_steps_=AT::max_irls_steps;
		max_newton_steps_=AT::max_newton_steps;
		tolerance_=AT::tolerance;
		sparse_pattern_analyzed_ = false;
	    }

	    void first_guess();
	    void smoothening(int smooth_steps);

	    newton_error_type newton_step();
	    void minimize();
	    void output() { std::cout << "OUTPUT TEST" << std::endl; }

	    void setMax_runtime(int t) { max_runtime_ = t; }
	    void setMax_irls_steps(int n) { max_irls_steps_ = n; }
	    void setMax_newton_steps(int n) { max_newton_steps_ = n; }
	    void setTolerance(double t) {tolerance_ =t; }

	    int max_runtime(int t) const { return max_runtime_; }
	    int max_irls_steps(int n) const { return max_irls_steps_; }
	    int max_newton_steps(int n) const { return max_newton_steps_; }
	    int tolerance(double t) const { return tolerance_; }

	private:
	    FUNCTIONAL& func_;
	    DATA& data_;

	    typename AT::template solver< hessian_type > solver_;
	    bool sparse_pattern_analyzed_;

	    int irls_step_;
	    int newton_step_;

	    int max_runtime_;
	    int max_irls_steps_;
	    int max_newton_steps_;
	    double tolerance_;

	    std::vector< std::chrono::duration<double> > Ts_;
	    std::vector< typename FUNCTIONAL::result_type > Js_;

    };

/*----- IMPLEMENTATION IRLS------*/

//First Guess
template <class FUNCTIONAL, class MANIFOLD, class DATA, enum PARALLEL PAR>
void TV_Minimizer<IRLS, FUNCTIONAL, MANIFOLD, DATA, PAR>::first_guess(){

    std::cout << "Starting interpolation of damaged Area" << std::endl;

    typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
    typedef CGAL::Delaunay_triangulation_2<K> Delaunay_triangulation;
    typedef CGAL::Interpolation_traits_2<K> Traits;
    typedef K::FT Coord_type;
    typedef K::Point_2 Point;

    typedef typename DATA::inp_type inp_type;
    int value_dim = FUNCTIONAL::value_dim;
    int value_rows = value_type::RowsAtCompileTime;
    int value_cols = value_type::ColsAtCompileTime;

    if(MANIFOLD::non_isometric_embedding)
	vpp::pixel_wise(data_.img_) | [&] (value_type& i){ MANIFOLD::interpolation_preprocessing(i); };

    for(int r=0; r<value_rows; r++)
	for(int c=0; c<value_cols; c++){
	    std::cout << "\t Channel " << value_cols*r+c+1 << " of " << value_dim << "..." << std::endl;
	    Delaunay_triangulation T;
	    std::map<Point, Coord_type, K::Less_xy_2> function_values;
	    typedef CGAL::Data_access< std::map<Point, Coord_type, K::Less_xy_2 > >  Value_access;
	    #ifdef TVMTL_TVMIN_DEBUG
		std::cout << "NZ-Entries in inpainting matrix:" << vpp::sum(data_.inp_) << std::endl;
	    #endif

	    int numnodes=0;
	    // Add Interpolation nodes
	    vpp::pixel_wise(data_.inp_, data_.img_, data_.img_.domain())(vpp::_no_threads)  | [&] (inp_type inp, const value_type& i, const vpp::vint2& coord) {
		if(!inp){
			Point p(coord[0], coord[1]);
			T.insert(p);
			function_values.insert(std::make_pair(p,i(r,c)));
			numnodes++;
		}
	    };
	    std::cout << "\t\tNumber of Nodes: " << numnodes << std::endl;

	    int numdampix=0;
	    // Interpolate missing nodes
	    vpp::pixel_wise(data_.inp_, data_.img_, data_.img_.domain())(vpp::_no_threads) | [&] (inp_type inp, value_type& i, const vpp::vint2& coord) {
		if(inp){
		    Point p(coord[0], coord[1]);
		    std::vector< std::pair< Point, Coord_type > > coords;
                    Coord_type norm =  CGAL::natural_neighbor_coordinates_2(T, p,std::back_inserter(coords)).second;
		    Coord_type res = CGAL::linear_interpolation(coords.begin(), coords.end(), norm,Value_access(function_values));
		    i(r,c)=static_cast<scalar_type>(res);
		    numdampix++;
		}
	    };
	    std::cout << "\t\tNumber of interpolated Pixels: " << numdampix << std::endl;
	}

	if(MANIFOLD::non_isometric_embedding)
	    vpp::pixel_wise(data_.img_) | [&] (value_type& i){ MANIFOLD::interpolation_postprocessing(i); };

    	vpp::pixel_wise(data_.img_) | [&] (value_type& i) { MANIFOLD::projector(i); };

}

//Smoothening
template <class FUNCTIONAL, class MANIFOLD, class DATA, enum PARALLEL PAR>
void TV_Minimizer<IRLS, FUNCTIONAL, MANIFOLD, DATA, PAR>::smoothening(int smooth_steps){

    std::cout << "Start Smoothening with max_steps = " << smooth_steps << std::endl;

    //TODO: Add Manifold dependent tranformation Before and after smoothening
    typename FUNCTIONAL::result_type Jnew = func_.evaluateJ();
    typename FUNCTIONAL::result_type Jold = Jnew + 1;
    int step = 0;

    typename FUNCTIONAL::img_type temp_img(data_.img_.domain(), vpp::_border=1);
    typename FUNCTIONAL::nbh_type N(temp_img);

    std::cout << "Initial functional value J=" << Jnew << "\n\n" << std::endl;

    while(Jnew<Jold && step < smooth_steps){
	#ifdef TVMTL_TVMIN_DEBUG_SPD
	   data_.output_matval_img("presmoothend_spd_img.csv");
	#endif
	if(MANIFOLD::non_isometric_embedding)
	    vpp::pixel_wise(data_.img_) | [&] (value_type& i){ MANIFOLD::interpolation_preprocessing(i); };

	#ifdef TVMTL_TVMIN_DEBUG_SPD
	   data_.output_matval_img("preprocessedsmoothend_spd_img.csv");
	#endif
	vpp::copy(data_.img_, temp_img);
	vpp::fill_border_closest(temp_img);

	std::cout << "\tSmoothen step #" << step+1 << std::endl;
	std::cout << "\t Value of Functional J: " << Jnew << std::endl;
	Jold = Jnew;
	// Standard smoothening stencil
	//	1
	//  1	4   1	/   8
	//	1
	auto boxfilter = [&] (value_type& i, const auto& nbh) {
	    i = (4 * nbh(0,0) + nbh(1,0) + nbh(0,1) + nbh(-1,0) + nbh(0,-1))/8.0;
	    MANIFOLD::projector(i);
	};

	vpp::pixel_wise(data_.img_, N)(/*vpp::_no_threads*/) | boxfilter;

	#ifdef TVMTL_TVMIN_DEBUG_SPD
	   data_.output_matval_img("boxfiltersmoothend_spd_img.csv");
	#endif

	if(MANIFOLD::non_isometric_embedding)
	    vpp::pixel_wise(data_.img_) | [&] (value_type& i){ MANIFOLD::interpolation_postprocessing(i); };

        #ifdef TVMTL_TVMIN_DEBUG_SPD
	   data_.output_matval_img("postsmoothend_spd_img.csv");
	#endif

	Jnew = func_.evaluateJ();
	step++;
    }

    std::cout << "Smoothening completed with J=" << Jnew << "\n\n" << std::endl;

}

template <class FUNCTIONAL, class MANIFOLD, class DATA, enum PARALLEL PAR>
typename TV_Minimizer<IRLS, FUNCTIONAL, MANIFOLD, DATA, PAR>::newton_error_type TV_Minimizer<IRLS, FUNCTIONAL, MANIFOLD, DATA, PAR>::newton_step(){

    int nr = data_.img_.nrows();
    int nc = data_.img_.ncols();
    int value_dim = FUNCTIONAL::value_dim;
    int manifold_dim = FUNCTIONAL::manifold_dim;

    // Calculate the gradient and hessian
    #ifdef TVMTL_TVMIN_DEBUG_VERBOSE
	std::cout << "\n\t\t...Calculate Gradient" << std::endl;
    #endif
    func_.evaluateDJ();

    #ifdef TVMTL_TVMIN_DEBUG_VERBOSE
	std::cout << "\t\t...Calculate Hessian" << std::endl;
    #endif
    func_.evaluateHJ();

    // Set up the sparse Linear system
    gradient_type x;
    const gradient_type& b = func_.getDJ();
    const hessian_type& A = func_.getHJ();//.template selfadjointView<Eigen::Upper>();

    #ifdef TVMTL_TVMIN_DEBUG_VERBOSE
	std::cout << "\t\t\t...Gradient Size: " << b.size() << std::endl;
	std::cout << "\t\t\t...Hessian Non-Zeros: " << A.nonZeros() << std::endl;
	std::cout << "\t\t\t...Hessian Rows: " << A.rows() << std::endl;
	std::cout << "\t\t\t...Hessian Cols: " << A.cols() << std::endl;
	std::cout << "\n\t\t...Analyze Sparse Pattern" << std::endl;
    #endif
    if (!sparse_pattern_analyzed_){
	solver_.analyzePattern(A);
	sparse_pattern_analyzed_ =  true;
    }

    #ifdef TVMTL_TVMIN_DEBUG_VERBOSE
	std::cout << "\t\t...Solve System" << std::endl;
    #endif

    // Solve the System
    solver_.factorize(A);
    x = solver_.solve(b);

    // Apply Newton correction to picture
    // TODO:
    // - Change VectorXd to something parametrized with scalar_type
    #ifdef TVMTL_TVMIN_DEBUG_VERBOSE
	std::cout << "\t\t...Apply Newton Correction" << std::endl;
    #endif
    const tm_base_mat_type& T = func_.getT();
    auto newton_correction = [&] (const tm_base_type& t, value_type& i, const vpp::vint2 coord) {
	Eigen::VectorXd v = -t*x.segment(manifold_dim*(coord[0]+nr*coord[1]), manifold_dim);
	MANIFOLD::exp(i, Eigen::Map<value_type>(v.data()), i);
	//MANIFOLD::exp(i, -t*x.segment(manifold_dim*(coord[0]+nr*coord[1]), manifold_dim), i);
    };
    vpp::pixel_wise(T, data_.img_, data_.img_.domain()) | newton_correction;

       // Compute the Error
     #ifdef TVMTL_TVMIN_DEBUG_VERBOSE
	std::cout << "\t\t...Compute Newton error" << std::endl;
    #endif
    newton_error_type error = x.norm();

    return error;
}

template <class FUNCTIONAL, class MANIFOLD, class DATA, enum PARALLEL PAR>
void TV_Minimizer<IRLS, FUNCTIONAL, MANIFOLD, DATA, PAR>::minimize(){
    std::cout << "Starting IRLS Algorithm with..." << std::endl;
    std::cout << "\t Lambda = \t" << func_.getlambda() << std::endl;
    std::cout << "\t eps^2 = \t" << func_.geteps2() << std::endl;
    std::cout << "\t Tolerance = \t" <<  tolerance_ << std::endl;
    std::cout << "\t Max Steps IRLS= \t" << max_irls_steps_ << std::endl;
    std::cout << "\t Max Steps Newton = \t" << max_newton_steps_ << std::endl;

    irls_step_ = 0;

    std::chrono::time_point<std::chrono::system_clock> start, end;
    std::chrono::duration<double> t = std::chrono::duration<double>::zero();
    start = std::chrono::system_clock::now();

    // IRLS Iteration Loop
    while(irls_step_ < max_irls_steps_ && t.count() < max_runtime_){

	std::cout << "IRLS Step #" << irls_step_+1 << std::endl;
	// NOTE: evaluation of J automatically calls updateWeights(): separate eventually
	typename FUNCTIONAL::result_type J = func_.evaluateJ();
	Js_.push_back(J);
	std::cout << "\t Value of Functional J: " << J << std::endl;

	newton_step_ = 0;
	newton_error_type error = tolerance_ + 1;

	// Newton Iteration Loop
	while(tolerance_ < error && t.count() < max_runtime_ && newton_step_ < max_newton_steps_){
	    std::cout << "\t Newton step #" << newton_step_+1;
	    error = newton_step();
	    #ifdef TVMTL_TVMIN_DEBUG
		    std::string fname("step_img.csv");
		    fname = std::to_string(irls_step_) + "." + std::to_string(newton_step_) + fname;
		    data_.output_matval_img(fname.c_str());
	    #endif

	    std::cout << "\t Error: " << error << std::endl;
	    newton_step_++;
	}

	end = std::chrono::system_clock::now();
	t = end - start;
	std::cout << "\t Elapsed time: " << t.count() << " seconds." << std::endl;
	irls_step_++;
	Ts_.push_back(t);
    }

    std::cout << "Minimization in " << t.count() << " seconds." << std::endl;
}

} // end namespace tvmtl

#endif


#include <cmath>

#include <string>
#include <iostream>
#include <random>
#include <algorithm>

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

#define EIGEN_INITIALIZE_MATRICES_BY_NAN

#include <cmath>
#include <cstdlib>
#include <complex>
#include <type_traits>

#include <iostream>
#include <iomanip>

// define the exception class, but don't override eigen's eigen_assert() macro itself
#include <tomographer/tools/eigen_assert_exception.h>

#include <Eigen/Core>
#include <unsupported/Eigen/MatrixFunctions> // matrix sqrt()

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

#include "testutils.h"

#include "entglfidelity_figofmerit.h"
#include "channelspace.h"

#include <tomographer/tools/boost_test_logger.h>
#include <tomographer/mathtools/pos_semidef_util.h>
#include <tomographer/densedm/dmtypes.h>

// -----------------------------------------------------------------------------
// fixture(s)

template<int QuDim_>
struct identdefs
{
  static constexpr int QuDim = QuDim_;
  static constexpr int QuDim2 = QuDim*QuDim;

  typedef Eigen::Matrix<std::complex<double>,QuDim2,1> PureKetType;
  typedef Eigen::Matrix<std::complex<double>,QuDim2,QuDim2> ChoiMatrixType;
  typedef Eigen::Matrix<std::complex<double>,QuDim,QuDim> ReducedDMType;

  PureKetType Psi;
  ChoiMatrixType  Eident;
  ChoiMatrixType  Eclassident;

  identdefs()
    : Psi(PureKetType::Zero())
  {
    BOOST_TEST_MESSAGE("identdefs(), QuDim="<<QuDim<<", QuDim2="<<QuDim2);

    // initialize Psi
    for (std::size_t j = 0; j < QuDim; ++j) {
      Psi(j+QuDim*j) = 1;
    }

    // initialize Eident
    Eident = Psi * Psi.adjoint();

    validate_channel<double>(Eident, QuDim, QuDim, "Eident");

    // initialize Eclassident (classical identity channel == fully depolarizing)
    Eclassident = ChoiMatrixType::Zero();
    for (std::size_t j = 0; j < QuDim; ++j) {
      Eclassident(QuDim*j+j, QuDim*j+j) = 1;
    }

    validate_channel<double>(Eclassident, QuDim, QuDim, "Eclassident");

    BOOST_TEST_MESSAGE("identdefs() done");
  }
};
template<int QuDim_> constexpr int identdefs<QuDim_>::QuDim;
template<int QuDim_> constexpr int identdefs<QuDim_>::QuDim2;

// -----------------------------------------------------------------------------
// test suites

BOOST_AUTO_TEST_SUITE(test_entanglement_fidelity)
// =============================================================================

BOOST_AUTO_TEST_SUITE(examples)

BOOST_FIXTURE_TEST_CASE(simple_qubit, identdefs<2>)
{
  // This is now a test channel which is hopefully close to Eclassident.
  ChoiMatrixType E;
  E <<
    0.9, 0, 0, 0,
    0, 0.1, 0, 0,
    0,   0, 0, 0,
    0,   0, 0, 1;

  // value calculated manually
  BOOST_CHECK_CLOSE( entanglement_fidelity(E, 2), 0.475, 1e-4/*percent*/ );
}

BOOST_FIXTURE_TEST_CASE(qutrit_case, identdefs<3>)
{
  // This is now a test of another channel

  ChoiMatrixType E;
  E  <<
    0.9,0,  0,  0,  0.5,0,  0,  0,0.2,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,0.1,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0.5,0,  0,  0,  1,  0,  0,  0,0.8,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
  0.2,  0,  0,  0,0.8,  0,  0,  0,  1 ;

  ChoiMatrixType Delta = E - Eident;

  // value calculated manually
  BOOST_CHECK_CLOSE( entanglement_fidelity(E, 3), 5.9/9, 1e-4/*percent*/ );
}

BOOST_FIXTURE_TEST_CASE(qutrit_case_close, identdefs<3>)
{
  // This is now a test channel which is hopefully close to Eident.

  ChoiMatrixType E;
  E  <<
    0.9,0,  0,  0,  0.9,0,  0,  0,0.9,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,0.1,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0.9,0,  0,  0,  0.9,0,  0,  0,0.9,
    0,  0,  0,  0,  0,0.1,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0.9,0,  0,  0,0.9,  0,  0,  0,  1 ;

  // value calculated manually
  BOOST_CHECK_CLOSE( entanglement_fidelity(E, 3), 8.2/9, 1e-4/*percent*/ );
}

BOOST_FIXTURE_TEST_CASE(qutrit_case_ideal, identdefs<3>)
{
  // This is now an ideal test channel

  ChoiMatrixType E;
  E  <<
    1,  0,  0,  0,  1,  0,  0,  0,  1,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    1,  0,  0,  0,  1,  0,  0,  0,  1,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,
    1,  0,  0,  0,  1,  0,  0,  0,  1 ;

  // value calculated manually
  BOOST_CHECK_CLOSE( entanglement_fidelity(E, 3), 1.0, 1e-4/*percent*/ );
}

BOOST_AUTO_TEST_SUITE_END(); // examples

BOOST_FIXTURE_TEST_SUITE(entanglement_fidelity_valcalc, identdefs<2>)

BOOST_FIXTURE_TEST_CASE(simple_qubit, identdefs<2>)
{
  // process matrix of the channel diag(0.9,0.1,0,1) applied to the state (0.8,0.2)
  ChoiMatrixType E;
  E <<
    0.72, 0, 0,   0,
    0, 0.08, 0,   0,
    0,    0, 0,   0,
    0,    0, 0, 0.2;

  ChoiMatrixType T = E.sqrt(); // a square root of E, to test the value calculator's getValue()

  typedef Tomographer::DenseDM::DMTypes<4> DMTypes;
  DMTypes dmt(4);

  EntglFidelityValueCalculator<DMTypes> efidcalc(dmt,2);

  // value calculated manually
  BOOST_CHECK_CLOSE( efidcalc.getValue(T), 0.475, 1e-4/*percent*/ );
}

BOOST_FIXTURE_TEST_CASE(simple_qubit_channelspace, identdefs<2>)
{
  // Choi matrix = [ 0.9  0.3  0    0
  //                 0.3  0    0    0
  //                 0    0    0    0
  //                 0    0    0    1 ]
  //
  // Here we need a Stinespring isometry:
  //
  //   |0>  -->  sqrt(0.9) * |0>_out |0>_ref + sqrt(0.1) * |1>_out |0>_ref
  //   |1>  -->  |1>_out |1>_ref
  //
  // ref actually has four dimensions (that's what's needed in general) but we
  // don't need all of them for this particular channel.

  Eigen::Matrix<std::complex<double>,8,2> Vpt;
  Vpt.col(0)
    << std::sqrt(0.9),0,0,0, std::sqrt(0.1),0,0,0 ;
  Vpt.col(1)
    << 0,0,0,0, 0,1.0,0,0 ;

  typedef ChannelTypes<double> MyChannelTypes;
  MyChannelTypes cht(2,2);

  EntglFidelityChannelSpaceValueCalculator<MyChannelTypes> efidcalc(cht);

  // value calculated manually
  BOOST_CHECK_CLOSE( efidcalc.getValue(Vpt), 0.475, 1e-4/*percent*/ );
}

BOOST_AUTO_TEST_SUITE_END() ;

// =============================================================================
BOOST_AUTO_TEST_SUITE_END() ;


#include <boost/test/unit_test.hpp>

#include <iostream>

#include "../../lib/datastructures/cad/projection/Projection.h"
#include "../../lib/datastructures/cad/lifting/Sample.h"
#include "../../lib/datastructures/cad/debug/Projection.h"
#include "../../lib/modules/NewCADModule/NewCADSettings.h"
#include "../../lib/datastructures/cad/CAD.h"

using namespace smtrat;
using namespace smtrat::cad;

BOOST_AUTO_TEST_SUITE(Test_Projection);

BOOST_AUTO_TEST_CASE(Projection)
{
	carl::Variable x = carl::freshRealVariable("x");
	carl::Variable y = carl::freshRealVariable("y");

	debug::Projection p({x,y});

	p.add(ConstraintT(Poly(x) + Poly(y), carl::Relation::LEQ));
	p.add(ConstraintT(Poly(y), carl::Relation::GREATER));
	p.add(ConstraintT(Poly(x) + Poly(1), carl::Relation::GREATER));

	std::cout << p.getProjection() << std::endl;

	//ProjectionT<NewCADSettingsSO> projection;
	//projection.reset({x,y});
	//projection.addPolynomial(p.toUnivariatePolynomial(x), 0);
	//projection.addPolynomial(q.toUnivariatePolynomial(x), 1);
	//std::cout << projection << std::endl;
	//
	//Sample s(RAN(1));
	//while (auto pid = projection.getPolyForLifting(1, s.liftedWith())) {
	//	std::cout << projection.getPolynomialById(1, *pid) << std::endl;
	//}
}

BOOST_AUTO_TEST_CASE(Test_CAD)
{
	carl::Variable x = carl::freshRealVariable("x");
	carl::Variable y = carl::freshRealVariable("y");
	Poly p = Poly(x*y)+Poly(y)+Rational(1);
	Poly q = Poly(y*y*y)+Poly(x*x*y)+Rational(2);

	CAD<NewCADSettingsSO> cad;
	cad.reset({x,y});
	cad.addConstraint(ConstraintT(p, carl::Relation::GEQ));
	cad.addConstraint(ConstraintT(q, carl::Relation::LEQ));

	Assignment a;
	cad.check(a);
}

BOOST_AUTO_TEST_SUITE_END();


#include <iostream>                    // std::cout
#include <fstream>                     // std::ifstream, std::ofstream
#include <filesystem>                  // std::filesystem
#include <string>                      // std::string
#include <chrono>                      // std::chrono
// For External Library
#include <torch/torch.h>               // torch
#include <boost/program_options.hpp>   // boost::program_options
// For Original Header
#include "loss.hpp"                    // Loss
#include "networks.hpp"                // MC_AlexNet
#include "transforms.hpp"              // transforms_Compose
#include "datasets.hpp"                // datasets::ImageFolderClassesWithPaths
#include "dataloader.hpp"              // DataLoader::ImageFolderClassesWithPaths

// Define Namespace
namespace fs = std::filesystem;
namespace po = boost::program_options;

// ---------------
// Test Function
// ---------------
void test(po::variables_map &vm, torch::Device &device, MC_AlexNet &model, std::vector<transforms_Compose> &transform, const std::vector<std::string> class_names){

    // (0) Initialization and Declaration
    size_t class_num;
    size_t match, counter;
    long int response, answer;
    char judge;
    float accuracy;
    float ave_loss;
    double seconds, ave_time;
    std::string path, result_dir;
    std::string dataroot;
    std::ofstream ofs, ofs2;
    std::chrono::system_clock::time_point start, end;
    std::tuple<torch::Tensor, torch::Tensor, std::vector<std::string>> data;
    torch::Tensor image, label, output;
    torch::Tensor loss;
    datasets::ImageFolderClassesWithPaths dataset;
    DataLoader::ImageFolderClassesWithPaths dataloader;

    // (1) Get Test Dataset
    dataroot = "datasets/" + vm["dataset"].as<std::string>() + '/' + vm["test_dir"].as<std::string>();
    dataset = datasets::ImageFolderClassesWithPaths(dataroot, transform, class_names);
    dataloader = DataLoader::ImageFolderClassesWithPaths(dataset, /*batch_size_=*/1, /*shuffle_=*/false, /*num_workers_=*/0);
    std::cout << "total test images : " << dataset.size() << std::endl << std::endl;

    // (2) Get Model
    path = "checkpoints/" + vm["dataset"].as<std::string>() + "/models/epoch_" + vm["test_load_epoch"].as<std::string>() + ".pth";
    torch::load(model, path, device);

    // (3) Set Loss Function
    auto criterion = Loss();

    // (4) Initialization of Value
    ave_loss = 0.0;
    ave_time = 0.0;
    match = 0;
    counter = 0;
    class_num = class_names.size();

    // (5) File Pre-processing
    result_dir = vm["test_result_dir"].as<std::string>();  fs::create_directories(result_dir);
    ofs.open(result_dir + "/loss.txt", std::ios::out);
    ofs2.open(result_dir + "/likelihood.csv", std::ios::out);
    ofs2 << "file name," << std::flush;
    ofs2 << "judge," << std::flush;
    for (size_t i = 0; i < class_num; i++){
        ofs2 << i << "(" << class_names.at(i) << ")," << std::flush;
    }
    ofs2 << std::endl;

    // (6) Tensor Forward
    torch::NoGradGuard no_grad;
    model->eval();
    while (dataloader(data)){

        image = std::get<0>(data).to(device);
        label = std::get<1>(data).to(device);

        if (!device.is_cpu()) torch::cuda::synchronize();
        start = std::chrono::system_clock::now();

        output = model->forward(image);

        if (!device.is_cpu()) torch::cuda::synchronize();
        end = std::chrono::system_clock::now();
        seconds = (double)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() * 0.001 * 0.001;

        loss = criterion(output, label);

        ave_loss += loss.item<float>();
        ave_time += seconds;

        output = output.exp();
        response = output.argmax(/*dim=*/1).item<long int>();
        answer = label[0].item<long int>();
        counter += 1;
        judge = 'F';
        if (response == answer){
            match += 1;
            judge = 'T';
        }

        std::cout << '<' << std::get<2>(data).at(0) << "> cross-entropy:" << loss.item<float>() << " judge:" << judge << " response:" << response << '(' << class_names.at(response) << ") answer:" << answer << '(' << class_names.at(answer) << ')' << std::endl;
        ofs << '<' << std::get<2>(data).at(0) << "> cross-entropy:" << loss.item<float>() << " judge:" << judge << " response:" << response << '(' << class_names.at(response) << ") answer:" << answer << '(' << class_names.at(answer) << ')' << std::endl;
        ofs2 << std::get<2>(data).at(0) << ',' << std::flush;
        ofs2 << judge << ',' << std::flush;
        output = output[0];  // {1, CN} ===> {CN}
        for (size_t i = 0; i < class_num; i++){
            ofs2 << output[i].item<float>() << ',' << std::flush;
        }
        ofs2 << std::endl;

    }

    // (7.1) Calculate Average
    ave_loss = ave_loss / (float)dataset.size();
    ave_time = ave_time / (double)dataset.size();

    // (7.2) Calculate Accuracy
    accuracy = (float)match / float(counter);

    // (8) Average Output
    std::cout << "<All> cross-entropy:" << ave_loss << " accuracy:" << accuracy << " (time:" << ave_time << ')' << std::endl;
    ofs << "<All> cross-entropy:" << ave_loss << " accuracy:" << accuracy << " (time:" << ave_time << ')' << std::endl;

    // Post Processing
    ofs.close();
    ofs2.close();

    // End Processing
    return;

}


// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#include <boost/hana/assert.hpp>
#include <boost/hana/core/make.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/range.hpp>
namespace hana = boost::hana;

int main() {
    using T = int;
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::range_c<T, 0, 0>,
        hana::make_range(hana::integral_c<T, 0>, hana::integral_c<T, 0>)
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::range_c<T, 0, 1>,
        hana::make_range(hana::integral_c<T, 0>, hana::integral_c<T, 1>)
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::range_c<T, 0, 2>,
        hana::make_range(hana::integral_c<T, 0>, hana::integral_c<T, 2>)
    ));

    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::range_c<T, 1, 1>,
        hana::make_range(hana::integral_c<T, 1>, hana::integral_c<T, 1>)
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::range_c<T, 1, 2>,
        hana::make_range(hana::integral_c<T, 1>, hana::integral_c<T, 2>)
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::range_c<T, 1, 3>,
        hana::make_range(hana::integral_c<T, 1>, hana::integral_c<T, 3>)
    ));
}


#include <complementary_filter.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <random>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE ComplementaryFilter
#include <boost/test/unit_test.hpp>

using namespace navigine::navigation_core;

static const double MAGNETIC_FLUX_DENSITY = 0.48;
static const double MAGNETIC_FIELD_INCLINATION = 60.48 * M_PI / 180;
static const double G = 9.81;

std::tuple<std::vector<SensorMeasurement>,
           std::vector<SensorMeasurement>,
           std::vector<SensorMeasurement>> getTiltedImuMeasurements(double durationStaticSec,
                                                                    double tiltPitch = 0.0,
                                                                    double freqHz = 100)
{
  std::random_device rd;
  std::mt19937 gen(rd());

  std::vector<long long> times;
  long long t = 1583315232492;
  double tick = 1.0 / freqHz;
  for (int i = 0; i < durationStaticSec / tick; i++) {
    times.emplace_back(t);
    t += 1000 * tick;
  }

  std::vector<SensorMeasurement> accelMeasurements;
  for (long long ts: times)
  {
    //the variance is choosen to be equal to typical accelerometer noise variance of cheap IMU sensor
    double var = 2 * M_PI * freqHz * G * pow(0.001, 2);
    std::normal_distribution<double> distr(0.0, var);

    double ax = -G * sin(tiltPitch) + distr(gen);
    double ay = 0.0 + distr(gen);
    double az = G * cos(tiltPitch) + distr(gen);
    SensorMeasurement msr;
    msr.ts = ts;
    msr.values = Vector3d(ax, ay, az);
    msr.type = SensorMeasurement::Type::ACCELEROMETER;
    accelMeasurements.emplace_back(msr);
  }

  std::vector<SensorMeasurement> gyroMeasurements;
  for (long long ts: times)
  {
    //the variance is choosen to be equal to typical gyroscope noise variance of cheap IMU sensor
    double var = 2 * M_PI * freqHz * pow(0.01 * M_PI / 180.0, 2);
    std::normal_distribution<double> distr(0.005, var);

    double wx = 0.0 + distr(gen);
    double wy = 0.0 + distr(gen);
    double wz = 0.0 + distr(gen);
    SensorMeasurement msr;
    msr.ts = ts;
    msr.values = Vector3d(wx, wy, wz);
    msr.type = SensorMeasurement::Type::GYROSCOPE;
    gyroMeasurements.emplace_back(msr);
  }

  std::vector<SensorMeasurement> magnMeasurements;
  for (long long ts: times)
  {
    double mx = MAGNETIC_FLUX_DENSITY * cos(MAGNETIC_FIELD_INCLINATION + tiltPitch);
    double my = 0.0;
    double mz = MAGNETIC_FLUX_DENSITY * sin(MAGNETIC_FIELD_INCLINATION + tiltPitch);
    SensorMeasurement msr;
    msr.ts = ts;
    msr.values = Vector3d(mx, my, mz);
    msr.type = SensorMeasurement::Type::MAGNETOMETER;
    magnMeasurements.emplace_back(msr);
  }

  return std::make_tuple(accelMeasurements, gyroMeasurements, magnMeasurements);
}

BOOST_AUTO_TEST_CASE(staticTilt)
{
  std::vector<SensorMeasurement> accelMeasurements;
  std::vector<SensorMeasurement> gyroMeasurements;
  std::vector<SensorMeasurement> magnMeasurements;

  double durationStaticSec = 10.0;
  double tiltPitch = 0.0;
  std::tie(accelMeasurements, gyroMeasurements, magnMeasurements) =
          getTiltedImuMeasurements(durationStaticSec, tiltPitch);

  Orientation ori(0, 0, 0, 0);
  ComplementaryFilter complementaryFilter;
  for (std::size_t i = 0; i < accelMeasurements.size(); i++)
  {
    const SensorMeasurement& accelMsr = accelMeasurements.at(i);
    const SensorMeasurement& gyroMsr = gyroMeasurements.at(i);
    const SensorMeasurement& magnMsr = magnMeasurements.at(i);
    complementaryFilter.update(accelMsr);
    complementaryFilter.update(gyroMsr);
    complementaryFilter.update(magnMsr);
    ori = complementaryFilter.getFusedOrientation();
  }

  BOOST_CHECK(std::abs(ori.roll) < M_PI * 1.0 / 180);
  BOOST_CHECK(std::abs(ori.pitch - tiltPitch) < M_PI * 1.0 / 180);
}


/* ----------------------------------------------------------------------------
 * GTDynamics Copyright 2020, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * See LICENSE for the license information
 * -------------------------------------------------------------------------- */

/**
 * @file  main.cpp
 * @brief Unitree A1 trajectory optimization with pre-specified footholds.
 * @author: Dan Barladeanu
 */

#include <gtdynamics/factors/ObjectiveFactors.h>
#include <gtdynamics/universal_robot/sdf.h>
#include <gtdynamics/utils/Trajectory.h>
#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <gtsam/base/timing.h>

#include <algorithm>
#include <boost/algorithm/string/join.hpp>
#include <boost/optional.hpp>
#include <fstream>
#include <iostream>
#include <utility>

using std::string;
using std::vector;

using gtsam::Point3;
using gtsam::Pose3;
using gtsam::Rot3;
using gtsam::Vector6;
using gtsam::noiseModel::Isotropic;
using gtsam::noiseModel::Unit;

using namespace gtdynamics;

// Returns a Trajectory object for a single a1 walk cycle.
Trajectory getTrajectory(const Robot& robot, size_t repeat) {
  vector<LinkSharedPtr> rlfr = {robot.link("RL_lower"),robot.link("FR_lower")};
  vector<LinkSharedPtr> rrfl = {robot.link("RR_lower"),robot.link("FL_lower")};
  auto all_feet = rlfr;
  all_feet.insert(all_feet.end(), rrfl.begin(), rrfl.end());

  // Create three different FootContactConstraintSpecs, one for all the feet on the
  // ground, one with RL and FR, one with RR and FL
  const Point3 contact_in_com(0, 0, -0.07);
  auto stationary = boost::make_shared<FootContactConstraintSpec>(all_feet, contact_in_com);
  auto RLFR = boost::make_shared<FootContactConstraintSpec>(rlfr, contact_in_com);
  auto RRFL = boost::make_shared<FootContactConstraintSpec>(rrfl, contact_in_com);

  //FootContactVector states = {noRL, noRR, noFR, noFL};
  FootContactVector states = {stationary, RRFL, stationary, RLFR};
  std::vector<size_t> phase_lengths = {1,5,1,5};

  WalkCycle walk_cycle(states, phase_lengths);

  return Trajectory(walk_cycle, repeat);
}

int main(int argc, char** argv) {

  gttic_(start); //need to build gtsam with timing for this

  // Load Unitree A1 robot urdf.
  auto robot =
      CreateRobotFromFile(std::string("/home/dan/.local/lib/python3.8/site-packages/pybullet_data/a1/a1.urdf"), "a1");

  double sigma_dynamics = 1e-6;    // std of dynamics constraints.
  double sigma_objectives = 1e-7;  // std of additional objectives.

  // Noise models.
  auto dynamics_model_6 = Isotropic::Sigma(6, sigma_dynamics),
       dynamics_model_1 = Isotropic::Sigma(1, sigma_dynamics),
       objectives_model_6 = Isotropic::Sigma(6, sigma_objectives),
       objectives_model_1 = Isotropic::Sigma(1, sigma_objectives);

  // Env parameters.
  gtsam::Vector3 gravity(0, 0, -9.8);
  double mu = 1.0;

  OptimizerSetting opt(sigma_dynamics);
  DynamicsGraph graph_builder(opt, gravity);

  // Create the trajectory, 1 walk cycle.
  auto trajectory = getTrajectory(robot, 1);

  // Create multi-phase trajectory factor graph
  auto collocation = CollocationScheme::Euler;
  auto graph =
      trajectory.multiPhaseFactorGraph(robot, graph_builder, collocation, mu);

  // Build the objective factors.
  double ground_height = 1.0;
  const Point3 step(0.5, 0, 0);
  gtsam::NonlinearFactorGraph objectives =
      trajectory.contactPointObjectives(robot, Isotropic::Sigma(3, 1e-7), step, ground_height);

  // Get final time step.
  int K = trajectory.getEndTimeStep(trajectory.numPhases() - 1);

  // Add body goal objectives to the factor graph.
  auto base_link = robot.link("trunk");
  for (int k = 0; k <= K; k++) {
    objectives.add(
        LinkObjectives(base_link->id(), k)
            .pose(Pose3(Rot3(), Point3(0, 0, 0.4)), Isotropic::Sigma(6, 1e-6))
            .twist(gtsam::Z_6x1, Isotropic::Sigma(6, 5e-5)));
  }

  // Add link and joint boundary conditions to FG.
  trajectory.addBoundaryConditions(&objectives, robot, dynamics_model_6,
                                   dynamics_model_6, objectives_model_6,
                                   objectives_model_1, objectives_model_1);

  // Constrain all Phase keys to have duration of 1 /240.
  const double desired_dt = 1. / 240;
  trajectory.addIntegrationTimeFactors(&objectives, desired_dt, 1e-30);

  // Add min torque objectives.
  trajectory.addMinimumTorqueFactors(&objectives, robot, Unit::Create(1));

  // Add prior on A1 lower joint angles
  auto prior_model = Isotropic::Sigma(1, 1e-6);
  for (auto&& joint : robot.joints())
    if (joint->name().find("lower") < 100)
      for (int k = 0; k <= K; k++) {
        //std::cout << joint->name() << joint->name().find("lower") << std::endl;
        objectives.add(JointObjectives(joint->id(), k).angle(-1.4, prior_model));
      }
  // Add objectives to factor graph.
  graph.add(objectives);

  // Add prior on A1 hip joint angles
  prior_model = Isotropic::Sigma(1, 1e-7);
  for (auto&& joint : robot.joints())
    if (joint->name().find("hip") < 100)
      for (int k = 0; k <= K; k++) {
        //std::cout << joint->name() << joint->name().find("hip") << std::endl;
        objectives.add(JointObjectives(joint->id(), k).angle(0.0, prior_model));
      }
  // Add objectives to factor graph.
   graph.add(objectives);

  // Initialize solution.
  double gaussian_noise = 1e-3;
  gtsam::Values init_vals =
      trajectory.multiPhaseInitialValues(robot, gaussian_noise, desired_dt);

  gttic_(optimization);

  // Optimize!
  gtsam::LevenbergMarquardtParams params;
  //params.setVerbosityLM("SUMMARY");
  params.setlambdaInitial(1e10);
  params.setlambdaLowerBound(1e-7);
  params.setlambdaUpperBound(1e10);
  params.setAbsoluteErrorTol(1.0);
  gtsam::LevenbergMarquardtOptimizer optimizer(graph, init_vals, params);
  auto results = optimizer.optimize();

  gttoc_(optimization);
  gttoc_(start);

  gtsam::tictoc_print_(); //need to build gtsam with timing for this
  // Write results to traj file
  trajectory.writeToFile(robot, "a1_traj.csv", results);

  return 0;
}


// Copyright 2017, 2018 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.

#include <boost/hash2/byte_type.hpp>
#include <boost/hash2/fnv1a.hpp>
#include <boost/hash2/siphash.hpp>
#include <boost/hash2/xxhash.hpp>
#include <boost/hash2/spooky2.hpp>
#include <boost/hash2/murmur3.hpp>
#include <boost/hash2/md5.hpp>
#include <boost/hash2/sha1.hpp>
#include <boost/core/lightweight_test.hpp>
#include <algorithm>
#include <cstddef>

using boost::hash2::byte_type;

template<class H> void test()
{
    char const * s = "xxxx";

    {
        H h;

        h.update( reinterpret_cast<byte_type const*>( s ), 4 );

        h.result();

        unsigned char const * p = reinterpret_cast<unsigned char const*>( &h );
        std::size_t n = sizeof( h );

        BOOST_TEST_EQ( std::search( p, p + n, s, s + 4 ) - p, n );
    }

    {
        H h;

        byte_type buffer[ 1024 ] = {};
        h.update( buffer, 1024 );

        h.update( reinterpret_cast<byte_type const*>( s ), 4 );

        h.result();

        unsigned char const * p = reinterpret_cast<unsigned char const*>( &h );
        std::size_t n = sizeof( h );

        BOOST_TEST_EQ( std::search( p, p + n, s, s + 4 ) - p, n );
    }
}

int main()
{
    test<boost::hash2::fnv1a_32>();
    test<boost::hash2::fnv1a_64>();
    test<boost::hash2::murmur3_32>();
    test<boost::hash2::murmur3_128>();
    test<boost::hash2::xxhash_32>();
    test<boost::hash2::xxhash_64>();
    test<boost::hash2::spooky2_128>();
    test<boost::hash2::siphash_32>();
    test<boost::hash2::siphash_64>();
    test<boost::hash2::md5_128>();
    test<boost::hash2::sha1_160>();
    test<boost::hash2::hmac_md5_128>();
    test<boost::hash2::hmac_sha1_160>();

    return boost::report_errors();
}


/** @file
 * @brief 数学ライブラリ
 * @author Takaaki Sato
 * @copyright Copyright (c) 2020 Demiquartz <info@demiquartz.jp> @n
 * Distributed under the MIT License (See accompanying file LICENSE
 * or copy at https://opensource.org/licenses/MIT)
 */
#ifndef FULLERENE_3B47EA0B_8CC7_4715_9074_318DADECFA0B
#define FULLERENE_3B47EA0B_8CC7_4715_9074_318DADECFA0B

#include <complex>
#include <boost/qvm/all.hpp>
#include <fullerene/types.hpp>

namespace Fullerene {

/**
 * @brief 複素数型
 *
 * @tparam T 数値型
 */
template<typename T>
using complex = std::complex<T>;

/**
 * @brief 四元数型
 *
 * @tparam T 数値型
 */
template<typename T>
using quaternion = boost::qvm::quat<T>;

} // Fullerene

#endif // FULLERENE_3B47EA0B_8CC7_4715_9074_318DADECFA0B


/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/list/instance.hpp>
#include <boost/hana/range.hpp>
#include <boost/hana/type_list.hpp>
using namespace boost::hana;

int main() {
    //! [main]
    BOOST_HANA_CONSTEXPR_LAMBDA auto grouped = group_by(comparing(length), list(
        list(1, 2, 3),
        list('x', 'y', 'z'),
        range_c<long, 0, 1>,
        type_list<char, int>,
        range_c<int, 0, 2>,
        list(123.4, nullptr)
    ));

    BOOST_HANA_CONSTEXPR_ASSERT(grouped == list(
        list(
            list(1, 2, 3),
            list('x', 'y', 'z')
        ),
        list(
            range_c<long, 0, 1>
        ),
        list(
            type_list<char, int>,
            range_c<int, 0, 2>,
            list(123.4, nullptr)
        )
    ));
    //! [main]
}


//
// Created by michel on 12-05-20.
//
#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>

/**
 * Never set these variables in code! These are meant to test the
 * test case:
 *  checkAlignment
 */
#define SIMPLE_CORE_SIMD_ALIGNMENT_COUNT 4
#define SIMPLE_CORE_SIMD_ALIGNMENT_TYPE 2

#include <simple-dsp/util/frame.h>

namespace {

static constexpr size_t FRAME_SIZE = 2;
typedef double vtype;
typedef simpledsp::Frame<vtype, FRAME_SIZE, true> Frame;
typedef simpledsp::Frame<vtype, FRAME_SIZE, false> UFrame;

template<bool algn>
void set(simpledsp::Frame<vtype, FRAME_SIZE, algn> &frame, vtype v1, vtype v2) {
  frame[0] = v1;
  frame[1] = v2;
}

template<bool algn1, bool algn2>
bool same(simpledsp::Frame<vtype, FRAME_SIZE, algn1> &frame1, simpledsp::Frame<vtype, FRAME_SIZE, algn2> &frame2) {
  for (size_t i = 0; i < Frame::size; i++) {
    if (frame1[i] != frame2[i]) {
      return false;
    }
  }
  return true;
}

} // namespace

BOOST_AUTO_TEST_SUITE(FrameTests)

/*
 * TODO: Much more test coverage!
 */

BOOST_AUTO_TEST_CASE(checkAlignment) {
  BOOST_CHECK_EQUAL(
      alignof(Frame), SIMPLE_CORE_SIMD_ALIGNMENT_COUNT * sizeof(vtype));
}

BOOST_AUTO_TEST_CASE(setAll) {
  Frame x;
  set(x, 13, 17);
  vtype value = 4;
  Frame expected;
  set(expected, value, value);
  x.set(value);
  BOOST_CHECK(same(x, expected));
}

BOOST_AUTO_TEST_CASE(testAddToAll) {
  Frame x;
  set(x, 13, 17);
  vtype add = 4;
  Frame expected;
  set(expected, x[0] + add, x[1] + add);
  x.add(add);
  BOOST_CHECK(same(x, expected));
}

BOOST_AUTO_TEST_CASE(testAddFrameToFrame) {
  Frame x;
  Frame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x + y;
  set(expected, 32, 46);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testAddUFrameToFrame) {
  Frame x;
  UFrame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x + y;
  set(expected, 32, 46);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testAddUFrameToFrameResultU) {
  Frame x;
  UFrame y;
  UFrame z;
  UFrame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x + y;
  set(expected, 32, 46);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testAddFrameToUFrame) {
  UFrame x;
  Frame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x + y;
  set(expected, 32, 46);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testAddFrameToUFrameResultU) {
  UFrame x;
  Frame y;
  UFrame z;
  UFrame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x + y;
  set(expected, 32, 46);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testSubFrameToFrame) {
  Frame x;
  Frame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x - y;
  set(expected, -6, -12);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testSubUFrameToFrame) {
  Frame x;
  UFrame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x - y;
  set(expected, -6, -12);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testSubUFrameToFrameResultU) {
  Frame x;
  UFrame y;
  UFrame z;
  UFrame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x - y;
  set(expected, -6, -12);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testSubFrameToUFrame) {
  UFrame x;
  Frame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x - y;
  set(expected, -6, -12);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testSubFrameToUFrameResultU) {
  UFrame x;
  Frame y;
  UFrame z;
  UFrame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x - y;
  set(expected, -6, -12);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testMulFrameWithValue) {
  Frame x;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  z = x * 4;
  set(expected, 52, 68);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testMulFrameWithValueAndAdd) {
  Frame x;
  Frame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = x * 4 + y;
  set(expected, 71, 97);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testAddToFrameWithAndMul) {
  Frame x;
  Frame y;
  Frame z;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  z = 4 * x + y;
  set(expected, 71, 97);
  BOOST_CHECK(same(z, expected));
}

BOOST_AUTO_TEST_CASE(testAssignSame) {
  Frame x;
  Frame y;
  Frame expected;
  printf("\n");
  set(x, 13, 17);
  set(y, 19, 29);
  y = x;
  set(expected, 13, 17);
  BOOST_CHECK(same(y, expected));
}

BOOST_AUTO_TEST_CASE(testAssignDifferent) {
  UFrame x;
  Frame y;
  Frame expected;
  set(x, 13, 17);
  set(y, 19, 29);
  y = x;
  set(expected, 13, 17);
  BOOST_CHECK(same(y, expected));
}

BOOST_AUTO_TEST_SUITE_END()


//============================================================================
// Name        : Reduction.cpp
// Author      : Gustavo Banegas
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <armadillo>
#include <fstream>

#include "GenerateMatrix.h"

#include <sstream>

#define SSTR( x ) dynamic_cast< std::ostringstream & >( \
        ( std::ostringstream() << std::dec << x ) ).str()

using namespace std;
using namespace arma;

std::vector<std::string> &split(const std::string &s, char delim,
		std::vector<std::string> &elems) {
	std::stringstream ss(s);
	std::string item;
	while (std::getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
	std::vector<std::string> elems;
	split(s, delim, elems);
	return elems;
}

std::string removechars(const std::string& source, const std::string& chars) {
	std::string result = "";
	for (unsigned int i = 0; i < source.length(); i++) {
		bool foundany = false;
		for (unsigned int j = 0; j < chars.length() && !foundany; j++) {
			foundany = (source[i] == chars[j]);
		}
		if (!foundany) {
			result += source[i];
		}
	}
	return result;
}

int main() {
	string line;
	ofstream writefile;
	writefile.open("result_teste_1.txt");
	ifstream myfile;
	myfile.open("pol_n.txt");
	std::vector<std::vector<int> > exps;
	std::map<std::vector<int>, std::string> vector_string;
	while (getline(myfile, line)) {
		std::string resultS;
		resultS = "[";
		vector<int> exp;
		std::vector<std::string> splited = split(line, '+');
		std::vector<std::string>::const_iterator cii;
		for (cii = splited.begin(); cii != splited.end() - 1; ++cii) {
			std::string re = removechars(*cii, "x^ ");
			if (re.empty())
				re = "1";
			resultS += re;
			resultS += ",";
			//cout << re << endl;
			exp.push_back(atoi(re.c_str()));
		}
		cout << line << '\n';

		exp.push_back(0);
		resultS += "0]:";
		exps.push_back(exp);
		vector_string[exp] = resultS;
		GenerateMatrix* matrix = new GenerateMatrix(exp);
		int result = matrix->red();
		//char *intStr = itoa(result);
		string str = SSTR(result);
		resultS += str;
		writefile << resultS << "\n";
		cout << resultS  << endl;

		//cout << "Result : " << result << endl;
	}
	writefile.close();

	// prints !!!Hello World!!!
	return 0;
}


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

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

#ifndef BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_NSPHERE_HPP
#define BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_NSPHERE_HPP

#include <cstddef>

#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>

#include <boost/geometry/extensions/nsphere/core/tags.hpp>
#include <boost/geometry/extensions/nsphere/algorithms/assign.hpp>
#include <boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp>

namespace boost { namespace geometry
{

namespace model
{

/*!
    \brief Class nsphere: defines a circle or a sphere: a point with radius
    \ingroup Geometry
    \details The name nsphere is quite funny but the best description of the class. It can be a circle (2D),
    a sphere (3D), or higher (hypersphere) or lower. According to Wikipedia this name is the most appropriate.
    It was mentioned on the Boost list.
    An alternative is the more fancy name "sphercle" but that might be a bit too much an invention.
    \note Circle is currently used for selections, for example polygon_in_circle. Currently not all
    algorithms are implemented for n-spheres.
    \tparam P point type of the center
    \tparam T number type of the radius
 */
template <typename P, typename T>
class nsphere
{
    BOOST_CONCEPT_ASSERT( (concept::Point<P>) );

public:

    typedef T radius_type;
    typedef typename coordinate_type<P>::type coordinate_type;

    nsphere()
        : m_radius(0)
    {
        assign_value(m_center, coordinate_type());
    }

    nsphere(P const& center, T const& radius)
        : m_radius(radius)
    {
        geometry::convert(center, m_center);
    }

    inline P const& center() const { return m_center; }
    inline T const& radius() const { return m_radius; }

    inline void radius(T const& r) { m_radius = r; }
    inline P& center() { return m_center; }

private:

    P m_center;
    T m_radius;
};

} // namespace model

// Traits specializations for n-sphere above
#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
namespace traits
{

template <typename Point, typename RadiusType>
struct tag<model::nsphere<Point, RadiusType> >
{
    typedef nsphere_tag type;
};

template <typename Point, typename RadiusType>
struct point_type<model::nsphere<Point, RadiusType> >
{
    typedef Point type;
};

template <typename Point, typename RadiusType>
struct radius_type<model::nsphere<Point, RadiusType> >
{
    typedef RadiusType type;
};

template <typename Point, typename CoordinateType, std::size_t Dimension>
struct access<model::nsphere<Point, CoordinateType>,  Dimension>
{
    typedef model::nsphere<Point, CoordinateType> nsphere_type;

    static inline CoordinateType get(nsphere_type const& s)
    {
        return geometry::get<Dimension>(s.center());
    }

    static inline void set(nsphere_type& s, CoordinateType const& value)
    {
        geometry::set<Dimension>(s.center(), value);
    }
};

template <typename Point, typename RadiusType>
struct radius_access<model::nsphere<Point, RadiusType>, 0>
{
    typedef model::nsphere<Point, RadiusType> nsphere_type;

    static inline RadiusType get(nsphere_type const& s)
    {
        return s.radius();
    }

    static inline void set(nsphere_type& s, RadiusType const& value)
    {
        s.radius(value);
    }
};

} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_NSPHERE_HPP


#include <blitz/array.h>
#include <blitz/array/cartesian.h>
#include <list>

BZ_USING_NAMESPACE(blitz)

int main()
{
    list<int> index1;
    index1.push_back(5);
    index1.push_back(7);
    index1.push_back(9);

    list<int> index2;
    index2.push_back(1);
    index2.push_back(2);
    index2.push_back(4);
    index2.push_back(7);

    CartesianProduct<TinyVector<int,2>,list<int>,2> indexSet(index1,index2);
    typedef CartesianProduct<TinyVector<int,2>,list<int>,2>::iterator T_iterator;

    T_iterator iter = indexSet.begin(), end = indexSet.end();
    for (; iter != end; ++iter)
        cout << *iter << endl;

    return 0;
}


#include "PID.h"

#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/range/numeric.hpp>

PID::PID() {}

PID::~PID() {}

void PID::Init(double Kp_, double Ki_, double Kd_) {
  Kp = Kp_;
  Ki = Ki_;
  Kd = Kd_;

  p_error = 0;
  i_error = 0;
  d_error = 0;

  cum_err = 0;

  twiddle_p = {Kp, Ki, Kd};
  double fdp = 0.1;
  twiddle_dp = {fdp, fdp, fdp};
  twiddle_set_large_up = false;
  twiddle_set_large_down = false;
  twiddle_check_large_up = false;
  twiddle_check_large_down = false;

}

void PID::UpdateError(double cte) {
  d_error = cte - p_error; // diff to prev. cte
  i_error += cte;
  p_error = cte;

}

double PID::TotalError() {
  /**
   * TODO: Calculate and return the total error
   */
  return 0.0;  // TODO: Add your total error calc here!
}

double PID::SteeringAngle(double max_steer=0.25) {
  double steer = -Kp * p_error - Ki * i_error - Kd * d_error;
  return std::max(std::min(steer, max_steer), -max_steer);

}

void PID::log_tune(std::ofstream &logfile, double &cte, double &speed, int &step) {
  logfile << std::max(0,tune_iter) << "," << cum_err << ","
          << cte << "," << speed << ","
          << Kp << "," << Ki << "," << Kd << "\n";
}

void PID::log_summary(std::ofstream &summary) {
  summary << std::max(0,tune_iter) << "," << cum_err << "," << best_err << ","
          << boost::accumulate(twiddle_dp, 0.) << "," << target_speed << ","
          << Kp << "," << Ki << "," << Kd << "\n";
}

// Twiddle 'in-line', i.e. this is called after each single run, setting params for next run
void PID::twiddle(std::ofstream &summary) {
  if (tune_iter == -1) {
    tune_iter = 0;
    best_err = cum_err;
  }
  if (twiddle_set_large_up == false) {
    twiddle_set_large_up = true;
    twiddle_p[twiddle_iter_p] += twiddle_p[twiddle_iter_p] * twiddle_dp[twiddle_iter_p];
  } else if (twiddle_check_large_up == false) {
      twiddle_check_large_up = true;
      if (cum_err < best_err) {
        twiddle_dp[twiddle_iter_p] *= 1.1;
      } else if (twiddle_set_large_down == false) {
          twiddle_set_large_down = true;
          twiddle_p[twiddle_iter_p] -= 2 * twiddle_p[twiddle_iter_p] *  twiddle_dp[twiddle_iter_p];
          }
    } else if (twiddle_check_large_down == false) {
        twiddle_check_large_down = true;
        if (cum_err < best_err) {
          twiddle_dp[twiddle_iter_p] *= 1.1;
        } else {
            twiddle_p[twiddle_iter_p] += twiddle_p[twiddle_iter_p] * twiddle_dp[twiddle_iter_p];
            twiddle_dp[twiddle_iter_p] *= 0.9;
          }
      }

  if (cum_err < best_err || (twiddle_check_large_down == true && twiddle_check_large_up == true)) {
    if (twiddle_iter_p < 2) {
      if (Ki == 0) { // skip I, for faster PD convergence
        twiddle_iter_p = 2;
      } else {
          twiddle_iter_p++;
        }
      } else {
        twiddle_iter_p = 0;
        tune_iter++;
      }
    if (cum_err < best_err) best_err = cum_err;
    twiddle_p[twiddle_iter_p] += twiddle_p[twiddle_iter_p] * twiddle_dp[twiddle_iter_p];
    twiddle_set_large_up = true;
    twiddle_set_large_down = false;
    twiddle_check_large_down = false;
    twiddle_check_large_up = false;
  }
  log_summary(summary);
  // stop updating PID params if twiddle is done
  if (boost::accumulate(twiddle_dp, 0.) > tune_tolerance) {
    Kp = twiddle_p[0];
    Ki = twiddle_p[1];
    Kd = twiddle_p[2];
  }

}


#ifdef DEALII
#include <deal.II/grid/tria.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_out.h>
#include <deal.II/grid/grid_in.h>
#include <iostream>
#include <fstream>
#include <cmath>
using namespace dealii;
using namespace std;

void _dealii() {
    auto first_grid = [&]() {
        Triangulation<2> tria;
        GridGenerator::hyper_cube(tria);
        tria.refine_global(4); // a cube with an area and patch size
        for (auto& cell : tria.active_cell_iterators()) {
            cout << cell->index() << endl;
        }
        map<unsigned, double> inputs;

        map<unsigned, double> outputs;

    };

    auto second_grid = [&]() {
        Triangulation<2> tria;
        ifstream file("grid-1.vtk");
        GridIn<2, 2> grid;
        grid.attach_triangulation(tria);
        grid.read_vtk(file);
        for (auto& cell : tria.active_cell_iterators()) {
            cout << cell->index() << endl;
        }
        cout << tria.n_active_cells() << endl;
    };
    first_grid();
    //second_grid();
}

#endif //dealii
#ifdef VTK
#include <vtkGenericDataObjectReader.h>
#include <vtkStructuredGrid.h>
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <string>
void _vtk()
{
    cout << "insde vtk" << endl;
    // simply set filename here (oh static joy)
    std::string inputFilename = "setYourPathToVtkFileHere";

    // Get all data from the file
    vtkSmartPointer<vtkGenericDataObjectReader> reader =
        vtkSmartPointer<vtkGenericDataObjectReader>::New();
    reader->SetFileName(inputFilename.c_str());
    reader->Update();

    // All of the standard data types can be checked and obtained like this:
    if (reader->IsFilePolyData())
    {
        std::cout << "output is a polydata" << std::endl;
        vtkPolyData* output = reader->GetPolyDataOutput();
        std::cout << "output has " << output->GetNumberOfPoints() << " points." << std::endl;
    }

}
#endif //vtk

int main()
{
#ifdef DEALII
    _dealii();
#endif //DEALII
#ifdef VTK
    _vtk();
#endif //vtk

}


/*=============================================================================
    Copyright (c) 2011 Jan Frederick Eick

    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/spirit/include/qi_uint.hpp>

#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/support_argument.hpp>

#include <climits>
#include <cstring>
#include "test.hpp"

#include "uint_radix.hpp"

int
main()
{
    using spirit_test::test;
    using spirit_test::test_attr;

    using boost::spirit::qi::uint_;
    using boost::spirit::qi::uint_parser;

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 3)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 3, 1, -1>             base3_parser;

        BOOST_TEST(test("210112221200",                 base3_parser));
        BOOST_TEST(test_attr("210112221200",            base3_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("1231",                        base3_parser));
        BOOST_TEST(!test_attr("1231",                   base3_parser, u));

        BOOST_TEST(test(max_unsigned_base3,             base3_parser));
        BOOST_TEST(test_attr(max_unsigned_base3,        base3_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base3,       base3_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base3,  base3_parser, u));
        BOOST_TEST(!test(digit_overflow_base3,          base3_parser));
        BOOST_TEST(!test_attr(digit_overflow_base3,     base3_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 4)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;

        uint_parser<unsigned int, 4, 1, -1>             base4_parser;

        BOOST_TEST(test("1213210302",                   base4_parser));
        BOOST_TEST(test_attr("1213210302",              base4_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("1234",                        base4_parser));
        BOOST_TEST(!test_attr("1234",                   base4_parser, u));

        BOOST_TEST(test(max_unsigned_base4,             base4_parser));
        BOOST_TEST(test_attr(max_unsigned_base4,        base4_parser, u));
        BOOST_TEST(!test(digit_overflow_base4,          base4_parser));
        BOOST_TEST(!test_attr(digit_overflow_base4,     base4_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 5)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;

        uint_parser<unsigned int, 5, 1, -1>             base5_parser;

        BOOST_TEST(test("102033432",                    base5_parser));
        BOOST_TEST(test_attr("102033432",               base5_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("2345",                        base5_parser));
        BOOST_TEST(!test_attr("2345",                   base5_parser, u));

        BOOST_TEST(test(max_unsigned_base5,             base5_parser));
        BOOST_TEST(test_attr(max_unsigned_base5,        base5_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base5,       base5_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base5,  base5_parser, u));
        BOOST_TEST(!test(digit_overflow_base5,          base5_parser));
        BOOST_TEST(!test_attr(digit_overflow_base5,     base5_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 6)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;

        uint_parser<unsigned int, 6, 1, -1>             base6_parser;

        BOOST_TEST(test("13032030",                     base6_parser));
        BOOST_TEST(test_attr("13032030",                base6_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("3456",                        base6_parser));
        BOOST_TEST(!test_attr("3456",                   base6_parser, u));

        BOOST_TEST(test(max_unsigned_base6,             base6_parser));
        BOOST_TEST(test_attr(max_unsigned_base6,        base6_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base6,       base6_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base6,  base6_parser, u));
        BOOST_TEST(!test(digit_overflow_base6,          base6_parser));
        BOOST_TEST(!test_attr(digit_overflow_base6,     base6_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 7)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;

        uint_parser<unsigned int, 7, 1, -1>             base7_parser;

        BOOST_TEST(test("3414600",                      base7_parser));
        BOOST_TEST(test_attr("3414600",                 base7_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("4567",                        base7_parser));
        BOOST_TEST(!test_attr("4567",                   base7_parser, u));

        BOOST_TEST(test(max_unsigned_base7,             base7_parser));
        BOOST_TEST(test_attr(max_unsigned_base7,        base7_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base7,       base7_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base7,  base7_parser, u));
        BOOST_TEST(!test(digit_overflow_base7,          base7_parser));
        BOOST_TEST(!test_attr(digit_overflow_base7,     base7_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 9)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;

        uint_parser<unsigned int, 9, 1, -1>             base9_parser;

        BOOST_TEST(test("715850",                       base9_parser));
        BOOST_TEST(test_attr("715850",                  base9_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("6789",                        base9_parser));
        BOOST_TEST(!test_attr("6789",                   base9_parser, u));

        BOOST_TEST(test(max_unsigned_base9,             base9_parser));
        BOOST_TEST(test_attr(max_unsigned_base9,        base9_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base9,       base9_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base9,  base9_parser, u));
        BOOST_TEST(!test(digit_overflow_base9,          base9_parser));
        BOOST_TEST(!test_attr(digit_overflow_base9,     base9_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 11)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;

        uint_parser<unsigned int, 11, 1, -1>            base11_parser;

        BOOST_TEST(test("26a815",                       base11_parser));
        BOOST_TEST(test_attr("26a815",                  base11_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("90ab",                        base11_parser));
        BOOST_TEST(!test_attr("90AB",                   base11_parser, u));

        BOOST_TEST(test(max_unsigned_base11,            base11_parser));
        BOOST_TEST(test_attr(max_unsigned_base11,       base11_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base11,      base11_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base11, base11_parser, u));
        BOOST_TEST(!test(digit_overflow_base11,         base11_parser));
        BOOST_TEST(!test_attr(digit_overflow_base11,    base11_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 12)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 12, 1, -1>            base12_parser;

        BOOST_TEST(test("185616",                       base12_parser));
        BOOST_TEST(test_attr("185616",                  base12_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("9abc",                        base12_parser));
        BOOST_TEST(!test_attr("9ABC",                   base12_parser, u));

        BOOST_TEST(test(max_unsigned_base12,            base12_parser));
        BOOST_TEST(test_attr(max_unsigned_base12,       base12_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base12,      base12_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base12, base12_parser, u));
        BOOST_TEST(!test(digit_overflow_base12,         base12_parser));
        BOOST_TEST(!test_attr(digit_overflow_base12,    base12_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 13)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 13, 1, -1>            base13_parser;

        BOOST_TEST(test("11b140",                       base13_parser));
        BOOST_TEST(test_attr("11b140",                  base13_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("abcd",                        base13_parser));
        BOOST_TEST(!test_attr("ABCD",                   base13_parser, u));

        BOOST_TEST(test(max_unsigned_base13,            base13_parser));
        BOOST_TEST(test_attr(max_unsigned_base13,       base13_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base13,      base13_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base13, base13_parser, u));
        BOOST_TEST(!test(digit_overflow_base13,         base13_parser));
        BOOST_TEST(!test_attr(digit_overflow_base13,    base13_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 14)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 14, 1, -1>            base14_parser;

        BOOST_TEST(test("b0870",                        base14_parser));
        BOOST_TEST(test_attr("b0870",                   base14_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("bcde",                        base14_parser));
        BOOST_TEST(!test_attr("BCDE",                   base14_parser, u));

        BOOST_TEST(test(max_unsigned_base14,            base14_parser));
        BOOST_TEST(test_attr(max_unsigned_base14,       base14_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base14,      base14_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base14, base14_parser, u));
        BOOST_TEST(!test(digit_overflow_base14,         base14_parser));
        BOOST_TEST(!test_attr(digit_overflow_base14,    base14_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 15)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 15, 1, -1>            base15_parser;

        BOOST_TEST(test("85a7c",                        base15_parser));
        BOOST_TEST(test_attr("85a7c",                   base15_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("cdef",                        base15_parser));
        BOOST_TEST(!test_attr("CDEF",                   base15_parser, u));

        BOOST_TEST(test(max_unsigned_base15,            base15_parser));
        BOOST_TEST(test_attr(max_unsigned_base15,       base15_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base15,      base15_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base15, base15_parser, u));
        BOOST_TEST(!test(digit_overflow_base15,         base15_parser));
        BOOST_TEST(!test_attr(digit_overflow_base15,    base15_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 17)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 17, 1, -1>            base17_parser;

        BOOST_TEST(test("515g7",                        base17_parser));
        BOOST_TEST(test_attr("515g7",                   base17_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("efgh",                        base17_parser));
        BOOST_TEST(!test_attr("EFGH",                   base17_parser, u));

        BOOST_TEST(test(max_unsigned_base17,            base17_parser));
        BOOST_TEST(test_attr(max_unsigned_base17,       base17_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base17,      base17_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base17, base17_parser, u));
        BOOST_TEST(!test(digit_overflow_base17,         base17_parser));
        BOOST_TEST(!test_attr(digit_overflow_base17,    base17_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 18)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 18, 1, -1>            base18_parser;

        BOOST_TEST(test("40d70",                        base18_parser));
        BOOST_TEST(test_attr("40d70",                   base18_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("fghi",                        base18_parser));
        BOOST_TEST(!test_attr("FGHI",                   base18_parser, u));

        BOOST_TEST(test(max_unsigned_base18,            base18_parser));
        BOOST_TEST(test_attr(max_unsigned_base18,       base18_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base18,      base18_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base18, base18_parser, u));
        BOOST_TEST(!test(digit_overflow_base18,         base18_parser));
        BOOST_TEST(!test_attr(digit_overflow_base18,    base18_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 19)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 19, 1, -1>            base19_parser;

        BOOST_TEST(test("34g3a",                        base19_parser));
        BOOST_TEST(test_attr("34g3a",                   base19_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("ghij",                        base19_parser));
        BOOST_TEST(!test_attr("GHIJ",                   base19_parser, u));

        BOOST_TEST(test(max_unsigned_base19,            base19_parser));
        BOOST_TEST(test_attr(max_unsigned_base19,       base19_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base19,      base19_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base19, base19_parser, u));
        BOOST_TEST(!test(digit_overflow_base19,         base19_parser));
        BOOST_TEST(!test_attr(digit_overflow_base19,    base19_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 20)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 20, 1, -1>            base20_parser;

        BOOST_TEST(test("2d0c2",                        base20_parser));
        BOOST_TEST(test_attr("2d0c2",                   base20_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("hijk",                        base20_parser));
        BOOST_TEST(!test_attr("HIJK",                   base20_parser, u));

        BOOST_TEST(test(max_unsigned_base20,            base20_parser));
        BOOST_TEST(test_attr(max_unsigned_base20,       base20_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base20,      base20_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base20, base20_parser, u));
        BOOST_TEST(!test(digit_overflow_base20,         base20_parser));
        BOOST_TEST(!test_attr(digit_overflow_base20,    base20_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 21)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 21, 1, -1>            base21_parser;

        BOOST_TEST(test("23h00",                        base21_parser));
        BOOST_TEST(test_attr("23h00",                   base21_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("ijkl",                        base21_parser));
        BOOST_TEST(!test_attr("IJKL",                   base21_parser, u));

        BOOST_TEST(test(max_unsigned_base21,            base21_parser));
        BOOST_TEST(test_attr(max_unsigned_base21,       base21_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base21,      base21_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base21, base21_parser, u));
        BOOST_TEST(!test(digit_overflow_base21,         base21_parser));
        BOOST_TEST(!test_attr(digit_overflow_base21,    base21_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 22)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 22, 1, -1>            base22_parser;

        BOOST_TEST(test("1hibg",                        base22_parser));
        BOOST_TEST(test_attr("1hibg",                   base22_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("jklm",                        base22_parser));
        BOOST_TEST(!test_attr("JKLM",                   base22_parser, u));

        BOOST_TEST(test(max_unsigned_base22,            base22_parser));
        BOOST_TEST(test_attr(max_unsigned_base22,       base22_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base22,      base22_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base22, base22_parser, u));
        BOOST_TEST(!test(digit_overflow_base22,         base22_parser));
        BOOST_TEST(!test_attr(digit_overflow_base22,    base22_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 23)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 23, 1, -1>            base23_parser;

        BOOST_TEST(test("1bjm7",                        base23_parser));
        BOOST_TEST(test_attr("1bjm7",                   base23_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("klmn",                        base23_parser));
        BOOST_TEST(!test_attr("KLMN",                   base23_parser, u));

        BOOST_TEST(test(max_unsigned_base23,            base23_parser));
        BOOST_TEST(test_attr(max_unsigned_base23,       base23_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base23,      base23_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base23, base23_parser, u));
        BOOST_TEST(!test(digit_overflow_base23,         base23_parser));
        BOOST_TEST(!test_attr(digit_overflow_base23,    base23_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 24)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 24, 1, -1>            base24_parser;

        BOOST_TEST(test("16gci",                        base24_parser));
        BOOST_TEST(test_attr("16gci",                   base24_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("lmno",                        base24_parser));
        BOOST_TEST(!test_attr("LMNO",                   base24_parser, u));

        BOOST_TEST(test(max_unsigned_base24,            base24_parser));
        BOOST_TEST(test_attr(max_unsigned_base24,       base24_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base24,      base24_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base24, base24_parser, u));
        BOOST_TEST(!test(digit_overflow_base24,         base24_parser));
        BOOST_TEST(!test_attr(digit_overflow_base24,    base24_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 25)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 25, 1, -1>            base25_parser;

        BOOST_TEST(test("123jh",                        base25_parser));
        BOOST_TEST(test_attr("123jh",                   base25_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("mnop",                        base25_parser));
        BOOST_TEST(!test_attr("MNOP",                   base25_parser, u));

        BOOST_TEST(test(max_unsigned_base25,            base25_parser));
        BOOST_TEST(test_attr(max_unsigned_base25,       base25_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base25,      base25_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base25, base25_parser, u));
        BOOST_TEST(!test(digit_overflow_base25,         base25_parser));
        BOOST_TEST(!test_attr(digit_overflow_base25,    base25_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 26)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 26, 1, -1>            base26_parser;

        BOOST_TEST(test("o3f0",                         base26_parser));
        BOOST_TEST(test_attr("o3f0",                    base26_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("nopq",                        base26_parser));
        BOOST_TEST(!test_attr("NOPQ",                   base26_parser, u));

        BOOST_TEST(test(max_unsigned_base26,            base26_parser));
        BOOST_TEST(test_attr(max_unsigned_base26,       base26_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base26,      base26_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base26, base26_parser, u));
        BOOST_TEST(!test(digit_overflow_base26,         base26_parser));
        BOOST_TEST(!test_attr(digit_overflow_base26,    base26_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 27)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 27, 1, -1>            base27_parser;

        BOOST_TEST(test("lepi",                         base27_parser));
        BOOST_TEST(test_attr("lepi",                    base27_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("opqr",                        base27_parser));
        BOOST_TEST(!test_attr("OPQR",                   base27_parser, u));

        BOOST_TEST(test(max_unsigned_base27,            base27_parser));
        BOOST_TEST(test_attr(max_unsigned_base27,       base27_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base27,      base27_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base27, base27_parser, u));
        BOOST_TEST(!test(digit_overflow_base27,         base27_parser));
        BOOST_TEST(!test_attr(digit_overflow_base27,    base27_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 28)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 28, 1, -1>            base28_parser;

        BOOST_TEST(test("j93e",                         base28_parser));
        BOOST_TEST(test_attr("j93e",                    base28_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("pqrs",                        base28_parser));
        BOOST_TEST(!test_attr("PQRS",                   base28_parser, u));

        BOOST_TEST(test(max_unsigned_base28,            base28_parser));
        BOOST_TEST(test_attr(max_unsigned_base28,       base28_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base28,      base28_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base28, base28_parser, u));
        BOOST_TEST(!test(digit_overflow_base28,         base28_parser));
        BOOST_TEST(!test_attr(digit_overflow_base28,    base28_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 29)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 29, 1, -1>            base29_parser;

        BOOST_TEST(test("hbd1",                         base29_parser));
        BOOST_TEST(test_attr("hbd1",                    base29_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("qrst",                        base29_parser));
        BOOST_TEST(!test_attr("QRST",                   base29_parser, u));

        BOOST_TEST(test(max_unsigned_base29,            base29_parser));
        BOOST_TEST(test_attr(max_unsigned_base29,       base29_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base29,      base29_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base29, base29_parser, u));
        BOOST_TEST(!test(digit_overflow_base29,         base29_parser));
        BOOST_TEST(!test_attr(digit_overflow_base29,    base29_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 30)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 30, 1, -1>            base30_parser;

        BOOST_TEST(test("flbc",                         base30_parser));
        BOOST_TEST(test_attr("flbc",                    base30_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("rstu",                        base30_parser));
        BOOST_TEST(!test_attr("RSTU",                   base30_parser, u));

        BOOST_TEST(test(max_unsigned_base30,            base30_parser));
        BOOST_TEST(test_attr(max_unsigned_base30,       base30_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base30,      base30_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base30, base30_parser, u));
        BOOST_TEST(!test(digit_overflow_base30,         base30_parser));
        BOOST_TEST(!test_attr(digit_overflow_base30,    base30_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 31)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 31, 1, -1>            base31_parser;

        BOOST_TEST(test("e7e7",                         base31_parser));
        BOOST_TEST(test_attr("e7e7",                    base31_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("stuv",                        base31_parser));
        BOOST_TEST(!test_attr("STUV",                   base31_parser, u));

        BOOST_TEST(test(max_unsigned_base31,            base31_parser));
        BOOST_TEST(test_attr(max_unsigned_base31,       base31_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base31,      base31_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base31, base31_parser, u));
        BOOST_TEST(!test(digit_overflow_base31,         base31_parser));
        BOOST_TEST(!test_attr(digit_overflow_base31,    base31_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 32)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 32, 1, -1>            base32_parser;

        BOOST_TEST(test("cu9i",                         base32_parser));
        BOOST_TEST(test_attr("cu9i",                    base32_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("tuvw",                        base32_parser));
        BOOST_TEST(!test_attr("TUVW",                   base32_parser, u));

        BOOST_TEST(test(max_unsigned_base32,            base32_parser));
        BOOST_TEST(test_attr(max_unsigned_base32,       base32_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base32,      base32_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base32, base32_parser, u));
        BOOST_TEST(!test(digit_overflow_base32,         base32_parser));
        BOOST_TEST(!test_attr(digit_overflow_base32,    base32_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 33)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 33, 1, -1>            base33_parser;

        BOOST_TEST(test("bqir",                         base33_parser));
        BOOST_TEST(test_attr("bqir",                    base33_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("uvwx",                        base33_parser));
        BOOST_TEST(!test_attr("UVWX",                   base33_parser, u));

        BOOST_TEST(test(max_unsigned_base33,            base33_parser));
        BOOST_TEST(test_attr(max_unsigned_base33,       base33_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base33,      base33_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base33, base33_parser, u));
        BOOST_TEST(!test(digit_overflow_base33,         base33_parser));
        BOOST_TEST(!test_attr(digit_overflow_base33,    base33_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 34)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 34, 1, -1>            base34_parser;

        BOOST_TEST(test("aqxo",                         base34_parser));
        BOOST_TEST(test_attr("aqxo",                    base34_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("vwxy",                        base34_parser));
        BOOST_TEST(!test_attr("VWXY",                   base34_parser, u));

        BOOST_TEST(test(max_unsigned_base34,            base34_parser));
        BOOST_TEST(test_attr(max_unsigned_base34,       base34_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base34,      base34_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base34, base34_parser, u));
        BOOST_TEST(!test(digit_overflow_base34,         base34_parser));
        BOOST_TEST(!test_attr(digit_overflow_base34,    base34_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 35)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 35, 1, -1>            base35_parser;

        BOOST_TEST(test("9vb7",                         base35_parser));
        BOOST_TEST(test_attr("9vb7",                    base35_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(!test("wxyz",                        base35_parser));
        BOOST_TEST(!test_attr("WXYZ",                   base35_parser, u));

        BOOST_TEST(test(max_unsigned_base35,            base35_parser));
        BOOST_TEST(test_attr(max_unsigned_base35,       base35_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base35,      base35_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base35, base35_parser, u));
        BOOST_TEST(!test(digit_overflow_base35,         base35_parser));
        BOOST_TEST(!test_attr(digit_overflow_base35,    base35_parser, u));
    }

    ///////////////////////////////////////////////////////////////////////////
    //  arbitrary radix test (base 36)
    ///////////////////////////////////////////////////////////////////////////
    {
        unsigned int u;
        uint_parser<unsigned int, 36, 1, -1>            base36_parser;

        BOOST_TEST(test("93ci",                         base36_parser));
        BOOST_TEST(test_attr("93ci",                    base36_parser, u));
        BOOST_TEST(424242 == u);

        BOOST_TEST(test(max_unsigned_base36,            base36_parser));
        BOOST_TEST(test_attr(max_unsigned_base36,       base36_parser, u));

        BOOST_TEST(!test(unsigned_overflow_base36,      base36_parser));
        BOOST_TEST(!test_attr(unsigned_overflow_base36, base36_parser, u));
        BOOST_TEST(!test(digit_overflow_base36,         base36_parser));
        BOOST_TEST(!test_attr(digit_overflow_base36,    base36_parser, u));
    }

    return boost::report_errors();
}


/**************************************************************************
** Copyright (C) 2010-2017 Toshinobu Hondo, Ph.D.
** Copyright (C) 2013-2017 MS-Cheminformatics LLC, Toin, Mie Japan
*
** Contact: toshi.hondo@qtplatz.com
**
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**************************************************************************/

#if ARRAYFIRE
# include <arrayfire.h>
# include <af/cuda.h>
#endif
#if OPENCV
# include <opencv2/opencv.hpp>
#endif
#include <boost/format.hpp>
#include "colormap.hpp"
#include <iomanip>

template< typename T > using af_unique_ptr = std::unique_ptr< T, std::function<void(T*)> >;

int
main(int argc, char * argv[])
{
    (void)argc;
    (void)argv;

    float data[]  = { 0.10, 0.11, 0.12, 0.13, 0.14, 0.15
                      , 0.20, 0.21, 0.22, 0.23, 0.24, 0.25
                      , 0.30, 0.31, 0.32, 0.33, 0.34, 0.35
                      , 0.40, 0.41, 0.42, 0.43, 0.44, 0.45
                      , 0.50, 0.51, 0.52, 0.53, 0.54, 0.55
    };
    constexpr size_t ncols = 6;
    constexpr size_t nrows = 5;

#if 1
    // OpenCV cv::Mat <--> af::arry conversion
    // no transposed version
    {
        // mat is the row,col array
        cv::Mat mat = cv::Mat( 5, ncols, CV_32FC(1), data );
        std::cout << "Source cv::Mat : " << mat << std::endl;

        // array is the col,row array
        std::cout << "--------------------------------------------------" << std::endl;
        af::array gray = af::array( mat.cols, mat.rows, 1, mat.ptr< float >( 0 ) );
        af::print( "Converted to af::array gray: ", gray );

        af::array rgb = af::gray2rgb( gray );
        af::print( "rgb: ", rgb );

        // https://groups.google.com/forum/#!topic/arrayfire-users/34_AFiXRnKg
        af::array rgb_t = af::reorder( rgb, 2, 0, 1 ) * 255; // Converts 3rd dimention to be the first dimension
        af::print( "rgb_t: ", rgb_t );

        auto mat2 = cv::Mat( mat.rows, mat.cols, CV_8UC(3) );
        rgb_t.as( u8 ).host( /* reinterpret_cast< void * > */ ( mat2.ptr< uchar >( 0 ) ) );

        std::cout << "Back to cv::Mat :\n" << mat2 << std::endl;
    }
#endif
#if 1
    // transposed version
    {
        cv::Mat mat = cv::Mat( 4, ncols, CV_32FC(1), data );
        std::cout << "--------------------------------------------------" << std::endl;
        af::array gray = af::array( mat.cols, mat.rows, 1, mat.ptr< float >( 0 ) ).T();
        af::print( "Converted to af::array (transposed) gray: ", gray );

        // rgb as af native format
        af::array rgb = af::gray2rgb( gray );
        af::print( "rgb: ", rgb );

        const int channels = rgb.dims( 2 );
        af::array rgb_t = rgb.T();
        af::print( "rgb_t", rgb_t );

        // https://groups.google.com/forum/#!topic/arrayfire-users/34_AFiXRnKg
        // Converts 3rd dimention to be the first dimension
        auto cv_format_rgb = af::reorder( rgb_t, 2, 0, 1 ); // * 255;
        af::print( "cv_format_rgb", cv_format_rgb );

        auto mat2 = cv::Mat( mat.rows, mat.cols, CV_8UC(3) );
        cv_format_rgb.as( u8 ).host( /* reinterpret_cast< void * > */ ( mat2.ptr< uchar >( 0 ) ) );

        std::cout << "Back to cv::Mat :\n" << mat2 << std::endl;
    }
#endif
#if 1
    // BGR color
    {
        // it seems that af::print does not properly working for u8 data array though f32 works well.
        typedef float bgr_dtype;
        //typedef uint8_t bgr_dtype;
        cv::Mat bgr;
        cv::Mat gray = cv::Mat( 4, ncols, CV_32FC(1), data ) * 100;
        //gray.convertTo( gray, CV_8U );
        cv::cvtColor( gray, bgr, cv::COLOR_GRAY2BGR );

        const uint32_t channels = ( ( uint32_t( bgr.type() ) >> 3 ) & 0xf ) + 1;
        std::cout << "bgr(" << bgr.rows << ", " << bgr.cols << ") channels=" << channels << ":\n" << bgr << std::oct << std::endl;

        af::array a = af::array( channels, bgr.cols, bgr.rows, bgr.ptr< bgr_dtype >() );
        af::array abgr = af::reorder( a, 1, 2, 0 );
        //af::print( "a", a );
        af::print( "af::bgr", abgr );
    }
#endif
#if 1
    // CUDA access test using colormap (a.k.a. heat map) color coding kernel
    {
        cv::Mat mat = cv::Mat( 4, ncols, CV_32FC(1), data );

        const float __levels [] = { 0.0, 0.2, 0.4, 0.6, 0.8, 0.97, 1.0 };
        //                          black, navy, cyan, green,yellow,red, white
        const float __colors [] = {   0.0,  0.0,  0.0,  0.0,  1.0,  1.0, 1.0      // R
                                    , 0.0,  0.0,  1.0,  1.0,  1.0,  0.0, 1.0      // G
                                    , 0.0,  0.5,  1.0,  0.0,  0.0,  0.0, 1.0 };   // B

        af::array levels = af::array( sizeof(__levels)/sizeof(__levels[0]), 1, __levels );
        af::array colors = af::array( 3, sizeof(__colors)/sizeof(__colors[0]) / 3, __colors );
        // af::print( "colors", colors );

        af::array gray = af::array( mat.cols, mat.rows, 1, mat.ptr< float >( 0 ) );

        auto rgb = colorMap( gray, levels, colors );

        af::print( "gray -> rgb", rgb );
    }
#endif
#if 1
    {
        cv::Mat mat = cv::Mat( 4, ncols, CV_32FC(1), data );
        af::array gray = af::array( mat.cols, mat.rows, 1, mat.ptr< float >( 0 ) );
        af::array rgb = af::array( mat.cols, mat.rows, 3 );

        for ( size_t i = 0; i < gray.dims( 0 ); ++i ) {
            for ( size_t j = 0; j < gray.dims( 1 ); ++j ) {
                std::cout << boost::format( "gray(%1%, %2%)= %3%" ) % i % j % gray(i,j).scalar<float>() << std::endl;
                rgb( i, j, 0 ) = gray( i, j ).scalar<float>();
                rgb( i, j, 1 ) = gray( i, j ).scalar<float>();
                rgb( i, j, 2 ) = gray( i, j ).scalar<float>();
            }
        }
        af::print( "rgb", rgb );
    }
#endif
	return 0;
}