//==================================================================================================
/*!
    @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_ARCH_X86_SSE1_SIMD_FUNCTION_ROL_HPP_INCLUDED
#define BOOST_SIMD_ARCH_X86_SSE1_SIMD_FUNCTION_ROL_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>
#include <boost/simd/detail/dispatch/meta/as_integer.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd =  boost::dispatch;
  namespace bs =  boost::simd;
  BOOST_DISPATCH_OVERLOAD ( rol_
                          , (typename A0, typename A1)
                          , bs::sse1_
                          , bs::pack_<bd::single_<A0>, bs::sse_>
                          , bd::scalar_<bd::integer_<A1>>
                         )
  {
    BOOST_FORCEINLINE A0 operator() ( const A0 & a0
                                    , const A1 & a1 ) const BOOST_NOEXCEPT
    {
      using iA0 = bd::as_integer_t<A0>;
      return rol(a0, iA0(a1));
    }
  };
} } }

#endif


#include "ExportTexture.h"
#include "ACPState.h"
#include "ResourceIdGenerator.h"

#include <boost/filesystem.hpp>

#include "../Includes/nvtt/include/nvimage/Image.h"
#include "../Includes/nvtt/include/nvtt/nvtt.h"

struct VeritasACP::ExportTexture::Impl
{

};

VeritasACP::ExportTexture::ExportTexture()
	: m_impl(std::make_unique<Impl>())
{

}

VeritasACP::ExportTexture::~ExportTexture()
{

}

struct MyErrorHandler : public nvtt::ErrorHandler
{
	virtual void error(nvtt::Error e)
	{
#if _DEBUG
		__debugbreak();
#endif
		printf("Error: '%s'\n", nvtt::errorString(e));
	}
};

// from nvtt.h

/** Return the next power of two.
* @see http://graphics.stanford.edu/~seander/bithacks.html
* @warning Behaviour for 0 is undefined.
* @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x
* @note nextPowerOfTwo(x) = 2 << log2(x-1)
*/
inline uint nextPowerOfTwo(uint x)
{
	nvDebugCheck(x != 0);
#if 1	// On modern CPUs this is supposed to be as fast as using the bsr instruction.
	x--;
	x |= x >> 1;
	x |= x >> 2;
	x |= x >> 4;
	x |= x >> 8;
	x |= x >> 16;
	return x + 1;
#else
	uint p = 1;
	while (x > p) {
		p += p;
	}
	return p;
#endif
}

VeritasACP::ExportTextureResult VeritasACP::ExportTexture::Export(fs::path& fileName, bool isNormalMap)
{
	nvtt::InputOptions inputOptions;
	nv::Image image;
	ExportTextureResult result;

	image.load(fileName.generic_string().c_str());

	result.OriginalHeight = image.height();
	result.OriginalWidth = image.width();

	inputOptions.setNormalMap(isNormalMap);
	inputOptions.setRoundMode(nvtt::RoundMode_ToNextPowerOfTwo);
	inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
	inputOptions.setMipmapData(image.pixels(), image.width(), image.height());

	nvtt::CompressionOptions compressionOptions;
	compressionOptions.setFormat(nvtt::Format_BC3);
	compressionOptions.setQuality(nvtt::Quality_Normal);

	auto fileNameCopy = fileName;
	auto resourceName = fileNameCopy.replace_extension(".dds");

	nvtt::OutputOptions outputOptions;
	outputOptions.setFileName(resourceName.generic_string().c_str());

	MyErrorHandler handler;
	outputOptions.setErrorHandler(&handler);

	nvtt::Context context;
	context.enableCudaAcceleration(true);

	context.process(inputOptions, compressionOptions, outputOptions);

	result.NewHeight = nextPowerOfTwo(image.height());
	result.NewWidth = nextPowerOfTwo(image.width());

	VeritasACP::ACPState::Instance().AddAsset(resourceName);

	result.ResourceName = ACPState::Instance().GetResourceIdGenerator().GenerateId(resourceName);

	return result;
}


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012          Domagoj Saric, Little Endian Ltd.
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <nt2/toolbox/signal/static_fft.hpp>

#include <nt2/sdk/bench/experiment.hpp>
#include <nt2/sdk/bench/perform_benchmark.hpp>
#include <nt2/sdk/bench/details/overheads.hpp>

#include <boost/simd/sdk/memory/allocator.hpp>
#include <boost/simd/include/functions/scalar/ilog2.hpp>

#include <boost/array.hpp>
#include <boost/assert.hpp>
#include <boost/foreach.hpp>
#include <boost/noncopyable.hpp>

#ifdef __APPLE__
    #include "Accelerate/Accelerate.h" //vDSP.h
#endif // __APPLE__

#ifdef _WIN32
    #include "windows.h"
#endif // _WIN32

#include <cstdlib>
#include <cstdio>
#include <vector>

namespace bench
{
#if defined( BOOST_SIMD_HAS_LRB_SUPPORT ) || defined( BOOST_SIMD_HAS_AVX_SUPPORT )
    typedef double T;
#else //...zzz...cardinal-must-be-4 limitation...
    typedef float T;
#endif // BOOST_SIMD_HAS_LRB_SUPPORT || BOOST_SIMD_HAS_AVX_SUPPORT

    namespace constants
    {
        static std::size_t const minimum_dft_size =    32;
        static std::size_t const maximum_dft_size = 16384;

        static T const test_data_range_minimum = -1;
        static T const test_data_range_maximum = +1;
    } // namespace constants

    typedef BOOST_SIMD_ALIGN_ON( BOOST_SIMD_CONFIG_ALIGNMENT ) boost::array<T, constants::maximum_dft_size      > aligned_array;
    typedef BOOST_SIMD_ALIGN_ON( BOOST_SIMD_CONFIG_ALIGNMENT ) boost::array<T, constants::maximum_dft_size/2 + 1> aligned_half_complex_array;

    typedef std::vector<T, boost::simd::memory::allocator<T> > dynamic_aligned_array;

    typedef nt2::static_fft<constants::minimum_dft_size, constants::maximum_dft_size, T> FFT;

    /// \note The used PRNG is relatively slow so we avoid slowing down the
    /// entire benchmark by regenerating the data over and over.
    ///                                       (11.10.2012.) (Domagoj Saric)
    class reproducible_random_data_provider
    {
    public:
        reproducible_random_data_provider()
        {
            nt2::prng_reset();
            randomize( real_data_ );
            randomize( imag_data_ );
        }

        void fill_with_real_data( dynamic_aligned_array & data )
        {
            std::copy( &real_data_[ 0 ], &real_data_[ data.size() - 1 ] + 1, data.begin() );
        }

        void fill_with_imag_data( dynamic_aligned_array & data )
        {
            std::copy( &imag_data_[ 0 ], &imag_data_[ data.size() - 1 ] + 1, data.begin() );
        }

        void fill( dynamic_aligned_array & data ) { fill_with_real_data( data ); }

    private:
        void randomize( aligned_array & data )
        {
           nt2::roll( real_data_, constants::test_data_range_minimum, constants::test_data_range_maximum );
        }

    private:
        aligned_array real_data_;
        aligned_array imag_data_;
    } random_data;

    NT2_EXPERIMENT(complex_fft_test)
    {
    public:
        BOOST_DISPATCH_NOTHROW void reset() BOOST_DISPATCH_OVERRIDE
        {
            random_data.fill_with_real_data( real_data_ );
            random_data.fill_with_imag_data( imag_data_ );
        }

        std::size_t size() const
        {
            BOOST_ASSERT( real_data_.size() == imag_data_.size() );
            return real_data_.size();
        }

        std::size_t number_of_values() const { return size() * 2; }

    protected:
        complex_fft_test( std::size_t const length )
            : real_data_( length )
            , imag_data_( length )
        {
            reset();
        }

        ~complex_fft_test() {}

    protected:
        mutable dynamic_aligned_array real_data_;
        mutable dynamic_aligned_array imag_data_;
    }; // class complex_fft_test

    struct test_fft_forward : complex_fft_test
    {
        test_fft_forward( std::size_t const length ) : complex_fft_test( length ) {}

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE { FFT::forward_transform( &real_data_[ 0 ], &imag_data_[ 0 ], size() ); }
    };

    struct test_fft_inverse : complex_fft_test
    {
        test_fft_inverse( std::size_t const length ) : complex_fft_test( length ) {}

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE { FFT::inverse_transform( &real_data_[ 0 ], &imag_data_[ 0 ], size() ); }
    };

    NT2_EXPERIMENT(real_fft_test)
    {
    public:
        std::size_t size            () const { return real_time_data_.size(); }
        std::size_t number_of_values() const { return size()                ; }

    protected:
        real_fft_test( std::size_t const length )
            : real_time_data_     ( length         )
            , real_frequency_data_( length / 2 + 1 )
            , imag_frequency_data_( length / 2 + 1 )
        {}

        ~real_fft_test() {}

    protected:
        /// \note The forward transform uses the frequency data as
        /// output/scratch buffers and the inverse transform uses the
        /// real_time_data as output/scratch buffer, in addition
        /// FFT::real_inverse_transform destroys input data (so it has
        /// to be regenerated). For the said reasons all of the arrays have to
        /// declared mutable
        ///                                   (10.10.2012.) (Domagoj Saric)
        mutable dynamic_aligned_array real_time_data_     ;
        mutable dynamic_aligned_array real_frequency_data_;
        mutable dynamic_aligned_array imag_frequency_data_;
    }; // class real_fft_test

    struct test_fft_real_forward : real_fft_test
    {
        test_fft_real_forward( std::size_t const length ) : real_fft_test( length )
        {
            random_data.fill_with_real_data( real_time_data_ );
        }

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE
        {
            FFT::real_forward_transform( &real_time_data_[ 0 ], &real_frequency_data_[ 0 ], &imag_frequency_data_[ 0 ], size() );
        }
    }; // class test_fft_real_forward

    struct test_fft_real_inverse : real_fft_test
    {
        test_fft_real_inverse( std::size_t const length ) : real_fft_test( length ) { reset(); }

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE
        {
            FFT::real_inverse_transform( &real_frequency_data_[ 0 ], &imag_frequency_data_[ 0 ], &real_time_data_[ 0 ], size() );
        }

        BOOST_DISPATCH_NOTHROW void reset() BOOST_DISPATCH_OVERRIDE
        {
            /// \note FFT::real_inverse_transform destroys input data so it has
            /// to be regenerated.
            ///                               (10.10.2012.) (Domagoj Saric)
            random_data.fill_with_real_data( real_frequency_data_ );
            random_data.fill_with_imag_data( imag_frequency_data_ );
        }
    }; // test_fft_real_inverse

#ifdef __APPLE__
    class apple_fft_test : boost::noncopyable
    {
    protected:
        apple_fft_test( std::size_t const length )
            :
            log2length_  ( boost::simd::ilog2( length )                      ),
            fft_instance_( ::vDSP_create_fftsetup( log2length_, kFFTRadix2 ) )
        {
            if ( !fft_instance_ )
                BOOST_THROW_EXCEPTION( std::bad_alloc() );
        }

