///////////////////////////////////////////////////////////////
//  Copyright 2011 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
//

#include <boost/detail/lightweight_test.hpp>
#include <boost/math/special_functions/sign.hpp>

#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif

#if !defined(TEST_CPP_BIN_FLOAT) && !defined(TEST_DOUBLE) && !defined(TEST_MPFR_FLOAT)
#define TEST_CPP_BIN_FLOAT
#define TEST_DOUBLE
#define TEST_MPFR_FLOAT
#endif

#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
#endif
#ifdef TEST_MPFR_FLOAT
#include <boost/multiprecision/mpfr.hpp>
#endif

template <class T>
struct extract_value_type
{
   typedef typename T::value_type type;
};
template <>
struct extract_value_type<double>
{
   typedef double type;
};

template <class T>
void test()
{
   using value_type = typename extract_value_type<T>::type;

   using std::real;
   using std::signbit;

   T mp_zero{0};
   T mp_m_zero{-mp_zero};
   T mp_finite{2};
   T mp_m_finite{-2};
   T mp_big{!std::is_same<T, value_type>::value ? std::numeric_limits<value_type>::has_infinity ? std::numeric_limits<value_type>::infinity() : (std::numeric_limits<value_type>::max)() : std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity()
                                                                                : (std::numeric_limits<T>::max)()};
   T mp_m_big{-mp_big};
   T mp_small{!std::is_same<T, value_type>::value ? (std::numeric_limits<value_type>::min)() : (std::numeric_limits<T>::min)()};
   T mp_m_small{-mp_small};

   T result;
   //
   // Multiplications:
   //
   result = mp_zero * mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero * mp_m_finite;
   BOOST_TEST(signbit(result));
   result = mp_m_zero * mp_finite;
   BOOST_TEST(signbit(result));
   result = mp_m_zero * mp_m_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero * -mp_finite;
   BOOST_TEST(signbit(result));
   result = -mp_zero * mp_finite;
   BOOST_TEST(signbit(result));
   result = -mp_zero * -mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_small * mp_small;
   BOOST_TEST(signbit(result) == 0);
   result = mp_small * mp_m_small;
   BOOST_TEST(signbit(result));
   result = mp_m_small * mp_m_small;
   BOOST_TEST(signbit(result) == 0);
   result = mp_small * -mp_small;
   BOOST_TEST(signbit(result));
   result = -mp_small * -mp_small;
   BOOST_TEST(signbit(result) == 0);
   //
   // Divisions:
   //
   result = mp_zero / mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero / mp_m_finite;
   BOOST_TEST(signbit(result));
   result = mp_m_zero / mp_finite;
   BOOST_TEST(signbit(result));
   result = mp_m_zero / mp_m_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero / -mp_finite;
   BOOST_TEST(signbit(result));
   result = -mp_zero / mp_finite;
   BOOST_TEST(signbit(result));
   result = -mp_zero / -mp_finite;
   BOOST_TEST(signbit(result) == 0);

   result = mp_small / mp_big;
   BOOST_TEST(signbit(result) == 0);
   result = mp_small / mp_m_big;
   BOOST_TEST(signbit(result));
   result = mp_m_small / mp_big;
   BOOST_TEST(signbit(result));
   result = mp_m_small / mp_m_big;
   BOOST_TEST(signbit(result) == 0);
   result = mp_small / -mp_big;
   BOOST_TEST(signbit(result));
   result = -mp_small / mp_big;
   BOOST_TEST(signbit(result));
   result = -mp_small / -mp_big;
   BOOST_TEST(signbit(result) == 0);
   //
   // Additions:
   //
   result = mp_zero + mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero + mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero + mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero + mp_m_zero;
   BOOST_TEST(signbit(result));
   //
   // Subtractions:
   //
   result = mp_zero - mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero - mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero - mp_zero;
   BOOST_TEST(signbit(result));
   result = mp_m_zero - mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_finite - mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_finite + mp_m_finite;
   BOOST_TEST(signbit(result) == 0);

   //
   // Over again for one arg an integer:
   //
   int i_zero{0};
   int i_finite{2};
   int i_m_finite{-2};
   result = i_zero * mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = i_zero * mp_m_finite;
   BOOST_TEST(signbit(result));
   result = i_zero * -mp_finite;
   BOOST_TEST(signbit(result));
   result = mp_zero * i_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero * i_finite;
   BOOST_TEST(signbit(result));
   result = mp_zero * i_m_finite;
   BOOST_TEST(signbit(result));
   //
   // Divisions:
   //
   result = i_zero / mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = i_zero / mp_m_finite;
   BOOST_TEST(signbit(result));
   result = mp_zero / i_m_finite;
   BOOST_TEST(signbit(result));
   result = -mp_zero / i_finite;
   BOOST_TEST(signbit(result));
   //
   // Additions:
   //
   result = mp_zero + i_zero;
   BOOST_TEST(signbit(result) == 0);
#ifndef TEST_MPFR_FLOAT
   //
   // There appears to be a bug in mpfr_add_ui here:
   //
   result = i_zero + mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
#endif
   //
   // Subtractions:
   //
   result = mp_zero - i_zero;
   BOOST_TEST(signbit(result) == 0);
   result = i_zero - mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero - i_zero;
   BOOST_TEST(signbit(result));
   result = i_finite - mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = i_finite + mp_m_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_finite - i_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_finite + i_m_finite;
   BOOST_TEST(signbit(result) == 0);
   //
   // Over again for one arg a float:
   //
   float f_zero{0};
   float f_m_zero{-f_zero};
   float f_finite{2};
   float f_m_finite{-2};
   result = f_zero * mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = f_zero * mp_m_finite;
   BOOST_TEST(signbit(result));
   result = f_zero * -mp_finite;
   BOOST_TEST(signbit(result));
   result = mp_zero * f_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero * f_finite;
   BOOST_TEST(signbit(result));
   result = mp_zero * f_m_finite;
   BOOST_TEST(signbit(result));
   //
   // Divisions:
   //
   result = f_zero / mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = f_zero / mp_m_finite;
   BOOST_TEST(signbit(result));
   result = mp_zero / f_m_finite;
   BOOST_TEST(signbit(result));
   result = -mp_zero / f_finite;
   BOOST_TEST(signbit(result));
   //
   // Additions:
   //
   result = f_zero + mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = f_zero + mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = f_m_zero + mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = f_m_zero + mp_m_zero;
   BOOST_TEST(signbit(result));
   //
   // Subtractions:
   //
   result = f_zero - mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = f_zero - mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = f_m_zero - mp_zero;
   BOOST_TEST(signbit(result));
   result = f_m_zero - mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero - f_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_zero - f_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero - f_zero;
   BOOST_TEST(signbit(result));
   result = mp_m_zero - f_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = f_finite - mp_finite;
   BOOST_TEST(signbit(result) == 0);
   result = f_finite + mp_m_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_finite - f_finite;
   BOOST_TEST(signbit(result) == 0);
   result = mp_finite + f_m_finite;
   BOOST_TEST(signbit(result) == 0);
   //
   // Special cases:
   //
   result = mp_m_zero * mp_m_zero;
   BOOST_TEST(signbit(result) == 0);
   result = mp_m_zero + mp_m_zero;
   BOOST_TEST(signbit(result));
   result = mp_zero + mp_zero;
   BOOST_TEST(signbit(result) == 0);
   result = abs(mp_m_zero);
   BOOST_TEST(signbit(result) == 0);
   result = fabs(mp_m_zero);
   BOOST_TEST(signbit(result) == 0);
   result = sqrt(mp_m_zero);
   BOOST_TEST(signbit(result));
}

int main()
{
#ifdef TEST_DOUBLE
   test<double>();
#endif
#ifdef TEST_CPP_BIN_FLOAT
   test<boost::multiprecision::cpp_bin_float_50>();
   test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<35, boost::multiprecision::digit_base_10, std::allocator<char>, boost::long_long_type>, boost::multiprecision::et_on>>();
#endif
#ifdef TEST_MPFR_FLOAT
   test<boost::multiprecision::mpfr_float_50>();
#endif
   return boost::report_errors();
}


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

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_IS_EVEN_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IS_EVEN_HPP_INCLUDED

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

  /*!

    @ingroup group-predicates
    This function object returns @ref True or @ref False according x is even or not.

    @par Header <boost/simd/function/is_even.hpp>

    @par Note:

    The call to `is_even(x)` is similar to  `to_int(x/2)*2 == x`

    A floating number is even if it is a  flint
    and divided by two it is still a flint.

    A flint is a 'floating integer' i.e. a floating number
    representing an integer value

    Be conscious that all sufficiently great floating points values are even...

    @see is_odd, is_flint

    @par Example:

      @snippet is_even.cpp is_even

    @par Possible output:

      @snippet is_even.txt is_even

  **/
  as_logical_t<Value> is_even(Value const& x);
} }
#endif

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

#endif


#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/IterativeLinearSolvers>
#include <unsupported/Eigen/IterativeSolvers>

class MatrixReplacement;
using Eigen::SparseMatrix;

namespace Eigen {
namespace internal {
  // MatrixReplacement looks-like a SparseMatrix, so let's inherits its traits:
  template<>
  struct traits<MatrixReplacement> :  public Eigen::internal::traits<Eigen::SparseMatrix<double> >
  {};
}
}

// Example of a matrix-free wrapper from a user type to Eigen's compatible type
// For the sake of simplicity, this example simply wrap a Eigen::SparseMatrix.
class MatrixReplacement : public Eigen::EigenBase<MatrixReplacement> {
public:
  // Required typedefs, constants, and method:
  typedef double Scalar;
  typedef double RealScalar;
  typedef int StorageIndex;
  enum {
    ColsAtCompileTime = Eigen::Dynamic,
    MaxColsAtCompileTime = Eigen::Dynamic,
    IsRowMajor = false
  };

  Index rows() const { return mp_mat->rows(); }
  Index cols() const { return mp_mat->cols(); }

  template<typename Rhs>
  Eigen::Product<MatrixReplacement,Rhs,Eigen::AliasFreeProduct> operator*(const Eigen::MatrixBase<Rhs>& x) const {
    return Eigen::Product<MatrixReplacement,Rhs,Eigen::AliasFreeProduct>(*this, x.derived());
  }

  // Custom API:
  MatrixReplacement() : mp_mat(0) {}

  void attachMyMatrix(const SparseMatrix<double> &mat) {
    mp_mat = &mat;
  }
  const SparseMatrix<double> my_matrix() const { return *mp_mat; }

private:
  const SparseMatrix<double> *mp_mat;
};

// Implementation of MatrixReplacement * Eigen::DenseVector though a specialization of internal::generic_product_impl:
namespace Eigen {
namespace internal {

  template<typename Rhs>
  struct generic_product_impl<MatrixReplacement, Rhs, SparseShape, DenseShape, GemvProduct> // GEMV stands for matrix-vector
  : generic_product_impl_base<MatrixReplacement,Rhs,generic_product_impl<MatrixReplacement,Rhs> >
  {
    typedef typename Product<MatrixReplacement,Rhs>::Scalar Scalar;

    template<typename Dest>
    static void scaleAndAddTo(Dest& dst, const MatrixReplacement& lhs, const Rhs& rhs, const Scalar& alpha)
    {
      // This method should implement "dst += alpha * lhs * rhs" inplace,
      // however, for iterative solvers, alpha is always equal to 1, so let's not bother about it.
      assert(alpha==Scalar(1) && "scaling is not implemented");

      // Here we could simply call dst.noalias() += lhs.my_matrix() * rhs,
      // but let's do something fancier (and less efficient):
      for(Index i=0; i<lhs.cols(); ++i)
        dst += rhs(i) * lhs.my_matrix().col(i);
    }
  };

}
}

int main()
{
  int n = 10;
  Eigen::SparseMatrix<double> S = Eigen::MatrixXd::Random(n,n).sparseView(0.5,1);
  S = S.transpose()*S;

  MatrixReplacement A;
  A.attachMyMatrix(S);

  Eigen::VectorXd b(n), x;
  b.setRandom();

  // Solve Ax = b using various iterative solver with matrix-free version:
  {
    Eigen::ConjugateGradient<MatrixReplacement, Eigen::Lower|Eigen::Upper, Eigen::IdentityPreconditioner> cg;
    cg.compute(A);
    x = cg.solve(b);
    std::cout << "CG:       #iterations: " << cg.iterations() << ", estimated error: " << cg.error() << std::endl;
  }

  {
    Eigen::BiCGSTAB<MatrixReplacement, Eigen::IdentityPreconditioner> bicg;
    bicg.compute(A);
    x = bicg.solve(b);
    std::cout << "BiCGSTAB: #iterations: " << bicg.iterations() << ", estimated error: " << bicg.error() << std::endl;
  }

  {
    Eigen::GMRES<MatrixReplacement, Eigen::IdentityPreconditioner> gmres;
    gmres.compute(A);
    x = gmres.solve(b);
    std::cout << "GMRES:    #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl;
  }

  {
    Eigen::DGMRES<MatrixReplacement, Eigen::IdentityPreconditioner> gmres;
    gmres.compute(A);
    x = gmres.solve(b);
    std::cout << "DGMRES:   #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl;
  }

  {
    Eigen::MINRES<MatrixReplacement, Eigen::Lower|Eigen::Upper, Eigen::IdentityPreconditioner> minres;
    minres.compute(A);
    x = minres.solve(b);
    std::cout << "MINRES:   #iterations: " << minres.iterations() << ", estimated error: " << minres.error() << std::endl;
  }
}


