////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// @project        Open Space Toolkit ▸ Physics
/// @file           OpenSpaceToolkit/Physics/Coordinate/Frame/Providers/IERS/Finals2000A.cpp
/// @author         Lucas Brémond <lucas@loftorbital.com>
/// @license        Apache License 2.0

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <OpenSpaceToolkit/Physics/Coordinate/Frame/Providers/IERS/Finals2000A.hpp>

#include <OpenSpaceToolkit/Core/Types/String.hpp>
#include <OpenSpaceToolkit/Core/Error.hpp>
#include <OpenSpaceToolkit/Core/Utilities.hpp>

#include <boost/lexical_cast.hpp>

#include <sstream>
#include <fstream>
#include <iostream>
#include <iterator>

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace ostk
{
namespace physics
{
namespace coord
{
namespace frame
{
namespace provider
{
namespace iers
{

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::ostream&                   operator <<                                 (           std::ostream&               anOutputStream,
                                                                                const   Finals2000A&                aFinals2000A                                )
{

    using ostk::core::types::String ;

    using ostk::physics::time::Scale ;

    ostk::core::utils::Print::Header(anOutputStream, "Finals 2000A") ;

    ostk::core::utils::Print::Line(anOutputStream) << "Interval:" << (aFinals2000A.getInterval().isDefined() ? aFinals2000A.getInterval().toString(Scale::UTC) : "Undefined") ;

    ostk::core::utils::Print::Footer(anOutputStream) ;

    return anOutputStream ;

}

bool                            Finals2000A::isDefined                      ( ) const
{
    return !data_.empty() ;
}

Interval                        Finals2000A::getInterval                    ( ) const
{

    if (!this->isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Finals 2000A") ;
    }

    return span_ ;

}

Vector2d                        Finals2000A::getPolarMotionAt               (   const   Instant&                    anInstant                                   ) const
{

    using ostk::physics::time::Scale ;

    if (!anInstant.isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Instant") ;
    }

    if (!this->isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Finals 2000A") ;
    }

    const Pair<const Finals2000A::Data*, const Finals2000A::Data*> dataRange = this->accessDataRange(anInstant) ;

    if ((dataRange.first != nullptr) && (dataRange.second != nullptr))
    {

        const Finals2000A::Data& previousData = *(dataRange.first) ;
        const Finals2000A::Data& nextData = *(dataRange.second) ;

        if (previousData.x_A.isDefined() && previousData.y_A.isDefined() && nextData.x_A.isDefined() && nextData.y_A.isDefined())
        {

            const Real instantMjd_UTC = anInstant.getModifiedJulianDate(Scale::UTC) ;

            const Real ratio = (instantMjd_UTC - previousData.mjd) / (nextData.mjd - previousData.mjd) ;

            const Real x_A = previousData.x_A + ratio * (nextData.x_A - previousData.x_A) ;
            const Real y_A = previousData.y_A + ratio * (nextData.y_A - previousData.y_A) ;

            return { x_A, y_A } ;

        }
        else
        {
            return Vector2d::Undefined() ;
        }

    }

    throw ostk::core::error::RuntimeError("Cannot get polar motion at [{}].", anInstant.toString(Scale::UTC)) ;

}

Real                            Finals2000A::getUt1MinusUtcAt               (   const   Instant&                    anInstant                                   ) const
{

    using ostk::physics::time::Scale ;

    if (!anInstant.isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Instant") ;
    }

    if (!this->isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Finals 2000A") ;
    }

    const Pair<const Finals2000A::Data*, const Finals2000A::Data*> dataRange = this->accessDataRange(anInstant) ;

    if ((dataRange.first != nullptr) && (dataRange.second != nullptr))
    {

        const Finals2000A::Data& previousData = *(dataRange.first) ;
        const Finals2000A::Data& nextData = *(dataRange.second) ;

        if (previousData.ut1MinusUtc_A.isDefined() && nextData.ut1MinusUtc_A.isDefined())
        {

            const Real instantMjd_UTC = anInstant.getModifiedJulianDate(Scale::UTC) ;

            const Real ratio = (instantMjd_UTC - previousData.mjd) / (nextData.mjd - previousData.mjd) ;

            const Real ut1MinusUtc_A = previousData.ut1MinusUtc_A + ratio * (nextData.ut1MinusUtc_A - previousData.ut1MinusUtc_A) ;
            // const Real ut1MinusUtc_B = previousData.ut1MinusUtc_B + ratio * (nextData.ut1MinusUtc_B - previousData.ut1MinusUtc_B) ;

            return ut1MinusUtc_A ;

        }
        else
        {
            return Real::Undefined() ;
        }

    }

    throw ostk::core::error::RuntimeError("Cannot get UT1 - UTC at [{}].", anInstant.toString(Scale::UTC)) ;

}

Real                            Finals2000A::getLodAt                       (   const   Instant&                    anInstant                                   ) const
{

    using ostk::physics::time::Scale ;

    if (!anInstant.isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Instant") ;
    }

    if (!this->isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Finals 2000A") ;
    }

    const Pair<const Finals2000A::Data*, const Finals2000A::Data*> dataRange = this->accessDataRange(anInstant) ;

    if ((dataRange.first != nullptr) && (dataRange.second != nullptr))
    {

        const Finals2000A::Data& previousData = *(dataRange.first) ;
        const Finals2000A::Data& nextData = *(dataRange.second) ;

        if (previousData.lod_A.isDefined() && nextData.lod_A.isDefined())
        {

            const Real instantMjd_UTC = anInstant.getModifiedJulianDate(Scale::UTC) ;

            const Real ratio = (instantMjd_UTC - previousData.mjd) / (nextData.mjd - previousData.mjd) ;

            const Real lod_A = previousData.lod_A + ratio * (nextData.lod_A - previousData.lod_A) ;

            return lod_A ;

        }
        else
        {
            return Real::Undefined() ;
        }

    }

    throw ostk::core::error::RuntimeError("Cannot get length of day at [{}].", anInstant.toString(Scale::UTC)) ;

}

Finals2000A::Data               Finals2000A::getDataAt                      (   const   Instant&                    anInstant                                   ) const
{

    using ostk::physics::time::Scale ;

    if (!anInstant.isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Instant") ;
    }

    if (!this->isDefined())
    {
        throw ostk::core::error::runtime::Undefined("Finals 2000A") ;
    }

    const Pair<const Finals2000A::Data*, const Finals2000A::Data*> dataRange = this->accessDataRange(anInstant) ;

    if ((dataRange.first != nullptr) && (dataRange.second != nullptr))
    {

        auto interpolate = [] (const Real& aPreviousValue, const Real& aNextValue, const Real& aRatio) -> Real
        {

            if (!aRatio.isDefined())
            {
                throw ostk::core::error::runtime::Undefined("Ratio") ;
            }

            if (aPreviousValue.isDefined() && aNextValue.isDefined())
            {
                return aPreviousValue + aRatio * (aNextValue - aPreviousValue) ;
            }

            return Real::Undefined() ;

        } ;

        const Finals2000A::Data& previousData = *(dataRange.first) ;
        const Finals2000A::Data& nextData = *(dataRange.second) ;

        const Real instantMjd_UTC = anInstant.getModifiedJulianDate(Scale::UTC) ;

        const Real ratio = (instantMjd_UTC - previousData.mjd) / (nextData.mjd - previousData.mjd) ;

        const Integer year = previousData.year ;
        const Integer month = previousData.month ;
        const Integer day = previousData.day ;

        const Real mjd = interpolate(previousData.mjd, nextData.mjd, ratio) ;

        const char polarMotionflag = (previousData.polarMotionflag == nextData.polarMotionflag) ? previousData.polarMotionflag : '?' ;

        const Real x_A = interpolate(previousData.x_A, nextData.x_A, ratio) ;
        const Real xError_A = interpolate(previousData.xError_A, nextData.xError_A, ratio) ;
        const Real y_A = interpolate(previousData.y_A, nextData.y_A, ratio) ;
        const Real yError_A = interpolate(previousData.yError_A, nextData.yError_A, ratio) ;

        const char ut1MinusUtcFlag = (previousData.ut1MinusUtcFlag == nextData.ut1MinusUtcFlag) ? previousData.ut1MinusUtcFlag : '?' ;

        const Real ut1MinusUtc_A = interpolate(previousData.ut1MinusUtc_A, nextData.ut1MinusUtc_A, ratio) ;
        const Real ut1MinusUtcError_A = interpolate(previousData.ut1MinusUtcError_A, nextData.ut1MinusUtcError_A, ratio) ;
        const Real lod_A = interpolate(previousData.lod_A, nextData.lod_A, ratio) ;
        const Real lodError_A = interpolate(previousData.lodError_A, nextData.lodError_A, ratio) ;

        const char nutationFlag = (previousData.nutationFlag == nextData.nutationFlag) ? previousData.nutationFlag : '?' ;

        const Real dx_A = interpolate(previousData.dx_A, nextData.dx_A, ratio) ;
        const Real dxError_A = interpolate(previousData.dxError_A, nextData.dxError_A, ratio) ;
        const Real dy_A = interpolate(previousData.dy_A, nextData.dy_A, ratio) ;
        const Real dyError_A = interpolate(previousData.dyError_A, nextData.dyError_A, ratio) ;
        const Real x_B = interpolate(previousData.x_B, nextData.x_B, ratio) ;
        const Real y_B = interpolate(previousData.y_B, nextData.y_B, ratio) ;
        const Real ut1MinusUtc_B = interpolate(previousData.ut1MinusUtc_B, nextData.ut1MinusUtc_B, ratio) ;
        const Real dx_B = interpolate(previousData.dx_B, nextData.dx_B, ratio) ;
        const Real dy_B = interpolate(previousData.dy_B, nextData.dy_B, ratio) ;

        const Finals2000A::Data data =
        {
            year,
            month,
            day,
            mjd,
            polarMotionflag,
            x_A,
            xError_A,
            y_A,
            yError_A,
            ut1MinusUtcFlag,
            ut1MinusUtc_A,
            ut1MinusUtcError_A,
            lod_A,
            lodError_A,
            nutationFlag,
            dx_A,
            dxError_A,
            dy_A,
            dyError_A,
            x_B,
            y_B,
            ut1MinusUtc_B,
            dx_B,
            dy_B
        } ;

        return data ;

    }

    throw ostk::core::error::RuntimeError("Cannot get data at [{}].", anInstant.toString(Scale::UTC)) ;

}

Finals2000A                     Finals2000A::Undefined                      ( )
{
    return Finals2000A() ;
}

Finals2000A                     Finals2000A::Load                           (   const   fs::File&                   aFile                                       )
{

    using ostk::core::types::Index ;
    using ostk::core::types::Uint8 ;
    using ostk::core::types::Uint16 ;
    using ostk::core::types::Real ;
    using ostk::core::types::String ;
    using ostk::core::ctnr::Array ;

    using ostk::physics::time::Scale ;
    using ostk::physics::time::Time ;
    using ostk::physics::time::DateTime ;

    if (!aFile.isDefined())
    {
        throw ostk::core::error::runtime::Undefined("File") ;
    }

    if (!aFile.exists())
    {
        throw ostk::core::error::RuntimeError("File [{}] does not exist.", aFile.toString()) ;
    }

    Finals2000A finals2000a ;

    std::ifstream fileStream(aFile.getPath().toString()) ;

    Index lineIndex = 0 ;
    String line ;

    // auto splitString = [] (const String& aString, char aDelimiter) -> Array<String>
    // {

    //     Array<String> aStringArray = Array<String>::Empty() ;

    //     std::stringstream stringStream(aString) ;

    //     String item ;

    //     while (std::getline(stringStream, item, aDelimiter))
    //     {

    //         if (!item.empty())
    //         {
    //             aStringArray.add(item) ;
    //         }

    //     }

    //     return aStringArray ;

    // } ;

    auto parseReal = [] (const String& aLine, const Index& aStartColumnNumber, const Index& anEndColumnNumber) -> Real
    {

        String string = aLine.getSubstring(aStartColumnNumber - 1, anEndColumnNumber - aStartColumnNumber + 1).trim() ;

        if (string.isEmpty())
        {
            return Real::Undefined() ;
        }

        if ((string.getLength() > 2) && (string.getHead(1) == "."))
        {
            string = "0." + string.getTail(string.getLength() - 1) ;
        }

        if ((string.getLength() > 2) && (string.getHead(2) == "-."))
        {
            string = "-0." + string.getTail(string.getLength() - 2) ;
        }

        return Real::Parse(string) ;

    } ;

    while (std::getline(fileStream, line))
    {

        const Integer year = Integer::Parse(line.getSubstring(0, 2).trim()) ;
        const Integer month = Integer::Parse(line.getSubstring(2, 2).trim()) ;
        const Integer day = Integer::Parse(line.getSubstring(4, 2).trim()) ;

        const Real mjd = parseReal(line, 8, 15) ;

        const char polarMotionflag = line.at(16) ;

        const Real x_A = parseReal(line, 19, 27) ;
        const Real xError_A = parseReal(line, 28, 36) ;
        const Real y_A = parseReal(line, 38, 46) ;
        const Real yError_A = parseReal(line, 47, 55) ;

        const char ut1MinusUtcFlag = line.at(57) ;

        const Real ut1MinusUtc_A = parseReal(line, 59, 68) ;
        const Real ut1MinusUtcError_A = parseReal(line, 69, 78) ;
        const Real lod_A = parseReal(line, 80, 86) ;
        const Real lodError_A = parseReal(line, 87, 93) ;

        const char nutationFlag = line.at(95) ;

        const Real dx_A = parseReal(line, 98, 106) ;
        const Real dxError_A = parseReal(line, 107, 115) ;
        const Real dy_A = parseReal(line, 117, 125) ;
        const Real dyError_A = parseReal(line, 126, 134) ;
        const Real x_B = parseReal(line, 135, 144) ;
        const Real y_B = parseReal(line, 145, 154) ;
        const Real ut1MinusUtc_B = parseReal(line, 155, 165) ;
        const Real dx_B = parseReal(line, 166, 175) ;
        const Real dy_B = parseReal(line, 176, 185) ;

        const Finals2000A::Data data =
        {
            year,
            month,
            day,
            mjd,
            polarMotionflag,
            x_A,
            xError_A,
            y_A,
            yError_A,
            ut1MinusUtcFlag,
            ut1MinusUtc_A,
            ut1MinusUtcError_A,
            lod_A,
            lodError_A,
            nutationFlag,
            dx_A,
            dxError_A,
            dy_A,
            dyError_A,
            x_B,
            y_B,
            ut1MinusUtc_B,
            dx_B,
            dy_B
        } ;

        finals2000a.data_.insert({ mjd, data }) ;

        lineIndex++ ;

    }

    if (!finals2000a.data_.empty())
    {

        const Instant startInstant = Instant::ModifiedJulianDate(finals2000a.data_.begin()->first, Scale::UTC) ;
        const Instant endInstant = Instant::ModifiedJulianDate(finals2000a.data_.rbegin()->first, Scale::UTC) ;

        finals2000a.span_ = Interval::Closed(startInstant, endInstant) ;

    }

    return finals2000a ;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

                                Finals2000A::Finals2000A                    ( )
                                :   span_(Interval::Undefined()),
                                    data_(Map<Real, Finals2000A::Data>())
{

}

Pair<const Finals2000A::Data*, const Finals2000A::Data*> Finals2000A::accessDataRange ( const Instant&              anInstant                                   ) const
{

    using ostk::physics::time::Scale ;

    const Real instantMjd_UTC = anInstant.getModifiedJulianDate(Scale::UTC) ;

    const auto nextDataIt = data_.lower_bound(instantMjd_UTC) ;

    if (nextDataIt == data_.end())
    {
        return { &(data_.rbegin()->second), nullptr } ;
    }
    else if (nextDataIt == data_.begin())
    {
        return { nullptr, &(nextDataIt->second) } ;
    }
    else
    {

        const auto previousDataIt = std::prev(nextDataIt) ;

        return { &(previousDataIt->second), &(nextDataIt->second) } ;

    }

    return { nullptr, nullptr } ;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
}
}
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/* ************************************************************************
 * Copyright 2016 Advanced Micro Devices, Inc.
 * ************************************************************************ */

#include <iostream>
#include <stdio.h>
#include <boost/program_options.hpp>

#include "rocblas.h"
#include "utility.h"
#include "rocblas.hpp"
#include "testing_iamax.hpp"
#include "testing_iamin.hpp"
#include "testing_asum.hpp"
#include "testing_axpy.hpp"
#include "testing_copy.hpp"
#include "testing_dot.hpp"
#include "testing_swap.hpp"
#include "testing_gemv.hpp"
#include "testing_ger.hpp"
#include "testing_syr.hpp"
#include "testing_nrm2.hpp"
#include "testing_scal.hpp"
#include "testing_trtri.hpp"
#include "testing_trtri_batched.hpp"
#include "testing_geam.hpp"
#include "testing_set_get_vector.hpp"
#include "testing_set_get_matrix.hpp"
#if BUILD_WITH_TENSILE
#include "testing_gemm.hpp"
#include "testing_gemm_strided_batched.hpp"
#include "testing_gemm_kernel_name.hpp"
#include "testing_gemm_strided_batched_kernel_name.hpp"
#include "testing_trsm.hpp"
#endif

namespace po = boost::program_options;

int main(int argc, char* argv[])
{
    Arguments argus;
    argus.unit_check =
        0;            // disable unit_check in client benchmark, it is only used in gtest unit test
    argus.timing = 1; // enable timing check,otherwise no performance data collected

    std::string function;
    char precision;

    rocblas_int device_id;
    vector<rocblas_int> range = {-1, -1, -1};

    po::options_description desc("rocblas client command line options");
    desc.add_options()("help,h", "produces this help message")
        // clang-format off
        ("range",
         po::value<vector<rocblas_int>>(&range)->multitoken(),
         "Range matrix size testing: BLAS-3 benchmarking only. Accept three positive integers. "
         "Usage: "
         "--range start end step"
         ". e.g "
         "--range 100 1000 200"
         ". Diabled if not specified. If enabled, user specified m,n,k will be nullified")

        ("sizem,m",
         po::value<rocblas_int>(&argus.M)->default_value(128),
         "Specific matrix size testing: sizem is only applicable to BLAS-2 & BLAS-3: the number of "
         "rows.")

        ("sizen,n",
         po::value<rocblas_int>(&argus.N)->default_value(128),
         "Specific matrix/vector size testing: BLAS-1: the length of the vector. BLAS-2 & "
         "BLAS-3: the number of columns")

        ("sizek,k",
         po::value<rocblas_int>(&argus.K)->default_value(128),
         "Specific matrix size testing:sizek is only applicable to BLAS-3: the number of columns in "
         "A & C  and rows in B.")

        ("lda",
         po::value<rocblas_int>(&argus.lda)->default_value(128),
         "Specific leading dimension of matrix A, is only applicable to "
         "BLAS-2 & BLAS-3: the number of rows.")

        ("ldb",
         po::value<rocblas_int>(&argus.ldb)->default_value(128),
         "Specific leading dimension of matrix B, is only applicable to BLAS-2 & BLAS-3: the number "
         "of rows.")

        ("ldc",
         po::value<rocblas_int>(&argus.ldc)->default_value(128),
         "Specific leading dimension of matrix C, is only applicable to BLAS-2 & "
         "BLAS-3: the number of rows.")

        ("stride_a",
         po::value<rocblas_int>(&argus.stride_a)->default_value(128*128),
         "Specific stride of strided_batched matrix A, is only applicable to strided batched"
         "BLAS-2 and BLAS-3: second dimension * leading dimension.")

        ("stride_b",
         po::value<rocblas_int>(&argus.stride_b)->default_value(128*128),
         "Specific stride of strided_batched matrix B, is only applicable to strided batched"
         "BLAS-2 and BLAS-3: second dimension * leading dimension.")

        ("stride_c",
         po::value<rocblas_int>(&argus.stride_c)->default_value(128*128),
         "Specific stride of strided_batched matrix C, is only applicable to strided batched"
         "BLAS-2 and BLAS-3: second dimension * leading dimension.")

        ("incx",
         po::value<rocblas_int>(&argus.incx)->default_value(1),
         "increment between values in x vector")

        ("incy",
         po::value<rocblas_int>(&argus.incy)->default_value(1),
         "increment between values in y vector")

        ("alpha",
          po::value<double>(&argus.alpha)->default_value(1.0), "specifies the scalar alpha")

        ("beta",
         po::value<double>(&argus.beta)->default_value(0.0), "specifies the scalar beta")

        ("function,f",
         po::value<std::string>(&function)->default_value("gemv"),
         "BLAS function to test. Options: gemv, ger, syr, trsm, trmm, symv, syrk, syr2k")

        ("precision,r",
         po::value<char>(&precision)->default_value('s'), "Options: h,s,d,c,z")

        ("transposeA",
         po::value<char>(&argus.transA_option)->default_value('N'),
         "N = no transpose, T = transpose, C = conjugate transpose")

        ("transposeB",
         po::value<char>(&argus.transB_option)->default_value('N'),
         "N = no transpose, T = transpose, C = conjugate transpose")

        ("side",
         po::value<char>(&argus.side_option)->default_value('L'),
         "L = left, R = right. Only applicable to certain routines")

        ("uplo",
         po::value<char>(&argus.uplo_option)->default_value('U'),
         "U = upper, L = lower. Only applicable to certain routines") // xsymv xsyrk xsyr2k xtrsm
                                                                     // xtrmm
        ("diag",
         po::value<char>(&argus.diag_option)->default_value('N'),
         "U = unit diagonal, N = non unit diagonal. Only applicable to certain routines") // xtrsm
                                                                                // xtrmm
        ("batch",
         po::value<rocblas_int>(&argus.batch_count)->default_value(1),
         "Number of matrices. Only applicable to batched routines") // xtrsm xtrmm xgemm

        ("verify,v",
         po::value<rocblas_int>(&argus.norm_check)->default_value(0),
         "Validate GPU results with CPU? 0 = No, 1 = Yes (default: No)")

        ("iters,i",
         po::value<rocblas_int>(&argus.iters)->default_value(10),
         "Iterations to run inside timing loop")

        ("device",
         po::value<rocblas_int>(&device_id)->default_value(0),
         "Set default device to be used for subsequent program runs");
    // clang-format on

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    if(vm.count("help"))
    {
        std::cout << desc << std::endl;
        return 0;
    }

    if(precision != 'h' && precision != 's' && precision != 'd' && precision != 'c' &&
       precision != 'z')
    {
        std::cerr << "Invalid value for --precision" << std::endl;
        return -1;
    }

    // Device Query
    rocblas_int device_count = query_device_property();

    if(device_count <= device_id)
    {
        printf("Error: invalid device ID. There may not be such device ID. Will exit \n");
        return -1;
    }
    else
    {
        set_device(device_id);
    }
    /* ============================================================================================
     */
    if(argus.M < 0 || argus.N < 0 || argus.K < 0)
    {
        printf("Invalide matrix dimension\n");
    }

    argus.start = range[0];
    argus.step  = range[1];
    argus.end   = range[2];

    if(function == "asum")
    {
        if(precision == 's')
            testing_asum<float, float>(argus);
        else if(precision == 'd')
            testing_asum<double, double>(argus);
    }
    else if(function == "axpy")
    {
        if(precision == 'h')
            testing_axpy<rocblas_half>(argus);
        else if(precision == 's')
            testing_axpy<float>(argus);
        else if(precision == 'd')
            testing_axpy<double>(argus);
    }
    else if(function == "copy")
    {
        if(precision == 's')
            testing_copy<float>(argus);
        else if(precision == 'd')
            testing_copy<double>(argus);
    }
    else if(function == "dot")
    {
        if(precision == 's')
            testing_dot<float>(argus);
        else if(precision == 'd')
            testing_dot<double>(argus);
    }
    else if(function == "swap")
    {
        if(precision == 's')
            testing_swap<float>(argus);
        else if(precision == 'd')
            testing_swap<double>(argus);
    }
    else if(function == "iamax")
    {
        if(precision == 's')
            testing_iamax<float>(argus);
        else if(precision == 'd')
            testing_iamax<double>(argus);
    }
    else if(function == "iamin")
    {
        if(precision == 's')
            testing_iamin<float>(argus);
        else if(precision == 'd')
            testing_iamin<double>(argus);
    }
    else if(function == "nrm2")
    {
        if(precision == 's')
            testing_nrm2<float, float>(argus);
        else if(precision == 'd')
            testing_nrm2<double, double>(argus);
    }
    else if(function == "scal")
    {
        if(precision == 's')
            testing_scal<float>(argus);
        else if(precision == 'd')
            testing_scal<double>(argus);
    }
    else if(function == "gemv")
    {
        if(precision == 's')
            testing_gemv<float>(argus);
        else if(precision == 'd')
            testing_gemv<double>(argus);
    }
    else if(function == "ger")
    {
        if(precision == 's')
            testing_ger<float>(argus);
        else if(precision == 'd')
            testing_ger<double>(argus);
    }
    else if(function == "syr")
    {
        if(precision == 's')
            testing_syr<float>(argus);
        else if(precision == 'd')
            testing_syr<double>(argus);
    }
    else if(function == "trtri")
    {
        if(precision == 's')
            testing_trtri<float>(argus);
        else if(precision == 'd')
            testing_trtri<double>(argus);
    }
    else if(function == "trtri_batched")
    {
        if(precision == 's')
            testing_trtri_batched<float>(argus);
        else if(precision == 'd')
            testing_trtri_batched<double>(argus);
    }
    else if(function == "geam")
    {
        if(precision == 's')
            testing_geam<float>(argus);
        else if(precision == 'd')
            testing_geam<double>(argus);
    }
    else if(function == "set_get_vector")
    {
        if(precision == 's')
            testing_set_get_vector<float>(argus);
        else if(precision == 'd')
            testing_set_get_vector<double>(argus);
    }
    else if(function == "set_get_matrix")
    {
        if(precision == 's')
            testing_set_get_matrix<float>(argus);
        else if(precision == 'd')
            testing_set_get_matrix<double>(argus);
    }
#if BUILD_WITH_TENSILE
    else if(function == "gemm")
    {
        // adjust dimension for GEMM routines
        rocblas_int min_lda = argus.transA_option == 'N' ? argus.M : argus.K;
        rocblas_int min_ldb = argus.transB_option == 'N' ? argus.K : argus.N;
        rocblas_int min_ldc = argus.M;

        if(argus.lda < min_lda)
        {
            std::cout << "rocblas-bench INFO: lda < min_lda, set lda = " << min_lda << std::endl;
            argus.lda = min_lda;
        }
        if(argus.ldb < min_ldb)
        {
            std::cout << "rocblas-bench INFO: ldb < min_ldb, set ldb = " << min_ldb << std::endl;
            argus.ldb = min_ldb;
        }
        if(argus.ldc < min_ldc)
        {
            std::cout << "rocblas-bench INFO: ldc < min_ldc, set ldc = " << min_ldc << std::endl;
            argus.ldc = min_ldc;
        }

        if(precision == 'h')
            testing_gemm<rocblas_half>(argus);
        else if(precision == 's')
            testing_gemm<float>(argus);
        else if(precision == 'd')
            testing_gemm<double>(argus);
    }
    else if(function == "gemm_strided_batched")
    {
        // adjust dimension for GEMM routines
        rocblas_int min_lda = argus.transA_option == 'N' ? argus.M : argus.K;
        rocblas_int min_ldb = argus.transB_option == 'N' ? argus.K : argus.N;
        rocblas_int min_ldc = argus.M;
        if(argus.lda < min_lda)
        {
            std::cout << "rocblas-bench INFO: lda < min_lda, set lda = " << min_lda << std::endl;
            argus.lda = min_lda;
        }
        if(argus.ldb < min_ldb)
        {
            std::cout << "rocblas-bench INFO: ldb < min_ldb, set ldb = " << min_ldb << std::endl;
            argus.ldb = min_ldb;
        }
        if(argus.ldc < min_ldc)
        {
            std::cout << "rocblas-bench INFO: ldc < min_ldc, set ldc = " << min_ldc << std::endl;
            argus.ldc = min_ldc;
        }

        //      rocblas_int min_stride_a =
        //          argus.transA_option == 'N' ? argus.K * argus.lda : argus.M * argus.lda;
        //      rocblas_int min_stride_b =
        //          argus.transB_option == 'N' ? argus.N * argus.ldb : argus.K * argus.ldb;
        //      rocblas_int min_stride_a =
        //          argus.transA_option == 'N' ? argus.K * argus.lda : argus.M * argus.lda;
        //      rocblas_int min_stride_b =
        //          argus.transB_option == 'N' ? argus.N * argus.ldb : argus.K * argus.ldb;
        rocblas_int min_stride_c = argus.ldc * argus.N;
        //      if(argus.stride_a < min_stride_a)
        //      {
        //          std::cout << "rocblas-bench INFO: stride_a < min_stride_a, set stride_a = " <<
        //          min_stride_a << std::endl;
        //          argus.stride_a = min_stride_a;
        //      }
        //      if(argus.stride_b < min_stride_b)
        //      {
        //          std::cout << "rocblas-bench INFO: stride_b < min_stride_b, set stride_b = " <<
        //          min_stride_b << std::endl;
        //          argus.stride_b = min_stride_b;
        //      }
        if(argus.stride_c < min_stride_c)
        {
            std::cout << "rocblas-bench INFO: stride_c < min_stride_c, set stride_c = "
                      << min_stride_c << std::endl;
            argus.stride_c = min_stride_c;
        }

        if(precision == 'h')
            testing_gemm_strided_batched<rocblas_half>(argus);
        else if(precision == 's')
            testing_gemm_strided_batched<float>(argus);
        else if(precision == 'd')
            testing_gemm_strided_batched<double>(argus);
    }
    else if(function == "gemm_kernel_name")
    {
        // adjust dimension for GEMM routines
        rocblas_int min_lda = argus.transA_option == 'N' ? argus.M : argus.K;
        rocblas_int min_ldb = argus.transB_option == 'N' ? argus.K : argus.N;
        rocblas_int min_ldc = argus.M;
        if(argus.lda < min_lda)
        {
            std::cout << "rocblas-bench INFO: lda < min_lda, set lda = " << min_lda << std::endl;
            argus.lda = min_lda;
        }
        if(argus.ldb < min_ldb)
        {
            std::cout << "rocblas-bench INFO: ldb < min_ldb, set ldb = " << min_ldb << std::endl;
            argus.ldb = min_ldb;
        }
        if(argus.ldc < min_ldc)
        {
            std::cout << "rocblas-bench INFO: ldc < min_ldc, set ldc = " << min_ldc << std::endl;
            argus.ldc = min_ldc;
        }

        if(precision == 'h')
            testing_gemm_strided_batched_kernel_name<rocblas_half>(argus);
        else if(precision == 's')
            testing_gemm_strided_batched_kernel_name<float>(argus);
        else if(precision == 'd')
            testing_gemm_strided_batched_kernel_name<double>(argus);
    }
    else if(function == "gemm_strided_batched_kernel_name")
    {
        // adjust dimension for GEMM routines
        rocblas_int min_lda = argus.transA_option == 'N' ? argus.M : argus.K;
        rocblas_int min_ldb = argus.transB_option == 'N' ? argus.K : argus.N;
        rocblas_int min_ldc = argus.M;
        if(argus.lda < min_lda)
        {
            std::cout << "rocblas-bench INFO: lda < min_lda, set lda = " << min_lda << std::endl;
            argus.lda = min_lda;
        }
        if(argus.ldb < min_ldb)
        {
            std::cout << "rocblas-bench INFO: ldb < min_ldb, set ldb = " << min_ldb << std::endl;
            argus.ldb = min_ldb;
        }
        if(argus.ldc < min_ldc)
        {
            std::cout << "rocblas-bench INFO: ldc < min_ldc, set ldc = " << min_ldc << std::endl;
            argus.ldc = min_ldc;
        }

        //      rocblas_int min_stride_a =
        //          argus.transA_option == 'N' ? argus.K * argus.lda : argus.M * argus.lda;
        //      rocblas_int min_stride_b =
        //          argus.transB_option == 'N' ? argus.N * argus.ldb : argus.K * argus.ldb;
        rocblas_int min_stride_c = argus.ldc * argus.N;
        //      if(argus.stride_a < min_stride_a)
        //      {
        //          std::cout << "rocblas-bench INFO: stride_a < min_stride_a, set stride_a = " <<
        //          min_stride_a << std::endl;
        //          argus.stride_a = min_stride_a;
        //      }
        //      if(argus.stride_b < min_stride_b)
        //      {
        //          std::cout << "rocblas-bench INFO: stride_b < min_stride_b, set stride_b = " <<
        //          min_stride_b << std::endl;
        //          argus.stride_b = min_stride_b;
        //      }
        if(argus.stride_c < min_stride_c)
        {
            std::cout << "rocblas-bench INFO: stride_c < min_stride_c, set stride_c = "
                      << min_stride_c << std::endl;
            argus.stride_c = min_stride_c;
        }

        if(precision == 'h')
            testing_gemm_strided_batched_kernel_name<rocblas_half>(argus);
        else if(precision == 's')
            testing_gemm_strided_batched_kernel_name<float>(argus);
        else if(precision == 'd')
            testing_gemm_strided_batched_kernel_name<double>(argus);
    }
    else if(function == "trsm")
    {
        if(precision == 's')
            testing_trsm<float>(argus);
        else if(precision == 'd')
            testing_trsm<double>(argus);
    }
#endif
    else
    {
        printf("Invalid value for --function \n");
        return -1;
    }

    return 0;
}


// Copyright (c) 2019 fortiss GmbH, Julian Bernhard, Klemens Esterle, Patrick Hart, Tobias Kessler
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.

#include <Eigen/Core>
#include "gtest/gtest.h"

#include "modules/geometry/polygon.hpp"
#include "modules/geometry/line.hpp"
#include "modules/geometry/commons.hpp"
#include "modules/models/dynamic/single_track.hpp"
#include "modules/models/behavior/motion_primitives/motion_primitives.hpp"
#include "modules/commons/params/setter_params.hpp"
#include "modules/commons/params/default_params.hpp"
#include "modules/world/observed_world.hpp"

using namespace modules::models::dynamic;
using namespace modules::models::execution;
using namespace modules::commons;
using namespace modules::models::behavior;
using namespace modules::models::dynamic;
using namespace modules::world;
using namespace modules::geometry;

class DummyObservedWorld : public ObservedWorld {
 public:
  DummyObservedWorld(const State& init_state,
                     Params* params) :
    ObservedWorld(std::make_shared<World>(params), AgentId()),
    init_state_(init_state) { }

  virtual State current_ego_state() const {
    return init_state_;
  }

  virtual double get_world_time() const {
    return 0.0f;
  }
 private:
  State init_state_;
};

TEST(behavior_motion_primitives_add, behavior_test) {
  DefaultParams* params = new DefaultParams();
  DynamicModelPtr dynamics(new SingleTrackModel(params));
  BehaviorMotionPrimitives behavior(dynamics, params);
  Input u(2);
  u << 0, 0;
  behavior.AddMotionPrimitive(u);
}

TEST(behavior_motion_primitives_plan, behavior_test) {
  SetterParams* params = new SetterParams();
  params->set_real("integration_time_delta", 0.01);
  DynamicModelPtr dynamics(new SingleTrackModel(params));

  BehaviorMotionPrimitives behavior(dynamics, params);
  Input u1(2);
  u1 << 2, 0;
  BehaviorMotionPrimitives::MotionIdx idx1 = behavior.AddMotionPrimitive(u1);
  Input u2(2);
  u2 << 0, 1;
  BehaviorMotionPrimitives::MotionIdx idx2 = behavior.AddMotionPrimitive(u2);
  Input u3(2);
  u3 << 0, 0;
  BehaviorMotionPrimitives::MotionIdx idx3 = behavior.AddMotionPrimitive(u3);

  // X Longitudinal with zero velocity
  State init_state(static_cast<int>(StateDefinition::MIN_STATE_SIZE));
  init_state << 0.0, 0.0, 0.0, 0.0, 0.0;
  DummyObservedWorld world(init_state, params);

  behavior.ActionToBehavior(idx1);
  Trajectory traj1 = behavior.Plan(0.5, world);
  EXPECT_NEAR(traj1(traj1.rows() - 1,
                    StateDefinition::X_POSITION),
              2/2*0.5*0.5, 0.05);

  // X Longitudinal with nonzero velocity
  init_state << 0.0, 0.0, 0.0, 0.0, 5.0;
  DummyObservedWorld world1(init_state, params);
  behavior.ActionToBehavior(idx1);
  traj1 = behavior.Plan(0.5, world1);
  EXPECT_NEAR(traj1(traj1.rows() - 1,
                    StateDefinition::X_POSITION),
              5.0*0.5 + 2/2*0.5*0.5, 0.1);

  // Y Longitudinal
  init_state << 0.0, 0.0, 0.0, B_PI_2, 0.0;
  DummyObservedWorld world2(init_state, params);
  behavior.ActionToBehavior(idx1);
  traj1 = behavior.Plan(0.5, world2);
  EXPECT_NEAR(traj1(traj1.rows() - 1,
                    StateDefinition::Y_POSITION),
              2/2*0.5*0.5, 0.05);

  // X Constant motion
  init_state << 0.0, 0.0, 0.0, 0.0, 2.0;
  DummyObservedWorld world3(init_state, params);
  behavior.ActionToBehavior(idx3);
  Trajectory traj3 = behavior.Plan(0.5, world3);
  EXPECT_NEAR(traj3(traj3.rows() - 1,
                    StateDefinition::X_POSITION),
              0.5 * 2, 0.005);
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_COMPUTER_VISION_SIMPLE_PLY_HPP
#define PIC_COMPUTER_VISION_SIMPLE_PLY_HPP

#include <vector>
#include <random>
#include <stdlib.h>

#include "../base.hpp"

#include "../util/math.hpp"

#include "../util/eigen_util.hpp"

#ifndef PIC_DISABLE_EIGEN

#ifndef PIC_EIGEN_NOT_BUNDLED
    #include "../externals/Eigen/Dense"
    #include "../externals/Eigen/SVD"
    #include "../externals/Eigen/Geometry"
#else
    #include <Eigen/Dense>
    #include <Eigen/SVD>
    #include <Eigen/Geometry>
#endif

#endif

namespace pic {

#ifndef PIC_DISABLE_EIGEN

PIC_INLINE bool writeSimplePLY(std::string name,
                               std::vector< Eigen::Vector3d > &points_3d,
                               std::vector< unsigned char > &colors)
{
    //write a PLY file
    FILE *file = fopen(name.c_str(), "w");

    if (file == NULL) {
        return false;
    }

    bool bColor = colors.size() == (points_3d.size() * 3);

    fprintf(file,"ply\n");
    fprintf(file,"format ascii 1.0\n");
    fprintf(file,"element vertex %d\n", int(points_3d.size()));

    fprintf(file,"property float x\n");
    fprintf(file,"property float y\n");
    fprintf(file,"property float z\n");

    if(bColor) {
        fprintf(file,"property uchar red\n");
        fprintf(file,"property uchar green\n");
        fprintf(file,"property uchar blue\n");
        fprintf(file,"property uchar alpha\n");
    }
    fprintf(file,"end_header\n");

    for(unsigned int i = 0; i < points_3d.size(); i++) {
        //write position information
        fprintf(file, "%3.4f %3.4f %3.4f ", points_3d[i][0], points_3d[i][1], points_3d[i][2]);

        //write color information
        if(bColor) {
            auto k = i * 3;
            fprintf(file, " %d %d %d 255\n", colors[k], colors[k + 1], colors[k + 2]);
        }
    }

    fclose(file);
    return true;
}

#endif // PIC_DISABLE_EIGEN

} // end namespace pic

#endif // PIC_COMPUTER_VISION_SIMPLE_PLY_HPP


// Copyright (c) 2000, 2001, 2002, 2003 by David Scherer and others.
// Copyright (c) 2003, 2004 by Jonathan Brandmeyer and others.
// See the file license.txt for complete license terms.
// See the file authors.txt for a complete list of contributors.

#include "cone.hpp"
#include "util/errors.hpp"
#include "util/displaylist.hpp"
#include "util/quadric.hpp"
#include "util/gl_enable.hpp"

#include <vector>

#if 0
#include <boost/scoped_array.hpp>
namespace cvisual {
	using boost::scoped_array;
}
#endif

namespace cvisual {

bool
cone::degenerate()
{
	return !visible || radius == 0.0 || axis.mag() == 0.0;
}

static void
render_cone_model( size_t n_sides, size_t n_stacks = 1)
{
#if 0
	// I've swapped out this algorithm for the GLU version, but I'm keeping it
	// around in case I need it for something else later. -JDB

	// A rotation matrix to generate the edge vertexes and normals.
	tmatrix rotator = rotation( -2 * M_PI / n_sides, vector( 1, 0, 0));
	// A buffer to hold the last calculated ring.
	scoped_array<vector> vertexes( new vector[n_sides+1]);
	// Another buffer to hold the normal vectors (it is only initialized once,
	// and not overwritten later).
	scoped_array<vector> normals( new vector[n_sides+1]);

	// Render the base and calculate the normals and the first ring of vertexes.
	vertexes[0] = vector(0, 1, 0);
	normals[0] = vector(1,1,0).norm();
	glBegin( GL_TRIANGLE_FAN);
	vector(-1, 0, 0).gl_normal();
	vector( 0, 0, 0).gl_render();
	for (size_t i = 0; i < n_sides; ++i) {
		normals[i+1] = rotator * normals[i];
		vertexes[i+1] = rotator * vertexes[i];
		vertexes[i].gl_render();
	}
	vertexes[n_sides].gl_render();
	glEnd();

	// Render the body of the cone.
	double steps[] = { 0.3, 0.25, 0.2, 0.15, 0.1 };
	for (size_t i = 0; i < 5; ++i) {
		glBegin( GL_TRIANGLE_STRIP);
		normals[0].gl_normal();
		vertexes[0].gl_render();
		vertexes[0] = vertexes[0] + vector(steps[i], -steps[i]);
		vertexes[0].gl_render();
		for (size_t i = 1; i < n_sides+1; ++i) {
			normals[i].gl_normal();
			vertexes[i].gl_render();
			vertexes[i] = rotator * vertexes[i-1];
			vertexes[i].gl_render();
		}
		glEnd();
	}
#else
	quadric q;
	q.render_cylinder( 1.0, 0.0, 1.0, n_sides, n_stacks);
	q.render_disk( 1.0, n_sides, n_stacks * 2, -1);
#endif
}

cone::cone()
{
}

void
cone::set_length( double l)
{
	axis = axis.norm() * l;
}

double
cone::get_length()
{
	return axis.mag();
}

void
cone::init_model(view& scene)
{
	if (!scene.cone_model[0].compiled()) {
		clear_gl_error();
		// The number of faces corrisponding to each level of detail.
		size_t n_faces[] = { 8, 16, 32, 46, 68, 90 };
		size_t n_stacks[] = { 1, 2, 4, 7, 10, 14 };
		for (size_t i = 0; i < 6; ++i) {
			scene.cone_model[i].gl_compile_begin();
			render_cone_model( n_faces[i], n_stacks[i]);
			scene.cone_model[i].gl_compile_end();
		}
		check_gl_error();
	}
}

void
cone::gl_pick_render(view& scene)
{
	if (degenerate())
		return;
	init_model(scene);

	size_t lod = 2;
	clear_gl_error();

	gl_matrix_stackguard guard;
	const double length = axis.mag();
	model_world_transform( scene.gcf, vector( length, radius, radius ) ).gl_mult();

	scene.cone_model[lod].gl_render();
	check_gl_error();
}

void
cone::gl_render(view& scene)
{
	if (degenerate())
		return;

	init_model(scene);

	clear_gl_error();

	// See sphere::gl_render() for a description of the level of detail calc.
	double coverage = scene.pixel_coverage( pos, radius);
	int lod = 0;
	if (coverage < 0)
		lod = 5;
	else if (coverage < 10)
		lod = 0;
	else if (coverage < 30)
		lod = 1;
	else if (coverage < 90)
		lod = 2;
	else if (coverage < 250)
		lod = 3;
	else if (coverage < 450)
		lod = 4;
	else
		lod = 5;
	lod += scene.lod_adjust;
	if (lod < 0)
		lod = 0;
	else if (lod > 5)
		lod = 5;

	gl_matrix_stackguard guard;
	const double length = axis.mag();
	model_world_transform( scene.gcf, vector( length, radius, radius ) ).gl_mult();

	color.gl_set(opacity);

	if (translucent()) {
		gl_enable cull_face( GL_CULL_FACE);

		// Render the back half.
		glCullFace( GL_FRONT);
		scene.cone_model[lod].gl_render();

		// Render the front half.
		glCullFace( GL_BACK);
		scene.cone_model[lod].gl_render();
	}
	else {
		scene.cone_model[lod].gl_render();
	}

	check_gl_error();
}

void
cone::grow_extent( extent& e)
{
	if (degenerate())
		return;
	e.add_circle( pos, axis.norm(), radius );
	e.add_point( pos + axis);
	e.add_body();
}

vector
cone::get_center() const
{
	return pos + axis/2.0;
}

PRIMITIVE_TYPEINFO_IMPL(cone)

} // !namespace cvisual


#ifndef data_hpp
#define data_hpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <set>
#include <bitset>
#include <iomanip>
#include <Eigen/Eigen>
#include <Eigen/Sparse>
#include <boost/format.hpp>
#include "gadgets.hpp"
#ifdef USE_MPI
#include <mpi.h>
#include "mpi_utils.hpp"
#endif

using namespace std;
using namespace Eigen;

class SnpInfo {
public:
    const string ID;
    const string a1; // the referece allele
    const string a2; // the coded allele
    const int chrom;
    const float genPos;
    const int physPos;

    int index;
    int window;
    int windStart;  // for window surrounding the SNP
    int windSize;   // for window surrounding the SNP
    float af;       // allele frequency
    bool included;  // flag for inclusion in panel
    bool isQTL;     // for simulation

    SnpInfo(const int idx, const string &id, const string &allele1, const string &allele2,
            const int chr, const float gpos, const int ppos)
    : ID(id), index(idx), a1(allele1), a2(allele2), chrom(chr), genPos(gpos), physPos(ppos) {
        window = 0;
        windStart = -1;
        windSize  = 0;
        af = -1;
        included = true;
        isQTL = false;
    };

    void resetWindow(void) {windStart = -1; windSize = 0;};
};

class IndInfo {
public:
    const string famID;
    const string indID;
    const string catID;    // catenated family and individual ID
    const string fatherID;
    const string motherID;
    const int famFileOrder; // original fam file order
    const int sex;  // 1: male, 2: female

    int index;
    bool kept;

    float phenotype;

    VectorXf covariates;  // covariates for fixed effects

    IndInfo(const int idx, const string &fid, const string &pid, const string &dad, const string &mom, const int sex)
    : famID(fid), indID(pid), catID(fid+":"+pid), fatherID(dad), motherID(mom), index(idx), famFileOrder(idx), sex(sex) {
        phenotype = -9;
        kept = true;
    }
};

// An entry for the index to the compressed preprocessed bed file
struct IndexEntry {
    long pos;
    long size;
};

class Data {
public:
    Data();

    // Original data
    MatrixXd X;              // coefficient matrix for fixed effects
    MatrixXd Z;
    VectorXf D;              // 2pqn

    VectorXd y;              // phenotypes
    MatrixXd phenosData;     // multiple phenotypes
    MatrixXi phenosNanMasks; // masks for NAs in phenotypes phenos
    VectorXi phenosNanNum;   // number of NAs in phenotypes phenos

    // marion : vector for annotation file and matrix for mS
    VectorXi groups;     	 // groups
    MatrixXd mS;			 // mixtures in groups
    MatrixXd priors;         // group priors v0, s0
    MatrixXd dPriors;        // group priors of dirichlet distribution

    VectorXd fail;           // Failure indicator

    //EO MRG
    //VectorXf ZPZdiag;        // Z'Z diagonal
    //VectorXf snp2pq;         // 2pq of SNPs
    //VectorXf se;             // se from GWAS summary data
    //VectorXf tss;            // total ss (ypy) for every SNP
    //VectorXf b;              // beta from GWAS summary data
    //VectorXf n;              // sample size for each SNP in GWAS

    vector<SnpInfo*> snpInfoVec;
    vector<IndInfo*> indInfoVec;

    map<string, SnpInfo*> snpInfoMap;
    map<string, IndInfo*> indInfoMap;

    unsigned numFixedEffects = 0;

    unsigned numSnps = 0;
    unsigned numInds = 0;
    unsigned numNAs  = 0;

    vector<uint> NAsInds;
    vector<int>  blocksStarts;
    vector<int>  blocksEnds;
    uint         numBlocks = 0;

#ifdef USE_MPI

    void center_and_scale(double* __restrict__ vec, int* __restrict__ mask, const uint N, const uint nas);

    void print_restart_banner(const string mcmcOut, const uint iteration_restart, const uint iteration_start);

    void read_mcmc_output_idx_file(const string mcmcOut, const string ext, const uint length, const uint iteration_restart,
                                   std::vector<int>& markerI);

    void read_mcmc_output_gam_file(const string mcmcOut, const int gamma_length, const uint iteration_restart,
                                   VectorXd& gamma);

    void read_mcmc_output_eps_file(const string mcmcOut, const uint Ntot, const uint iteration_restart,
                                   VectorXd&    epsilon);

    void read_mcmc_output_cpn_file(const string mcmcOut, const uint Mtot,
                                   const uint   iteration_restart, const uint first_saved_it_restart, const int thin,
                                   const int*   MrankS,  const int* MrankL, const bool use_xfiles,
                                   VectorXi&    components);

    void read_mcmc_output_bet_file(const string mcmcOut, const uint Mtot,
                                   const uint   iteration_restart, const uint first_saved_it_restart, const int thin,
                                   const int*   MrankS,  const int* MrankL, const bool use_xfiles,
                                   VectorXd&    Beta);

    void read_mcmc_output_csv_file(const string mcmcOut,
                                   const uint optThin, const uint optSave,
                                   const int K, VectorXd& sigmaG, double& sigmaE, MatrixXd& pi,
                                   uint& iteration_to_restart_from,
                                   uint& first_thinned_iteration,
                                   uint& first_saved_iteration);

    // Three functions tailored for bW output. Consider using same format in bR
    void read_mcmc_output_csv_file_bW(const string mcmcOut, const uint optThin, const uint optSave, const int K, double& mu,
                                        VectorXd& sigmaG, double& sigmaE, MatrixXd& pi,
                                        uint& iteration_to_restart_from, uint& first_thinned_iteration, uint& first_saved_iteration);

    void read_mcmc_output_gam_file_bW(const string mcmcOut, const uint optSave, const int gamma_length,
                                     VectorXd& gamma);

    void read_mcmc_output_idx_file_bW(const string mcmcOut, const string ext, const uint length, const uint iteration_to_restart_from,
                                     std::vector<int>& markerI);

    void read_mcmc_output_mus_file(const string mcmcOut,
                                   const uint  iteration_restart, const uint first_saved_it_restart, const int thin,
                                   double& mu);

    void load_data_from_bed_file(const string bedfp, const uint Ntot, const int M,
                                 const int    rank,  const int start,
                                 size_t* N1S, size_t* N1L, uint*& I1,
                                 size_t* N2S, size_t* N2L, uint*& I2,
                                 size_t* NMS, size_t* NML, uint*& IM,
                                 size_t& taskBytes);

    void load_data_from_sparse_files(const int rank, const int nranks, const int M,
                                     const int* MrankS, const int* MrankL,
                                     const string sparseOut,
                                     size_t* N1S, size_t* N1L, uint*& I1,
                                     size_t* N2S, size_t* N2L, uint*& I2,
                                     size_t* NMS, size_t* NML, uint*& IM,
                                     size_t& taskBytes);

    void get_bed_marker_from_sparse(char* bed,
                                    const int    Ntot,
                                    const size_t S1, const size_t L1, const uint* I1,
                                    const size_t S2, const size_t L2, const uint* I2,
                                    const size_t SM, const size_t LM, const uint* IM);

    void load_data_from_mixed_representations(const string bedfp,         const string sparseOut,
                                              const int    rank,          const int nranks,
                                              const int    Ntot,          const int M,
                                              const int*   MrankS,        const int* MrankL,
                                              size_t* N1S,  size_t* N1L,  uint*& I1,
                                              size_t* N2S,  size_t* N2L,  uint*& I2,
                                              size_t* NMS,  size_t* NML,  uint*& IM,
                                              const double threshold_fnz, bool* USEBED,
                                              size_t& taskBytes);

    void sparse_data_correct_for_missing_phenotype(const size_t* NS, size_t* NL, uint* I, const int M, const bool* USEBED);

    void sparse_data_get_sizes_from_raw(const char* rawdata,
                                        const uint NC, const uint NB, const uint NA,
                                        size_t& N1,    size_t& N2,    size_t& NM);

    void sparse_data_fill_indices(const char* rawdata,
                                  const uint  NC,
                                  const uint  NB,
                                  const uint  NA,
                                  size_t* N1S, size_t* N1L, uint* I1,
                                  size_t* N2S, size_t* N2L, uint* I2,
                                  size_t* NMS, size_t* NML, uint* IM);

    size_t get_number_of_elements_from_sparse_files(const std::string basename, const std::string id, const int* MrankS, const int* MrankL,
                                                    size_t* S, size_t* L);

    void read_sparse_data_file(const std::string filename, const size_t N, const size_t OFF, const int NREAD, uint* out);

    // MPI_File_read_at_all handling count argument larger than INT_MAX
    //
    template <typename T>
    void mpi_file_read_at_all(const size_t N, const MPI_Offset offset, const MPI_File fh, const MPI_Datatype MPI_DT, const int NREADS, T buffer, size_t &bytes) {

        int rank, dtsize;
        MPI_Status status;

        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Type_size(MPI_DT, &dtsize);
        //printf("dtsize = %d vs %lu\n", dtsize, sizeof(buffer[0]));
        //fflush(stdout);
        assert(dtsize == sizeof(buffer[0]));

        if (NREADS == 0) return;

        int SPLIT_ON = check_int_overflow(size_t(ceil(double(N)/double(NREADS))), __LINE__, __FILE__);
        int count = SPLIT_ON;

        double totime = 0.0;
        bytes = 0;

        for (uint i=0; i<NREADS; ++i) {

            double t1 = -mysecond();

            const size_t iim = size_t(i) * size_t(SPLIT_ON);

            // Last iteration takes only the leftover
            if (i == NREADS-1) count = check_int_overflow(N - iim, __LINE__, __FILE__);

            //printf("read %d with count = %d x %lu = %lu Bytes to read\n", i, count, sizeof(buffer[0]), sizeof(buffer[0]) * size_t(count));
            //fflush(stdout);

            //check_mpi(MPI_File_read_at_all(fh, offset + iim * size_t(dtsize), &buffer[iim], count, MPI_DT, &status), __LINE__, __FILE__);
            check_mpi(MPI_File_read_at(fh, offset + iim * size_t(dtsize), &buffer[iim], count, MPI_DT, &status), __LINE__, __FILE__);
            t1 += mysecond();
            totime += t1;
            bytes += size_t(count) * size_t(dtsize);
            if (rank % 10 == 0) {
                printf("INFO   : rank %3d cumulated read time at %2d/%2d: %7.3f sec, avg time %7.3f, BW = %7.3f GB/s\n",
                       rank, i+1, NREADS, totime, totime / (i + 1), double(bytes) / totime / 1E9 );
                fflush(stdout);
            }

            //MPI_Barrier(MPI_COMM_WORLD);
        }

        //MPI_Barrier(MPI_COMM_WORLD);
    }

    // MPI_File_write_at_all handling count argument larger than INT_MAX
    //
    template <typename T>
    void mpi_file_write_at_all(const size_t N, MPI_Offset offset, MPI_File fh, MPI_Datatype MPI_DT, const int NWRITES, T buffer)
    {
        int rank, dtsize;
        MPI_Status status;

        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Type_size(MPI_DT, &dtsize);
        assert(dtsize == sizeof(buffer[0]));

        if (NWRITES == 0) return;

        int SPLIT_ON = check_int_overflow(size_t(ceil(double(N)/double(NWRITES))), __LINE__, __FILE__);
        int count = SPLIT_ON;

        for (uint i=0; i<NWRITES; ++i) {

            const size_t iim = size_t(i) * size_t(SPLIT_ON);

            // Last iteration takes only the leftover
            if (i == NWRITES-1) count = check_int_overflow(N - iim, __LINE__, __FILE__);

            check_mpi(MPI_File_write_at_all(fh, offset + iim * size_t(dtsize), &buffer[iim], count, MPI_DT, &status), __LINE__, __FILE__);
        }
    }

    void preprocess_data(const char* data, const uint NC, const uint NB, double* ppdata, const int rank);
#endif

    //EO to read definitions of blocks of markers to process
    void readMarkerBlocksFile(const string &markerBlocksFile);

    void readFamFile(const string &famFile);

    void readBimFile(const string &bimFile);

    void readPhenotypeFile(const string &phenFile);
    void readPhenotypeFile(const string &phenFile, const int numberIndividuals, VectorXd& dest);

    void readPhenotypeFileAndSetNanMask(const string &phenFile, const int numberIndividuals, VectorXd& phen, VectorXi& mask, uint& nas);

    void readPhenotypeFiles(const vector<string> &phenFile, const int numberIndividuals, MatrixXd& dest);

    void readPhenCovFiles(const string &phenFile, const string covFile, const int numberIndividuals, VectorXd& dest, const int rank);

    // Functions to read for bayesW
    //
    void readPhenFailCovFiles(const string &phenFile, const string covFile, const string &failFile, const int numberIndividuals, VectorXd& dest, VectorXd& dfail, const int rank);

    void readPhenFailFiles(const string &phenFile, const string &failFile, const int numberIndividuals, VectorXd& dest, VectorXd& dfail, const int rank);

    template<typename M>
    M readCSVFile(const string &covariateFile);

    // marion : annotation variables
    unsigned numGroups = 1;	// number of annotations
    void readGroupFile(const string &groupFile);
    void readmSFile(const string& mSfile);
    void printGroupMixtureComponents();

    //bW var
    void readFailureFile(const string &failureFile);
    void read_group_priors(const string& file);
    void read_dirichlet_priors(const string& file);
};

#endif /* data_hpp */


#ifndef TYPEDEF
#define TYPEDEF

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/timer/timer.hpp>
#include <iostream>
#include <vector>
#include <stack>
#include <boost/graph/strong_components.hpp>

using namespace boost;

typedef adjacency_list <vecS, vecS, directedS, no_property, disallow_parallel_edge_tag> Graph;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<adjacency_list<vecS, vecS, directedS> >::vertex_descriptor Vertex;
typedef typename property_map<Graph, vertex_index_t>::type IndexMap;
typedef std::pair<int, int> Edge;

typedef typename boost::iterator_property_map<__gnu_cxx::__normal_iterator<int*, std::vector<int> >,
        boost::vec_adj_list_vertex_id_map<boost::no_property, long unsigned int>, int, int&> typeInt;

typedef typename boost::iterator_property_map<std::_Bit_iterator,
        boost::vec_adj_list_vertex_id_map<boost::no_property, long unsigned int>, bool, std::_Bit_reference> typeBool;

#endif


/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "embed_bdd.hpp"

#include <vector>

#include <boost/assign/std/vector.hpp>

#include <core/utils/range_utils.hpp>
#include <core/utils/timer.hpp>

#include <reversible/functions/calculate_additional_lines.hpp>

using namespace boost::assign;

namespace cirkit
{

/******************************************************************************
 * Types                                                                      *
 ******************************************************************************/

/******************************************************************************
 * Private functions                                                          *
 ******************************************************************************/

struct garbage_manager
{
public:
  garbage_manager( const rcbdd& cf ) : cf( cf )
  {
    std::vector<BDD> garbage;

    for ( auto i = cf.num_outputs(); i < cf.num_vars(); ++i )
    {
      garbage += cf.y(i);
    }

    store += garbage;
  }

  const std::vector<BDD>& operator[]( unsigned index )
  {
    if ( index >= store.size() )
    {
      for ( auto i = store.size(); i <= index; ++i )
      {
        store += dec( store[i - 1u] );
      }
    }

    return store.at( index );
  }

  std::vector<BDD> dec( const std::vector<BDD>& vars )
  {
    std::vector<BDD> outputs;

    for ( auto i = 0u; i < vars.size(); ++i )
    {
      auto cube = cf.manager().bddOne();

      for ( auto j = 0u; j < i; ++j )
      {
        cube &= !vars.at(j);
      }

      outputs += vars.at(i) ^ cube;
    }

    return outputs;
  }

private:
  const rcbdd& cf;
  std::vector<std::vector<BDD>> store;
};

/******************************************************************************
 * Public functions                                                           *
 ******************************************************************************/

bool embed_bdd( rcbdd& cf, const bdd_function_t& bdd,
                const properties::ptr& settings,
                const properties::ptr& statistics )
{
  /* timer */
  properties_timer t( statistics );

  /* some statistics */
  const unsigned n = bdd.first.ReadSize();
  const unsigned m = bdd.second.size();

  /* compute number of additional lines */
  const auto cal_settings = std::make_shared<properties>();
  const auto cal_statistics = std::make_shared<properties>();
  const auto additional_lines = calculate_additional_lines( bdd, cal_settings, cal_statistics );

  const auto r = additional_lines + n;

  const auto constant_lines = r - n;
  const auto garbage_lines  = r - m;

  /* initialize RCBDD */
  cf.initialize_manager();
  cf.create_variables( r );
  cf.set_num_inputs( n );
  cf.set_num_outputs( m );
  cf.set_input_labels( create_name_list( "x%d", n, 1u ) );
  cf.set_output_labels( create_name_list( "y%d", m, 1u ) );

  /* copy bdd to cf */
  std::vector<unsigned> index_map( n );
  for ( auto i = 0u; i < n; ++i )
  {
    index_map[i] = ( constant_lines + i ) * 3u;
  }
  const auto copied = bdd_copy( bdd.first, bdd.second, cf.manager(), index_map );

  /* create non-embedded characteristic function */
  auto small_chi = cf.manager().bddOne();

  for ( const auto& f : index( copied ) )
  {
    small_chi &= cf.y( f.index ).Xnor( f.value );
  }

  /* create embedded characteristic function */
  auto chi = cf.manager().bddZero();

  auto constants = cf.manager().bddOne();
  for ( auto i = 0u; i < constant_lines; ++i )
  {
    constants &= !cf.x( i );
  }

  garbage_manager garbage( cf );

  for ( const auto& pattern : cal_statistics->get<std::vector<std::string>>( "patterns" ) )
  {
    auto patternf = cf.manager().bddOne();

    for ( auto c : index( pattern ) )
    {
      assert( c.value == '0' || c.value == '1' );
      patternf &= ( c.value == '0' ) ? !cf.y( c.index ) : cf.y( c.index );
    }

    /* restrict small_chi */
    const auto restr = small_chi & patternf;

    /* mu */
    auto mu = 0ul;

    /* iterate through each cube */
    DdGen *gen;
    int *cube;
    CUDD_VALUE_TYPE value;
    Cudd_ForeachCube( cf.manager().getManager(), restr.getNode(), gen, cube, value )
    {
      auto cubef = constants & patternf;
      std::vector<BDD> dont_cares;

      /* inputs */
      for ( auto i = constant_lines; i < r; ++i )
      {
        if ( cube[3u * i] == 0 )
        {
          cubef &= !cf.x( i );
        }
        else if ( cube[3u * i] == 1 )
        {
          cubef &= cf.x( i );
        }
        else
        {
          dont_cares += cf.x( i );
        }
      }

      /* garbage */
      auto dec_garbage = garbage[mu];

      for ( auto i = 0u; i < garbage_lines; ++i )
      {
        if ( i < dont_cares.size() )
        {
          cubef &= dec_garbage.at( i ).Xnor( dont_cares.at( dont_cares.size() - i - 1u ) );
        }
        else
        {
          cubef &= !dec_garbage.at( i );
        }
      }

      chi |= cubef;
      mu += ( 1ul << dont_cares.size() );
    }
  }

  cf.set_chi( chi );

  return true;
}

}

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:


/**
 * @file   ev_record.hpp
 * @author Yi Zhang <yiz@Yis-MacBook-Pro.local>
 * @date   Wed Aug 26 23:43:13 2020
 *
 * @brief  raw event record
 *
 *
 */
#ifndef STAN_MATH_TORSTEN_NONMEN_EVENTS_RECORD_HPP
#define STAN_MATH_TORSTEN_NONMEN_EVENTS_RECORD_HPP

#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/rev/fun/value_of.hpp>
#include <stan/math/prim/meta/return_type.hpp>
#include <Eigen/Dense>
#include <numeric>
#include <string>
#include <vector>

namespace torsten {

  /**
   * Raw events record in the form of NONMEN, except that
   * for the population input @c len consisting of data record
   * length for each individual.
   * @tparam T0 type of scalar for time of events.
   * @tparam T1 type of scalar for amount at each event.
   * @tparam T2 type of scalar for rate at each event.
   * @tparam T3 type of scalar for inter-dose inteveral at each event.
   * @tparam theta_container type of container for parameter. linode model uses
   *         matrix as parameter, other than std::vector used by others.
   */
  template <typename T0, typename T1, typename T2, typename T3>
  struct NONMENEventsRecord {
    using T_scalar = typename stan::return_type_t<T0, T1, T2, T3>;
    using T_time = typename stan::return_type_t<T0, T1, T2, T3>;
    using T_rate = T2;
    using T_amt = T1;
    using T_par_rate = T2;
    using T_par_ii = T3;

  private:
    /// len needs actual variable to ref to.
    const std::vector<int> len_1_;

  public:
    static const double lag_time_min; /**< minimum lag time allowed */

    /// nb. of compartments
    const int ncmt;
    /// begin id for each subject in concat vector time_, etc
    std::vector<int> begin_;
    /// data length for each subject
    const std::vector<int>& len_;
    /// nb. of events in the entire population
    const int total_num_event_times;
    /// event time
    const std::vector<T0>& time_;
    /// dosing amount
    const std::vector<T1>& amt_;
    /// dosing rate
    const std::vector<T2>& rate_;
    /// dosing interval
    const std::vector<T3>& ii_;
    /// dosing event id\n
    ///      (0) observation\n
    ///      (1) dosing\n
    ///      (2) other\n
    ///      (3) reset\n
    ///      (4) reset AND dosing
    const std::vector<int>& evid_;
    /// event compartment
    const std::vector<int>& cmt_;
    /// nb. of additional doses
    const std::vector<int>& addl_;
    /// steady-states flag
    const std::vector<int>& ss_;

    /**
     * Constructor using population data with parameter give as
     * matrix, such as in linear ODE models
     * @param[in] n number of compartments in model
     * @param[in] len record length for each individual.
     * @param[in] time times of events
     * @param[in] amt amount at each event
     * @param[in] rate rate at each event
     * @param[in] ii inter-dose interval at each event
     * @param[in] evid event identity: \n
     *                    (0) observation\n
     *                    (1) dosing\n
     *                    (2) other \n
     *                    (3) reset \n
     *                    (4) reset AND dosing
     * @param[in] cmt compartment number at each event
     * @param[in] addl additional dosing at each event
     * @param[in] ss steady state approximation at each event (0: no, 1: yes)
     */
    template <typename T0_, typename T1_, typename T2_, typename T3_>
    NONMENEventsRecord(int n,
                       const std::vector<int>& len,
                       const std::vector<T0_>& time,
                       const std::vector<T1_>& amt,
                       const std::vector<T2_>& rate,
                       const std::vector<T3_>& ii,
                       const std::vector<int>& evid,
                       const std::vector<int>& cmt,
                       const std::vector<int>& addl,
                       const std::vector<int>& ss) :
      len_1_(),
      ncmt(n),
      begin_(len.size()),
      len_(len),
      total_num_event_times(std::accumulate(len_.begin(), len_.end(), 0)),
      time_   (time  ),
      amt_    (amt   ),
      rate_   (rate   ),
      ii_     (ii     ),
      evid_   (evid   ),
      cmt_    (cmt    ),
      addl_   (addl   ),
      ss_     (ss     )
    {
      begin_[0] = 0;
      std::partial_sum(len.begin(), len.end() - 1, begin_.begin() + 1);
    }

    /**
     * Constructor using individual data with parameter give as
     * matrix, such as in linear ODE models
     * @param[in] n number of compartments in model
     * @param[in] time times of events
     * @param[in] amt amount at each event
     * @param[in] rate rate at each event
     * @param[in] ii inter-dose interval at each event
     * @param[in] evid event identity: \n
     *                    (0) observation \n
     *                    (1) dosing\n
     *                    (2) other \n
     *                    (3) reset \n
     *                    (4) reset AND dosing
     * @param[in] cmt compartment number at each event
     * @param[in] addl additional dosing at each event
     * @param[in] ss steady state approximation at each event (0: no, 1: yes)
     */
    template <typename T0_, typename T1_, typename T2_, typename T3_>
    NONMENEventsRecord(int n,
                       const std::vector<T0_>& time,
                       const std::vector<T1_>& amt,
                       const std::vector<T2_>& rate,
                       const std::vector<T3_>& ii,
                       const std::vector<int>& evid,
                       const std::vector<int>& cmt,
                       const std::vector<int>& addl,
                       const std::vector<int>& ss) :
      len_1_(1, time.size()),
      ncmt(n),
      begin_{0},
      len_(len_1_),
      total_num_event_times(std::accumulate(len_.begin(), len_.end(), 0)),
      time_   (time   ),
      amt_    (amt    ),
      rate_   (rate   ),
      ii_     (ii     ),
      evid_   (evid   ),
      cmt_    (cmt    ),
      addl_   (addl   ),
      ss_     (ss     )
    {}

    /**
     * begin of parameters for a subject @c id
     * in @c pMatrix. It is assumed that all the paramter are
     * either constant or time dependent.
     *
     * @param id subject id
     *
     * @return begin index in @c pMatrix for the subject
     */
    template<typename T>
    int begin_param(int id, const std::vector<T>& param) const {
      return param.size() == len_.size() ? id : begin_[id];
    }

    /**
     * length of parameters for a subject @c id
     * in @c pMatrix. It is assumed that all the paramter are
     * either constant or time dependent.
     *
     * @param id subject id
     *
     * @return len in @c pMatrix for the subject
     */
    template<typename T>
    int len_param(int id, const std::vector<T>& param) const {
      return param.size() == len_.size() ? 1 : len_[id];
    }

    /**
     * check the exisitence of steady state dosing events
     * for the 1st subject, used for single-individual data.
     *
     * @return if the subject has any SS dosing event.
     */
    inline bool has_ss_dosing() const {
      return has_ss_dosing(0);
    }

    /**
     * check the exisitence of steady state dosing events
     *
     * @param id subject id
     *
     * @return if the subject has any SS dosing event.
     */
    inline bool has_ss_dosing(int id) const {
      bool res = false;
      int begin = begin_[id];
      int end = size_t(id + 1) == len_.size() ? time_.size() : begin_[id + 1];
      for (int i = begin; i < end; ++i) {
        if ((evid_[i] == 1 || evid_[i] == 4) && ss_[i] != 0) {
          res = true;
          break;
        }
      }
      return res;
    }

    /**
     * check the exisitence of time-lagged events
     *
     * @param id subject id
     *
     * @return if the subject has any time-lagged dosing event.
     */
    template<typename T>
    inline bool has_positive_param(int id, const std::vector<std::vector<T>>& params) const {
      using stan::math::value_of;
      return std::any_of(params.begin() + begin_param(id, params),
                         params.begin() + begin_param(id, params) + len_param(id, params),
                         [](const std::vector<T>& v) {
                           return std::any_of(v.begin(), v.end(), [](const T& x) { return std::abs(value_of(x)) > lag_time_min; });
                         });
    }

    /**
     * check the exisitence of time-lagged dosing events
     * for the 1st subject, used for single-individual data.
     *
     * @return if the subject has any time-lagged dosing event.
     */
    template<typename T>
    inline bool has_positive_param(const std::vector<std::vector<T>>& params) const {
      return has_positive_param(0, params);
    }

    /**
     * @param id subject id
     *
     * @return nb. of events for the subject
     */
    inline int num_event_times(int id) const {
      return len_.at(id);
    }

    /**
     * @return nb. of events for subject 0.
     */
    inline int num_event_times() const {
      return len_.at(0);
    }

    /**
     * @return population size.
     */
    inline int num_subjects() const {
      return len_.size();
    }
  };

  template <typename T0, typename T1, typename T2, typename T3>
  const double NONMENEventsRecord<T0, T1, T2, T3>::lag_time_min = 1.e-12;

}

#endif


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

#include "ssmkit/filter/resampler/base.hpp"
#include "ssmkit/filter/resampler/systematic.hpp"

#include <armadillo>

using namespace ssmkit;

BOOST_AUTO_TEST_SUITE(filter_resampler_base);

BOOST_AUTO_TEST_CASE(operator_parenthesis) {
  struct AlwaysTrue {
    bool operator()(arma::vec t) { return true; }
  };

  auto resampler = filter::resampler::makeSystematic(AlwaysTrue());
  random::setRandomSeed();

  int N = 500;

  arma::umat pars(1,N);
  for (int i=0; i<N; ++i)
     pars(0,i) = i+1;

  arma::vec w = arma::ones<arma::vec>(N) * 1.0 / N;

  arma::vec w_r = w;
  decltype(pars) pars_r = pars;

  // uniform weights, nothing should change
  resampler(pars_r, w_r);
  BOOST_CHECK(arma::all(w_r == w));
  BOOST_CHECK(arma::all(arma::all(pars_r == pars)));

  // make first i weights non-zero, any particle with zero weight
  // should not appear in the output
  for (int i = 1; i < N-1; ++i) {
    w_r.zeros();
    w_r.head(i).fill(1.0 / i);

    pars_r = pars;
    resampler(pars_r, w_r);
    BOOST_CHECK(arma::all(w_r == w));

    for (int j = i + 1; j <= N; ++j)
      BOOST_CHECK(!arma::any(arma::vectorise(pars_r) == j));
  }
}

BOOST_AUTO_TEST_CASE(operator_parenthesis_no_action) {
  struct AlwaysFalse {
    bool operator()(arma::vec t) { return false; }
  };

  auto resampler = filter::resampler::makeSystematic(AlwaysFalse());
  random::setRandomSeed();

  int N = 500;

  arma::umat pars(1,N);
  for (int i=0; i<N; ++i)
     pars(0,i) = i+1;

  arma::vec w = arma::zeros<arma::vec>(N);
  w(0) = 1;

  arma::vec w_r = w;
  decltype(pars) pars_r = pars;

  // criterion is false, shouldn't do anything
  resampler(pars_r, w_r);
  BOOST_CHECK(arma::all(w_r == w));
  BOOST_CHECK(arma::all(arma::all(pars_r == pars)));

}

BOOST_AUTO_TEST_SUITE_END();


// Searches for good delimiters to cut streams into relatively well sized
// segments.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <boost/cstdint.hpp>
#include <boost/array.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <map>

// Desired size range
#define MIN_DESIRED_SIZE 4096
#define MAX_DESIRED_SIZE 131072

#define DELIMITER_SET_SIZE 1
typedef boost::array<boost::uint16_t,DELIMITER_SET_SIZE> DelimArray;

struct BestEntry
{
  DelimArray best;
  double bestScore;
  std::vector<unsigned char> data;
};

boost::mutex bestLock;
boost::mutex outLock;
std::map<std::string,BestEntry> best;

static void runThread(const std::string &fileName)
{
  char tmp[4096];

  boost::mt19937 prng;
  {
    boost::uint32_t seed;
    FILE *ur = fopen("/dev/urandom","r");
    fread((void *)&seed,1,sizeof(seed),ur);
    fclose(ur);
    prng.seed(seed);
  }

  BestEntry *myEntry;
  {
    boost::mutex::scoped_lock l(bestLock);
    myEntry = &(best[fileName]);
    myEntry->bestScore = 99999999.0;
  }

  {
    boost::mutex::scoped_lock l(outLock);

    std::cout << "*** Reading test data from: " << fileName << std::endl;
    FILE *f = fopen(fileName.c_str(),"r");
    if (f) {
      int n;
      while ((n = fread((void *)tmp,1,sizeof(tmp),f)) > 0) {
        for(int i=0;i<n;++i)
          myEntry->data.push_back((unsigned char)tmp[i]);
      }
      fclose(f);
    }

    if (myEntry->data.size() <= 0) {
      std::cout << "Error: no data read." << std::endl;
      exit(1);
    } else std::cout << "*** Read " << myEntry->data.size() << " bytes of test data." << std::endl;

    std::cout.flush();
  }

  DelimArray current;
  for(unsigned int i=0;i<DELIMITER_SET_SIZE;++i)
    current[i] = (boost::uint16_t)prng();

  for(;;) {
    unsigned long numTooShort = 0;
    unsigned long numTooLong = 0;
    unsigned long numGood = 0;

    boost::uint32_t shiftRegister = 0;
    unsigned long segSize = 0;
    for(std::vector<unsigned char>::iterator i=myEntry->data.begin();i!=myEntry->data.end();++i) {
      shiftRegister <<= 1;
      shiftRegister |= (((boost::uint32_t)*i) & 1);

      ++segSize;

      boost::uint16_t transformedShiftRegister = (boost::uint16_t)(shiftRegister);

      for(DelimArray::iterator d=current.begin();d!=current.end();++d) {
        if (transformedShiftRegister == *d) {
          if (segSize < MIN_DESIRED_SIZE)
            ++numTooShort;
          else if (segSize > MAX_DESIRED_SIZE)
            ++numTooLong;
          else ++numGood;
          segSize = 0;
          break;
        }
      }
    }
    if (segSize) {
      if (segSize < MIN_DESIRED_SIZE)
        ++numTooShort;
      else if (segSize > MAX_DESIRED_SIZE)
        ++numTooLong;
      else ++numGood;
    }

    if (numGood) {
      double score = ((double)(numTooShort + numTooLong)) / ((double)numGood);

      if (score < myEntry->bestScore) {
        myEntry->best = current;
        myEntry->bestScore = score;

        boost::mutex::scoped_lock l(outLock);

        std::cout << fileName << ": ";

        for(DelimArray::iterator d=current.begin();d!=current.end();++d) {
          sprintf(tmp,"0x%.4x",(unsigned int)*d);
          if (d != current.begin())
            std::cout << ',';
          std::cout << tmp;
        }

        std::cout << ": " << numTooShort << " / " << numGood << " / " << numTooLong << " (" << score << ")" << std::endl;
        std::cout.flush();

        if ((numTooShort == 0)&&(numTooLong == 0))
          break;
      }
    }

    for(DelimArray::iterator i=current.begin();i!=current.end();++i)
      *i = (boost::uint16_t)prng();
  }
}

int main(int argc,char **argv)
{
  std::vector< boost::shared_ptr<boost::thread> > threads;

  for(int i=1;i<argc;++i) {
    boost::shared_ptr<boost::thread> t(new boost::thread(boost::bind(&runThread,std::string(argv[i]))));
    threads.push_back(t);
  }

  for(std::vector< boost::shared_ptr<boost::thread> >::iterator i=threads.begin();i!=threads.end();++i)
    (*i)->join();

  return 0;
}


//==============================================================================
//         Copyright 2003 & onward LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 & onward LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          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
//==============================================================================
#ifndef BOOST_SIMD_SDK_CONSTANT_IMPL_SIMD_COMMON_HPP_INCLUDED
#define BOOST_SIMD_SDK_CONSTANT_IMPL_SIMD_COMMON_HPP_INCLUDED

#include <boost/simd/include/functions/simd/splat.hpp>
#include <boost/simd/include/functions/simd/bitwise_cast.hpp>
#include <boost/simd/sdk/simd/category.hpp>
#include <boost/simd/sdk/simd/tags.hpp>
#include <boost/dispatch/meta/as.hpp>
#include <boost/dispatch/meta/scalar_of.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/dispatch/meta/property_of.hpp>
#include <boost/simd/sdk/constant/constant.hpp>

//==============================================================================
// Forward all constant call to the simd version of themselves that splat
// the appropriate scalar constants into a proper SIMD vector.
//==============================================================================
namespace boost { namespace simd { namespace ext
{
  //============================================================================
  // By default we splat the constant contained into the extarcted value from
  // the Tag over a given Target.
  //============================================================================
  BOOST_SIMD_FUNCTOR_IMPLEMENTATION ( pure_constant_<Tag>, tag::cpu_
                                    , (Tag)(A0)
                                    , ((target_< scalar_< arithmetic_<A0> > >))
                                    )
  {
    typedef typename A0::type                                     base_type;
    typedef typename dispatch::meta::property_of<base_type>::type disp_type;
    typedef typename boost::mpl::apply<Tag,disp_type>::type       value_type;
    typedef typename value_type::value_type                       result_type;

    BOOST_DISPATCH_FORCE_INLINE result_type operator()(A0 const&) const
    {
      return boost::simd::splat<result_type>( result_type(value_type()) );
    }
  };

  //============================================================================
  // In the SIMD case, if we generate an integral vector, we do a simple
  // splat from the Tag/Target bit pattern immediate, if not we add a bitwise
  // cast
  //============================================================================
  BOOST_SIMD_FUNCTOR_IMPLEMENTATION ( pure_constant_<Tag>, tag::cpu_
                                    , (Tag)(A0)(X)
                                    , ((target_< simd_< arithmetic_<A0>,X> >))
                                    )
  {
    typedef typename A0::type                                       target_type;
    typedef typename dispatch::meta::scalar_of<target_type>::type   base_type;
    typedef typename dispatch::meta::property_of<base_type>::type   disp_type;
    typedef typename boost::mpl::apply<Tag,disp_type>::type         value_type;
    typedef boost::simd::native<typename value_type::value_type,X>  result_type;

    BOOST_DISPATCH_FORCE_INLINE result_type operator()(A0 const&) const
    {
      typedef typename dispatch::meta::
                       as_integer<typename value_type::value_type>::type
                                                                    pattern_type;
      typedef boost::simd::native<pattern_type,X>                   tmp_type;

      return  bitwise_cast<result_type>
              ( boost::simd::
                splat<tmp_type>( pattern_type(value_type::value) )
              );
    }
  };
} } }

#endif


#include <armadillo>
#include <iostream>
#include <ostream>
#include <target/kalman.hpp>
#include <target/utils.hpp>

using namespace arma;
using std::string;
using std::cout;
using std::endl;

int main(int argc, char **argv) {
  cout << target::RED << "Kalman filter test\n\n";
  mat H(4, 4);
  H.fill(10);
  mat Q = arma::ones(4, 4);
  vec y(2);
  // target::KalmanFilter KF(H, Q, y);
  // mat res = KF.filter();
  // cout << res << endl;
  cout << target::COL_RESET;
  return 0;
}


#include <cctbx/boost_python/flex_fwd.h>

#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/def.hpp>
#include <boost/python/args.hpp>
#include <mmtbx/pair_interaction/interaction.h>
#include <scitbx/array_family/boost_python/shared_wrapper.h>
#include <scitbx/boost_python/is_polymorphic_workaround.h>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/return_by_value.hpp>
#include <boost/python.hpp>

namespace mmtbx { namespace pair_interaction {
  namespace bp = boost::python;

namespace {

  boost::python::tuple
  getinitargs(wfc const& self)
  {
    return boost::python::make_tuple(self.ngrid, self.zz, self.r_array, self.wfcin_array, self.occ_electrons);
  }

  void init_module()
  {
    using namespace boost::python;
    using boost::python::arg;
    typedef return_value_policy<return_by_value> rbv;
    typedef default_call_policies dcp;

   class_<wfc>("wfc")
     .def(init<int const&,
               double const&,
               af::shared<double>  const&,
               boost::python::list const&,
               af::shared<double>
               >(
                 (arg("ngrid"),
                  arg("zz"),
                  arg("r_array"),
                  arg("wfcin_array"),
                  arg("occ_electrons")
                  )))
     .add_property("ngrid", make_getter(&wfc::ngrid, rbv()), make_setter(&wfc::ngrid, dcp()))
     .add_property("zz", make_getter(&wfc::zz, rbv()), make_setter(&wfc::zz, dcp()))
     .add_property("r_array", make_getter(&wfc::r_array, rbv()), make_setter(&wfc::r_array, dcp()))
     .add_property("wfcin_array", make_getter(&wfc::wfcin_array, rbv()), make_setter(&wfc::wfcin_array, dcp()))
     .add_property("occ_electrons", make_getter(&wfc::occ_electrons, rbv()), make_setter(&wfc::occ_electrons, dcp()))

     .enable_pickling()
     .def("__getinitargs__", getinitargs)
   ;

   class_<density_props<> >("density_props")
     .def(init<double,
               vec3<double> const&,
               mat3<double> const&
               >(
                 (arg("density"),
                  arg("gradient_vector"),
                  arg("hessian")
                  )))
     .def("add", &density_props<>::add, arg("density_props"))
     .def("has_silva_interaction", &density_props<>::has_silva_interaction)
     .add_property("density", make_getter(&density_props<>::density, rbv()), make_setter(&density_props<>::density, dcp()))
     .add_property("gradient_vector", make_getter(&density_props<>::gradient_vector, rbv()), make_setter(&density_props<>::gradient_vector, dcp()))
     .add_property("hessian", make_getter(&density_props<>::hessian, rbv()), make_setter(&density_props<>::hessian, dcp()))
     .add_property("gradient", make_getter(&density_props<>::gradient, rbv()), make_setter(&density_props<>::gradient, dcp()))
   ;

   def("hessian", (mat3<double>(*)(
                     vec3<double> const&,
                     double,
                     vec3<double> const&,
                     double,
                     double)) hessian, (arg("distanceVector"),
       arg("distanceReciprocal"),
       arg("distanceUnitVector"),arg("fac1"),arg("fac2")))
   ;

   def("atom_density_props", (density_props<double>(*)(
                     vec3<double> const&,
                     vec3<double> const& ,
                     wfc          const&
                     )) atom_density_props, (
       arg("p"),
       arg("a_xyz"),
       arg("wfc_obj")
       ))
   ;
   // add argument for choosing dori or sedd
   def("has_interaction_at_point", (bool(*)(
                     vec3<double> const&,
                     af::shared<vec3<double> > const&,
                     af::shared<int> const&,
                     boost::python::list const&,
                     std::string const & silva_type
                     )) has_interaction_at_point, (
       arg("p"),
       arg("a_xyz"),
       arg("element_flags"),
       arg("wfc_obj"),
       arg("silva_type")
       ))
   ;

   def("points_and_pairs", (af::shared<vec3<int> >(*)(
                     vec3<int> const&,
                     double const&,
                     af::shared<vec3<double> > const&,
                     vec3<double> const&,
                     af::shared<int> const&,
                     af::shared<int> const&,
                     boost::python::list const&,
                     std::string const & silva_type)) points_and_pairs, (
       arg("ngrid"),
       arg("step_size"),
       arg("xyz"),
       arg("xyz_min"),
       arg("atom_in_residue"),
       arg("element_flags"),
       arg("wfc_obj"),
       arg("silva_type")
       ))
   ;

  }

} // namespace <anonymous>
}} // namespace mmtbx::tls

BOOST_PYTHON_MODULE(mmtbx_pair_interaction_ext)
{
  mmtbx::pair_interaction::init_module();
}


//==================================================================================================
/**
  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_PPC_VMX_SIMD_FUNCTION_MULTIPLIES_HPP_INCLUDED
#define BOOST_SIMD_ARCH_PPC_VMX_SIMD_FUNCTION_MULTIPLIES_HPP_INCLUDED

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/function/bitwise_cast.hpp>
#include <boost/simd/constant/mzero.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/detail/dispatch/meta/as_unsigned.hpp>
#include <boost/predef/compiler.h>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  namespace bs = boost::simd;

  BOOST_DISPATCH_OVERLOAD ( multiplies_
                          , (typename A0)
                          , bs::vmx_
                          , bs::pack_<bd::single_<A0>, bs::vmx_>
                          , bs::pack_<bd::single_<A0>, bs::vmx_>
                          )
  {
    BOOST_FORCEINLINE A0 operator()(const A0& a0, const A0& a1) const BOOST_NOEXCEPT
    {
      return vec_madd(a0.storage(),a1.storage(), bs::Mzero<A0>().storage());
    }
  };

  BOOST_DISPATCH_OVERLOAD ( multiplies_
                          , (typename A0)
                          , bs::vmx_
                          , bs::pack_<bd::type16_<A0>, bs::vmx_>
                          , bs::pack_<bd::type16_<A0>, bs::vmx_>
                          )
  {
    BOOST_FORCEINLINE A0 operator()(const A0& a0, const A0& a1) const BOOST_NOEXCEPT
    {
      return vec_mladd(a0.storage(),a1.storage(),Zero<A0>().storage());
    }
  };

  BOOST_DISPATCH_OVERLOAD ( multiplies_
                          , (typename A0)
                          , bs::vmx_
                          , bs::pack_<bd::type8_<A0>, bs::vmx_>
                          , bs::pack_<bd::type8_<A0>, bs::vmx_>
                          )
  {
    BOOST_FORCEINLINE A0 operator()(const A0& a0, const A0& a1) const BOOST_NOEXCEPT
    {
      auto l = vec_mule(a0.storage(),a1.storage());
      auto r = vec_mulo(a0.storage(),a1.storage());
      return vec_mergel(vec_pack(l,l),vec_pack(r,r));
    }
  };

  #if BOOST_COMP_CLANG || BOOST_COMP_GNUC
  BOOST_DISPATCH_OVERLOAD ( multiplies_
                          , (typename A0)
                          , bs::vmx_
                          , bs::pack_<bd::ints32_<A0>, bs::vmx_>
                          , bs::pack_<bd::ints32_<A0>, bs::vmx_>
                          )
  {
    BOOST_FORCEINLINE A0 operator()(const A0& a0, const A0& a1) const BOOST_NOEXCEPT
    {
      return a0.storage() * a1.storage();
    }
  };
  #endif
} } }

#endif