        ~apple_fft_test() { ::vDSP_destroy_fftsetup( fft_instance_ ); }

        FFTSetup     instance  () const { return fft_instance_; }
        unsigned int log2length() const { return log2length_  ; }

    private:
        unsigned int const log2length_  ;
        FFTSetup     const fft_instance_;
    }; // class apple_fft_test

    template <FFTDirection direction>
    class apple_complex_fft_test
        :
        public apple_fft_test,
        public complex_fft_test
    {
    public:
        apple_complex_fft_test( std::size_t const length ) : apple_fft_test( length ), complex_fft_test( length ) {}

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE
        {
            DSPSplitComplex complex_data( split_data() );
            ::vDSP_fft_zip( instance(), &complex_data, 1, log2length(), direction );
        }

        DSPSplitComplex split_data() const
        {
            DSPSplitComplex complex_data = { &real_data_[ 0 ], &imag_data_[ 0 ] };
            return complex_data;
        }
    }; // class apple_complex_fft_test

    class apple_real_fft_test
        :
        public apple_fft_test,
        public real_fft_test
    {
    protected:
        apple_real_fft_test( std::size_t const length ) : apple_fft_test( length ), real_fft_test( length ) {}

        DSPSplitComplex split_data() const
        {
            DSPSplitComplex complex_data = { &real_frequency_data_[ 0 ], &imag_frequency_data_[ 0 ] };
            return complex_data;
        }
    }; // class apple_real_fft_test

    class apple_real_forward_fft_test : public apple_real_fft_test
    {
    public:
        apple_real_forward_fft_test( std::size_t const length ) : apple_real_fft_test( length ) { random_data.fill_with_real_data( real_time_data_ ); }

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE
        {
            DSPSplitComplex split_real_data( split_data() );
            vDSP_ctoz    ( reinterpret_cast<DSPComplex const *>( &real_time_data_[ 0 ] ), 2, &split_real_data, 1, size() / 2 );
            vDSP_fft_zrip( instance(), &split_real_data, 1, log2length(), FFT_FORWARD );
        }
    }; // class apple_real_forward_fft_test

    class apple_real_inverse_fft_test : public apple_real_fft_test
    {
    public:
        apple_real_inverse_fft_test( std::size_t const length ) : apple_real_fft_test( length ) { reset(); }

        BOOST_DISPATCH_NOTHROW void run() const BOOST_DISPATCH_OVERRIDE
        {
            DSPSplitComplex split_real_data( split_data() );
            vDSP_fft_zrip( instance(), &split_real_data, 1, log2length(), FFT_INVERSE );
            vDSP_ztoc    ( &split_real_data, 1, reinterpret_cast<DSPComplex *>( &real_time_data_[ 0 ] ), 2, size() / 2 );
        }

        BOOST_DISPATCH_NOTHROW void reset() BOOST_DISPATCH_OVERRIDE
        {
            random_data.fill_with_real_data( real_frequency_data_ );
            random_data.fill_with_imag_data( imag_frequency_data_ );
        }
    }; // class apple_real_fft_test
#endif // __APPLE__

    template <class Benchmark>
    void do_perform_benchmark( char const * const benchmark_name, std::size_t const length )
    {
        typedef nt2::cycles_t           cycles_t          ;
        typedef nt2::microseconds_t     microseconds_t    ;
        typedef nt2::benchmark_result_t benchmark_result_t;

        double const benchmark_run_time( 0.6 );

        printf( "%s (%u):\t\t", benchmark_name, static_cast<unsigned int>( length ) );

        Benchmark benchmark( length );
        benchmark_result_t const benchmark_result( nt2::perform_benchmark( benchmark, benchmark_run_time ) );

        printf
        (
            "%.2f cycles/value,\t %.2f microseconds/array\n",
            static_cast<double>( benchmark_result.first ) / benchmark.number_of_values(),
            benchmark_result.second
        );
    }

    void do_test()
    {
        for
        (
            std::size_t length( constants::minimum_dft_size );
            length <= constants::maximum_dft_size;
            length *=2
        )
        {
            do_perform_benchmark<test_fft_forward     >( "(nt2) complex forward transform", length );
            do_perform_benchmark<test_fft_inverse     >( "(nt2) complex inverse transform", length );
            do_perform_benchmark<test_fft_real_forward>( "(nt2) real forward transform"   , length );
            do_perform_benchmark<test_fft_real_inverse>( "(nt2) real inverse transform"   , length );

        #ifdef __APPLE__
            do_perform_benchmark<apple_complex_fft_test<FFT_FORWARD> >( "(apple) complex forward transform", length );
            do_perform_benchmark<apple_complex_fft_test<FFT_INVERSE> >( "(apple) complex inverse transform", length );
            do_perform_benchmark<apple_real_forward_fft_test         >( "(apple) real forward transform"   , length );
            do_perform_benchmark<apple_real_inverse_fft_test         >( "(apple) real inverse transform"   , length );
        #endif // __APPLE__
        }
    }
} // namespace bench

extern "C" int main( int /*argc*/, char * /*argv*/[] )
{
    {
        using namespace nt2::details;
        std::printf
        (
            "NT2 timing code overhead information:"
            "\n\tnow() + read_cycles() + virtual run() in nanoseconds %.3f"
            "\n\tread_cycles() + virtual run() in cycles %d"
            "\n",
            nt2::to_microseconds( quantums_overhead ) * 1000,
                                  cycles_overhead
                                );
    }

#if !defined( BOOST_NO_EXCEPTIONS ) || defined( _MSC_VER )
    try
    {
        bench::do_test();
        //...zzz...return EXIT_SUCCESS;
    }
    catch ( std::exception const & e )
    {
        std::puts( e.what() );
        //...zzz...return EXIT_FAILURE;
    }
    catch ( ... )
    {
        std::puts( "Unknown failure." );
        //...zzz...return EXIT_FAILURE;
    }
#else
    bench::do_test();
#endif // _DEBUG
}


//  (C) Copyright Gennadiy Rozental 2001-2008.
//  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)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : defines algoirthms for comparing 2 floating point values
// ***************************************************************************

#ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
#define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER

// Boost.Test
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/utils/class_properties.hpp>
#include <boost/test/predicate_result.hpp>

// Boost
#include <boost/limits.hpp>  // for std::numeric_limits
#include <boost/numeric/conversion/conversion_traits.hpp> // for numeric::conversion_traits
#include <boost/static_assert.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {

namespace test_tools {

using unit_test::readonly_property;

// ************************************************************************** //
// **************        floating_point_comparison_type        ************** //
// ************************************************************************** //

enum floating_point_comparison_type {
    FPC_STRONG, // "Very close"   - equation 1' in docs, the default
    FPC_WEAK    // "Close enough" - equation 2' in docs.

};

// ************************************************************************** //
// **************                    details                   ************** //
// ************************************************************************** //

namespace tt_detail {

// FPT is Floating-Point Type: float, double, long double or User-Defined.
template<typename FPT>
inline FPT
fpt_abs( FPT fpv )
{
    return fpv < static_cast<FPT>(0) ? -fpv : fpv;
}

//____________________________________________________________________________//

template<typename FPT>
struct fpt_limits {
    static FPT    min_value()
    {
        return std::numeric_limits<FPT>::is_specialized
                    ? (std::numeric_limits<FPT>::min)()
                    : 0;
    }
    static FPT    max_value()
    {
        return std::numeric_limits<FPT>::is_specialized
                    ? (std::numeric_limits<FPT>::max)()
                    : static_cast<FPT>(1000000); // for the our purpuses it doesn't really matter what value is returned here
    }
};

//____________________________________________________________________________//

// both f1 and f2 are unsigned here
template<typename FPT>
inline FPT
safe_fpt_division( FPT f1, FPT f2 )
{
    // Avoid overflow.
    if( (f2 < static_cast<FPT>(1))  && (f1 > f2*fpt_limits<FPT>::max_value()) )
        return fpt_limits<FPT>::max_value();

    // Avoid underflow.
    if( (f1 == static_cast<FPT>(0)) ||
        ((f2 > static_cast<FPT>(1)) && (f1 < f2*fpt_limits<FPT>::min_value())) )
        return static_cast<FPT>(0);

    return f1/f2;
}

//____________________________________________________________________________//

} // namespace tt_detail

// ************************************************************************** //
// **************         tolerance presentation types         ************** //
// ************************************************************************** //

template<typename FPT>
struct percent_tolerance_t {
    explicit    percent_tolerance_t( FPT v ) : m_value( v ) {}

    FPT m_value;
};

//____________________________________________________________________________//

template<typename Out,typename FPT>
Out& operator<<( Out& out, percent_tolerance_t<FPT> t )
{
    return out << t.m_value;
}

//____________________________________________________________________________//

template<typename FPT>
inline percent_tolerance_t<FPT>
percent_tolerance( FPT v )
{
    return percent_tolerance_t<FPT>( v );
}

//____________________________________________________________________________//

template<typename FPT>
struct fraction_tolerance_t {
    explicit fraction_tolerance_t( FPT v ) : m_value( v ) {}

    FPT m_value;
};

//____________________________________________________________________________//

template<typename Out,typename FPT>
Out& operator<<( Out& out, fraction_tolerance_t<FPT> t )
{
    return out << t.m_value;
}

//____________________________________________________________________________//

template<typename FPT>
inline fraction_tolerance_t<FPT>
fraction_tolerance( FPT v )
{
    return fraction_tolerance_t<FPT>( v );
}

//____________________________________________________________________________//

// ************************************************************************** //
// **************             close_at_tolerance               ************** //
// ************************************************************************** //

template<typename FPT>
class close_at_tolerance {
public:
    // Public typedefs
    typedef bool result_type;

    // Constructor
    template<typename ToleranceBaseType>
    explicit    close_at_tolerance( percent_tolerance_t<ToleranceBaseType>  tolerance,
                                    floating_point_comparison_type          fpc_type = FPC_STRONG )
    : p_fraction_tolerance( tt_detail::fpt_abs( static_cast<FPT>(0.01)*tolerance.m_value ) )
    , p_strong_or_weak( fpc_type ==  FPC_STRONG )
    , m_report_modifier( 100. )
    {}
    template<typename ToleranceBaseType>
    explicit    close_at_tolerance( fraction_tolerance_t<ToleranceBaseType> tolerance,
                                    floating_point_comparison_type          fpc_type = FPC_STRONG )
    : p_fraction_tolerance( tt_detail::fpt_abs( tolerance.m_value ) )
    , p_strong_or_weak( fpc_type ==  FPC_STRONG )
    , m_report_modifier( 1. )
    {}

    predicate_result        operator()( FPT left, FPT right ) const
    {
        FPT diff = tt_detail::fpt_abs( left - right );
        FPT d1   = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( right ) );
        FPT d2   = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( left ) );

        predicate_result res( p_strong_or_weak
            ? (d1 <= p_fraction_tolerance.get() && d2 <= p_fraction_tolerance.get())
            : (d1 <= p_fraction_tolerance.get() || d2 <= p_fraction_tolerance.get()) );