#include <iostream>
#include <cstring>
#include <NTL/ZZ.h>
#include <algorithm>
#include <bitset>

using namespace NTL;
using namespace std;
using std::bitset;

string ZZToBits(ZZ num, const size_t n) {
	string s = "";
	ZZ last;

	while (num != 0) {
		last = num % 2;
		if (last == 1) {
			s += '1';
		} else {
			s += '0';
		}
		num /= 2;
	}
	for (size_t i = s.length(); i < n; i++) {
		s += '0';
	}
	reverse(s.begin(), s.end());
	return s;
}

const unsigned char DERTable[] = "0123456789ABCDEF";

void PrintInDER(const string s) {
    cout << "modulus:";
    string pairstr = "";
    for (size_t i = 0; i < s.length(); i += 4) {
        int index = 0;

        for (size_t j = i; j < i + 4; j++) {
            index = index << 1;
            if (s[j] == '1') {
                index += 1;
            }
        }
        pairstr += DERTable[index];
        if (pairstr.length() == 2) {
            cout << pairstr;
            if (i + 4 < s.length()) {
                cout << ":";
            }
            pairstr = "";
        }
        if (i % 120 == 0) {
            cout << endl << '\t';
        }
    }
    cout << endl;
}

const string Base64Map =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	"abcdefghijklmnopqrstuvwxyz"
	"0123456789+/";

void PrintInPEM(const string s) {
	string res = "";
	size_t len = s.length() / 8;	// 比特串转化为字节的长度
	size_t i;
	unsigned char triBytes[3];		// 存储三个字节

	for (i = 0; i+3 <= len; i += 3) {
		for (int j = 0; j < 3; j++) {
			bitset<8> tmp(s.substr(8*i + 8*j, 8));
			triBytes[j] = tmp.to_ulong();
		}
		res += Base64Map[triBytes[0] >> 2];
		res += Base64Map[((triBytes[0]<<4) & 0x30) | (triBytes[1] >> 4)];
		res += Base64Map[((triBytes[1]<<2) & 0x3c) | (triBytes[2] >> 6)];
		res += Base64Map[triBytes[2] & 0x3f];
	}

	if (i < len) {
		if (len - i == 1) {
			bitset<8> tmp(s.substr(8*i, 8));
			triBytes[0] = tmp.to_ulong();
			res += Base64Map[triBytes[0] >> 2];
			res += Base64Map[(triBytes[0]<<4) & 0x30];
			res += "==";
		} else {
			for (int j = 0; j < 2; j++) {
				bitset<8> tmp(s.substr(8*i + 8*j, 8));
				triBytes[j] = tmp.to_ulong();
			}
			res += Base64Map[triBytes[0] >> 2];
			res += Base64Map[((triBytes[0]<<4) & 0x30) | (triBytes[1] >> 4)];
			res += Base64Map[(triBytes[1]<<2) & 0x3c];
			res += "=";
		}
	}

	cout << res << endl;
}

int main() {
	ZZ num(4164596496416416);

	string s = ZZToBits(num, 64);
	cout << s << endl;
	cout << s.length() << endl;
	PrintInDER(s);
	cout << endl;
	PrintInPEM(s);

	return 0;
}


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

  @copyright 2017 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#ifndef BOOST_SIMD_ALGORITHM_MAX_ELEMENT_HPP_INCLUDED
#define BOOST_SIMD_ALGORITHM_MAX_ELEMENT_HPP_INCLUDED

#include <boost/simd/algorithm/max_val.hpp>
#include <boost/simd/algorithm/find.hpp>

namespace boost { namespace simd
{
  /*!
    @ingroup group-algo

    Returns an iterator pointing to the element with the greatest value in the range [first,last).

    @param first  Beginning of the range of elements to max_element
    @param last   End of the range of elements to max_element
    @param comp   comparison function object that will be applied.

    @par Requirement

      - @c first and @c last must be pointer to Vectorizable type.
      - @c comp must be a polymorphic unary function object, i.e callable on generic types.
      - if @c comp is not present the function test is done with operator <

    @par Example:

      @snippet max_element.cpp max_element

    @par Possible output:

      @snippet max_element.txt max_element

  **/
  template<typename T, typename Comp>
  T const * max_element(T const* first, T const* last, Comp comp)
  {
    if (first == last) return last;
    return find(first, last, max_val(first, last, comp));
  }

  template<typename T>
  T const * max_element(T const* first, T const* last)
  {
    if (first == last) return last;
    return find(first, last, max_val(first, last));
  }
} }

#endif


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

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_FMA_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_FMA_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{
  /*!

    @ingroup group-arithmetic
    Function object function implementing fma capabilities

    Computes the (fused) multiply add of the three parameters.

    @par semantic:
    For any given value @c x,  @c y,  @c z of type @c T:

    @code
    T r = fma(x, y, z);
    @endcode

    The code is similar to:

    @code
    T r = x*y+z;
    @endcode

    @par Note
    Conformant fused multiply/add implies

    - only one rounding

    - no "intermediate" overflow

    fma provides this for all integral types and each time it is reasonable
    in terms of performance for floating ones (i.e. if the system has the hard
    wired capability).

    If you need pedantic fma capabilities in all circumstances in your own
    code you can use the pedantic_ or  std_ decorator
    (although both can can be very expensive).

     @par Decorators

    - std_ for floating entries to call directly std::fma. This implies pedantic
      fma behaviour, but in no way improved performances.
    - pedantic_ ensures the fma properties and allows SIMD acceleration if available.

    @see fms, fnma, fnms
  **/
    Value fma(Value const& v0, Value const& v1, Value const& v2);
  }
} }
#endif

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

#endif


#include <exe/inputParser.h>

#include <base/cgal_typedefs.h>
#include <IO/fileIO.h>

#include <CGAL/optimal_bounding_box.h>
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>

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

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

    cliParser ip("clf");
    if(ip.parse(argc, argv))
        return 1;
    if(ip.getInput())
        return 1;
    if(ip.getOutput())
        return 1;

    auto start = std::chrono::high_resolution_clock::now();
    cout << "\n-----MAKE AN ORIENTED BOUNDING BOX AND SAVE AS PLY-----" << endl;
    cout << "\nWorking dir set to:\n\t-" << ip.dh.path << endl;

    dataHolder data;

    importLidarPoints(ip.dh,data);
    std::array<Point, 8> obb_points;
    CGAL::oriented_bounding_box(data.points,obb_points);
    SurfaceMesh obb_sm;
    if(ip.ro.scale > 0.0){
        double mx = 0, my = 0, mz = 0;
        for(const auto p : obb_points){
            mx+=p.x();
            my+=p.y();
            mz+=p.z();
        }
        Point centroid(mx/8,my/8,mz/8);
        std::array<Point, 8> obb_scaled;
        int i = 0;
        for(const auto p : obb_points){
            Vector mover(ip.ro.scale*(p.x() - centroid.x()),
                         ip.ro.scale*(p.y() - centroid.y()),
                         ip.ro.scale*(p.z() - centroid.z()));
            obb_scaled[i++] = p + mover;
        }
        CGAL::make_hexahedron(obb_scaled[0], obb_scaled[1], obb_scaled[2], obb_scaled[3],
                              obb_scaled[4], obb_scaled[5], obb_scaled[6], obb_scaled[7], obb_sm);

    }
    else{
        CGAL::make_hexahedron(obb_points[0], obb_points[1], obb_points[2], obb_points[3],
                              obb_points[4], obb_points[5], obb_points[6], obb_points[7], obb_sm);
    }
    CGAL::Polygon_mesh_processing::triangulate_faces(obb_sm);

    if(ip.dh.write_file.empty())
        ip.dh.write_file = ip.dh.read_file;
    std::ofstream out(ip.dh.path+ip.dh.write_file+"_obb.ply");
    CGAL::write_ply(out,obb_sm);

    auto stop = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
    cout << "\n-----MAKE AN ORIENTED BOUNDING BOX AND SAVE AS PLY FINISHED in "<< duration.count() << "s -----\n" << endl;

    return 0;

}