        if( !res )
            res.message() << (( d1 <= p_fraction_tolerance.get() ? d2 : d1 ) * m_report_modifier);

        return res;
    }

    // Public properties
    readonly_property<FPT>  p_fraction_tolerance;
    readonly_property<bool> p_strong_or_weak;
private:
    // Data members
    FPT                     m_report_modifier;
};

//____________________________________________________________________________//

// ************************************************************************** //
// **************               check_is_close                 ************** //
// ************************************************************************** //

struct BOOST_TEST_DECL check_is_close_t {
    // Public typedefs
    typedef bool result_type;

    template<typename FPT1, typename FPT2, typename ToleranceBaseType>
    predicate_result
    operator()( FPT1 left, FPT2 right, percent_tolerance_t<ToleranceBaseType> tolerance,
                floating_point_comparison_type fpc_type = FPC_STRONG ) const
    {
        // deduce "better" type from types of arguments being compared
        // if one type is floating and the second integral we use floating type and
        // value of integral type is promoted to the floating. The same for float and double
        // But we don't want to compare two values of integral types using this tool.
        typedef typename numeric::conversion_traits<FPT1,FPT2>::supertype FPT;
        BOOST_STATIC_ASSERT( !is_integral<FPT>::value );

        close_at_tolerance<FPT> pred( tolerance, fpc_type );

        return pred( left, right );
    }
    template<typename FPT1, typename FPT2, typename ToleranceBaseType>
    predicate_result
    operator()( FPT1 left, FPT2 right, fraction_tolerance_t<ToleranceBaseType> tolerance,
                floating_point_comparison_type fpc_type = FPC_STRONG ) const
    {
        // same as in a comment above
        typedef typename numeric::conversion_traits<FPT1,FPT2>::supertype FPT;
        BOOST_STATIC_ASSERT( !is_integral<FPT>::value );

        close_at_tolerance<FPT> pred( tolerance, fpc_type );

        return pred( left, right );
    }
};

namespace {
check_is_close_t const& check_is_close = unit_test::ut_detail::static_constant<check_is_close_t>::value;
}

//____________________________________________________________________________//

// ************************************************************************** //
// **************               check_is_small                 ************** //
// ************************************************************************** //

struct BOOST_TEST_DECL check_is_small_t {
    // Public typedefs
    typedef bool result_type;

    template<typename FPT>
    bool
    operator()( FPT fpv, FPT tolerance ) const
    {
        return tt_detail::fpt_abs( fpv ) < tt_detail::fpt_abs( tolerance );
    }
};

namespace {
check_is_small_t const& check_is_small = unit_test::ut_detail::static_constant<check_is_small_t>::value;
}

//____________________________________________________________________________//

} // namespace test_tools

} // namespace boost

//____________________________________________________________________________//

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER


/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE overlap_filter_test

// Standard includes
#include <iostream>

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include <votca/xtp/filterfactory.h>

// VOTCA includes
#include <libint2/initialize.h>
#include <votca/tools/eigenio_matrixmarket.h>
using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(overlap_filter_test)

BOOST_AUTO_TEST_CASE(coeffs_test) {

  libint2::initialize();
  FilterFactory::RegisterAll();
  std::unique_ptr<StateFilter_base> rho_f =
      std::unique_ptr<StateFilter_base>(Filter().Create("overlap"));

  std::ofstream opt("overlap_filter.xml");
  opt << "<overlap>0.0045</overlap>" << std::endl;
  opt.close();
  votca::tools::Property prop;
  prop.LoadFromXML("overlap_filter.xml");
  rho_f->Initialize(prop.get("overlap"));

  Orbitals A;
  A.QMAtoms().LoadFromFile(std::string(XTP_TEST_DATA_FOLDER) +
                           "/overlap_filter/molecule.xyz");
  A.SetupDftBasis(std::string(XTP_TEST_DATA_FOLDER) +
                  "/overlap_filter/3-21G.xml");

  A.setNumberOfAlphaElectrons(5);
  A.setNumberOfOccupiedLevels(5);
  A.MOs().eigenvalues() = Eigen::VectorXd::Zero(17);
  A.MOs().eigenvalues() << -19.8117, -6.22408, -6.14094, -6.14094, -6.14094,
      -3.72889, -3.72889, -3.72889, -3.64731, -3.09048, -3.09048, -3.09048,
      -2.63214, -2.08206, -2.08206, -2.08206, -2.03268;

  A.QPpertEnergies() = Eigen::VectorXd::Zero(17);
  A.QPpertEnergies() << -10.189, -1.01045, -0.620145, -0.620146, -0.620148,
      0.261183, 0.348342, 0.348343, 0.348342, 0.920829, 0.920829, 0.920829,
      1.18002, 1.27325, 1.27325, 1.27325, 1.96983;

  A.MOs().eigenvectors() = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/overlap_filter/MOs_A.mm");

  A.setBSEindices(0, 16);
  A.setTDAApprox(true);
  A.setGWindices(0, 16);
  Eigen::MatrixXd spsi_ref = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/overlap_filter/spsi_ref.mm");
  A.BSESinglets().eigenvectors() = spsi_ref;

  // reference energy
  Eigen::VectorXd se_ref = Eigen::VectorXd::Zero(3);
  se_ref << 0.107455, 0.107455, 0.107455;

  A.BSESinglets().eigenvalues() = se_ref;
  A.CalcCoupledTransition_Dipoles();

  BOOST_CHECK_EQUAL(rho_f->NeedsInitialState(), true);

  rho_f->UpdateHist(A, QMState("s1"));

  std::vector<votca::Index> ref = {0};
  std::vector<votca::Index> results =
      rho_f->CalcIndeces(A, QMStateType::Singlet);

  BOOST_CHECK_EQUAL(results.size(), ref.size());
  for (votca::Index i = 0; i < votca::Index(ref.size()); i++) {
    BOOST_CHECK_EQUAL(ref[i], results[i]);
  }

  rho_f->UpdateHist(A, QMState("s2"));
  std::vector<votca::Index> results2 =
      rho_f->CalcIndeces(A, QMStateType::Singlet);
  std::vector<votca::Index> ref2 = {1};
  for (votca::Index i = 0; i < votca::Index(ref2.size()); i++) {
    BOOST_CHECK_EQUAL(ref2[i], results2[i]);
  }
  BOOST_CHECK_EQUAL(results2.size(), ref2.size());
  std::unique_ptr<StateFilter_base> rho_f2 =
      std::unique_ptr<StateFilter_base>(Filter().Create("overlap"));

  rho_f2->Initialize(prop.get("overlap"));

  rho_f2->UpdateHist(A, QMState("pqp8"));
  std::vector<votca::Index> results3 =
      rho_f2->CalcIndeces(A, QMStateType::PQPstate);

  std::vector<votca::Index> ref3 = {8};
  BOOST_CHECK_EQUAL(results3.size(), ref3.size());
  for (votca::Index i = 0; i < votca::Index(ref3.size()); i++) {
    BOOST_CHECK_EQUAL(ref3[i], results3[i]);
  }

  // reference energy
  Eigen::VectorXd se_ref_btda = Eigen::VectorXd::Zero(3);
  se_ref_btda << 0.0887758, 0.0887758, 0.0887758;

  // reference coefficients
  Eigen::MatrixXd spsi_ref_btda =
      votca::tools::EigenIO_MatrixMarket::ReadMatrix(
          std::string(XTP_TEST_DATA_FOLDER) +
          "/overlap_filter/spsi_ref_btda.mm");

  // // reference coefficients AR
  Eigen::MatrixXd spsi_ref_btda_AR =
      votca::tools::EigenIO_MatrixMarket::ReadMatrix(
          std::string(XTP_TEST_DATA_FOLDER) +
          "/overlap_filter/spsi_ref_btda_AR.mm");

  A.BSESinglets().eigenvectors() = spsi_ref_btda;
  A.BSESinglets().eigenvectors2() = spsi_ref_btda_AR;

  A.BSESinglets().eigenvalues() = se_ref_btda;
  A.setTDAApprox(false);
  A.CalcCoupledTransition_Dipoles();

  std::unique_ptr<StateFilter_base> rho_f3 =
      std::unique_ptr<StateFilter_base>(Filter().Create("overlap"));

  rho_f3->Initialize(prop.get("overlap"));

  rho_f3->UpdateHist(A, QMState("s1"));

  std::vector<votca::Index> ref_btda = {0};
  std::vector<votca::Index> results_btda =
      rho_f3->CalcIndeces(A, QMStateType::Singlet);

  BOOST_CHECK_EQUAL(results_btda.size(), ref_btda.size());
  for (votca::Index i = 0; i < votca::Index(ref_btda.size()); i++) {
    BOOST_CHECK_EQUAL(ref_btda[i], results_btda[i]);
  }

  libint2::finalize();
}

BOOST_AUTO_TEST_SUITE_END()


/**
 ** Isaac Genome Alignment Software
 ** Copyright (c) 2010-2017 Illumina, Inc.
 ** All rights reserved.
 **
 ** This software is provided under the terms and conditions of the
 ** GNU GENERAL PUBLIC LICENSE Version 3
 **
 ** You should have received a copy of the GNU GENERAL PUBLIC LICENSE Version 3
 ** along with this program. If not, see
 ** <https://github.com/illumina/licenses/>.
 **
 ** \file Mask.hh
 **
 ** Masking operations on oligomers.
 **
 ** \author Come Raczy
 **/

#ifndef iSAAC_OLIGO_MASK_HH
#define iSAAC_OLIGO_MASK_HH

#include <string>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/numeric/conversion/cast.hpp>

#include "oligo/Kmer.hh"

namespace isaac
{
namespace oligo
{

inline unsigned int getMaskCount(const unsigned int maskWidth) {return (1 << maskWidth);}

} // namespace oligo
} // namespace isaac

#endif // #ifndef iSAAC_OLIGO_MASK_HH


// g2o - General Graph Optimization
// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "solver_slam2d_linear.h"

#include <Eigen/Core>

#include "g2o/core/sparse_block_matrix.h"
#include "g2o/core/sparse_optimizer.h"
#include "g2o/core/hyper_dijkstra.h"

#include "g2o/types/slam2d/edge_se2.h"

#include "g2o/stuff/misc.h"
#include "g2o/stuff/scoped_pointer.h"

#include "g2o/solvers/csparse/linear_solver_csparse.h"

#include "g2o/core/solver.h"

using namespace std;

namespace g2o {

  /**
   * \brief compute the initial guess of theta while travelling along the MST
   */
  class ThetaTreeAction : public HyperDijkstra::TreeAction
  {
    public:
      ThetaTreeAction(double* theta) : HyperDijkstra::TreeAction(), _thetaGuess(theta) {}
      virtual double perform(HyperGraph::Vertex* v, HyperGraph::Vertex* vParent, HyperGraph::Edge* e)
      {
        if (! vParent)
          return 0.;
        EdgeSE2* odom    = static_cast<EdgeSE2*>(e);
        VertexSE2* from  = static_cast<VertexSE2*>(vParent);
        VertexSE2* to    = static_cast<VertexSE2*>(v);
        assert(to->hessianIndex() >= 0);
        double fromTheta = from->hessianIndex() < 0 ? 0. : _thetaGuess[from->hessianIndex()];
        bool direct      = odom->vertices()[0] == from;
        if (direct)
          _thetaGuess[to->hessianIndex()] = fromTheta + odom->measurement().rotation().angle();
        else
          _thetaGuess[to->hessianIndex()] = fromTheta - odom->measurement().rotation().angle();
        return 1.;
      }
    protected:
      double* _thetaGuess;
  };

  SolverSLAM2DLinear::SolverSLAM2DLinear(std::unique_ptr<Solver> solver)
    : OptimizationAlgorithmGaussNewton(std::move(solver))
  {}

  SolverSLAM2DLinear::~SolverSLAM2DLinear()
  {}

  OptimizationAlgorithm::SolverResult SolverSLAM2DLinear::solve(int iteration, bool online)
  {
    if (iteration == 0) {
      bool status = solveOrientation();
      if (! status)
        return OptimizationAlgorithm::Fail;
    }

    return OptimizationAlgorithmGaussNewton::solve(iteration, online);
  }

  bool SolverSLAM2DLinear::solveOrientation()
  {
    assert(_optimizer->indexMapping().size() + 1 == _optimizer->vertices().size() && "Needs to operate on full graph");
    assert(_optimizer->vertex(0)->fixed() && "Graph is not fixed by vertex 0");
    VectorXD b, x; // will be used for theta and x/y update
    b.setZero(_optimizer->indexMapping().size());
    x.setZero(_optimizer->indexMapping().size());

    typedef Eigen::Matrix<double, 1, 1, Eigen::ColMajor> ScalarMatrix;

    ScopedArray<int> blockIndeces(new int[_optimizer->indexMapping().size()]);
    for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i)
      blockIndeces[i] = i+1;

    SparseBlockMatrix<ScalarMatrix> H(blockIndeces.get(), blockIndeces.get(), _optimizer->indexMapping().size(), _optimizer->indexMapping().size());

    // building the structure, diagonal for each active vertex
    for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) {
      OptimizableGraph::Vertex* v = _optimizer->indexMapping()[i];
      int poseIdx = v->hessianIndex();
      ScalarMatrix* m = H.block(poseIdx, poseIdx, true);
      m->setZero();
    }

    HyperGraph::VertexSet fixedSet;

    // off diagonal for each edge
    for (SparseOptimizer::EdgeContainer::const_iterator it = _optimizer->activeEdges().begin(); it != _optimizer->activeEdges().end(); ++it) {
#    ifndef NDEBUG
      EdgeSE2* e = dynamic_cast<EdgeSE2*>(*it);
      assert(e && "Active edges contain non-odometry edge"); //
#    else
      EdgeSE2* e = static_cast<EdgeSE2*>(*it);
#    endif
      OptimizableGraph::Vertex* from = static_cast<OptimizableGraph::Vertex*>(e->vertices()[0]);
      OptimizableGraph::Vertex* to   = static_cast<OptimizableGraph::Vertex*>(e->vertices()[1]);

      int ind1 = from->hessianIndex();
      int ind2 = to->hessianIndex();
      if (ind1 == -1 || ind2 == -1) {
        if (ind1 == -1) fixedSet.insert(from); // collect the fixed vertices
        if (ind2 == -1) fixedSet.insert(to);
        continue;
      }

      bool transposedBlock = ind1 > ind2;
      if (transposedBlock){ // make sure, we allocate the upper triangle block
        std::swap(ind1, ind2);
      }

      ScalarMatrix* m = H.block(ind1, ind2, true);
      m->setZero();
    }

    // walk along the Minimal Spanning Tree to compute the guess for the robot orientation
    assert(fixedSet.size() == 1);
    VertexSE2* root = static_cast<VertexSE2*>(*fixedSet.begin());
    VectorXD thetaGuess;
    thetaGuess.setZero(_optimizer->indexMapping().size());
    UniformCostFunction uniformCost;
    HyperDijkstra hyperDijkstra(_optimizer);
    hyperDijkstra.shortestPaths(root, &uniformCost);

    HyperDijkstra::computeTree(hyperDijkstra.adjacencyMap());
    ThetaTreeAction thetaTreeAction(thetaGuess.data());
    HyperDijkstra::visitAdjacencyMap(hyperDijkstra.adjacencyMap(), &thetaTreeAction);

    // construct for the orientation
    for (SparseOptimizer::EdgeContainer::const_iterator it = _optimizer->activeEdges().begin(); it != _optimizer->activeEdges().end(); ++it) {
      EdgeSE2* e = static_cast<EdgeSE2*>(*it);
      VertexSE2* from = static_cast<VertexSE2*>(e->vertices()[0]);
      VertexSE2* to   = static_cast<VertexSE2*>(e->vertices()[1]);

      double omega = e->information()(2,2);

      double fromThetaGuess = from->hessianIndex() < 0 ? 0. : thetaGuess[from->hessianIndex()];
      double toThetaGuess   = to->hessianIndex() < 0 ? 0. : thetaGuess[to->hessianIndex()];
      double error          = normalize_theta(-e->measurement().rotation().angle() + toThetaGuess - fromThetaGuess);

      bool fromNotFixed = !(from->fixed());
      bool toNotFixed   = !(to->fixed());

      if (fromNotFixed || toNotFixed) {
        double omega_r = - omega * error;
        if (fromNotFixed) {
          b(from->hessianIndex()) -= omega_r;
          (*H.block(from->hessianIndex(), from->hessianIndex()))(0,0) += omega;
          if (toNotFixed) {
            if (from->hessianIndex() > to->hessianIndex())
              (*H.block(to->hessianIndex(), from->hessianIndex()))(0,0) -= omega;
            else
              (*H.block(from->hessianIndex(), to->hessianIndex()))(0,0) -= omega;
          }
        }
        if (toNotFixed ) {
          b(to->hessianIndex()) += omega_r;
          (*H.block(to->hessianIndex(), to->hessianIndex()))(0,0) += omega;
        }
      }
    }

    // solve orientation
    typedef LinearSolverCSparse<ScalarMatrix> SystemSolver;
    SystemSolver linearSystemSolver;
    linearSystemSolver.init();
    bool ok = linearSystemSolver.solve(H, x.data(), b.data());
    if (!ok) {
      cerr << __PRETTY_FUNCTION__ << "Failure while solving linear system" << endl;
      return false;
    }

    // update the orientation of the 2D poses and set translation to 0, GN shall solve that
    root->setToOrigin();
    for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) {
      VertexSE2* v = static_cast<VertexSE2*>(_optimizer->indexMapping()[i]);
      int poseIdx = v->hessianIndex();
      SE2 poseUpdate(0, 0, normalize_theta(thetaGuess(poseIdx) + x(poseIdx)));
      v->setEstimate(poseUpdate);
    }

    return true;
  }

} // end namespace


#include <chrono>
#include <vector>
#include <map>
#include <iostream>
#include <math.h>
#include <string>
#include <fstream>
#include <exception>

#include "Vector3.h"
#include "AABB.h"
#include "Point.h"
#include "GridIndex.h"
#include "SparseGrid.h"
#include "GridCell.h"
#include "PotreeConverter.h"
#include "PotreeException.h"

#include "boost/program_options.hpp"
#include <boost/filesystem.hpp>

namespace po = boost::program_options;

using std::ifstream;
using std::ofstream;
using std::ios;
using std::string;
using std::min;
using std::max;
using std::ostream;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
using std::binary_function;
using std::map;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using boost::filesystem::path;
using std::exception;

#define MAX_FLOAT std::numeric_limits<float>::max()

class SparseGrid;

void printUsage(po::options_description &desc){
	cout << "usage: PotreeConverter [OPTIONS] SOURCE" << endl;
	cout << desc << endl;
}

#include "LASPointReader.h"
#include "LASPointWriter.hpp"
#include "BINPointWriter.hpp"

//int main(int argc, char **argv){
//	string path = "C:/dev/workspaces/potree/develop/resources/pointclouds/lion_takanawa/laz/r.laz";
//	string pathOut = "C:/temp/test.las";
//	LASPointReader *reader = new LASPointReader(path);
//	LASPointWriter *writer = new LASPointWriter(pathOut, reader->getAABB());
//
//	int i = 0;
//	while(reader->readNextPoint()){
//		Point p = reader->getPoint();
//
//		if(i < 10){
//			cout << p.position() << endl;
//		}
//
//		writer->write(p);
//		i++;
//	}
//	writer->close();
//	reader->close();
//}

//#include "BINPointReader.hpp"
//#include "BINPointWriter.hpp"
//
//int main(int argc, char **argv){
//	string path = "C:/dev/pointclouds/converted/skatepark/data/r";
//	string pathOut = "C:/temp/skatepark";
//	BINPointReader *reader = new BINPointReader(path);
//	BINPointWriter *writer = new BINPointWriter(pathOut);
//
//	int i = 0;
//	while(reader->readNextPoint()){
//		Point p = reader->getPoint();
//
//		if(i < 10){
//			cout << p.position() << endl;
//		}
//
//		writer->write(p);
//		i++;
//	}
//	writer->close();
//	reader->close();
//}