/*
 Copyright (C) 2016 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include "toplevelfixture.hpp"
#include <boost/make_shared.hpp>
#include <boost/test/unit_test.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/volatility/equityfx/blackvariancecurve.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <qle/termstructures/blackvariancecurve3.hpp>

using namespace boost::unit_test_framework;
using namespace QuantLib;
using namespace QuantExt;
using namespace std;

BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)

BOOST_AUTO_TEST_SUITE(BlackVarianceCurveTest)

BOOST_AUTO_TEST_CASE(testBlackVarianceCurve) {

    BOOST_TEST_MESSAGE("Testing QuantExt::BlackVarianceCurve3...");

    SavedSettings backup;
    Settings::instance().evaluationDate() = Date(1, Dec, 2015);
    Date today = Settings::instance().evaluationDate();

    Natural settlementDays = 0;
    Calendar cal = TARGET();
    BusinessDayConvention bdc = Following;
    DayCounter dc = ActualActual();

    vector<Time> times;
    vector<Date> dates;
    vector<Volatility> vols;
    vector<boost::shared_ptr<SimpleQuote> > simpleQuotes;
    vector<Handle<Quote> > quotes;

    Size numYears = 10;
    for (Size i = 1; i < numYears; i++) {

        Volatility vol = 0.1 + (0.01 * i); // 11% at 1Y, 12% at 2Y
        vols.push_back(vol);

        simpleQuotes.push_back(boost::make_shared<SimpleQuote>(vol));
        quotes.push_back(Handle<Quote>(simpleQuotes.back()));

        dates.push_back(Date(1, Dec, today.year() + i));
        times.push_back(dc.yearFraction(today, dates.back()));
    }

    // Build a QuantLib::BlackVarianceCurve
    BlackVarianceCurve bvcBase(today, dates, vols, dc);
    bvcBase.enableExtrapolation();

    // Build a QuantExt::BlackVarianceCurve3
    BlackVarianceCurve3 bvcTest(settlementDays, cal, bdc, dc, times, quotes);
    bvcTest.enableExtrapolation();

    Real strike = 1.0; // this is all ATM so we don't care

    // Check that bvcTest returns the expected values
    for (Size i = 0; i < times.size(); ++i) {
        BOOST_CHECK_CLOSE(bvcTest.blackVol(times[i], strike), vols[i], 1e-12);
        BOOST_CHECK_CLOSE(bvcTest.blackVol(dates[i], strike), vols[i], 1e-12);
    }

    // Now check that they give the same vols (including extrapolation)
    for (Time t = 0.1; t < numYears + 10.0; t += 0.1) {
        BOOST_CHECK_CLOSE(bvcBase.blackVol(t, strike), bvcTest.blackVol(t, strike), 1e-12);
    }

    // Now double the quotes
    for (Size i = 0; i < simpleQuotes.size(); ++i) {
        simpleQuotes[i]->setValue(simpleQuotes[i]->value() * 2.0);
    }
    // and check again
    for (Time t = 0.1; t < numYears + 10.0; t += 0.1) {
        BOOST_CHECK_CLOSE(bvcBase.blackVol(t, strike), 0.5 * bvcTest.blackVol(t, strike), 1e-12);
    }
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


// Author(s): Wieger Wesselink
// Copyright: see the accompanying file COPYING or copy at
// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
/// \file bisimulation_test.cpp
/// \brief Test the bisimulation algorithm.

#define BOOST_TEST_MODULE bisimulation_test
#include <boost/test/included/unit_test_framework.hpp>
#include "mcrl2/lps/detail/test_input.h"
#include "mcrl2/lps/linearise.h"
#include "mcrl2/pbes/bisimulation.h"
#include "mcrl2/pbes/detail/pbessolve.h"

using namespace mcrl2;
using namespace mcrl2::lps;
using namespace mcrl2::pbes_system;
using namespace mcrl2::log;

void test_bisimulation(const std::string& s1, const std::string& s2,
                       bool strongly_bisimilar,
                       bool branching_bisimilar,
                       bool branching_similar,
                       bool weakly_bisimilar,
                       bool linearize = false)
{
  specification spec1;
  specification spec2;
  if (linearize)
  {
    spec1 = remove_stochastic_operators(linearise(s1));
    spec2 = remove_stochastic_operators(linearise(s2));
  }
  else
  {
    spec1 = parse_linear_process_specification(s1);
    spec2 = parse_linear_process_specification(s2);
  }

  std::clog << "Testing strong bisimulation" << std::endl;
  pbes sb  = strong_bisimulation(spec1, spec2);
  BOOST_CHECK(sb.is_well_typed());
  bool sb_solution = pbes_system::detail::pbessolve(sb);
  BOOST_CHECK(sb_solution == strongly_bisimilar);

  std::clog << "Testing branching bisimulation" << std::endl;
  pbes bb  = branching_bisimulation(spec1, spec2);
  bool bb_solution = pbes_system::detail::pbessolve(bb);
  BOOST_CHECK(bb.is_well_typed());
  BOOST_CHECK(bb_solution == branching_bisimilar);

  std::clog << "Testing branching simulation" << std::endl;
  pbes bs = branching_simulation_equivalence(spec1, spec2);
  bool bs_solution = pbes_system::detail::pbessolve(bs);
  BOOST_CHECK(bs.is_well_typed());
  BOOST_CHECK(bs_solution == branching_similar);

  std::clog << "Testing weak bisimulation" << std::endl;
  pbes wb  = weak_bisimulation(spec1, spec2);
  bool wb_solution = pbes_system::detail::pbessolve(wb);
  BOOST_CHECK(wb.is_well_typed());
  BOOST_CHECK(wb_solution == weakly_bisimilar);
}

BOOST_AUTO_TEST_CASE(ABP)
{
  test_bisimulation(lps::detail::LINEAR_ABP_SPECIFICATION(), lps::detail::LINEAR_ABP_SPECIFICATION(), true, true, true, true);
}

BOOST_AUTO_TEST_CASE(SMALLSPEC)
{
  const std::string SMALLSPEC =
    "act a,b;                 \n"
    "proc X(s: Pos) =         \n"
    "  (s == 1) -> a . X(2)   \n"
    "+ (s == 2) -> tau . X(3) \n"
    "+ (s == 3) -> tau . X(4) \n"
    "+ (s == 4) -> b . X(1);  \n"
    "init X(1);               \n"
    ;
  test_bisimulation(SMALLSPEC, SMALLSPEC, true, true, true, true);
}

BOOST_AUTO_TEST_CASE(small_different_specs)
{
  const std::string s1 =
    "act a,b;                 \n"
    "proc X(s: Pos) =         \n"
    "  (s == 1) ->  a . X(2)  \n"
    "+ (s == 2) -> b . X(1);  \n"
    "init X(1);               \n"
    ;
  const std::string s2 =
    "act a,b,c;               \n"
    "proc X(s: Pos) =     \n"
    "  (s == 1) ->  a . X(2)  \n"
    "+ (s == 1) ->  c . X(1)  \n"
    "+ (s == 2) -> b . X(1);  \n"
    "init X(1);               \n"
    ;
    ;
  test_bisimulation(s1, s2, false, false, false, false);
  test_bisimulation(s2, s1, false, false, false, false);
}

BOOST_AUTO_TEST_CASE(buffers_silent_lose)
{
  const std::string buffer =
    "sort D = struct d1 | d2;\n"
    "map  n: Pos;\n"
    "eqn  n  =  2;\n"
    "act  r,s: D;\n"
    "proc P(b_Buffer: List(D)) =\n"
    "       !(b_Buffer == []) ->\n"
    "         s(rhead(b_Buffer)) .\n"
    "         P(b_Buffer = rtail(b_Buffer))\n"
    "     + sum d_Buffer: D.\n"
    "         (#b_Buffer < 2) ->\n"
    "         r(d_Buffer) .\n"
    "         P(b_Buffer = d_Buffer |> b_Buffer)\n"
    "     + delta;\n"
    "init P([]);\n";

  const std::string lossy_buffer =
    "sort D = struct d1 | d2;\n"
    "map  n: Pos;\n"
    "eqn  n  =  2;\n"
    "act  r,s: D;\n"
    "proc P(s3_Buffer: Pos, d_Buffer: D, b_Buffer: List(D)) =\n"
    "       sum e_Buffer: Bool.\n"
    "         (s3_Buffer == 2) ->\n"
    "         tau .\n"
    "         P(s3_Buffer = 1, d_Buffer = d1, b_Buffer = if(e_Buffer, d_Buffer |> b_Buffer, b_Buffer))\n"
    "     + (s3_Buffer == 1 && !(b_Buffer == [])) ->\n"
    "         s(rhead(b_Buffer)) .\n"
    "         P(s3_Buffer = 1, d_Buffer = d1, b_Buffer = rtail(b_Buffer))\n"
    "     + sum d0_Buffer: D.\n"
    "         (s3_Buffer == 1 && #b_Buffer < 2) ->\n"
    "         r(d0_Buffer) .\n"
    "         P(s3_Buffer = 2, d_Buffer = d0_Buffer)\n"
    "     + delta;\n"
    "init P(1, d1, []);\n";

  test_bisimulation(buffer, lossy_buffer, false, false, false, false);
  test_bisimulation(lossy_buffer, buffer, false, false, false, false);
}

BOOST_AUTO_TEST_CASE(buffers_explicit_lose)
{
  const std::string buffer =
    "sort D = struct d1 | d2;\n"
    "map  n: Pos;\n"
    "eqn  n  =  2;\n"
    "act  r,s: D;\n"
    "proc P(b_Buffer: List(D)) =\n"
    "       !(b_Buffer == []) ->\n"
    "         s(rhead(b_Buffer)) .\n"
    "         P(b_Buffer = rtail(b_Buffer))\n"
    "     + sum d_Buffer: D.\n"
    "         (#b_Buffer < 2) ->\n"
    "         r(d_Buffer) .\n"
    "         P(b_Buffer = d_Buffer |> b_Buffer)\n"
    "     + delta;\n"
    "init P([]);\n";

  const std::string lossy_buffer =
      "sort D = struct d1 | d2;\n"
      "map  n: Pos;\n"
      "eqn  n  =  2;\n"
      "act  r,s: D;\n"
      "     lose;\n"
      "proc P(s3_Buffer: Pos, d_Buffer: D, b_Buffer: List(D)) =\n"
      "       sum d0_Buffer: D.\n"
      "         (s3_Buffer == 1 && #b_Buffer < 2) ->\n"
      "         r(d0_Buffer) .\n"
      "         P(s3_Buffer = 2, d_Buffer = d0_Buffer)\n"
      "     + (s3_Buffer == 1 && !(b_Buffer == [])) ->\n"
      "         s(rhead(b_Buffer)) .\n"
      "         P(s3_Buffer = 1, d_Buffer = d1, b_Buffer = rtail(b_Buffer))\n"
      "     + (s3_Buffer == 2) ->\n"
      "         tau .\n"
      "         P(s3_Buffer = 3, d_Buffer = d1)\n"
      "     + (s3_Buffer == 2) ->\n"
      "         tau .\n"
      "         P(s3_Buffer = 1, d_Buffer = d1, b_Buffer = d_Buffer |> b_Buffer)\n"
      "     + (s3_Buffer == 3) ->\n"
      "         lose .\n"
      "         P(s3_Buffer = 1, d_Buffer = d1)\n"
      "     + delta;\n"
      "init P(1, d1, []);\n";

  test_bisimulation(buffer, lossy_buffer, false, false, false, false);
  test_bisimulation(lossy_buffer, buffer, false, false, false, false);
}


//
// Created by Kaung Zaw Htet on 2019-11-24.
//

#include <gtest/gtest.h>
#include <iostream>
#include <randomizer/ph_number_randomizer.h>
#include <randomizer/faster_random.h>
#include <random>
using namespace std;
TEST(GeneralTest,fasterRandom){

    std::random_device gen;
    pcg generatorObject(gen);
    std::uniform_int_distribution<int> myanNumDistribution(1, 1000);
    for (int i = 0; i < 100; ++i) {

      //  boost::random::random_device gen=boost::random::random_device();
        std::cout<< myanNumDistribution(generatorObject)<<std::endl;
        // std::mt19937 generatorObject(static_cast<unsigned int>(time(0)));
    }
}

template<typename T>
void showMinMax() {
    cout << "min: " << numeric_limits<T>::min() << endl;
    cout << "max: " << numeric_limits<T>::max() << endl;
    cout << endl;
}

TEST(GeneralTest,limit){

    cout << "short:" << endl;
    showMinMax<short>();
    cout << "int:" << endl;
    showMinMax<int>();
    cout << "long:" << endl;
    showMinMax<long>();
    cout << "float:" << endl;
    showMinMax<float>();
    cout << "double:" << endl;
    showMinMax<double>();
    cout << "long double:" << endl;
    showMinMax<long double>();
    cout << "unsigned short:" << endl;
    showMinMax<unsigned short>();
    cout << "unsigned int:" << endl;
    showMinMax<unsigned int>();
    cout << "unsigned long:" << endl;
    showMinMax<unsigned long>();

}

TEST(GeneralTest,uniqueToArr){

   auto a= std::make_unique<std::string[]>(100);
    /*a[0]= "h";
    a[1]= "rw";
    a[2]= "rwh";
    a[3]= "egeg";
    a[4]= "rgwgwh";
    a[5]= "g3g";*/
    int count = sizeof(a)/ sizeof(a[0]);
   for (int i=0; i < 6; i++)
   {
       cout<<a[i] <<endl;

   }
}
#include <boost/hana.hpp>
namespace hana = boost::hana;

TEST(GeneralTest,datastructures){

}


// multi_precision.cpp : example program comparing float vs posit matrix inversion algorithms
//
// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc.
//
// This file is part of the HPR-BLAS project, which is released under an MIT Open Source license.

//#include <chrono>
// Boost arbitrary precision floats
#include <boost/multiprecision/cpp_bin_float.hpp>

// configure the posit number system behavior
#define POSIT_ROUNDING_ERROR_FREE_IO_FORMAT 0
// configure the HPR-BLAS behavior
#define HPRBLAS_TRACE_ROUNDING_EVENTS 0
#include <hprblas>
#include <mtl_extensions.hpp>
// matrix generators
#include <generators/matrix_generators.hpp>
#include <utils/print_utils.hpp>

using namespace sw::universal;

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace mtl;
	using namespace sw::hprblas;
	using namespace boost::multiprecision;

	using sp = boost::multiprecision::cpp_bin_float_single;
	using dp = boost::multiprecision::cpp_bin_float_double;
	using qp = boost::multiprecision::cpp_bin_float_quad;

	{
		sp a{ 1.0 };
		sp b( 2.0 );
		sp c = a + b;
		cout << c << endl;
	}

	return EXIT_SUCCESS;
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const posit_arithmetic_exception& err) {
	std::cerr << "Uncaught posit arithmetic exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const quire_exception& err) {
	std::cerr << "Uncaught quire exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const posit_internal_exception& err) {
	std::cerr << "Uncaught posit internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (std::runtime_error& err) {
	std::cerr << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}


// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the deep learning tools from the
    dlib C++ Library.  In it, we will show how to use the loss_metric layer to do
    metric learning.

    The main reason you might want to use this kind of algorithm is because you
    would like to use a k-nearest neighbor classifier or similar algorithm, but
    you don't know a good way to calculate the distance between two things.  A
    popular example would be face recognition.  There are a whole lot of papers
    that train some kind of deep metric learning algorithm that embeds face
    images in some vector space where images of the same person are close to each
    other and images of different people are far apart.  Then in that vector
    space it's very easy to do face recognition with some kind of k-nearest
    neighbor classifier.

    To keep this example as simple as possible we won't do face recognition.
    Instead, we will create a very simple network and use it to learn a mapping
    from 8D vectors to 2D vectors such that vectors with the same class labels
    are near each other.  If you want to see a more complex example that learns
    the kind of network you would use for something like face recognition read
    the dnn_metric_learning_on_images_ex.cpp example.

    You should also have read the examples that introduce the dlib DNN API before
    continuing.  These are dnn_introduction_ex.cpp and dnn_introduction2_ex.cpp.
*/