int main(int argc, char **argv){
	vector<string> source;
	string outdir;
	float spacing;
	int levels;
	string format;
	float range;
	string outFormatString;
	double scale;
	int diagonalFraction;
	OutputFormat outFormat;

	cout.imbue(std::locale(""));

	try{
		// read parameters from command line
		po::options_description desc("Options");
		desc.add_options()
			("help,h", "prints usage")
			("outdir,o", po::value<string>(&outdir), "output directory")
			("spacing,s", po::value<float>(&spacing), "Distance between points at root level. Distance halves each level.")
			("spacing-by-diagonal-fraction,d", po::value<int>(&diagonalFraction), "Maximum number of points on the diagonal in the first level (sets spacing). spacing = diagonal / value")
			("levels,l", po::value<int>(&levels), "Number of levels that will be generated. 0: only root, 1: root and its children, ...")
			("input-format,f", po::value<string>(&format), "Input format. xyz: cartesian coordinates as floats, rgb: colors as numbers, i: intensity as number")
			("range,r", po::value<float>(&range), "Range of rgb or intensity. ")
			("output-format", po::value<string>(&outFormatString), "Output format can be BINARY, LAS or LAZ. Default is BINARY")
			("scale", po::value<double>(&scale), "Scale of the X, Y, Z coordinate in LAS and LAZ files.")
			("source", po::value<std::vector<std::string> >(), "Source file. Can be LAS, LAZ or PLY");
		po::positional_options_description p;
		p.add("source", -1);

		po::variables_map vm;
		po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
		po::notify(vm);

		if(vm.count("help") || !vm.count("source")){
			printUsage(desc);

			return 0;
		}

		if(vm.count("source")){
			source = vm["source"].as<std::vector<std::string> >();
		}else{
			cout << "source file parameter is missing" << endl;
			return 1;
		}

		// set default parameters
		path pSource(source[0]);
		outdir = vm.count("outdir") ? vm["outdir"].as<string>() : pSource.generic_string() + "_converted";
		if(!vm.count("spacing")) spacing = 0;
		if(!vm.count("spacing-by-diagonal-fraction")) diagonalFraction = 0;
		if(!vm.count("levels")) levels = 3;
		if(!vm.count("input-format")) format = "xyzrgb";
		if(!vm.count("range")) range = 255;
		if(!vm.count("scale")) scale = 0.01;
		if(!vm.count("output-format")) outFormatString = "BINARY";
		if(outFormatString == "BINARY"){
			outFormat = OutputFormat::BINARY;
		}else if(outFormatString == "LAS"){
			outFormat = OutputFormat::LAS;
		}else if(outFormatString == "LAZ"){
			outFormat = OutputFormat::LAZ;
		}
		if (diagonalFraction != 0) {
			spacing = 0;
		}else if(spacing == 0){
				diagonalFraction = 250;
		}

		cout << "== params ==" << endl;
		for(int i = 0; i < source.size(); i++){
			cout << "source[" << i << "]: " << source[i] << endl;
		}
		cout << "outdir: " << outdir << endl;
		cout << "spacing: " << spacing << endl;
		cout << "diagonal-fraction: " << diagonalFraction << endl;
		cout << "levels: " << levels << endl;
		cout << "format: " << format << endl;
		cout << "range: " << range << endl;
		cout << "scale: " << scale << endl;
		cout << "output-format: " << outFormatString << endl;
		cout << endl;
	}catch(exception &e){
		cout << "ERROR: " << e.what() << endl;

		return 1;
	}

	auto start = high_resolution_clock::now();

	try{
		PotreeConverter pc(source, outdir, spacing, diagonalFraction, levels, format, range, scale, outFormat);
		pc.convert();
	}catch(exception &e){
		cout << "ERROR: " << e.what() << endl;
		return 1;
	}

	auto end = high_resolution_clock::now();
	milliseconds duration = duration_cast<milliseconds>(end-start);
	cout << "duration: " << (duration.count()/1000.0f) << "s" << endl;

	return 0;
}


/**
 * @file    run_vo.cpp
 * @version v1.0.0
 * @date    Dec,19 2017
 * @author  jacob.lin
 * @brief   test the visual odometry
 */

#include <fstream>
#include <boost/timer.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/viz.hpp>
#include <cstdlib>

#include "config.h"
#include "visual_odometry.h"

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        cout << "usage: run_vo parameter_file" << endl;
        return 1;
    }

    visual_odometry::Config::setParameterFile(argv[1]);
    visual_odometry::VisualOdometry::Ptr vo(new visual_odometry::VisualOdometry);

    std::string dataset_dir = visual_odometry::Config::get<std::string>("dataset_dir");
    cout << "dataset: " << dataset_dir << endl;
    ifstream fin(dataset_dir + "/associate.txt");
    if (!fin)
    {
        cout << "Please generate the associate file called associate.txt!" << endl;
        return 1;
    }

    std::vector<std::string> rgb_files, depth_files;
    std::vector<double> rgb_times, depth_times;
    while (!fin.eof())  // end of file
    {
        std::string rgb_time, rgb_file, depth_time, depth_file;
        fin >> rgb_time >> rgb_file >> depth_time >> depth_file;
        rgb_times.push_back(std::atof(rgb_time.c_str()));
        depth_times.push_back(std::atof(rgb_time.c_str()));
        rgb_files.push_back(dataset_dir + "/" + rgb_file);
        depth_files.push_back(dataset_dir + "/" + depth_file);

        if (fin.good() == false)
        {
            break;
        }
    }

    visual_odometry::Camera::Ptr camera(new visual_odometry::Camera);

    /* visualization */
    cv::viz::Viz3d vis("Visual Odometry");
    cv::viz::WCoordinateSystem world_coor(1.0), camera_coor(0.5);
    cv::Point3d cam_pos(0, -1.0, -1.0), cam_focal_point(0, 0, 0), cam_y_dir(0, 1, 0);
    cv::Affine3d cam_pose = cv::viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir);
    vis.setViewerPose(cam_pose);

    world_coor.setRenderingProperty(cv::viz::LINE_WIDTH, 2.0);
    camera_coor.setRenderingProperty(cv::viz::LINE_WIDTH, 1.0);
    vis.showWidget("World", world_coor);
    vis.showWidget("Camera", camera_coor);

    cout << "read total " << rgb_files.size() << "entries" << endl;

    for (int i = 0; i < rgb_files.size(); i ++)
    {
        cout << "********** loop " << i << "**********" << endl;
        cv::Mat color = cv::imread(rgb_files[i]);
        cv::Mat depth = cv::imread(depth_files[i]);
        if (color.data == nullptr || depth.data == nullptr)
        {
            break;
        }
        visual_odometry::Frame::Ptr pFrame = visual_odometry::Frame::createFrame();
        pFrame->_camera = camera;
        pFrame->_color = color;
        pFrame->_depth = depth;
        pFrame->_time_stamp = rgb_times[i];

        boost::timer timer;
        vo->addFrame(pFrame);
        cout << "VO costs time: " << timer.elapsed() << endl;

        if (vo->_state == visual_odometry::VisualOdometry::LOST)
        {
            break;
        }
        Sophus::SE3 Tcw = pFrame->_T_c_w.inverse();

        /* show the map and the camera pose */
        cv::Affine3d M(
            cv::Affine3d::Mat3(
                Tcw.rotation_matrix()(0, 0), Tcw.rotation_matrix()(0, 1), Tcw.rotation_matrix()(0, 2),
                Tcw.rotation_matrix()(1, 0), Tcw.rotation_matrix()(1, 1), Tcw.rotation_matrix()(1, 2),
                Tcw.rotation_matrix()(2, 0), Tcw.rotation_matrix()(2, 1), Tcw.rotation_matrix()(2, 2)
            ),
            cv::Affine3d::Vec3(
                Tcw.translation()(0, 0), Tcw.translation()(1, 0), Tcw.translation()(2, 0)
            )
        );

        cv::Mat img_show = color.clone();
        for (auto& pt :  vo->_map->_map_points)
        {
            visual_odometry::MapPoint::Ptr p = pt.second;
            Eigen::Vector2d pixel = pFrame->_camera->world2pixel(p->_pos, pFrame->_T_c_w);
            cv::circle(img_show, cv::Point2f(pixel(0, 0), pixel(1, 0)), 5, cv::Scalar(0, 255, 0), 2);
        }

        cv::imshow("image", img_show);
        cv::waitKey(1);
        vis.setWidgetPose("Camera", M);
        vis.spinOnce(1, false);
        cout << endl;
    }

    return 0;
}


/*
 Copyright 2012 Google Inc. All Rights Reserved.
 Author: blakely@google.com (Tim Blakely)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#include <boost/random/taus88.hpp>
#include <iostream>

#include "base_types.h"
#include "boost/random/uniform_01.hpp"
#include "network/objects/neuron.h"
#include "protos/basics.pb.h"
#include "protos/neuron.pb.h"
#include "protos/topology.pb.h"
#include "topology/arrangement.h"
#include "topology/arrangement/flat_rectangular.h"

namespace google {
namespace protobuf {
class Message;
}  // namespace protobuf
}  // namespace google

namespace bigbrain {

using boost::random::uniform_01;

FlatRectangularArrangement::FlatRectangularArrangement(const int32 &random_seed)
    : Arrangement(random_seed),
      num_neurons_placed_(0) {
}

FlatRectangularArrangement::~FlatRectangularArrangement() {
}

google::protobuf::Message *FlatRectangularArrangement::get_params() {
  return &params_;
}

void FlatRectangularArrangement::SetNeuronPosition(
    Neuron* cell, const int32& num_this_type_neurons) {
  Position* pos = cell->get_common_params()->mutable_pos();

  float neg_one_to_one;
  uniform_01<> range;

  double x, y;

  switch (params_.distribution()) {
    case DIST_RANDOM:
      // X

      neg_one_to_one = 2 * range(random_) - 1;
      pos->set_x(
          neg_one_to_one * params_.dimensions().width() / 2
              + params_.origin().x());
      // Y
      neg_one_to_one = 2 * range(random_) - 1;
      pos->set_y(
          neg_one_to_one * params_.dimensions().height() / 2
              + params_.origin().y());
      // Z
      neg_one_to_one = 2 * range(random_) - 1;
      pos->set_z(
          neg_one_to_one * params_.dimensions().depth() / 2
              + params_.origin().z());
      break;
    case DIST_UNIFORM:
      if (params_.num_cols() == 1) {
        x = params_.origin().x();
      } else {
        x = num_neurons_placed_ % params_.num_cols()
            * params_.dimensions().width() / (params_.num_cols() - 1)
            - params_.dimensions().width() / 2 + params_.origin().x();
      }
      if (params_.num_rows() == 1) {
        y = params_.origin().y();
      } else {
        y = floor(num_neurons_placed_ / params_.num_cols())
            * params_.dimensions().height() / (params_.num_rows() - 1)
            - params_.dimensions().height() / 2 + params_.origin().y();
      }

      pos->set_x(x);
      pos->set_y(y);
      pos->set_z(0);
      break;
  }
  ++num_neurons_placed_;
}

}  // namespace bigbrain


#include "utils/util.h"

#include <haptics/thread_socket_interface.h>
#include <boost/foreach.hpp>

using namespace std;

using Eigen::Matrix3d;
using Eigen::Vector3d;

namespace util
{
    osg::ref_ptr<osg::Vec3Array> toVec3Array(const vector<btVector3>& in)
    {
        osg::ref_ptr<osg::Vec3Array> out = new osg::Vec3Array();
        out->reserve(in.size());
        BOOST_FOREACH(const btVector3& pt, in) out->push_back(osg::Vec3(pt.x(),pt.y(),pt.z()));
        return out;
    }

    osg::ref_ptr<osg::Vec4Array> toVec4Array(const vector<btVector4>& in)
    {
        osg::ref_ptr<osg::Vec4Array> out = new osg::Vec4Array();
        out->reserve(in.size());
        BOOST_FOREACH(const btVector3& pt, in) out->push_back(osg::Vec4(pt.x(),pt.y(),pt.z(),pt.w()));
        return out;
    }

    static const btMatrix3x3 HAPTIC_ROTATION(btQuaternion(-M_PI/2., 0., 0.));

    static inline btMatrix3x3 toHapticBtMatrix(const Matrix3d &m)
    {
        // note: the rows are permuted
        return btMatrix3x3(m(2, 0), m(2, 1), m(2, 2),
                           m(0, 0), m(0, 1), m(0, 2),
                           m(1, 0), m(1, 1), m(1, 2));
    }

    static inline btVector3 toHapticBtVector(const Vector3d &v)
    {
        // note: the components are permuted
        return btVector3(v.z(), v.x(), v.y());
    }

    bool getHapticInput(btTransform &trans0, bool buttons0[2], btTransform &trans1, bool buttons1[2])
    {
        Vector3d start_proxy_pos, end_proxy_pos;
        Matrix3d start_proxy_rot, end_proxy_rot;
        if (!getDeviceState(start_proxy_pos, start_proxy_rot, buttons0,
                            end_proxy_pos, end_proxy_rot, buttons1))
            return false;
        trans0 = btTransform(toHapticBtMatrix(start_proxy_rot) * HAPTIC_ROTATION,
                             toHapticBtVector(start_proxy_pos));
        trans1 = btTransform(toHapticBtMatrix(end_proxy_rot) * HAPTIC_ROTATION,
                             toHapticBtVector(end_proxy_pos));

        return true;
    }

    void sendRobotState(btVector3 pos0, btVector3 pos1)
    {
        double out0[3] = {pos0[1], pos0[2], pos0[0]};
        double out1[3] = {pos1[1], pos1[2], pos1[0]};
        sendDeviceState(out0, true, out1, true);
        cout << "send pos: " << out0[0] << " " << out0[1] << " " << out0[2] << ", " <<
          out1[0] << " " << out1[1] << " " << out1[2] << endl;
      }
}


#include <iostream>
#include <numeric>
#include <cmath>
#include <string>
#include <optional>
#include <regex>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/process.hpp>
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
#include <csv-parser/csv.h>
#include <xpas/newick.h>
#include <xpas/phylo_tree.h>
#include "ar.h"
#include "row.h"
#include "proba_matrix.h"
#include "command_line.h"

using std::string;
using std::cout, std::endl;
namespace bp = boost::process;
namespace fs = boost::filesystem;

namespace xpas::ar
{
    /// \brief Reads ancestral reconstruction output
    class ar_reader
    {
    public:
        virtual ~ar_reader() noexcept = default;
        virtual xpas::proba_matrix read() = 0;
    };

    /// \brief Reads a PhyML output into a matrix.
    class phyml_reader : public ar_reader
    {
    public:
        phyml_reader(const string& file_name) noexcept;
        phyml_reader(const phyml_reader&) = delete;
        phyml_reader(phyml_reader&&) = delete;
        phyml_reader& operator=(const phyml_reader&) = delete;
        phyml_reader& operator=(phyml_reader&&) = delete;
        ~phyml_reader() noexcept override = default;

        proba_matrix read() override;

    private:
        proba_matrix read_matrix();

        string _file_name;
    };

    /// \brief Reads RAXML-NG output into a matrix.
    class raxmlng_reader : public ar_reader
    {
    public:
        raxmlng_reader(const string& file_name) noexcept;
        raxmlng_reader(const phyml_reader&) = delete;
        raxmlng_reader(raxmlng_reader&&) = delete;
        raxmlng_reader& operator=(const raxmlng_reader&) = delete;
        raxmlng_reader& operator=(raxmlng_reader&&) = delete;
        ~raxmlng_reader() noexcept override = default;

        proba_matrix read();

    private:
        proba_matrix read_matrix();

        string _file_name;
    };

    phyml_reader::phyml_reader(const string& file_name) noexcept
        : _file_name{ file_name }
    {}

    proba_matrix phyml_reader::read()
    {
        try
        {
            cout << "Loading PhyML results: " + _file_name << "..." << endl;
            std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
            auto matrix = read_matrix();

            cout << "Loaded " << matrix.num_branches() << " matrices of " <<
                 matrix.num_sites() << " rows." << endl;
            cout << "Time (ms): " << std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - begin).count() << endl << endl;
            return matrix;
        }
        catch (::io::error::integer_overflow& error)
        {
            throw std::runtime_error("PhyML result parsing error: " + string(error.what()));
        }
    }

    proba_matrix phyml_reader::read_matrix()
    {
#ifdef SEQ_TYPE_DNA
        std::ios::sync_with_stdio(false);

        proba_matrix matrix;
        std::ifstream infile(_file_name);

        bool is_header = true;

        string line;
        while (std::getline(infile, line))
        {
            if (is_header)
            {
                // if the line starts with 'Site', the header is finished
                if (line.size() > 4 && line.rfind("Site", 0) == 0)
                {
                    is_header = false;
                }
            }
            else
            {
                size_t site = 0;
                std::string node_label;
                xpas::phylo_kmer::score_type a, c, g, t;

                std::istringstream iss(line);
                if (!(iss >> site >> node_label >> a >> c >> g >> t))
                {
                    throw std::runtime_error("Parsing error: could not parse the line " + line);
                }

                /// log-transform the probabilities
                auto new_row = row_type { { { a, 0 }, { c, 1 }, { g, 2 }, { t, 3 } } };
                auto log = [](const proba_pair& p) { return proba_pair{ std::log10(p.score), p.index }; };
                std::transform(begin(new_row), end(new_row), begin(new_row), log);

                // sort them
                auto compare = [](const proba_pair& p1, const proba_pair& p2) { return p1.score > p2.score; };
                std::sort(begin(new_row), end(new_row), compare);

                /// insert
                auto it = matrix.find(node_label);
                if (it != std::end(matrix))
                {
                    it->second.push_back(new_row);
                }
                else
                {
                    /// WARNING: it is cheap to copy new_row here in the case of DNA.
                    /// It is probably makes sense to move it in the case of amino acids though.
                    matrix[node_label] = proba_matrix::mapped_type{ node_label, { new_row } };
                }
            }
        }
        return matrix;
#elif SEQ_TYPE_AA
        throw std::runtime_error("PhyML for proteins is not supported yet.");
#else
        static_assert(false, """Make sure the sequence type is defined. Supported types:\n"""
                             """SEQ_TYPE_DNA"""
                             """SEQ_TYPE_AA""");
#endif

    }

    raxmlng_reader::raxmlng_reader(const string& file_name) noexcept
        : _file_name{ file_name }
    {}

    proba_matrix raxmlng_reader::read()
    {
        try
        {
            cout << "Loading RAXML-NG results: " + _file_name << "..." << endl;
            std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
            auto matrix = read_matrix();

            cout << "Loaded " << matrix.num_branches() << " matrices of " <<
                 matrix.num_sites() << " rows." << endl;
            cout << "Time (ms): " << std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - begin).count() << endl << endl;
            return matrix;
        }
        catch (::io::error::integer_overflow& error)
        {
            throw std::runtime_error("PhyML result parsing error: " + string(error.what()));
        }
    }

    proba_matrix raxmlng_reader::read_matrix()
    {
        proba_matrix matrix;

#ifdef SEQ_TYPE_DNA
        ::io::CSVReader<5,
            ::io::trim_chars<' '>,
            ::io::no_quote_escape<'\t'>,
            ::io::throw_on_overflow,
            ::io::single_and_empty_line_comment<'.'>> _in(_file_name);

        _in.read_header(::io::ignore_extra_column, "Node", "p_A", "p_C", "p_G", "p_T");

        std::string node_label;
        xpas::phylo_kmer::score_type a, c, g, t;
        while (_in.read_row(node_label, a, c, g, t))
        {
            /// log-transform the probabilities
            auto new_row = row_type { { { a, 0 }, { c, 1 }, { g, 2 }, { t, 3 } } };

#elif SEQ_TYPE_AA
        ::io::CSVReader<21,
            ::io::trim_chars<' '>,
            ::io::no_quote_escape<'\t'>,
            ::io::throw_on_overflow,
            ::io::single_and_empty_line_comment<'.'>> _in(_file_name);

        _in.read_header(::io::ignore_extra_column, "Node", "p_A", "p_R", "p_N", "p_D", "p_C", "p_Q", "p_E", "p_G",
                        "p_H", "p_I", "p_L", "p_K", "p_M", "p_F", "p_P", "p_S", "p_T", "p_W", "p_Y", "p_V");

        std::string node_label;
        xpas::phylo_kmer::score_type a, r, n, d, c, q, e, g, h, i, l, k, m, f, p, s, t, w, y, v;
        while (_in.read_row(node_label, a, r, n, d, c, q, e, g, h, i, l, k, m, f, p, s, t, w, y, v))
        {
            /// log-transform the probabilities
            auto new_row = row_type {
                { { a, *xpas::seq_traits::key_to_code('a') },
                    { r, *xpas::seq_traits::key_to_code('r') },
                    { n, *xpas::seq_traits::key_to_code('n')},
                    { d, *xpas::seq_traits::key_to_code('d') },
                    { c, *xpas::seq_traits::key_to_code('c') },
                    { q, *xpas::seq_traits::key_to_code('q') },
                    { e, *xpas::seq_traits::key_to_code('e') },
                    { g, *xpas::seq_traits::key_to_code('g') },
                    { h, *xpas::seq_traits::key_to_code('h') },
                    { i, *xpas::seq_traits::key_to_code('i') },
                    { l, *xpas::seq_traits::key_to_code('l') },
                    { k, *xpas::seq_traits::key_to_code('k') },
                    { m, *xpas::seq_traits::key_to_code('m') },
                    { f, *xpas::seq_traits::key_to_code('f') },
                    { p, *xpas::seq_traits::key_to_code('p') },
                    { s, *xpas::seq_traits::key_to_code('s') },
                    { t, *xpas::seq_traits::key_to_code('t') },
                    { w, *xpas::seq_traits::key_to_code('w') },
                    { y, *xpas::seq_traits::key_to_code('y') },
                    { v, *xpas::seq_traits::key_to_code('v') } }
            };
#else
            static_assert(false, """Make sure the sequence type is defined. Supported types:\n"""
                             """SEQ_TYPE_DNA"""
                             """SEQ_TYPE_AA""");
#endif
            auto log = [](const proba_pair& p) { return proba_pair{ std::log10(p.score), p.index }; };
            std::transform(begin(new_row), end(new_row), begin(new_row), log);

            // sort them
            auto compare = [](const proba_pair& p1, const proba_pair& p2) { return p1.score > p2.score; };
            std::sort(begin(new_row), end(new_row), compare);

            /// insert into the matrix
            auto it = matrix.find(node_label);
            if (it != std::end(matrix))
            {
                it->second.push_back(new_row);
            }
            else
            {
                /// WARNING: it is cheap to copy new_row here in the case of DNA.
                /// It probably makes sense to move it in the case of amino acids though.
                matrix[node_label] = proba_matrix::mapped_type{ node_label, { new_row } };
            }
        }
        return matrix;
    }

    /// Figures out which AR software is used by running BINARY_FILE --help
    class ar_guesser
    {
    public:
        ar_guesser(std::string working_directory, std::string binary_file)
            : _working_dir{ std::move(working_directory) }
            , _binary_file{ std::move(binary_file) }
        {
            fs::create_directories(_working_dir);
            _ar_output_file = fs::path{ _working_dir } / "ar_help.log";
        }

        ar::software run()
        {
            try
            {
                bp::system(_binary_file, "--help", bp::std_out > _ar_output_file.string());
                return parse_ar_output();
            }
            catch (const std::system_error& err)
            {
                throw std::runtime_error("Error: Could not run ancestral reconstruction software: " + _binary_file);
            }

        }

    private:
        ar::software parse_ar_output()
        {
            std::ifstream in(_ar_output_file.string());

            if (in.is_open())
            {
                std::string line;
                while (getline(in, line))
                {
                    boost::algorithm::to_lower(line);

                    if (line.find("phyml") != string::npos)
                    {
                        return ar::software::PHYML;
                    }
                    else if (line.find("raxml-ng") != string::npos)
                    {
                        return ar::software::RAXML_NG;
                    }
                }
            }

            throw std::runtime_error("Error: Unsupported ancestral reconstruction software: " + _binary_file);
        }

        std::string _working_dir;
        std::string _binary_file;

        fs::path _ar_output_file;
    };

    std::unique_ptr<ar_reader> make_reader(ar::software software, const string& filename)
    {
        if (software == ar::software::PHYML)
        {
            return std::make_unique<phyml_reader>(filename);
        }
        else if (software == ar::software::RAXML_NG)
        {
            return std::make_unique<raxmlng_reader>(filename);
        }
        else
        {
            throw std::runtime_error("Unsupported ancestral reconstruction output format.");
        }
    }

/*
    /// \brief Reads a "extended_tree_node_mapping.tsv" file produced by the old RAPPAS.
    extended_mapping load_extended_mapping(const string& file_name)
    {
        cout << "Loading a node mapping: " + file_name << endl;
        extended_mapping mapping;

        ::io::CSVReader<2, ::io::trim_chars<' '>, ::io::no_quote_escape<'\t'>> in(file_name);
        in.read_header(::io::ignore_extra_column, "original_id", "extended_name");
        std::string extended_name;
        branch_type original_id = xpas::phylo_kmer::na_branch;
        while (in.read_row(original_id, extended_name))
        {
            mapping[extended_name] = original_id;
        }
        cout << "Loaded " << mapping.size() << " mapped ids." << endl << endl;
        return mapping;
    }*/

    std::optional<xpas::phylo_kmer::branch_type> extract_number(const std::string& s)
    {
        /// take the first sequence of digits from the string
        string output = std::regex_replace(s,
            std::regex("[^0-9]*([0-9]+).*"),
            string("$1")
        );

        /// return it if there was any
        if (output.size() > 0)
        {
            const auto casted = static_cast<xpas::phylo_kmer::branch_type>(std::stoul(output));
            return { casted };
        }
        else
        {
            return std::nullopt;
        }
    }

    /// \brief Returns if the input string is a number
    bool is_number(const std::string& s)
    {
        auto it = s.begin();
        while (it != s.end() && std::isdigit(*it))
        {
            ++it;
        }
        return !s.empty() && it == s.end();
    }
    /*

    /// \brief Reads a "ARtree_id_mapping.tsv" file produced by the old RAPPAS.
    artree_label_mapping load_artree_mapping(const std::string& file_name)
    {
        cout << "Loading a node mapping: " + file_name << endl;
        artree_label_mapping mapping;

        ::io::CSVReader<2, ::io::trim_chars<' '>, ::io::no_quote_escape<'\t'>> in(file_name);
        in.read_header(::io::ignore_extra_column, "extended_label", "ARtree_label");
        std::string extended_label, artree_label;
        while (in.read_row(extended_label, artree_label))
        {
            mapping[extended_label] = artree_label;
        }
        cout << "Loaded " << mapping.size() << " mapped ids." << endl << endl;
        return mapping;
    }
*/

    ar::model parse_model(const std::string& model)
    {
        std::map<std::string, ar::model> map = {
            {"JC69", ar::model::JC69 },
            {"K80", ar::model::K80 },
            {"F81", ar::model::F81 },
            {"F84", ar::model::F84 },
            {"HKY85", ar::model::HKY85 },
            {"TN93",ar::model::TN93 },
            {"GTR", ar::model::GTR },
            {"LG", ar::model::LG },
            {"WAG", ar::model::WAG },
            {"JTT", ar::model::JTT },
            {"DAYHOFF", ar::model::DAYHOFF },
            {"DCMUT", ar::model::DCMUT },
            {"CPREV", ar::model::CPREV },
            {"MTMAM", ar::model::MTMAM },
            {"MTREV", ar::model::MTREV },
            {"MTART", ar::model::MTART }
        };

        if (const auto it = map.find(model); it != map.end())
        {
            return it->second;
        }
        else
        {
            throw std::runtime_error("Unsupported AR model: " + model);
        }
    }

    std::string model_to_string(ar::model model)
    {
        switch(model)
        {
            case ar::model::JC69:
                return "JC69";
            case ar::model::K80:
                return "K80";
            case ar::model::F81:
                return "F81";
            case ar::model::F84:
                return "F84";
            case ar::model::HKY85:
                return "HKY85";
            case ar::model::TN93:
                return "TN93";
            case ar::model::GTR:
                return "GTR";
            case ar::model::LG:
                return "LG";
            case ar::model::WAG:
                return "WAG";
            case ar::model::JTT:
                return "JTT";
            case ar::model::DAYHOFF:
                return "DAYHOFF";
            case ar::model::DCMUT:
                return "DCMUT";
            case ar::model::CPREV:
                return "CPREV";
            case ar::model::MTMAM:
                return "MTMAM";
            case ar::model::MTREV:
                return "MTREV";
            case ar::model::MTART:
                return "MTART";
        }
        throw std::runtime_error("Internal error: wrong model");
    }

    struct ar_result
    {
        std::string matrix_file;
        std::string tree_file;
    };

    /// Iterates over files in the directory, looks for the first file with the given suffix
    optional<fs::path> find_file_by_suffix(const fs::path& directory, const std::string& suffix)
    {
        auto it = fs::directory_iterator(directory);
        for (const auto& entry : boost::make_iterator_range(it, {}))
        {
            if (fs::is_regular_file(entry) && boost::ends_with(entry.path().string(), suffix))
            {
                return entry;
            }
        }
        return nullopt;
    }

    /// Wrapper for ancestral reconstruction software.
    class ar_wrapper
    {
    public:
        virtual ~ar_wrapper() noexcept = default;

        /// Runs the software. Returns the output files on success
        virtual ar_result run() = 0;
    };

    class phyml_wrapper : public ar_wrapper
    {
    public:
        explicit phyml_wrapper(ar::parameters parameters)
            : _params{ std::move(parameters) }
        {
        }

        ~phyml_wrapper() noexcept override = default;

        ar_result run() override
        {
            fs::path matrix_file;
            fs::path tree_file;

            /// --ar-dir not provided
            if (_params.ar_dir.empty())
            {
                _run();

                matrix_file = _params.alignment_file + "_phyml_ancestral_seq.txt";
                tree_file = _params.alignment_file + "_phyml_ancestral_tree.txt";

                check_file(matrix_file);
                check_file(tree_file);
            }
            /// look in the directory provided by --ar-dir
            else
            {
                const auto ar_dir = _params.ar_dir;
                if (fs::is_directory(_params.ar_dir))
                {
                    if (auto found_matrix = find_file_by_suffix(_params.ar_dir, "_phyml_ancestral_seq.txt"); found_matrix)
                    {
                        matrix_file = *found_matrix;
                    }
                    else
                    {
                        throw std::runtime_error("Could not find \"*_phyml_ancestral_seq.txt\" in"
                                                 "the folder provided by --ar-dir: " + _params.ar_dir);
                    }

                    if (auto found_tree = find_file_by_suffix(_params.ar_dir, "_phyml_ancestral_tree.txt"); found_tree)
                    {
                        tree_file = *found_tree;
                    }
                    else
                    {
                        throw std::runtime_error("Could not find \"*_phyml_ancestral_tree.txt\" in"
                                                 "the folder provided by --ar-dir: " + _params.ar_dir);
                    }
                }
                else
                {
                    throw std::runtime_error("Error! No such directory: " + _params.ar_dir);
                }
            }

            std::cout << "Ancestral reconstruction results have been found: " << std::endl
                      << '\t' << matrix_file.string() << std::endl
                      << '\t' << tree_file.string() << std::endl;
            return { matrix_file.string(), tree_file.string() };
        }

    private:

        void _run()
        {
            int result = bp::system(_params.binary_file,
                                    "--ancestral",
                                    "--no_memory_check",
                                    "-i", _params.alignment_file,
                                    "-u", _params.tree_file,
                                    "-m", model_to_string(_params.ar_model),
                                    "-c", std::to_string(_params.categories),
                                    "-b", std::to_string(0),
                                    "-v", std::to_string(0.0),
                                    "-o", "r",
                                    "-a", std::to_string(_params.alpha),
                                    "-f", "e",
                                    "--leave_duplicates"
            );

            if (result != 0)
            {
                throw std::runtime_error("Error during ancestral reconstruction: exit code"
                                         + std::to_string(result));
            }
        }

        void check_file(const fs::path& file)
        {
            if (!fs::exists(file) || fs::is_empty(file))
            {
                throw std::runtime_error("Error during ancestral reconstruction: could not find "
                                         + file.string());
            }
        }

        ar::parameters _params;

    };

    class raxml_wrapper : public ar_wrapper
    {
    public:
        explicit raxml_wrapper(ar::parameters parameters)
            : _params{ std::move(parameters) }
        {
        }

        ~raxml_wrapper() noexcept override = default;

        ar_result run() override
        {
            fs::path matrix_file;
            fs::path tree_file;

            /// --ar-dir not provided
            if (_params.ar_dir.empty())
            {
                _run();

                matrix_file = _params.alignment_file + ".raxml.ancestralProbs";
                tree_file = _params.alignment_file + ".raxml.ancestralTree";

                check_file(matrix_file);
                check_file(tree_file);
            }
            /// look in the directory provided by --ar-dir
            else
            {
                const auto ar_dir = _params.ar_dir;
                if (fs::is_directory(_params.ar_dir))
                {
                    if (auto found_matrix = find_file_by_suffix(_params.ar_dir, ".raxml.ancestralProbs"); found_matrix)
                    {
                        matrix_file = *found_matrix;
                    }
                    else
                    {
                        throw std::runtime_error("Could not find \"*.raxml.ancestralTree\" in"
                                                 "the folder provided by --ar-dir: " + _params.ar_dir);
                    }

                    if (auto found_tree = find_file_by_suffix(_params.ar_dir, ".raxml.ancestralTree"); found_tree)
                    {
                        tree_file = *found_tree;
                    }
                    else
                    {
                        throw std::runtime_error("Could not find \"*.raxml.ancestralTree\" in"
                                                 "the folder provided by --ar-dir: " + _params.ar_dir);
                    }
                }
                else
                {
                    throw std::runtime_error("Error! No such directory: " + _params.ar_dir);
                }
            }

            std::cout << "Ancestral reconstruction results have been found: " << std::endl
                      << '\t' << matrix_file.string() << std::endl
                      << '\t' << tree_file.string() << std::endl;
            return { matrix_file.string(), tree_file.string() };
        }

    private:

        void _run()
        {
            throw std::runtime_error("RAXML-NG is not supported yet.");
        }

        void check_file(const fs::path& file)
        {
            if (!fs::exists(file) || fs::is_empty(file))
            {
                throw std::runtime_error("Error during ancestral reconstruction: could not find "
                                         + file.string());
            }
        }

        ar::parameters _params;

    };

    std::unique_ptr<ar_wrapper> make_ar_wrapper(ar::software software, const ar::parameters& parameters)
    {
        if (software == ar::software::PHYML)
        {
            return std::make_unique<phyml_wrapper>(parameters);
        }
        else if (software == ar::software::RAXML_NG)
        {
            return std::make_unique<raxml_wrapper>(parameters);
        }
        else
        {
            throw std::runtime_error("Unsupported ancestral reconstruction output format.");
        }
    }

    std::pair<ar::software, ar::parameters> make_parameters(const cli::parameters& parameters,
                                                            const std::string& ext_tree_file,
                                                            const std::string& ext_alignment_phylip)
    {
        ar::parameters ar_params;
        ar_params.ar_dir = parameters.ar_dir;
        ar_params.binary_file = parameters.ar_binary_file;
        ar_params.ar_model = parse_model(parameters.ar_model);
        ar_params.alpha = parameters.ar_alpha;
        ar_params.categories = parameters.ar_categories;
        ar_params.tree_file = ext_tree_file;
        ar_params.alignment_file = ext_alignment_phylip;

        /// Find out what AR software is used
        ar_guesser arguesser(parameters.working_directory, parameters.ar_binary_file);
        const auto ar_software = arguesser.run();

        return { ar_software, ar_params };
    }

    std::tuple<proba_matrix, phylo_tree> ancestral_reconstruction(ar::software software, const ar::parameters& parameters)
    {
        /// Run ancestral reconstruction
        auto wrapper = make_ar_wrapper(software, parameters);
        const auto& result = wrapper->run();

        /// Parse the probability matrix
        auto reader = make_reader(software, result.matrix_file);
        auto matrix = reader->read();

        /// Read the tree generated by AR software
        auto ar_tree = xpas::io::load_newick(result.tree_file);

        return { std::move(matrix), std::move(ar_tree) };
    }

    size_t count_leaves(const phylo_tree& tree)
    {
        size_t count = 0;
        for (const auto& node : tree)
        {
            if (node.is_leaf())
            {
                ++count;
            }
        }
        return count;
    }

    ar::mapping map_nodes(const phylo_tree& extended_tree, const phylo_tree& ar_tree)
    {
        if (extended_tree.get_node_count() != ar_tree.get_node_count())
        {
            throw std::runtime_error("Error during database construction: extended tree and "
                                     "AR differ in the number of nodes: "
                                     + std::to_string(extended_tree.get_node_count())
                                     + " vs. " + std::to_string(ar_tree.get_node_count()));
        }

        ar::mapping ext_to_ar;

        /// Traverse the AR tree
        using const_iterator = postorder_tree_iterator<true>;
        for (const auto& ext_node : visit_subtree<const_iterator>(extended_tree.get_root()))
        {
            if (ext_node.is_root())
            {
                continue;
            }

            if (ext_node.is_leaf())
            {
                /// For leaves the node labels must be the same
                const auto label = ext_node.get_label();
                const auto ar_node_ptr = ar_tree.get_by_label(label);

                if (!ar_node_ptr || *ar_node_ptr == nullptr)
                {
                    throw std::runtime_error("Internal error: could not find a node in the AR tree: label = '"
                                             + label + "'");
                }

                /// Map the the Extended tree leaf to the AR tree leaf
                /// They are actually the same.
                ext_to_ar[label] = (*ar_node_ptr)->get_label();

                /// Map their parents if they exist
                if (!ext_node.is_root())
                {
                    const auto ext_parent_ptr = ext_node.get_parent();
                    const auto ar_parent_ptr = (*ar_node_ptr)->get_parent();

                    ext_to_ar[ext_parent_ptr->get_label()] = ar_parent_ptr->get_label();
                }
            }
            /// Internal node
            else
            {
                const auto ar_node_label = ext_to_ar[ext_node.get_label()];
                const auto ar_node_ptr = ar_tree.get_by_label(ar_node_label);
                if (!ar_node_ptr || *ar_node_ptr == nullptr)
                {
                    throw std::runtime_error("Internal error: could not a find node in the AR tree: label = '"
                                             + ar_node_label + "'");
                }

                /// Map their parent if they exist
                const auto ext_parent_ptr = ext_node.get_parent();
                const auto ar_parent_ptr = (*ar_node_ptr)->get_parent();
                if (ar_parent_ptr && ext_parent_ptr)
                {
                    ext_to_ar[ext_parent_ptr->get_label()] = ar_parent_ptr->get_label();
                }
            }
        }

        /*std::cout << std::endl << "EXT -> AR MAPPING" << std::endl;
        for (const auto& [ext_label, ar_label] : ext_to_ar)
        {
            std::cout << ext_label << " -> " << ar_label << std::endl;
        }*/
        return ext_to_ar;
    }
}