#include <dlib/dnn.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main() try
{
    // The API for doing metric learning is very similar to the API for
    // multi-class classification.  In fact, the inputs are the same, a bunch of
    // labeled objects.  So here we create our dataset.  We make up some simple
    // vectors and label them with the integers 1,2,3,4.  The specific values of
    // the integer labels don't matter.
    std::vector<matrix<double,0,1>> samples;
    std::vector<unsigned long> labels;

    // class 1 training vectors
    samples.push_back({1,0,0,0,0,0,0,0}); labels.push_back(1);
    samples.push_back({0,1,0,0,0,0,0,0}); labels.push_back(1);

    // class 2 training vectors
    samples.push_back({0,0,1,0,0,0,0,0}); labels.push_back(2);
    samples.push_back({0,0,0,1,0,0,0,0}); labels.push_back(2);

    // class 3 training vectors
    samples.push_back({0,0,0,0,1,0,0,0}); labels.push_back(3);
    samples.push_back({0,0,0,0,0,1,0,0}); labels.push_back(3);

    // class 4 training vectors
    samples.push_back({0,0,0,0,0,0,1,0}); labels.push_back(4);
    samples.push_back({0,0,0,0,0,0,0,1}); labels.push_back(4);

    // Make a network that simply learns a linear mapping from 8D vectors to 2D
    // vectors.
    using net_type = loss_metric<fc<2,input<matrix<double,0,1>>>>;
    net_type net;
    dnn_trainer<net_type> trainer(net);
    trainer.set_learning_rate(0.1);

    // It should be emphasized out that it's really important that each mini-batch contain
    // multiple instances of each class of object.  This is because the metric learning
    // algorithm needs to consider pairs of objects that should be close as well as pairs
    // of objects that should be far apart during each training step.  Here we just keep
    // training on the same small batch so this constraint is trivially satisfied.
    while(trainer.get_learning_rate() >= 1e-4)
        trainer.train_one_step(samples, labels);

    // Wait for training threads to stop
    trainer.get_net();
    cout << "done training" << endl;

    // Run all the samples through the network to get their 2D vector embeddings.
    std::vector<matrix<float,0,1>> embedded = net(samples);

    // Print the embedding for each sample to the screen.  If you look at the
    // outputs carefully you should notice that they are grouped together in 2D
    // space according to their label.
    for (size_t i = 0; i < embedded.size(); ++i)
        cout << "label: " << labels[i] << "\t" << trans(embedded[i]);

    // Now, check if the embedding puts things with the same labels near each other and
    // things with different labels far apart.
    int num_right = 0;
    int num_wrong = 0;
    for (size_t i = 0; i < embedded.size(); ++i)
    {
        for (size_t j = i+1; j < embedded.size(); ++j)
        {
            if (labels[i] == labels[j])
            {
                // The loss_metric layer will cause things with the same label to be less
                // than net.loss_details().get_distance_threshold() distance from each
                // other.  So we can use that distance value as our testing threshold for
                // "being near to each other".
                if (length(embedded[i]-embedded[j]) < net.loss_details().get_distance_threshold())
                    ++num_right;
                else
                    ++num_wrong;
            }
            else
            {
                if (length(embedded[i]-embedded[j]) >= net.loss_details().get_distance_threshold())
                    ++num_right;
                else
                    ++num_wrong;
            }
        }
    }

    cout << "num_right: "<< num_right << endl;
    cout << "num_wrong: "<< num_wrong << endl;
}
catch(std::exception& e)
{
    cout << e.what() << endl;
}


// ----------------------------------------------------------------------------------------------------------
/// @file   vector_foo.cpp
/// @brief  Test cases for Vector.
// ----------------------------------------------------------------------------------------------------------
#define BOOST_TEST_DYN_LINK

#ifdef SEPARATE_TEST
#define BOOST_TEST_MODULE NDArrayTest
#endif

#include <boost/test/unit_test.hpp>
#include <iostream>
#include <vector>

#include "ndarray.h"
#define N 7

BOOST_AUTO_TEST_SUITE(VectorTestCases)

BOOST_AUTO_TEST_CASE(VectorBasicBinaryOp) {
  float *a = (float*)malloc(N * sizeof(float));
  float *b = (float*)malloc(N * sizeof(float));
  // bin op add
  for(int i = 0; i<N; ++i) {
    a[i] = b[i] = 1.f;
  }
  ndarray::Vector<float, N> v1(a);
  ndarray::Vector<float, N> v2(b);
  ndarray::Vector<float, N> v3;
  v3 = v1 + v2;
  std::cout << v3;
  BOOST_CHECK(v3[0] == 2.f);
  BOOST_CHECK(v3[1] == 2.f);
  BOOST_CHECK(v3[2] == 2.f);
  BOOST_CHECK(v3[3] == 2.f);
  BOOST_CHECK(v3[4] == 2.f);
  BOOST_CHECK(v3[5] == 2.f);
  BOOST_CHECK(v3[6] == 2.f);

  // bin op sub
  for(int i = 0; i<N; ++i) {
    a[i] = 3.f;
    b[i] = 1.f;
  }
  ndarray::Vector<float, N> v4(a);
  ndarray::Vector<float, N> v5(b);
  ndarray::Vector<float, N> v6;
  v6 = v4 - v5;
  std::cout << v6;
  BOOST_CHECK(v6[0] == 2.f);
  BOOST_CHECK(v6[1] == 2.f);
  BOOST_CHECK(v6[2] == 2.f);
  BOOST_CHECK(v6[3] == 2.f);
  BOOST_CHECK(v6[4] == 2.f);
  BOOST_CHECK(v6[5] == 2.f);
  BOOST_CHECK(v6[6] == 2.f);
  // bin op mul
  ndarray::Vector<float, N> v7;
  v7 = v4 * v5;
  std::cout << v7;
  BOOST_CHECK(v7[0] == 3.f);
  BOOST_CHECK(v7[1] == 3.f);
  BOOST_CHECK(v7[2] == 3.f);
  BOOST_CHECK(v7[3] == 3.f);
  BOOST_CHECK(v7[4] == 3.f);
  BOOST_CHECK(v7[5] == 3.f);
  BOOST_CHECK(v7[6] == 3.f);

  // bin op div
  ndarray::Vector<float, N> v8;
  v8 = v4 / v5;
  std::cout << v8;
  BOOST_CHECK(v8[0] == 3.f);
  BOOST_CHECK(v8[1] == 3.f);
  BOOST_CHECK(v8[2] == 3.f);
  BOOST_CHECK(v8[3] == 3.f);
  BOOST_CHECK(v8[4] == 3.f);
  BOOST_CHECK(v8[5] == 3.f);
  BOOST_CHECK(v8[6] == 3.f);

  // bin op max
  ndarray::Vector<float, N> v9;
  v9 = max(v4, v5);
  std::cout << v9;
  BOOST_CHECK(v9[0] == 3.f);
  BOOST_CHECK(v9[1] == 3.f);
  BOOST_CHECK(v9[2] == 3.f);
  BOOST_CHECK(v9[3] == 3.f);
  BOOST_CHECK(v9[4] == 3.f);
  BOOST_CHECK(v9[5] == 3.f);
  BOOST_CHECK(v9[6] == 3.f);

  // bin op min
  ndarray::Vector<float, N> v10;
  v10 = min(v4, v5);
  std::cout << v10;
  BOOST_CHECK(v10[0] == 1.f);
  BOOST_CHECK(v10[1] == 1.f);
  BOOST_CHECK(v10[2] == 1.f);
  BOOST_CHECK(v10[3] == 1.f);
  BOOST_CHECK(v10[4] == 1.f);
  BOOST_CHECK(v10[5] == 1.f);
  BOOST_CHECK(v10[6] == 1.f);
  free(a);
  free(b);
}

BOOST_AUTO_TEST_CASE(VectorBasicUnaryOp) {
  float *a = (float*)malloc(N * sizeof(float));
  // unary op sqrt
  for(int i = 0; i<N; ++i) {
    a[i] = 9.f;
  }
  ndarray::Vector<float, N> v1(a);
  ndarray::Vector<float, N> v2;
  v2 = sqrt(v1);
  std::cout << v2;
  BOOST_CHECK(v2[0] == 3.f);
  BOOST_CHECK(v2[1] == 3.f);
  BOOST_CHECK(v2[2] == 3.f);
  BOOST_CHECK(v2[3] == 3.f);
  BOOST_CHECK(v2[4] == 3.f);
  BOOST_CHECK(v2[5] == 3.f);
  BOOST_CHECK(v2[6] == 3.f);

  // unary op rsqrt
  for(int i = 0; i<N; ++i) {
    a[i] = 16.f;
  }
  ndarray::Vector<float, N> v3(a);
  ndarray::Vector<float, N> v4;
  v4 = rsqrt(v3);
  std::cout << v4;
  BOOST_CHECK(std::abs(v4[0] - 0.25f) <= 1e-3);
  BOOST_CHECK(std::abs(v4[1] - 0.25f) <= 1e-3);
  BOOST_CHECK(std::abs(v4[2] - 0.25f) <= 1e-3);
  BOOST_CHECK(std::abs(v4[3] - 0.25f) <= 1e-3);
  BOOST_CHECK(std::abs(v4[4] - 0.25f) <= 1e-3);
  BOOST_CHECK(std::abs(v4[5] - 0.25f) <= 1e-3);
  BOOST_CHECK(std::abs(v4[6] - 0.25f) <= 1e-3);
  free(a);
}
BOOST_AUTO_TEST_SUITE_END()


#include <cstdlib>
#include <iostream>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/bindings/lower.hpp>
#include <boost/numeric/bindings/upper.hpp>
#include <boost/numeric/bindings/ublas/vector.hpp>
#include <boost/numeric/bindings/ublas/matrix.hpp>
#include <boost/numeric/bindings/blas/level2.hpp>
#include "print.hpp"
#include "random.hpp"

namespace ublas=boost::numeric::ublas;
namespace blas=boost::numeric::bindings::blas;

int main(int argc, char *argv[]) {
  {
    typedef ublas::vector<double> vector;
    typedef ublas::matrix<double, ublas::column_major> matrix;
    typedef vector::size_type size_type;
    rand_normal<double>::reset();
    size_type n=8;
    matrix A(n, n);
    for (size_type j=0; j<n; ++j) {
      A(j, j)=rand_normal<double>::get();
      for (size_type i=0; i<j; ++i) {
	A(i, j)=rand_normal<double>::get();
	A(j, i)=A(i, j);
      }
    }
    vector x(n);
    for (size_type i=0; i<n; ++i)
      x(i)=rand_normal<double>::get();
    double alpha(rand_normal<double>::get());
    matrix P;
    {
      P=alpha*ublas::outer_prod(x, x);
      for (size_type j=0; j<n; ++j)
	for (size_type i=0; i<j; ++i)
	  P(i, j)=0;
      matrix A1(P+A);
      matrix A2(A);
      blas::syr(alpha, x, blas::lower(A2));
      std::cout << print_mat(A1) << '\n'
		<< print_mat(A2) << '\n';
    }
    {
      P=alpha*ublas::outer_prod(x, x);
      for (size_type j=0; j<n; ++j)
	for (size_type i=j+1; i<n; ++i)
	  P(i, j)=0;
      matrix A1(P+A);
      matrix A2(A);
      blas::syr(alpha, x, blas::upper(A2));
      std::cout << print_mat(A1) << '\n'
		<< print_mat(A2) << '\n';
    }
  }
  return EXIT_SUCCESS;
}


/*!
 * Copyright (C) tkornuta, IBM Corporation 2015-2019
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*!
 * @file mnist_hebbian_features_visualization_test.cpp
 * @brief Program for visualization of features of hebbian network trained on MNIST digits.
 * @Author: Tomasz Kornuta <tkornut@us.ibm.com>
 * @Date:   May 16, 2017
 *
 * Copyright (c) 2017, Tomasz Kornuta, IBM Corporation. All rights reserved.
 *
 */

#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>

#include <data_io/MNISTMatrixImporter.hpp>

#include <logger/Log.hpp>
#include <logger/ConsoleOutput.hpp>
using namespace mic::logger;

#include <application/ApplicationState.hpp>

#include <configuration/ParameterServer.hpp>

#include <opengl/visualization/WindowManager.hpp>
#include <opengl/visualization/WindowGrayscaleBatch.hpp>
using namespace mic::opengl::visualization;

// Hebbian neural net.
#include <mlnn/HebbianNeuralNetwork.hpp>
using namespace mic::mlnn;

// Encoders.
#include <encoders/MatrixXfMatrixXfEncoder.hpp>
#include <encoders/UIntMatrixXfEncoder.hpp>

/// Window for displaying the MNIST batch.
WindowGrayscaleBatch<float>* w_input;
WindowGrayscaleBatch<float>* w_reconstruction;
/// Window for displaying the weights.
WindowGrayscaleBatch<float>* w_weights1;
WindowGrayscaleBatch<float>* w_weights2;

/// MNIST importer.
mic::data_io::MNISTMatrixImporter<float>* importer;
/// Multi-layer neural network.
HebbianNeuralNetwork<float> neural_net;

/// MNIST matrix encoder.
mic::encoders::MatrixXfMatrixXfEncoder* mnist_encoder;
/// Label 2 matrix encoder (1 hot).
//mic::encoders::UIntMatrixXfEncoder* label_encoder;

const size_t patch_size = 28;
const size_t batch_size = 4;
const size_t output_units = 12;

/*!
 * \brief Function for batch sampling.
 * \author tkornuta
 */