#ifndef IMLP__CPU_IMPL_H
#define IMLP__CPU_IMPL_H

#include <datastructures/problem.hpp>
#include <datastructures/tableau.hpp>
#include <impl/impl_common.hpp>
#include <util/primitive_structures.hpp>
#include <util/print_printable.hpp>

#include <vector>

#include <boost/optional.hpp>

namespace simplex {
namespace cpu {

#if __cplusplus >= 201103L
template<typename FloatType>
struct ThetaValuesAndEnteringColumn : util::print_printable {
	std::vector<FloatType> theta_values;
	std::vector<FloatType> entering_column;

	ThetaValuesAndEnteringColumn(std::ptrdiff_t height)
		: theta_values((std::size_t)height)
		, entering_column((std::size_t)height)
	{ }

	ThetaValuesAndEnteringColumn(const ThetaValuesAndEnteringColumn&) = default;
	ThetaValuesAndEnteringColumn(ThetaValuesAndEnteringColumn&&) = default;
	ThetaValuesAndEnteringColumn& operator=(const ThetaValuesAndEnteringColumn&) = default;
	ThetaValuesAndEnteringColumn& operator=(ThetaValuesAndEnteringColumn&&) = default;

	template<typename STREAM>
	void print(STREAM& os) const {
		os << "{tv = {";
		for (const auto& tv : theta_values) {
			os << tv << ", ";
		}
		os << "}, ec = {";
		for (const auto& ecv : entering_column) {
			os << ecv << ", ";
		}
		os << "}}";
	}
};
#endif

Tableau<double> create_tableau(const Problem& problem_stmt);

// find smallest also negative value in the first row
boost::optional<VariableIndex> find_entering_variable(const util::PointerAndSize<double>& first_row);

ThetaValuesAndEnteringColumn<double> get_theta_values_and_entering_column(const Tableau<double>& tab, VariableIndex entering);

boost::optional<VariableIndex> find_leaving_variable(const ThetaValuesAndEnteringColumn<double>& tvals_and_centering);

#if __cplusplus >= 201103L
Tableau<double> update_leaving_row(Tableau<double>&& tab, const std::vector<double>& entering_column, VariablePair leaving_and_entering);

Tableau<double> update_rest_of_basis(Tableau<double>&& tab, const std::vector<double>& entering_column, VariableIndex leaving);

Tableau<double> update_entering_column(Tableau<double>&& tab, const std::vector<double>& entering_column, VariablePair leaving_and_entering);
#endif

} // end namespace simplex
} // end namespace cpu