void batch_function (void) {

/*	if (neural_net.load(fileName)) {
		LOG(LINFO) << "Loaded neural network from a file";
	} else {*/
		{
		// Create a simple hebbian network.
		neural_net.pushLayer(new BinaryCorrelator<float>(patch_size*patch_size, output_units, 0.6, 28*28*0.01));
		neural_net.setOptimization<  mic::neural_nets::learning::NormalizedHebbianRule<float> >();

		LOG(LINFO) << "Generated new neural network";
	}//: else

	size_t iteration = 0;

	// Main application loop.
	while (!APP_STATE->Quit()) {

		// If not paused.
		if (!APP_STATE->isPaused()) {

			// If single step mode - pause after the step.
			if (APP_STATE->isSingleStepModeOn())
				APP_STATE->pressPause();

			{ // Enter critical section - with the use of scoped lock from AppState!
				APP_DATA_SYNCHRONIZATION_SCOPED_LOCK();

				// Retrieve the next minibatch.
				mic::types::MNISTBatch<float> bt = importer->getRandomBatch();

				// Set batch to be displayed.
				w_input->setBatchUnsynchronized(bt.data());

				// Encode data.
				mic::types::MatrixXfPtr encoded_batch = mnist_encoder->encodeBatch(bt.data());
				mic::types::MatrixXfPtr encoded_labels = mnist_encoder->encodeBatch(bt.data());

				// Train the autoencoder.
				float loss = neural_net.train (encoded_batch, 0.05);

				// Get reconstruction.
				mic::types::MatrixXfPtr encoded_reconstruction = neural_net.getPredictions();

				std::vector<mic::types::MatrixXfPtr> decoded_reconstruction = mnist_encoder->decodeBatch(encoded_reconstruction);
				w_reconstruction->setBatchUnsynchronized(decoded_reconstruction);

				if (iteration%10 == 0) {
					// Visualize the weights.
					std::shared_ptr<mic::mlnn::BinaryCorrelator<float> > layer1 = neural_net.getLayer<mic::mlnn::BinaryCorrelator<float> >(0);
					w_weights1->setBatchUnsynchronized(layer1->getActivations(patch_size, patch_size));

				}//: if

				iteration++;
				LOG(LINFO) << "Iteration: " << iteration << "loss= " << loss;
			}//: end of critical section

		}//: if

		// Sleep.
		APP_SLEEP();
	}//: while

}//: image_encoder_and_visualization_test

/*!
 * \brief Main program function. Runs two threads: main (for GLUT) and another one (for data processing).
 * \author tkornuta
 * @param[in] argc Number of parameters (passed to glManaged).
 * @param[in] argv List of parameters (passed to glManaged).
 * @return (not used)
 */
int main(int argc, char* argv[]) {
	// Set console output to logger.
	LOGGER->addOutput(new ConsoleOutput());
	LOG(LINFO) << "Logger initialized. Starting application";

	// Parse parameters.
	PARAM_SERVER->parseApplicationParameters(argc, argv);

	// Initilize application state ("touch it") ;)
	APP_STATE;

	// Load dataset.
	importer = new mic::data_io::MNISTMatrixImporter<float>();
	importer->setBatchSize(batch_size);

	// Initialize the encoders.
	mnist_encoder = new mic::encoders::MatrixXfMatrixXfEncoder(patch_size, patch_size);
	//label_encoder = new mic::encoders::UIntMatrixXfEncoder(batch_size);

	// Set parameters of all property-tree derived objects - USER independent part.
	PARAM_SERVER->loadPropertiesFromConfiguration();

	// Initialize property-dependent variables of all registered property-tree objects - USER dependent part.
	PARAM_SERVER->initializePropertyDependentVariables();

	// Import data from datasets.
	if (!importer->importData())
		return -1;

	// Initialize GLUT! :]
	VGL_MANAGER->initializeGLUT(argc, argv);

	// Create batch visualization window.
	w_input = new WindowGrayscaleBatch<float>("Input batch", Grayscale::Norm_HotCold, Grayscale::Grid_Both, 70, 0, 250, 250);
	w_reconstruction = new WindowGrayscaleBatch<float>("Reconstructed batch", Grayscale::Norm_HotCold, Grayscale::Grid_Both, 320, 0, 250, 250);
	w_weights1 = new WindowGrayscaleBatch<float>("Permanences", Grayscale::Norm_HotCold, Grayscale::Grid_Both, 570, 0, 250, 250);
//	w_weights2 = new WindowGrayscaleBatch<float>("Connectivity", 1092, 0, 512, 512);

	boost::thread batch_thread(boost::bind(&batch_function));

	// Start visualization thread.
	VGL_MANAGER->startVisualizationLoop();

	LOG(LINFO) << "Waiting for threads to join...";
	// End test thread.
	batch_thread.join();
	LOG(LINFO) << "Threads joined - ending application";
}//: main


#include "Board.hpp"
#include "BoardOrganism.hpp"
#include "GA.hpp"
#include "HexGridPrint.hpp"
#include <boost/lexical_cast.hpp>
#include <math.h>

void ShowStatistics(const std::vector<BoardOrganism *> &i_organisms)
{
  size_t j;

  double smallest = -1;
  double largest = -1;
  double meannum = 0;
  double meanden = 0;
  for (j = 0 ; j < i_organisms.size() ; ++j)
  {
    double f=i_organisms[j]->GetFitness();
    if (smallest == -1 || f < smallest)
    {
      smallest = f;
    }
    if (largest == -1 || f > largest)
    {
      largest = f;
    }

    meannum += f;
    meanden += 1;
  }
  double mean = meannum / meanden;
  double ssq = 0;
  for (j = 0 ; j < i_organisms.size() ; ++j)
  {
    double var = i_organisms[j]->GetFitness() - mean;
    ssq += var * var;
  }
  double stdev = sqrt(ssq / meanden);

  std::cout << smallest << "--|" << mean - stdev << "|||" << mean <<
    "|||" << mean+stdev << "|--" << largest << std::endl;
}

void ShowBoardOrganism(const BoardOrganism &bo,const Board &b)
{
  HexGridPrint hgp(11,12,false,true);

  int i,j;
  for (i = 0 ; i < 11 ; ++i)
  {
    for (j = 0 ; j < 11 + (i%2) ; j++)
    {
      const BoardCell &bc = b.GetCell(i,j);

      if (bc.GetType() == BoardCell::BOTTLE)
      {
        hgp.AddItem(i,j,HexGridPrint::DIR3,ColorInfo::GetColorChar(bc.GetColor()));
        hgp.AddItem(i,j,HexGridPrint::STAT1,boost::lexical_cast<char>(bc.GetBottleSize()));
      }
      else if (bc.GetType() == BoardCell::SOURCE)
      {
        hgp.AddItem(i,j,HexGridPrint::DIR0,ColorInfo::GetColorChar(bc.GetColor()));
      }
      else
      {
        size_t k;
        for (k = 0 ; k < 6 ; ++k)
        {
          const PipeDefinition &pdef = bc.GetUniquePipeRotations()[bo.GetAllele(i,j)];

          if (pdef[k] != 0)
            hgp.AddItem(i,j,(HexGridPrint::HexLoc)k,boost::lexical_cast<char>(pdef[k]));
        }
      }
    }
  }
  std::cout << hgp.Show() << "Fitness: " << bo.GetFitnessDescriptor() << std::endl << bo.GetMetaState();
}

const BoardOrganism *bestone = NULL;

void ManageBestOrganism(const std::vector<BoardOrganism *> &i_organisms,const Board &b)
{
  size_t j;

  bool bested = false;
  for (j = 0 ; j < i_organisms.size() ; ++j)
  {
    if (!bestone || bestone->GetFitness() < i_organisms[j]->GetFitness())
    {
      bestone = i_organisms[j];
      bested = true;
    }
  }
  if (bested)
  {
    ShowBoardOrganism(*bestone,b);
  }
}

int main(int argc,char **argv)
{
  if (argc != 2)
  {
    std::cout << "Bad command line; need file name." << std::endl;
    exit(1);
  }

  Board b(argv[1]);

  BoardOrganism::Initialize(b);

  GA<BoardOrganism> ga(100);

  int i;
  for (i = 0 ; i < 100 ; ++i)
  {
    std::cout << "Generation " << i << " ";

    ShowStatistics(ga.GetCurrentPopulation());
    ManageBestOrganism(ga.GetCurrentPopulation(),b);

    ga.Generate(10);
  }
}


//
// Created by keszocze on 27.09.18.
//

#include "cudd_helpers.hpp"
#include "string_helpers.hpp"

#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
#include <cudd/cudd/cudd.h>
#include <tuple>
#include <map>
#include <set>
#include <stack>
#include <algorithm>
#include <assert.h>
#include <cmath>

namespace abo::util {

    unsigned int terminal_level(const std::vector<std::vector<BDD>>& bdds) {
        unsigned int max_index = 0;
        for (const auto &f : bdds) {
            for (const BDD &b : f) {
                std::vector<unsigned int> support = b.SupportIndices();
                auto max_support_index = std::max_element(support.begin(), support.end());
                max_index = std::max(max_index, (max_support_index == support.end() ? 0 : *max_support_index) + 1);
            }
        }
        return max_index;
    }

    long eval_adder(const std::vector<BDD> &adder, long input1, long input2, int bits) {
        std::vector<int> bdd_inputs;
        for (int i = 0;i<bits;i++) {
            bdd_inputs.push_back((input1 & (1 << i)) > 0 ? 1 : 0);
            bdd_inputs.push_back((input2 & (1 << i)) > 0 ? 1 : 0);
        }

        long result = 0;
        for (unsigned int i = 0;i<adder.size();i++) {
            if (adder[i].Eval(bdd_inputs.data()).IsOne()) {
                result |= 1 << i;
            }
        }

        return result;
    }

    static double count_minterms_rec(DdNode* node, std::map<DdNode*, double> &minterms_map) {
        auto it = minterms_map.find(node);
        if (it != minterms_map.end()) {
            return it->second;
        }

        if (Cudd_IsConstant(node)) {
            double value = Cudd_V(node);
            if (Cudd_IsComplement(node)) {
                value = value == 0.0 ? 1.0 : 0.0;
            }
            minterms_map[node] = value;
            return value;
        }

        DdNode *N = Cudd_Regular(node);

        DdNode *Nv = Cudd_T(N);
        DdNode *Nnv = Cudd_E(N);

        Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
        Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));

        double highResult = count_minterms_rec(Nv, minterms_map);
        double lowResult = count_minterms_rec(Nnv, minterms_map);
        double minTerms = highResult / 2 + lowResult / 2;

        minterms_map[node] = minTerms;
        return minTerms;
    }

    std::map<DdNode*, double> count_minterms(const BDD &bdd) {
        std::map<DdNode*, double> result;

        count_minterms_rec(bdd.getNode(), result);
        return result;
    }

    static double count_solutions_rec(DdNode* node, std::map<DdNode*, double> &solutions_map, int terminal_level) {
        auto it = solutions_map.find(node);
        if (it != solutions_map.end()) {
            return it->second;
        }

        if (Cudd_IsConstant(node)) {
            double value = Cudd_V(node);
            if (Cudd_IsComplement(node)) {
                value = value == 0.0 ? 1.0 : 0.0;
            }
            solutions_map[node] = value;
            return value;
        }

        DdNode *N = Cudd_Regular(node);

        DdNode *Nv = Cudd_T(N);
        DdNode *Nnv = Cudd_E(N);

        Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
        Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));

        double high_result = count_solutions_rec(Nv, solutions_map, terminal_level);
        double low_result = count_solutions_rec(Nnv, solutions_map, terminal_level);

        unsigned long high_level = Cudd_IsConstant(Nv) ? terminal_level : Cudd_NodeReadIndex(Nv);
        unsigned long low_level = Cudd_IsConstant(Nnv) ? terminal_level : Cudd_NodeReadIndex(Nnv);
        unsigned long own_level = Cudd_NodeReadIndex(node);

        double solutions = high_result * std::pow(2.0, high_level - own_level - 1) +
                low_result * std::pow(2.0, low_level - own_level - 1);

        solutions_map[node] = solutions;
        return solutions;
    }

    std::map<DdNode*, double> count_solutions(const BDD &bdd) {
        std::map<DdNode*, double> result;

        count_solutions_rec(bdd.getNode(), result, terminal_level({{bdd}}));
        return result;
    }

    std::vector<int> random_satisfying_input(const BDD &bdd, const std::map<DdNode*, double> &minterm_count, int max_level) {
            std::vector<int> result;

            DdNode *node = bdd.getNode();

            for(int level = 0;level < max_level;level++) {
                long node_level = Cudd_IsConstant(node) ? max_level : Cudd_NodeReadIndex(node);
                if (level < node_level) {
                    result.push_back(rand() % 2);
                } else {
                    assert(!Cudd_IsConstant(node));

                    DdNode *N = Cudd_Regular(node);
                    DdNode *then_node = Cudd_T(N);
                    DdNode *else_node = Cudd_E(N);

                    then_node = Cudd_NotCond(then_node, Cudd_IsComplement(node));
                    else_node = Cudd_NotCond(else_node, Cudd_IsComplement(node));

                    double then_weight = minterm_count.at(then_node);
                    double else_weight = minterm_count.at(else_node);

                    double r = rand() / double(RAND_MAX);
                    if (r <= then_weight / (then_weight + else_weight)) {
                        result.push_back(1);
                        node = then_node;
                    } else {
                        result.push_back(0);
                        node = else_node;
                    }
                }
            }

            return result;
        }

    unsigned int const_ADD_value(const ADD &add) {
        DdNode *node = add.getNode();
        if (Cudd_IsConstant(node)) {
            return static_cast<unsigned int>(Cudd_V(node));
        }
        return 0;
    }

    static std::map<DdNode*, unsigned long> count_paths(DdNode* node, unsigned int terminal_level) {
        if (Cudd_IsConstant(node)) {
            return {{node, 1}};
        }

        // do a sort of breadth first search, visiting all variable levels from top to bottom
        std::vector<std::stack<DdNode*>> levels;
        levels.push_back(std::stack<DdNode*>({Cudd_Regular(node)}));

        std::map<DdNode*, unsigned long> node_to_count;
        std::set<DdNode*> visited;
        node_to_count[node] = 1;
        visited.insert(node);
        for (unsigned int level = 0;level<levels.size();level++) {
            // a reference can not be used here since the vector may resize and move the data elsewhere
            std::stack<DdNode*> nodes = levels[level];
            while (nodes.size() > 0) {
                DdNode *current = nodes.top();
                nodes.pop();

                if (!Cudd_IsConstant(current)) {
                    DdNode *then_node = Cudd_Regular(Cudd_T(current));
                    DdNode *else_node = Cudd_Regular(Cudd_E(current));

                    unsigned long current_count = node_to_count[current];

                    unsigned long then_level = Cudd_IsConstant(then_node) ? terminal_level : Cudd_NodeReadIndex(then_node);
                    // the map will automatically use 0 if the node is not yet present
                    node_to_count[then_node] += current_count << (then_level - level - 1);
                    if (visited.find(then_node) == visited.end()) {
                        levels.resize(std::max(levels.size(), then_level+1));
                        levels[then_level].push(then_node);
                        visited.insert(then_node);
                    }

                    unsigned long else_level = Cudd_IsConstant(else_node) ? terminal_level : Cudd_NodeReadIndex(else_node);
                    node_to_count[else_node] += current_count << (else_level - level - 1);
                    if (visited.find(else_node) == visited.end()) {
                        levels.resize(std::max(levels.size(), else_level+1));
                        levels[else_level].push(else_node);
                        visited.insert(else_node);
                    }
                }
            }
        }

        return node_to_count;
    }

    std::vector<std::pair<double, unsigned long>> add_terminal_values(const ADD &add) {
        std::set<DdNode*> visited;
        std::stack<DdNode*> toVisit;
        toVisit.push(add.getNode());
        visited.insert(add.getNode());

        // determine the level that terminal nodes should be interpreted as
        std::vector<unsigned int> support = add.SupportIndices();
        auto max_support_index = std::max_element(support.begin(), support.end());
        unsigned int term_level = (max_support_index == support.end() ? 0 : *max_support_index) + 1;

        auto path_count = count_paths(add.getNode(), term_level);

        std::vector<std::pair<double, unsigned long>> result;
        while (toVisit.size() > 0) {
            DdNode *node = toVisit.top();
            toVisit.pop();

            if (Cudd_IsConstant(node)) {
                result.push_back({Cudd_V(node), path_count[node]});
            } else {
                DdNode *thenNode = Cudd_T(node);
                if (visited.find(thenNode) == visited.end()) {
                    // cppcheck-suppress stlFindInsert
                    visited.insert(thenNode);
                    toVisit.push(thenNode);
                }
                DdNode *elseNode = Cudd_E(node);
                if (visited.find(elseNode) == visited.end()) {
                    // cppcheck-suppress stlFindInsert
                    visited.insert(elseNode);
                    toVisit.push(elseNode);
                }
            }
        }
        return result;
    }

    ADD bdd_forest_to_add(const Cudd &mgr, const std::vector<BDD> &bdds, const NumberRepresentation num_rep) {

        std::vector<BDD> bdds_ = bdds;
        if (num_rep == NumberRepresentation::BaseTwo) {
            bdds_.push_back(mgr.bddZero());
        }

        ADD result = mgr.addZero();
        ADD two = mgr.addOne() + mgr.addOne();
        ADD signBitPower = mgr.addOne();

        for (auto it = bdds_.rbegin() + 1;it != bdds_.rend();it++) {
            result *= two;
            signBitPower *= two;
            result += it->Add();
        }

        result -= bdds.back().Add() * signBitPower;

        return result;
    }

    ADD xor_difference_add(const Cudd &mgr, const std::vector<BDD> &f, const std::vector<BDD> &f_hat) {
        std::vector<BDD> diff;
        for (unsigned int i = 0;i<f.size();i++) {
            diff.push_back(f[i] ^ f_hat[i]);
        }

        return bdd_forest_to_add(mgr, diff, NumberRepresentation::BaseTwo);
    }

    static DdNode * add_absolute_difference_apply(DdManager * dd, DdNode ** f, DdNode ** g) {
        // basically copied from cuddAddApply.c (the operator is modified of course)
        DdNode *F = *f;
        DdNode *G = *g;
        if (Cudd_IsConstant(F) && Cudd_IsConstant(G)) {
            CUDD_VALUE_TYPE value = std::abs(Cudd_V(F) - Cudd_V(G));
            DdNode * res = Cudd_addConst(dd, value);
            return res;
        }
        if (F > G) { /* swap f and g */
            *f = G;
            *g = F;
        }
        return nullptr;
    }

    ADD absolute_difference_add(const Cudd &mgr, const std::vector<BDD> &f, const std::vector<BDD> &f_hat, const NumberRepresentation num_rep) {
        ADD a = bdd_forest_to_add(mgr, f, num_rep);
        ADD b = bdd_forest_to_add(mgr, f_hat, num_rep);
        DdNode *result_node = Cudd_addApply(mgr.getManager(), add_absolute_difference_apply, a.getNode(), b.getNode());
        return ADD(mgr, result_node);
    }

    void dump_dot(
            const Cudd &mgr,
            const std::vector<BDD> &bdd,
            const std::vector<std::string> &innames,
            const std::vector<std::string> &outnames) {

        if (bdd.empty()) {
            return;
        }

        char **ins = innames.empty() ? nullptr : vec_to_arr(innames);
        char **outs = outnames.empty() ? nullptr : vec_to_arr(outnames);

        mgr.DumpDot(bdd, ins, outs);

        del_arr(ins, innames.size());
        del_arr(outs, outnames.size());
    }

    void dump_dot(
            const Cudd &mgr,
            const BDD &bdd,
            const std::vector<std::string> &inames,
            const std::string &funname) {
        std::vector<BDD> bddv{bdd};
        std::vector<std::string> funnames{funname};
        dump_dot(mgr, bddv, inames, funnames);
    }

    /*
     * How to get the children of nodes has been taken from StackOverflow:
     * https://stackoverflow.com/questions/47704600/cudd-access-bdd-childs
     */

    BDD high(const Cudd &mgr, const BDD &v) {
        DdNode *n = v.getNode();

        if (Cudd_IsConstant(n)) {
            throw std::invalid_argument("high(mgr,v): Cannot retrieve child of a terminal node");
        }

        if (Cudd_IsComplement(n)) {
            return !BDD(mgr, Cudd_Regular(Cudd_T(n)));
        } else {
            return BDD(mgr, Cudd_T(n));
        }
    }

    BDD low(const Cudd &mgr, const BDD &v) {
        DdNode *n = v.getNode();

        if (Cudd_IsConstant(n)) {
            throw std::invalid_argument("low(mgr,v): Cannot retrieve child of a terminal node");
        }

        if (Cudd_IsComplement(n)) {
            return !BDD(mgr, Cudd_Regular(Cudd_E(n)));
        } else {
            return BDD(mgr, Cudd_E(n));
        }
    }

    /**
     * @
     */
    std::pair<BDD, BDD> full_adder(const BDD &f, const BDD &g, const BDD &carry_in) {
        BDD carry_out = (f * g) | (f * carry_in) | (g * carry_in);
        BDD sum = f ^ g ^carry_in;
        return {sum, carry_out};
    }

    std::vector<BDD>
    bdd_subtract(const Cudd &mgr, const std::vector<BDD> &minuend, const std::vector<BDD> &subtrahend) {
        std::vector<BDD> diff;
        diff.reserve(minuend.size());

        // using one as carry in serves as an implicit method to add one to the subtrahend, which is necessary to
        // change its sign
        BDD carry = mgr.bddOne();

        for (size_t i = 0; i < minuend.size(); ++i) {
            // the subtrahend's bits are negated to change the sign of the subtrahend
            auto tmp  = full_adder(minuend[i], !subtrahend[i], carry);
            diff.push_back(tmp.first);
            carry = tmp.second;

        }

        return diff;
    }

    std::vector<BDD> bdd_absolute_difference(const Cudd &mgr, const std::vector<BDD> &f, const std::vector<BDD> &g,
                                             const NumberRepresentation num_rep) {

        std::vector<BDD> f_= f;
        std::vector<BDD> g_ = g;

        if (num_rep == NumberRepresentation::BaseTwo) {
            // we need to add sign bits to the functions as they don't have one right now
            // these are necessary to be able to add the negative number instead of actually subtracting
            f_.push_back(mgr.bddZero());
            g_.push_back(mgr.bddZero());
        }

        bool smaller = true;
        for (std::size_t i = 0;i<f_.size();i++) {
            if (f_[i] > g_[i]) {
                smaller = false;
                break;
            }
        }

        // use correct order for the difference calculation to minimize computation time
        const std::vector<BDD> &f__ = smaller ? g_ : f_;
        const std::vector<BDD> &g__ = smaller ? f_ : g_;

        std::vector<BDD> difference = abo::util::bdd_subtract(mgr, f__, g__);
        return abo::util::abs(mgr,difference);
    }

    std::vector<BDD> abs(const Cudd &mgr, const std::vector<BDD> &f) {

        // create mask consisting of the sign bit only
        BDD sign_bit = f.back();
        std::vector<BDD> mask(f.size(), sign_bit);

        std::vector<BDD> tmp;

        for (size_t i=0; i < f.size(); ++i) {
            tmp.push_back(f[i] ^ sign_bit);
        }

        std::vector<BDD> abs = abo::util::bdd_subtract(mgr,tmp,mask);

        return abs;
    }

    std::vector<BDD> bdd_shift(const Cudd &mgr, const std::vector<BDD> &f, int bits_to_shift) {
        std::vector<BDD> result;
        result.reserve(f.size());

        for (int i = 0;i<int(f.size());i++) {
            if (i < bits_to_shift || i >= int(f.size()) + bits_to_shift) {
                result.push_back(mgr.bddZero());
            } else {
                result.push_back(f[i - bits_to_shift]);
            }
        }

        return result;
    }

    std::vector<BDD> bdd_add(const Cudd &mgr, const std::vector<BDD> &f, const std::vector<BDD> &g) {
        std::vector<BDD> sum;
        sum.reserve(f.size());

        BDD carry = mgr.bddZero();

        for (unsigned int i = 0; i < f.size(); ++i) {
            auto tmp  = full_adder(f[i], g[i], carry);
            sum.push_back(tmp.first);
            carry = tmp.second;

        }

        return sum;
    }

    std::vector<BDD> bdd_multiply_constant(const Cudd &mgr, const std::vector<BDD> &f, double factor, const unsigned int num_extra_bits) {

        std::vector<BDD> result(f.size() + size_t(std::ceil(std::log2(factor))) + 2, mgr.bddZero());

        std::vector<BDD> fc = f;
        while (result.size() > fc.size()) {
            fc.push_back(mgr.bddZero());
        }

        assert (factor <= static_cast<double>(std::numeric_limits<boost::multiprecision::uint256_t>::max()));

        boost::multiprecision::uint256_t great_factor = static_cast<boost::multiprecision::uint256_t>(factor);
        boost::multiprecision::uint256_t one = 1;
        for (int i = 0;i<256;i++) {
            if (great_factor & (one << i)) {
                result = bdd_add(mgr, result, bdd_shift(mgr, fc, i));
            }
        }
        unsigned long lesser_factor = static_cast<unsigned long>(std::fmod(factor, 1.0) * (1UL << num_extra_bits));
        for (unsigned int i = 0;i<num_extra_bits;i++) {
            if (lesser_factor & (1UL << i)) {
                result = bdd_add(mgr, result, bdd_shift(mgr, fc, -static_cast<int>(num_extra_bits - i)));
            }
        }

        return result;
    }

    void equalize_vector_size(const Cudd &mgr, std::vector<BDD> &f1, std::vector<BDD> &f2) {
        while (f1.size() < f2.size()) {
            f1.push_back(mgr.bddZero());
        }
        while (f2.size() < f1.size()) {
            f2.push_back(mgr.bddZero());
        }
    }

    std::pair<bool, bool> exists_greater_equals(const Cudd &mgr, const std::vector<BDD> &f1, const std::vector<BDD> &f2) {
        std::vector<BDD> f1_ = f1;
        std::vector<BDD> f2_ = f2;

        equalize_vector_size(mgr, f1_, f2_);

        BDD zero_condition = mgr.bddOne();
        BDD equal_condition = mgr.bddOne();
        for (int i = int(f1_.size())-1;i>=0;i--) {
            zero_condition &= !f2_[i];
            if (!((f1_[i] & zero_condition).IsZero())) {
                return {true, false};
            }
            if (!((f1_[i] & !f2_[i] & equal_condition).IsZero())) {
                return {true, false};
            }
            equal_condition &= (f1_[i] & f2_[i]) | ((!f1_[i]) & (!f2_[i]));
        }
        if (!equal_condition.IsZero()) {
            return {true, true};
        }
        return {false, false};
    }

    std::vector<BDD> bdd_max_one(const Cudd &mgr, const std::vector<BDD> &f) {
        std::vector<BDD> result = f;

        BDD zero_condition = mgr.bddOne();
        for (int i = int(result.size())-1;i>0;i--) {
            zero_condition &= !result[i];
        }
        result[0] |= zero_condition;

        return result;
    }

    BDD greater_equals(const Cudd &mgr, const std::vector<BDD> &f, const std::vector<BDD> &g) {
        std::vector<BDD> f_ = f;
        std::vector<BDD> g_ = g;

        equalize_vector_size(mgr, f_, g_);

        BDD zero_condition = mgr.bddOne();
        BDD equal_condition = mgr.bddOne();

        BDD result = mgr.bddZero();
        for (int i = int(f_.size()) - 1; i >= 0; i--) {
            zero_condition &= !g_[i];
            result |= f_[i] & zero_condition;
            result |= f_[i] & !g_[i] & equal_condition;
            equal_condition &= (f_[i] & g_[i]) | ((!f_[i]) & (!g_[i]));
        }
        result |= equal_condition;
        return result;
    }

    std::vector<BDD> bdd_divide(const Cudd &mgr, const std::vector<BDD> &f, const std::vector<BDD> &g, unsigned int extra_bits) {

        std::vector<BDD> values(extra_bits, mgr.bddZero());
        std::vector<BDD> temp = f;
        temp.insert(temp.begin(), values.begin(), values.end());

        std::vector<BDD> g_ = g;
        for (unsigned int i = 0;i<f.size()+1;i++) {
            g_.push_back(mgr.bddZero());
        }
        g_.insert(g_.begin(), values.begin(), values.end());

        std::vector<BDD> result;
        for (int i = int(f.size())+1;i >= -int(extra_bits);i--) {
            auto shifted = bdd_shift(mgr, g_, i);
            BDD subtract_condition = greater_equals(mgr, temp, shifted);
            std::vector<BDD> to_subtract = shifted;
            for (BDD &b : to_subtract) {
                b &= subtract_condition;
            }
            equalize_vector_size(mgr, to_subtract, temp);
            temp = bdd_subtract(mgr, temp, to_subtract);
            result.push_back(subtract_condition);
        }
        std::reverse(result.begin(), result.end());
        return result;
    }

}


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

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

 * See LICENSE for the license information

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