#endif /* IMLP__CPU_IMPL_H */


/*! \file getdata.h
\brief rのメッシュと、そのメッシュにおける電子密度を与えるクラスの実装

Copyright © 2015 @dc1394 All Rights Reserved.
This software is released under the BSD 2-Clause License.
*/

#include "DXUT.h"
#include "getdata.h"
#include "readdatafile.h"
#include <stdexcept>                    // for std::runtime_error
#include <tuple>                        // for std::tie
#include <boost/algorithm/string.hpp>   // for boost::algorithm
#include <boost/assert.hpp>             // for BOOST_ASSERT
#include <boost/cast.hpp>               // for boost::cast
#include <boost/range/algorithm.hpp>    // for boost::max_element

namespace getdata {
    // #region コンストラクタ

    GetData::GetData(std::string const & filename) :
        Atomname([this] { return std::cref(atomname_); }, nullptr),
        Funcmax([this] { return funcmax_; }, nullptr),
        Funcmin([this] { return funcmin_; }, nullptr),
        L([this] { return l_; }, nullptr),
        N([this] { return n_; }, nullptr),
        Orbital([this] { return orbital_; }, nullptr),
        Rho_wf_type_([this] { return rho_wf_type_; }, nullptr),
        R_meshmin([this] { return r_meshmin_; }, nullptr),
        acc_(gsl_interp_accel_alloc(), gsl_interp_accel_deleter)
    {
        using namespace boost::algorithm;

        // トークン分割
        std::vector<std::string> tokens;
        split(tokens, filename, is_any_of("_"), token_compress_on);

        if (tokens[0].find("rho") != std::string::npos) {
            rho_wf_type_ = GetData::Rho_Wf_type::RHO;
        }
        else if (tokens[0].find("wf") != std::string::npos) {
            rho_wf_type_ = GetData::Rho_Wf_type::WF;
        }
        else {
            throw std::runtime_error("ファイル名が異常です！");
        }

        if (tokens[1] == "H") {
            atomname_ = "Hydrogen";
        }
        else if (tokens[1] == "He") {
            atomname_ = "Helium";
        }
        else {
            throw std::runtime_error("ファイル名が異常です！");
        }

        orbital_ = tokens[2][0];
        n_ = static_cast<std::int32_t>(tokens[2][0] - '0');

        switch (tokens[2][1]) {
        case 's':
            l_ = 0;
            orbital_ += 's';
            break;

        case 'p':
            l_ = 1;
            orbital_ += 'p';
            break;

        case 'd':
            l_ = 2;
            orbital_ += 'd';
            break;

        case 'f':
            l_ = 3;
            orbital_ += 'f';
            break;

        case 'g':
            l_ = 4;
            orbital_ += 'g';
            break;

        default:
            throw std::runtime_error("ファイル名が異常です！");
            break;
        }

        std::vector<double> r_mesh, phi;
        std::tie(r_mesh, phi) = ReadDataFile().readdatafile(filename);

        BOOST_ASSERT(r_mesh.size() == phi.size());

        funcmax_ = *boost::max_element(phi);

        std::vector<double> temp(phi);
        boost::for_each(temp, [](double & v) { v = v >= 0.0 ? 0.0 : -v; });
        funcmin_ = -*boost::max_element(temp);

        r_meshmin_ = r_mesh[0];

        spline_ = std::unique_ptr<gsl_spline, decltype(gsl_spline_deleter)>(
            gsl_spline_alloc(gsl_interp_cspline, r_mesh.size()), gsl_spline_deleter);

        gsl_spline_init(spline_.get(), r_mesh.data(), phi.data(), r_mesh.size());
    }

    // #endregion コンストラクタ

    // #region メンバ関数

    double GetData::operator()(double r) const
    {
        return gsl_spline_eval(spline_.get(), r, acc_.get());
    }

    // #endsregion メンバ関数
}