/**
 * @file    testGaussMarkov1stOrderFactor.cpp
 * @brief   Unit tests for the GaussMarkov1stOrder factor
 * @author  Vadim Indelman
 * @date    Jan 17, 2012
 */

#include <gtsam_unstable/slam/GaussMarkov1stOrderFactor.h>
#include <gtsam/nonlinear/Values.h>
#include <gtsam/inference/Key.h>
#include <gtsam/base/numericalDerivative.h>
#include <CppUnitLite/TestHarness.h>
#include <gtsam/base/deprecated/LieVector.h>

#include <boost/bind/bind.hpp>

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

//! Factors
typedef GaussMarkov1stOrderFactor<LieVector> GaussMarkovFactor;

/* ************************************************************************* */
LieVector predictionError(const LieVector& v1, const LieVector& v2, const GaussMarkovFactor factor) {
  return factor.evaluateError(v1, v2);
}

/* ************************************************************************* */
TEST( GaussMarkovFactor, equals )
{
  // Create two identical factors and make sure they're equal
  Key x1(1);
  Key x2(2);
  double delta_t = 0.10;
  Vector tau = Vector3(100.0, 150.0, 10.0);
  SharedGaussian model = noiseModel::Isotropic::Sigma(3, 1.0);

  GaussMarkovFactor factor1(x1, x2, delta_t, tau, model);
  GaussMarkovFactor factor2(x1, x2, delta_t, tau, model);

  CHECK(assert_equal(factor1, factor2));
}

/* ************************************************************************* */
TEST( GaussMarkovFactor, error )
{
  Values linPoint;
  Key x1(1);
  Key x2(2);
  double delta_t = 0.10;
  Vector tau = Vector3(100.0, 150.0, 10.0);
  SharedGaussian model = noiseModel::Isotropic::Sigma(3, 1.0);

  LieVector v1 = LieVector(Vector3(10.0, 12.0, 13.0));
  LieVector v2 = LieVector(Vector3(10.0, 15.0, 14.0));

  // Create two nodes
  linPoint.insert(x1, v1);
  linPoint.insert(x2, v2);

  GaussMarkovFactor factor(x1, x2, delta_t, tau, model);
  Vector Err1( factor.evaluateError(v1, v2) );

  // Manually calculate the error
  Vector alpha(tau.size());
  Vector alpha_v1(tau.size());
  for(int i=0; i<tau.size(); i++){
    alpha(i) = exp(- 1/tau(i)*delta_t );
    alpha_v1(i) = alpha(i) * v1(i);
  }
  Vector Err2( v2 - alpha_v1 );

  CHECK(assert_equal(Err1, Err2, 1e-9));
}

/* ************************************************************************* */
TEST (GaussMarkovFactor, jacobian ) {

  Values linPoint;
  Key x1(1);
  Key x2(2);
  double delta_t = 0.10;
  Vector tau = Vector3(100.0, 150.0, 10.0);
  SharedGaussian model = noiseModel::Isotropic::Sigma(3, 1.0);

  GaussMarkovFactor factor(x1, x2, delta_t, tau, model);

  // Update the linearization point
  LieVector v1_upd = LieVector(Vector3(0.5, -0.7, 0.3));
  LieVector v2_upd = LieVector(Vector3(-0.7, 0.4, 0.9));

  // Calculate the Jacobian matrix using the factor
  Matrix computed_H1, computed_H2;
  factor.evaluateError(v1_upd, v2_upd, computed_H1, computed_H2);

  // Calculate the Jacobian matrices H1 and H2 using the numerical derivative function
  Matrix numerical_H1, numerical_H2;
  numerical_H1 = numericalDerivative21<Vector3, Vector3, Vector3>(
      boost::bind(&predictionError, _1, _2, factor), v1_upd, v2_upd);
  numerical_H2 = numericalDerivative22<Vector3, Vector3, Vector3>(
      boost::bind(&predictionError, _1, _2, factor), v1_upd, v2_upd);

  // Verify they are equal for this choice of state
  CHECK( assert_equal(numerical_H1, computed_H1, 1e-9));
  CHECK( assert_equal(numerical_H2, computed_H2, 1e-9));
}

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


//
// Copyright (c) 2016 CNRS
//

#ifndef __math_matrix_hpp__
#define __math_matrix_hpp__

#include <Eigen/Dense>

namespace pinocchio
{

  template<typename Derived>
  inline bool hasNaN(const Eigen::DenseBase<Derived> & m)
  {
    return !((m.derived().array()==m.derived().array()).all());
  }

}
#endif //#ifndef __math_matrix_hpp__


#ifndef STAN_MATH_PRIM_MAT_PROB_MULTI_NORMAL_CHOLESKY_RNG_HPP
#define STAN_MATH_PRIM_MAT_PROB_MULTI_NORMAL_CHOLESKY_RNG_HPP

#include <boost/random/normal_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <stan/math/prim/scal/err/check_size_match.hpp>
#include <stan/math/prim/scal/err/check_finite.hpp>
#include <stan/math/prim/scal/err/check_not_nan.hpp>
#include <stan/math/prim/mat/fun/columns_dot_product.hpp>
#include <stan/math/prim/mat/fun/columns_dot_self.hpp>
#include <stan/math/prim/mat/fun/dot_product.hpp>
#include <stan/math/prim/mat/fun/dot_self.hpp>
#include <stan/math/prim/mat/fun/log.hpp>
#include <stan/math/prim/mat/fun/log_determinant.hpp>
#include <stan/math/prim/mat/fun/mdivide_left_spd.hpp>
#include <stan/math/prim/mat/fun/mdivide_left_tri_low.hpp>
#include <stan/math/prim/mat/fun/multiply.hpp>
#include <stan/math/prim/mat/fun/subtract.hpp>
#include <stan/math/prim/mat/fun/sum.hpp>

#include <stan/math/prim/scal/fun/constants.hpp>
#include <stan/math/prim/scal/meta/include_summand.hpp>

namespace stan {
  namespace math {
    template <class RNG>
    inline Eigen::VectorXd
    multi_normal_cholesky_rng(
        const Eigen::Matrix<double, Eigen::Dynamic, 1>& mu,
        const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>& S,
        RNG& rng) {
      using boost::variate_generator;
      using boost::normal_distribution;

      static const char* function("multi_normal_cholesky_rng");
      check_finite(function, "Location parameter", mu);

      variate_generator<RNG&, normal_distribution<> >
        std_normal_rng(rng, normal_distribution<>(0, 1));

      Eigen::VectorXd z(S.cols());
      for (int i = 0; i < S.cols(); i++)
        z(i) = std_normal_rng();

      return mu + S * z;
    }
  }
}
#endif


//==================================================================================================
/*
  Copyright 2017 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
//! [direct_hyperbolic]
#include <boost/simd/hyperbolic.hpp>
#include <boost/simd/pack.hpp>
#include <boost/simd/function/enumerate.hpp>
#include <iostream>

namespace bs =  boost::simd;
using pack_ft =  bs::pack <float, 8>;

int main()
{
  pack_ft p = bs::enumerate<pack_ft>(-4.0f, 1.0f);
  std::cout << " p =  " << p << std::endl
            <<  " -> bs::cosh(p) =  " << bs::cosh(p) << std::endl
            <<  " -> bs::sinh(p) =  " << bs::sinh(p) << std::endl
            <<  " -> bs::tanh(p) =  " << bs::tanh(p) << std::endl
            <<  " -> bs::sech(p) =  " << bs::sech(p) << std::endl
            <<  " -> bs::csch(p) =  " << bs::csch(p) << std::endl;
  pack_ft s, c;
  std::tie(s, c) = bs::sinhcosh(p);
  std::cout <<  " using sinhcosh " << std::endl
            <<  " -> bs::cosh(p) =  " << c << std::endl
            <<  " -> bs::sinh(p) =  " << s << std::endl;
  return 0;
}
//! [direct_hyperbolic]


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

/*
 * File:   TestModuloInverseComputation.cpp
 * Author: Till Kolditz <till.kolditz@gmail.com>
 *
 * Created on 20. Februar 2017, 18:21
 */

#include <cstdlib>
#include <iostream>
#include <iomanip>

#include <boost/multiprecision/cpp_int.hpp>

#include <Util/Euclidean.hpp>
#include <Util/Stopwatch.hpp>

using boost::multiprecision::uint128_t;

const size_t wCmin = 3;
const size_t wCmax = 127;
const size_t wAmin = 2;
//const size_t wAmax = 16;

uint64_t convert(
        uint128_t & source) {
    uint64_t target = 0;
    const unsigned limb_num = source.backend().size(); // number of limbs
    const unsigned limb_bits = sizeof(boost::multiprecision::limb_type) * CHAR_BIT; // size of limb in bits
    for (unsigned i = 0; i < limb_num && ((i * limb_bits) < (sizeof(target) * 8)); ++i) {
        target |= (source.backend().limbs()[i]) << (i * limb_bits);
    }
    return target;
}

template<typename T>
T test(
        size_t TOTALNUM,
        size_t wC,
        size_t wAmin) {
    T result(0);
    std::cout << wC;
#ifdef DEBUG
    for (size_t wA = wAmin; wA <= (wC - (wCmin - (wAmin - 1))); ++wA) {
        std::cout << "\t-";
    }
    for (size_t wA = (wC - (wCmin - (wAmin - 1))); wA < wC; ++wA) {
#else
    for (size_t wA = wAmin; wA < wC; ++wA) {
#endif
        T A(1);
        A <<= (wA - 1);
        A += 1;
        Stopwatch sw;
        for (size_t i = 0; i < TOTALNUM; ++i) {
            result = ext_euclidean(A, wC);
            if (result == 0) {
                std::cerr << "Error @ wA=" << wA << ", A=" << A << std::endl;
            }
        }
        auto nanoseconds = sw.Current();
#ifdef DEBUG
        std::cout << '\t' << std::hex << std::showbase << A << ':' << std::dec << std::noshowbase << nanoseconds;
#else
        std::cout << '\t' << nanoseconds;
#endif
    }
    std::cout << std::endl;
    return result;
}

int main(
        int argc,
        char ** argv) {
    if (argc != 4) {
        std::cerr << "Usage: " << argv[0] << " <totalnum [#iterations]> <|A| min> <|C| max>" << std::endl;
        return 1;
    }

    size_t TOTALNUM = strtoll(argv[1], nullptr, 0);

    const size_t wAmin = strtoll(argv[2], nullptr, 0); // 2
    //const size_t wAmax = 16;
    const size_t wCmin = wAmin + 1; // 3
    const size_t wCmax = strtoll(argv[3], nullptr, 0); // 127

    std::cout << TOTALNUM << " iterations per combination of |A| and |C|." << std::endl;
    std::cout << "|C|";
    for (size_t wA = wAmin; wA <= wCmax; ++wA) {
        std::cout << '\t' << wA;
    }
    std::cout << std::endl;

    for (size_t wC = wCmin; wC <= wCmax; ++wC) {
        if (wC < 8) {
            // std::cout << "using   8-bit case\n";
            __attribute__((unused)) volatile uint8_t result = test<uint8_t>(TOTALNUM, wC, wAmin);
        } else if (wC < 16) {
            // std::cout << "using  16-bit case\n";
            __attribute__((unused)) volatile uint16_t result = test<uint16_t>(TOTALNUM, wC, wAmin);
        } else if (wC < 32) {
            // std::cout << "using  32-bit case\n";
            __attribute__((unused)) volatile uint32_t result = test<uint32_t>(TOTALNUM, wC, wAmin);
        } else if (wC < 64) {
            // std::cout << "using  64-bit case\n";
            __attribute__((unused)) volatile uint64_t result = test<uint64_t>(TOTALNUM, wC, wAmin);
        } else if (wC < 128) {
            // std::cout << "using 128-bit case\n";
            __attribute__((unused)) volatile uint128_t result = test<uint128_t>(TOTALNUM, wC, wAmin);
        } else {
            throw std::runtime_error("unsupported code word width");
        }
    }
}


#include <iostream>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

#include <pcl/ModelCoefficients.h>

#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>

#include <pcl/filters/passthrough.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/project_inliers.h>

#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/surface/convex_hull.h>

#include <pcl/segmentation/extract_polygonal_prism_data.h>

#include <pcl/visualization/pcl_visualizer.h>
//#include <Eigen/Dense>

typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;

int
scale (pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_pol, double offset)
{
	float x_total = 0.0,
		y_total = 0.0,
		num_points = 0.0,
		x_centr = 0.0,
		y_centr = 0.0,
		X = 0.0,
		Y = 0.0;

	//ciclo de leitura das coordenadas e cálculo da média
	for (size_t i = 0; i < cloud_pol->points.size (); ++i)
	{
	X = cloud_pol->points[i].x;
	Y = cloud_pol->points[i].y;

	x_total = x_total + X;
	y_total = y_total + Y;
/*
	std::cout << "    " << X
		  << "    " << Y<< std::endl;
	*/

	}

	num_points = cloud_pol->points.size ();

	x_centr = x_total / num_points;
	y_centr = y_total / num_points;

/*	std::cout << "    " << x_total
		  << "    " << y_total
		  << "    " << num_points
		  << "    " << x_centr
		  << "    " << y_centr << std::endl;
	*/

	for (size_t i = 0; i < cloud_pol->points.size (); ++i)
	{
	X = cloud_pol->points[i].x;
	Y = cloud_pol->points[i].y;

	X = X - x_centr;
	Y = Y - y_centr;

	X = X * offset;
	Y = Y * offset;

	X = X + x_centr;
	Y = Y + y_centr;

	cloud_pol->points[i].x = X;
	cloud_pol->points[i].y = Y;
/*
	std::cout << "    " << X
		  << "    " << Y
		  << "    " << cloud_pol->points[i].x
		  << "    " << cloud_pol->points[i].y << std::endl;
	*/
	}

return 1;
}

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

	PointCloudT::Ptr	cloud (new PointCloudT),
				cloud_inliers_table (new PointCloudT),
				cloud_outliers_table (new PointCloudT),
				cloud_edge (new PointCloudT),
				cloud_edge_projected (new PointCloudT),
				cloud_poligonal_prism (new PointCloudT);

	/*// Load point cloud
	if (pcl::io::loadPCDFile ("caixacomobjectos.pcd", *cloud) < 0) {
		PCL_ERROR ("Could not load PCD file !\n");
		return (-1);
	}*/

	// Load point cloud
	if (pcl::io::loadPCDFile (argv[1], *cloud) < 0) {
		PCL_ERROR ("Could not load PCD file !\n");
		return (-1);
	}

///////////////////////////////////////////
//          Table Plane Extract          //
///////////////////////////////////////////

	// Segment the ground
	pcl::ModelCoefficients::Ptr plane_table (new pcl::ModelCoefficients);
	pcl::PointIndices::Ptr inliers_plane_table (new pcl::PointIndices);
	PointCloudT::Ptr cloud_plane_table (new PointCloudT);

	// Make room for a plane equation (ax+by+cz+d=0)
	plane_table->values.resize (4);

	pcl::SACSegmentation<PointT> seg_table;	// Create the segmentation object
	seg_table.setOptimizeCoefficients (true);			// Optional
	seg_table.setMethodType (pcl::SAC_RANSAC);
	seg_table.setModelType (pcl::SACMODEL_PLANE);
	seg_table.setDistanceThreshold (0.025f);
	seg_table.setInputCloud (cloud);
	seg_table.segment (*inliers_plane_table, *plane_table);

	if (inliers_plane_table->indices.size () == 0) {
		PCL_ERROR ("Could not estimate a planar model for the given dataset.\n");
		return (-1);
	}

	// Extract inliers
	pcl::ExtractIndices<PointT> extract;
	extract.setInputCloud (cloud);
	extract.setIndices (inliers_plane_table);
	extract.setNegative (false);			// Extract the inliers
	extract.filter (*cloud_inliers_table);		// cloud_inliers contains the plane

	// Extract outliers
	//extract.setInputCloud (cloud);		// Already done line 50
	//extract.setIndices (inliers);			// Already done line 51
	extract.setNegative (true);				// Extract the outliers
	extract.filter (*cloud_outliers_table);		// cloud_outliers contains everything but the plane

	printf ("Plane segmentation equation [ax+by+cz+d]=0: [%3.4f | %3.4f | %3.4f | %3.4f]     \t\n",
			plane_table->values[0], plane_table->values[1], plane_table->values[2] , plane_table->values[3]);

///////////////////////////////////////////
//           Box Edge Extract            //
///////////////////////////////////////////

	pcl::PassThrough<PointT> pass;
    	pass.setInputCloud (cloud_outliers_table);
    	pass.setFilterFieldName ("z");
    	pass.setFilterLimits (0.63, 0.68);
    	pass.filter (*cloud_edge);

	pcl::ModelCoefficients::Ptr coefficients_edge (new pcl::ModelCoefficients);
	pcl::PointIndices::Ptr inliers_edge (new pcl::PointIndices);
	// Create the segmentation object
	pcl::SACSegmentation<pcl::PointXYZ> seg_edge;
	// Optional
	seg_edge.setOptimizeCoefficients (true);
	// Mandatory
	seg_edge.setModelType (pcl::SACMODEL_PLANE);
	seg_edge.setMethodType (pcl::SAC_RANSAC);
	seg_edge.setDistanceThreshold (0.01);

	seg_edge.setInputCloud (cloud_edge);
	seg_edge.segment (*inliers_edge, *coefficients_edge);

	///////////////////////////////
	// Project the model inliers //
	///////////////////////////////
	pcl::ProjectInliers<pcl::PointXYZ> proj_edge;
	proj_edge.setModelType (pcl::SACMODEL_PLANE);
	proj_edge.setIndices (inliers_edge);
	proj_edge.setInputCloud (cloud_edge);
	proj_edge.setModelCoefficients (coefficients_edge);
	proj_edge.filter (*cloud_edge_projected);

	double merge = 0.75;
	scale(cloud_edge_projected, merge);

	////////////////////////////////////////////////////////////////////
	//       Create a Concave Hull representation of the box edge     //
	////////////////////////////////////////////////////////////////////
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_edge_hull (new pcl::PointCloud<pcl::PointXYZ>);
	pcl::ConvexHull<pcl::PointXYZ> chull;
	chull.setInputCloud (cloud_edge_projected);
	//chull.setAlpha (0.1);
	chull.reconstruct (*cloud_edge_hull);

	///////////////////////////////////////////////
	// Create a Poligonal Prism of the box edge  //
	///////////////////////////////////////////////
	pcl::PointIndices::Ptr inliers_poligonal_prism (new pcl::PointIndices);
	double z_min = -1.0, z_max = 0.0; // we want the points above the plane, no farther than 5 cm from the surface
	pcl::ExtractPolygonalPrismData<pcl::PointXYZ> prism;
	prism.setInputCloud (cloud_outliers_table);
	prism.setInputPlanarHull (cloud_edge_hull);
	prism.setHeightLimits (z_min, z_max);
	prism.segment (*inliers_poligonal_prism);

	// Extract poligonal inliers
	pcl::ExtractIndices<PointT> extract_polygonal_data;
	extract_polygonal_data.setInputCloud (cloud_outliers_table);
	extract_polygonal_data.setIndices (inliers_poligonal_prism);
	extract_polygonal_data.setNegative (false);		// Extract the inliers
	extract_polygonal_data.filter (*cloud_poligonal_prism);	// cloud_poligonal_prism contains the box

	//guarda a nuvem filtrada num novo ficheiro
	pcl::io::savePCDFileASCII ("test_seg_3pecas.pcd", *cloud_poligonal_prism);

///////////////////
// Visualization //
///////////////////
	pcl::visualization::PCLVisualizer viewer ("PCL visualizer");

	// Table Plane
	pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_inliers_table_handler (cloud, 20, 255, 255);
	viewer.addPointCloud (cloud_inliers_table, cloud_inliers_table_handler, "cloud inliers");

	// Everything else in GRAY
	pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_outliers_table_handler (cloud, 200, 200, 200);
	viewer.addPointCloud (cloud_outliers_table, cloud_outliers_table_handler, "cloud outliers");

	// Edge in Green
	pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_edge_handler (cloud, 20, 255, 20);
	viewer.addPointCloud (cloud_edge, cloud_edge_handler, "cloud edge");

	// Edge projected
	pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_edge_projected_handler (cloud, 255, 69, 20);
	viewer.addPointCloud (cloud_edge_projected, cloud_edge_projected_handler, "cloud edge projected");

	// Edge hull
	pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_edge_hull_handler (cloud, 255, 20, 20);
	viewer.addPointCloud (cloud_edge_hull, cloud_edge_hull_handler, "cloud edge hull");

	// Poligonal Prism data
	pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_poligonal_prism_handler (cloud, 20, 20, 255);
	viewer.addPointCloud (cloud_poligonal_prism, cloud_poligonal_prism_handler, "cloud Poligonal Prism");

	while (!viewer.wasStopped ()) {
		viewer.spinOnce ();
	}
	return (0);
}


#include "solver/eigenvalue/krylov_schur_eigenvalue_solver.hpp"

#include <deal.II/lac/petsc_full_matrix.h>

#include "test_helpers/gmock_wrapper.h"
#include "solver/eigenvalue/tests/spectral_radius_mock.hpp"

namespace  {

using namespace bart;
using ::testing::ContainerEq;

class SolverEigenvalueKrylovSchurEigenvalueSolverTest : public ::testing::Test {
 public:
  using Matrix = dealii::PETScWrappers::FullMatrix;
  Matrix test_matrix_;
  auto SetUp() -> void override;
};

auto SolverEigenvalueKrylovSchurEigenvalueSolverTest::SetUp() -> void {
  const std::vector<std::vector<double>> matrix_values{ {3, 2, 4}, {2, 0, 2}, {4, 2, 3}};
  test_matrix_.reinit(3,3);
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
      test_matrix_.set(i, j, matrix_values.at(i).at(j));
    }
  }
  test_matrix_.compress(dealii::VectorOperation::insert);
}

TEST_F(SolverEigenvalueKrylovSchurEigenvalueSolverTest, Dummy) {
  std::vector<double> expected_eigenvector{ 2.0/3.0, 1.0/3.0, 2.0/3.0};
  const double expected_spectral_radius{ 8 };
  solver::eigenvalue::KrylovSchurEigenvalueSolver solver;
  const auto [spectral_radius, eigenvector] = solver.SpectralRadius(test_matrix_);
  EXPECT_NEAR(spectral_radius, expected_spectral_radius, 1e-6);
  ASSERT_EQ(eigenvector.size(), 3);
  for (int i = 0; i < 3; ++i) {
    EXPECT_NEAR(std::abs(eigenvector.at(i)), expected_eigenvector.at(i), 1e-6);
  }

}

} // namespace