//
//=======================================================================
// Copyright 2012
// Author: Alex Hagen-Zanker
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
//
// The dijkstra shortest path algorithm, without initialization
//
//=======================================================================
//
#ifndef BLINK_DIJKSTRA_SHORTEST_PATH_HPP
#define BLINK_DIJKSTRA_SHORTEST_PATH_HPP

#include <blink/graph/breadth_first_search.hpp>
#include <blink/graph/relax.hpp>

#include <boost/property_map/property_map.hpp>

namespace blink {

namespace detail {

// mostly a copy fROm BGL, but uses relax_target and relax_target_confident: https://svn.boost.org/trac/boost/attachment/ticket/7387/minor_improvements.patch
template <class UniformCostVisitor, class UpdatableQueue,
  class WeightMap, class PredecessorMap, class DistanceMap,
  class BinaryFunction, class BinaryPredicate>
struct dijkstra_bfs_visitor
{
  typedef typename boost::property_traits<DistanceMap>::value_type D;

  dijkstra_bfs_visitor(UniformCostVisitor vis, UpdatableQueue& Q,
                        WeightMap w, PredecessorMap p, DistanceMap d,
                        BinaryFunction combine, BinaryPredicate compare,
                        D zero)
    : m_vis(vis), m_Q(Q), m_weight(w), m_predecessor(p), m_distance(d),
      m_combine(combine), m_compare(compare), m_zero(zero)
  { }

  template <class Edge, class Graph>
  void tree_edge(Edge e, Graph& g) {
    relax_target_confident(e, g, m_weight, m_predecessor, m_distance,
                            m_combine);
    m_vis.edge_relaxed(e, g);
  }

  template <class Edge, class Graph>
  void gray_target(Edge e, Graph& g) {
    bool decreased = relax_target(e, g, m_weight, m_predecessor, m_distance,
                          m_combine, m_compare);
    if (decreased) {
      m_Q.update(target(e, g));
      m_vis.edge_relaxed(e, g);
    } else
      m_vis.edge_not_relaxed(e, g);
  }

  template <class Vertex, class Graph>
  void initialize_vertex(Vertex u, Graph& g)
  {
	  m_vis.initialize_vertex(u, g);
  }

  template <class Edge, class Graph>
  void non_tree_edge(Edge, Graph&)
  { }

  template <class Vertex, class Graph>
  void discover_vertex(Vertex u, Graph& g)
  {
	  m_vis.discover_vertex(u, g);
  }

  template <class Vertex, class Graph>
  void examine_vertex(Vertex u, Graph& g)
  {
	  m_vis.examine_vertex(u, g);
  }

  template <class Edge, class Graph>
  void examine_edge(Edge e, Graph& g)
  {
    if (m_compare(get(m_weight, e), m_zero)) {
        boost::throw_exception(boost::negative_edge());
    }
    m_vis.examine_edge(e, g);
  }

  template <class Edge, class Graph>
  void black_target(Edge, Graph&)
  { }

  template <class Vertex, class Graph>
  void finish_vertex(Vertex u, Graph& g)
  {
	  m_vis.finish_vertex(u, g);
  }

  UniformCostVisitor m_vis;
  UpdatableQueue& m_Q;
  WeightMap m_weight;
  PredecessorMap m_predecessor;
  DistanceMap m_distance;
  BinaryFunction m_combine;
  BinaryPredicate m_compare;
  D m_zero;
};

} // namespace detail

// Call breadth first search
template <class Graph, class DijkstraVisitor, class PredecessorMap,
  class DistanceMap, class WeightMap, class IndexMap, class Compare,
  class Combine, class DistZero, class ColorMap, class MutableQueue,
  class Interruptor>
inline void
  dijkstra_shortest_paths_no_init_at_all( const Graph& g,
    PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
    IndexMap index_map, Compare compare, Combine combine, DistZero zero,
    DijkstraVisitor vis, ColorMap color, MutableQueue& queue,
    Interruptor interruptor)
{
  detail::dijkstra_bfs_visitor<DijkstraVisitor, MutableQueue, WeightMap,
    PredecessorMap, DistanceMap, Combine, Compare>
    bfs_vis(vis, queue, weight, predecessor, distance, combine, compare, zero);

  breadth_first_visit_no_init(g, queue, bfs_vis, color, interruptor);
}

} // namespace blink

#endif


// Boost.Geometry - gis-projections (based on PROJ4)

// Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.

// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.

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

// This file is converted from PROJ4, http://trac.osgeo.org/proj
// PROJ4 is originally written by Gerald Evenden (then of the USGS)
// PROJ4 is maintained by Frank Warmerdam
// PROJ4 is converted to Boost.Geometry by Barend Gehrels

// Last updated version of proj: 5.0.0

// Original copyright notice:

// 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.

#ifndef BOOST_GEOMETRY_PROJECTIONS_GOODE_HPP
#define BOOST_GEOMETRY_PROJECTIONS_GOODE_HPP

#include <boost/geometry/srs/projections/impl/base_static.hpp>
#include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
#include <boost/geometry/srs/projections/impl/projects.hpp>
#include <boost/geometry/srs/projections/impl/factory_entry.hpp>
#include <boost/geometry/srs/projections/proj/gn_sinu.hpp>
#include <boost/geometry/srs/projections/proj/moll.hpp>

namespace boost { namespace geometry
{

namespace srs { namespace par4
{
    struct goode {}; // Goode Homolosine

}} //namespace srs::par4

namespace projections
{
    #ifndef DOXYGEN_NO_DETAIL
    namespace detail { namespace goode
    {

            static const double Y_COR = 0.05280;
            static const double PHI_LIM = .71093078197902358062;

            // TODO: consider storing references to Parameters instead of copies
            template <typename T, typename Par>
            struct par_goode
            {
                sinu_spheroid<T, Par>    sinu;
                moll_spheroid<T, Par>    moll;

                par_goode(Par const& par) : sinu(par), moll(par) {}
            };

            template <typename T, typename Par>
            inline void s_forward(T& lp_lon, T& lp_lat, T& xy_x, T& xy_y,
                                  Par const& par, par_goode<T, Par> const& proj_par)
            {
                if (fabs(lp_lat) <= PHI_LIM)
                    proj_par.sinu.fwd(lp_lon, lp_lat, xy_x, xy_y);
                else {
                    proj_par.moll.fwd(lp_lon, lp_lat, xy_x, xy_y);
                    xy_y -= lp_lat >= 0.0 ? Y_COR : -Y_COR;
                }
            }

            template <typename T, typename Par>
            inline void s_inverse(T& xy_x, T& xy_y, T& lp_lon, T& lp_lat,
                                  Par const& par, par_goode<T, Par> const& proj_par)
            {
                if (fabs(xy_y) <= PHI_LIM)
                    proj_par.sinu.inv(xy_x, xy_y, lp_lon, lp_lat);
                else {
                    xy_y += xy_y >= 0.0 ? Y_COR : -Y_COR;
                    proj_par.moll.inv(xy_x, xy_y, lp_lon, lp_lat);
                }
            }

            // Goode Homolosine
            template <typename Par>
            inline void setup_goode(Par& par)
            {
                par.es = 0.;

                // NOTE: The following explicit initialization of sinu projection
                // is not needed because setup_goode() is called before proj_par.sinu
                // is constructed and m_par of parent projection is used.

                //proj_par.sinu.m_par.es = 0.;
                //detail::gn_sinu::setup_sinu(proj_par.sinu.m_par, proj_par.sinu.m_proj_parm);
            }

    }} // namespace detail::goode
    #endif // doxygen

    /*!
        \brief Goode Homolosine projection
        \ingroup projections
        \tparam Geographic latlong point type
        \tparam Cartesian xy point type
        \tparam Parameters parameter type
        \par Projection characteristics
         - Pseudocylindrical
         - Spheroid
        \par Example
        \image html ex_goode.gif
    */
    template <typename T, typename Parameters>
    struct goode_spheroid : public detail::base_t_fi<goode_spheroid<T, Parameters>, T, Parameters>
    {
        detail::goode::par_goode<T, Parameters> m_proj_parm;

        inline goode_spheroid(const Parameters& par)
            : detail::base_t_fi<goode_spheroid<T, Parameters>, T, Parameters>(*this, par)
            , m_proj_parm(setup(this->m_par))
        {}

        // FORWARD(s_forward)  spheroid
        // Project coordinates from geographic (lon, lat) to cartesian (x, y)
        inline void fwd(T& lp_lon, T& lp_lat, T& xy_x, T& xy_y) const
        {
            detail::goode::s_forward(lp_lon, lp_lat, xy_x, xy_y, this->m_par, this->m_proj_parm);
        }

        // INVERSE(s_inverse)  spheroid
        // Project coordinates from cartesian (x, y) to geographic (lon, lat)
        inline void inv(T& xy_x, T& xy_y, T& lp_lon, T& lp_lat) const
        {
            detail::goode::s_inverse(xy_x, xy_y, lp_lon, lp_lat, this->m_par, this->m_proj_parm);
        }

        static inline std::string get_name()
        {
            return "goode_spheroid";
        }

    private:
        static Parameters& setup(Parameters& par)
        {
            detail::goode::setup_goode(par);
            return par;
        }

    };

    #ifndef DOXYGEN_NO_DETAIL
    namespace detail
    {

        // Static projection
        BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::par4::goode, goode_spheroid, goode_spheroid)

        // Factory entry(s)
        template <typename T, typename Parameters>
        class goode_entry : public detail::factory_entry<T, Parameters>
        {
            public :
                virtual base_v<T, Parameters>* create_new(const Parameters& par) const
                {
                    return new base_v_fi<goode_spheroid<T, Parameters>, T, Parameters>(par);
                }
        };

        template <typename T, typename Parameters>
        inline void goode_init(detail::base_factory<T, Parameters>& factory)
        {
            factory.add_to_factory("goode", new goode_entry<T, Parameters>);
        }

    } // namespace detail
    #endif // doxygen

} // namespace projections

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_PROJECTIONS_GOODE_HPP


// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2007-2008 Steven Watanabe
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_UNIT_SYSTEMS_METRIC_TON_HPP_INCLUDED
#define BOOST_UNIT_SYSTEMS_METRIC_TON_HPP_INCLUDED

#include <boost/units/scaled_base_unit.hpp>
#include <boost/units/static_rational.hpp>
#include <boost/units/scale.hpp>
#include <boost/units/units_fwd.hpp>
#include <boost/units/base_units/si/kilogram.hpp>
//#include <boost/units/base_units/cgs/gram.hpp>

namespace boost {
namespace units {
namespace metric {

//typedef scaled_base_unit<boost::units::cgs::gram_base_unit, scale<10, static_rational<6> > > ton_base_unit;
typedef scaled_base_unit<boost::units::si::kilogram_base_unit, scale<1000, static_rational<1> > > ton_base_unit;

}

template<>
struct base_unit_info<metric::ton_base_unit> {
    static BOOST_CONSTEXPR const char* name()   { return("metric ton"); }
    static BOOST_CONSTEXPR const char* symbol() { return("t"); }
};

}
}

#endif // BOOST_UNIT_SYSTEMS_METRIC_TON_HPP_INCLUDED


#define ARMA_NO_DEBUG

#include <armadillo>
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo, BH, bigmemory)]]

#include <Rcpp.h>
#include <vector>

using namespace Rcpp;
using namespace arma;

#include <bigmemory/BigMatrix.h>
// [[Rcpp::plugins(cpp11)]]

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calcT0Wsim1 (arma::mat& CvSqrt,arma::mat& weight, arma::vec powV, int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int k = CvSqrt.n_rows;
    // containers
    arma::mat T0s1(nperm,npow);
    T0s1.fill(0);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;
        arma::mat U0tmp = weight % U0;

        for (int j = 0; j < npow; j++) {
            if (powV[j] == 0) {
                arma::mat tmpU01 = abs(U0tmp);
                T0s1(i,j) = tmpU01.max();
            } else {
                T0s1(i,j) = accu(pow(U0tmp,powV[j]));
            }
        }
    }
    Rcpp::List res;
    res["T0"] =T0s1;

    return(res);
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
arma::vec avg_rank(arma::vec x) {

    arma::uvec w  = arma::stable_sort_index(x,"descend");
    R_xlen_t sz = x.size();
    arma::vec r(sz);

    for (R_xlen_t n, i = 0; i < sz; i += n) {
        n = 1;
        while (i + n < sz && x[w[i]] == x[w[i + n]]) ++n;
        for (R_xlen_t k = 0; k < n; k++) {
            r[w[i + k]] = i + (n + 1) / 2.;
        }
    }

    return r;

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calcT0Wsim3 (arma::mat& CvSqrt,arma::mat& weight, arma::vec powV, arma::vec Tsabs, SEXP pBigMat, int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int k = CvSqrt.n_rows;

    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;
        arma::mat U0tmp = weight % U0;

        for (int j = 0; j < npow; j++) {
            if (powV[j] == 0) {
                arma::mat tmpU01 = abs(U0tmp);
                T0s(i,j) = tmpU01.max();
            } else {
                T0s(i,j) = accu(pow(U0tmp,powV[j]));
            }
        }
    }

    T0s = arma::abs(T0s);

    arma::vec minp0(nperm);
    arma::vec P0s(nperm);
    arma::vec pPerm0(npow);

    for (int i = 0; i < npow; i++) {

        // Calculate p-value
        arma::vec T0stmp = T0s.col(i);
        int tmp3 = 0;
        arma::vec rankarma  = avg_rank(T0stmp);

        for( int tt=0 ; tt < nperm ; tt++) {
            if( Tsabs(i)  <= T0stmp(tt) ) {
                tmp3++;
            }

            P0s(tt) = (double) rankarma(tt) / (double) nperm;
        }

        if(i == 0) {
            minp0 = P0s;
        } else {
            for( int ii = 0; ii < nperm; ii++) {
                if( minp0(ii) > P0s(ii) ) {
                    minp0(ii) = P0s(ii);
                }
            }
        }
        pPerm0(i) = (double) tmp3/ (double) nperm;

    }

    return Rcpp::List::create(Rcpp::Named("minp0") = minp0,
                              Rcpp::Named("pPerm0") = pPerm0 );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calcT0Wsim4 (arma::mat& CvSqrt,arma::mat& weight, arma::vec Tsabs, arma::vec powV, SEXP pBigMat, SEXP pBigMat3, int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;
    const int k = CvSqrt.n_rows;
    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    XPtr<BigMatrix> xpMat3(pBigMat3);
    arma::mat minp0_sign = arma::Mat<double> ( (double *)xpMat3->matrix(), xpMat3->nrow(), xpMat3->ncol(), false);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;

        for (int k = 0; k < nweight; k++) {
            arma::mat weight_tmp = weight.col(k);
            arma::mat U0tmp = weight_tmp % U0;

            for (int j = 0; j < npow; j++) {
                if (powV[j] == 0) {
                    arma::mat tmpU01 = abs(U0tmp);
                    T0s(i,j * nweight + k) = tmpU01.max();
                } else {
                    T0s(i,j * nweight + k) = accu(pow(U0tmp,powV[j]));
                }
            }
        }
    }

    for (int k =0; k<nweight; k++) {
        minp0_sign.col(k) = T0s.col(k);
    }

    int npw = npow * nweight;
    arma::mat cov_res(npw,npw);
    cov_res.fill(0);
    cov_res = cov(T0s);

    T0s = arma::abs(T0s);

    arma::vec minp0(nperm);
    arma::vec P0s(nperm);
    arma::mat pPerm0(npow + 1,nweight);
    pPerm0.fill(-1);

    for(int k = 0; k < nweight; k++) {

        double minP_tmp = 1.0;

        for (int j = 0; j < npow; j++) {

            // Calculate p-value
            arma::vec T0stmp = T0s.col(j * nweight + k);
            int tmp3 = 0;
            arma::vec rankarma  = avg_rank(T0stmp);

            for( int tt=0 ; tt < nperm ; tt++) {
                if( Tsabs(j * nweight + k)  <= T0stmp(tt) ) {
                    tmp3++;
                }

                P0s(tt) = (double) rankarma(tt) / (double) nperm;
            }

            if(j == 0) {
                minp0 = P0s;
            } else {
                for( int ii = 0; ii < nperm; ii++) {
                    if( minp0(ii) > P0s(ii) ) {
                        minp0(ii) = P0s(ii);
                    }
                }
            }
            double tmp_pvalue = (double) tmp3 / (double) nperm;
            pPerm0(j,k) = tmp_pvalue;

            if (tmp_pvalue <= minP_tmp) {
                minP_tmp = tmp_pvalue;
            }
        }

        int count_pvalue = 0;
        for(int j=0; j < nperm; j++) {
            if( minP_tmp > minp0(j) ) {
                count_pvalue = count_pvalue + 1;
            }
        }

        pPerm0(npow,k) = (double) (count_pvalue + 1) / (double) (nperm + 1);

    }

    return Rcpp::List::create(Rcpp::Named("pPerm0") = pPerm0,
                              Rcpp::Named("cov") = cov_res );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calcT0WsimV3 (arma::mat& CvSqrt,arma::mat& weight, arma::vec powV, SEXP pBigMat, SEXP pBigMat3,int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;
    const int k = CvSqrt.n_rows;
    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    XPtr<BigMatrix> xpMat3(pBigMat3);
    arma::mat minp0_sign = arma::Mat<double> ( (double *)xpMat3->matrix(), xpMat3->nrow(), xpMat3->ncol(), false);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;

        for (int k = 0; k < nweight; k++) {
            arma::mat weight_tmp = weight.col(k);
            arma::mat U0tmp = weight_tmp % U0;

            for (int j = 0; j < npow; j++) {
                if (powV[j] == 0) {
                    arma::mat tmpU01 = abs(U0tmp);
                    T0s(i,j * nweight + k) = tmpU01.max();
                } else {
                    T0s(i,j * nweight + k) = accu(pow(U0tmp,powV[j]));
                }
            }
        }
    }

    for (int k =0; k<nweight; k++) {
        minp0_sign.col(k) = T0s.col(k);
    }

    int npw = npow * nweight;
    arma::mat cov_res(npw,npw);
    cov_res.fill(0);
    cov_res = arma::cov(T0s);

    arma::mat mean_res(npw,1);
    mean_res.fill(0);
    mean_res = arma::mean(T0s,0);

    return Rcpp::List::create(Rcpp::Named("cov") = cov_res,
                              Rcpp::Named("mean") = mean_res );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
void calc_test_ch(arma::mat& cov, arma::mat& weight, arma::vec powV, SEXP pBigMat, SEXP pBigMat2,int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;

    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat T1s = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    arma::vec pPerm0(npow);

    for (int i = 0; i < npow; i++) {

        arma::mat subcov(nweight,nweight);
        subcov.fill(0);

        subcov = cov.submat(i*nweight,i*nweight,((i+1)*nweight -1),((i+1)*nweight -1));
        subcov = subcov.i();

        for (int j =0; j < nperm; j++) {
            arma::vec tmp_ts = T0s.row(j);
            arma::mat tmp_ts2(1,nweight);
            tmp_ts2 = tmp_ts.subvec(i*nweight,((i+1) * nweight -1));
            arma::mat tmp = tmp_ts2.t() * subcov * tmp_ts2;
            T1s(j,i) = tmp(0,0);
        }
    }
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
void calc_test_ch_V3(arma::mat& cov,arma::vec & mean, arma::mat& weight, arma::vec powV, SEXP pBigMat, SEXP pBigMat2,int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;

    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat T1s = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    arma::vec pPerm0(npow);

    for (int i = 0; i < npow; i++) {

        arma::mat subcov(nweight,nweight);
        subcov.fill(0);

        subcov = cov.submat(i*nweight,i*nweight,((i+1)*nweight -1),((i+1)*nweight -1));
        subcov = subcov.i();

        arma::mat tmp_mean(1,nweight);
        tmp_mean = mean.subvec(i*nweight,((i+1) * nweight -1));
        for (int j =0; j < nperm; j++) {
            arma::vec tmp_ts = T0s.row(j);
            arma::mat tmp_ts2(1,nweight);

            tmp_ts2 = tmp_ts.subvec(i*nweight,((i+1) * nweight -1));
            tmp_ts2 = tmp_ts2 - tmp_mean;
            arma::mat tmp = tmp_ts2.t() * subcov * tmp_ts2;
            T1s(j,i) = tmp(0,0);
        }
    }
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
void calc_test_pan(arma::mat& cov, arma::mat& weight, arma::vec powV, SEXP pBigMat,SEXP pBigMat2, int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;

    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T1s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat T2s = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    arma::vec pPerm0(npow);

    for (int i = 0; i < npow; i++) {

        arma::mat subcov(nweight,nweight);
        subcov.fill(0);

        subcov = cov.submat(i*nweight,i*nweight,((i+1)*nweight -1),((i+1)*nweight -1));

        for (int j =0; j < nperm; j++) {
            arma::vec tmp_ts = T2s.row(j);
            arma::mat tmp_ts2(1,nweight);
            tmp_ts2 = tmp_ts.subvec(i*nweight,((i+1) * nweight -1));
            arma::mat tmp = tmp_ts2.t() * subcov * tmp_ts2;
            T1s(j,i) = tmp(0,0);
        }
    }
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
arma::mat calc_test_ts(arma::mat& cov, arma::mat& weight, arma::vec powV, arma::vec Ts) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;

    arma::mat Ts2(npow,1);
    Ts2.fill(0);

    for (int i = 0; i < npow; i++) {
        arma::mat subcov(nweight,nweight);
        subcov.fill(0);

        subcov = cov.submat(i*nweight,i*nweight,((i+1)*nweight -1),((i+1)*nweight -1));

        arma::mat tmp_ts2(1,nweight);
        tmp_ts2 = Ts.subvec(i*nweight,((i+1)*nweight -1));
        arma::mat tmp =  tmp_ts2.t() * subcov * tmp_ts2;
        Ts2(i,0) = tmp(0,0);
    }

    return Ts2;
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
arma::mat calc_test_ts_V3(arma::mat& cov, arma::vec & mean, arma::mat& weight, arma::vec powV, arma::vec Ts) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;

    arma::mat Ts2(npow,1);
    Ts2.fill(0);

    for (int i = 0; i < npow; i++) {
        arma::mat subcov(nweight,nweight);
        subcov.fill(0);

        subcov = cov.submat(i*nweight,i*nweight,((i+1)*nweight -1),((i+1)*nweight -1));
        subcov = subcov.i();

        arma::mat tmp_mean(1,nweight);
        tmp_mean = mean.subvec(i*nweight,((i+1) * nweight -1));

        arma::mat tmp_ts2(1,nweight);
        tmp_ts2 = Ts.subvec(i*nweight,((i+1)*nweight -1));
        tmp_ts2 = tmp_ts2 - tmp_mean;

        arma::mat tmp =  tmp_ts2.t() * subcov * tmp_ts2;
        Ts2(i,0) = tmp(0,0);
    }

    return Ts2;
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calc_p_ch (arma::vec powV, arma::vec Tsabs, SEXP pBigMat2, int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;

    // containers
    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat T1s = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    arma::vec minp0(nperm);
    arma::vec P0s(nperm);
    arma::vec pPerm0(npow);

    for (int i = 0; i < npow; i++) {

        // Calculate p-value
        arma::vec T1stmp = T1s.col(i);
        int tmp3 = 0;

        arma::vec rankarma  = avg_rank(T1stmp);

        for( int tt=0 ; tt < nperm ; tt++) {
            if( Tsabs(i)  <= T1stmp(tt) ) {
                tmp3++;
            }
            P0s(tt) = (double) rankarma(tt) / (double) nperm;
        }

        if(i == 0) {
            minp0 = P0s;
        } else {
            for( int ii = 0; ii < nperm; ii++) {
                if( minp0(ii) > P0s(ii) ) {
                    minp0(ii) = P0s(ii);
                }
            }
        }
        pPerm0(i) = (double) tmp3 / (double) nperm;

    }

    return Rcpp::List::create(Rcpp::Named("minp0") = minp0,
                              Rcpp::Named("pPerm0") = pPerm0 );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calc_p_ch_pan (arma::vec powV, arma::vec Tsabs, SEXP pBigMat, int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;

    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T1s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    arma::vec minp0(nperm);
    arma::vec P0s(nperm);
    arma::vec pPerm0(npow);

    for (int i = 0; i < npow; i++) {

        // Calculate p-value
        arma::vec T1stmp = T1s.col(i);
        int tmp3 = 0;

        arma::vec rankarma  = avg_rank(T1stmp);

        for( int tt=0 ; tt < nperm ; tt++) {
            if( Tsabs(i)  <= T1stmp(tt) ) {
                tmp3++;
            }
            P0s(tt) = (double) rankarma(tt) / (double) nperm;
        }

        if(i == 0) {
            minp0 = P0s;
        } else {
            for( int ii = 0; ii < nperm; ii++) {
                if( minp0(ii) > P0s(ii) ) {
                    minp0(ii) = P0s(ii);
                }
            }
        }
        pPerm0(i) = (double) tmp3 / (double) nperm;

    }

    return Rcpp::List::create(Rcpp::Named("minp0") = minp0,
                              Rcpp::Named("pPerm0") = pPerm0 );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calc_p_pan (arma::vec Tsabs,SEXP pBigMat,SEXP pBigMat2,SEXP pBigMat3, int nTs,int nweight, int nperm) {

    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat T2s = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    XPtr<BigMatrix> xpMat3(pBigMat3);
    arma::mat minp0_sign = arma::Mat<double> ( (double *)xpMat3->matrix(), xpMat3->nrow(), xpMat3->ncol(), false);

    // T0s = arma::abs(T0s);

    arma::vec minp0(nperm);
    arma::vec P0s(nperm);
    arma::vec pPerm0(nTs);

    for (int i = 0; i < nTs; i++) {

        // Calculate p-value
        arma::vec T1stmp = T0s.col(i);
        int tmp3 = 0;

        arma::vec rankarma  = avg_rank(T1stmp);

        int minp0_index = i - floor(i/nweight) * nweight;

        for( int tt=0 ; tt < nperm ; tt++) {
            if( Tsabs(i)  <= T1stmp(tt) ) {
                tmp3++;
            }

            NumericVector tmp_res;
            tmp_res = (double) rankarma(tt) / (double) nperm;

            int p0_sign = -1;
            if (minp0_sign(tt,minp0_index) >0) {
                p0_sign = 1;
            }

            tmp_res = qnorm(1 - tmp_res/2) * p0_sign;
            T2s(tt,i) = tmp_res[0];
        }

        pPerm0(i) = (double) tmp3 / (double) nperm;
    }

    arma::mat cov_res(nTs,nTs);
    cov_res.fill(0);
    cov_res = arma::cov(T2s);

    return Rcpp::List::create(Rcpp::Named("pPerm0") = pPerm0,
                              Rcpp::Named("cov") = cov_res );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
arma::vec calc_aSPU (arma::mat p_cov, SEXP pBigMat2, int nperm) {

    // containers
    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat minp0 = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    arma::vec res(nperm);

    for (int i = 0; i < nperm; i++) {
        arma::mat tmp =  minp0.row(i) * p_cov * minp0.row(i).t();
        res(i) = tmp(0,0);
    }

    return res;
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List daSPU_calcT0Wsim4 (arma::mat& CvSqrt,arma::mat& weight, arma::vec powV, arma::vec Tsabs, SEXP pBigMat, SEXP pBigMat2,SEXP pBigMat3,int nperm) {

    //const int n = X1.n_rows;
    const int npow = powV.n_rows;
    const int nweight = weight.n_cols;
    const int k = CvSqrt.n_rows;
    // containers
    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    // containers
    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat minp0 = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    // containers
    XPtr<BigMatrix> xpMat3(pBigMat3);
    arma::mat minp0_sign = arma::Mat<double> ( (double *)xpMat3->matrix(), xpMat3->nrow(), xpMat3->ncol(), false);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;

        for (int k = 0; k < nweight; k++) {
            arma::mat weight_tmp = weight.col(k);
            arma::mat U0tmp = weight_tmp % U0;

            for (int j = 0; j < npow; j++) {
                if (powV[j] == 0) {
                    arma::mat tmpU01 = abs(U0tmp);
                    T0s(i,k * npow + j) = tmpU01.max();
                } else {
                    T0s(i,k * npow + j) = accu(pow(U0tmp,powV[j]));
                }
            }
        }
    }

    for (int k =0; k<nweight; k++) {
        minp0_sign.col(k) = T0s.col(k * npow);
    }

    T0s = arma::abs(T0s);

    arma::vec minp0_tmp(nperm);

    arma::vec P0s(nperm);
    arma::vec pPerm0(npow* nweight);

    for (int k = 0; k < nweight; k++) {

        for (int i = (npow*k); i < (npow* (k + 1)); i++) {

            // Calculate p-value
            arma::vec T0stmp = T0s.col(i);
            int tmp3 = 0;
            arma::vec rankarma  = avg_rank(T0stmp);

            for( int tt=0 ; tt < nperm ; tt++) {
                if( Tsabs(i)  <= T0stmp(tt) ) {
                    tmp3++;
                }

                P0s(tt) = (double) rankarma(tt) / (double) nperm;
            }

            if(i == 0) {
                minp0_tmp = P0s;
            } else {
                for( int ii = 0; ii < nperm; ii++) {
                    if( minp0_tmp(ii) > P0s(ii) ) {
                        minp0_tmp(ii) = P0s(ii);
                    }
                }
            }
            pPerm0(i) = (double) tmp3/ (double) nperm;
        }

        minp0.col(k) = minp0_tmp;
    }

    for (int k = 0; k < nweight; k++) {
        for (int i = 0; i <nperm; i++) {
            NumericVector tmp_res;

            tmp_res = minp0(i,k);
            int p0_sign = -1;
            if (minp0_sign(i,k) >0) {
                p0_sign = 1;
            }
            tmp_res = qnorm(1 - tmp_res/2) * p0_sign;
            minp0(i,k) = tmp_res[0];
        }
    }

    arma::mat cov_res(nweight,nweight);
    cov_res.fill(0);
    cov_res = arma::cov(minp0);

    return Rcpp::List::create(Rcpp::Named("pPerm0") = pPerm0,
                              Rcpp::Named("cov") = cov_res );

}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
arma::vec daSPU_calc_aSPU (arma::mat p_cov, SEXP pBigMat2, int nperm) {

    // containers
    XPtr<BigMatrix> xpMat2(pBigMat2);
    arma::mat minp0 = arma::Mat<double> ( (double *)xpMat2->matrix(), xpMat2->nrow(), xpMat2->ncol(), false);

    arma::vec res(nperm);

    for (int i = 0; i < nperm; i++) {
        arma::mat tmp =  minp0.row(i) * p_cov * minp0.row(i).t();
        res(i) = tmp(0,0);
    }

    return res;
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
Rcpp::List calcT0Wsim2 (arma::mat& CvSqrt,arma::mat& weight, arma::vec pow1, arma::vec pow2, int nperm) {

    //const int n = X1.n_rows;
    const int n_pow1 = pow1.size();
    const int n_pow2 = pow2.size();
    const int n_weight = weight.n_cols;

    const int k = CvSqrt.n_rows;
    // containers
    arma::mat T0s1(n_pow1,n_weight);
    T0s1.fill(0);
    arma::mat T0s(nperm,n_pow1 * n_pow2);
    T0s.fill(0);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;

        for (int i2 = 0; i2 < n_weight; i2 ++) {
            arma::mat U0tmp = weight.col(i2) % U0;
            for (int j1 = 0; j1 < n_pow1; j1++) {
                if( pow1[j1] > 0) {
                    arma::vec tmp1 = pow(U0tmp,pow1[j1]);
                    double tmp2 = sum(tmp1);

                    if( tmp2 > 0 ) {
                        T0s1(j1,i2) = pow(std::abs(tmp2), 1/pow1[j1]);
                    } else {
                        T0s1(j1,i2) = -pow(std::abs(tmp2), 1/pow1[j1]);
                    }

                } else {
                    arma::vec tmp1 = abs(U0tmp);
                    T0s1(j1,i2) = max(tmp1);
                }
            }
        }

        for (int j1 = 0; j1 < n_pow1; j1++) {
            for (int j2 = 0; j2 < n_pow2; j2++) {
                if (pow2[j2] > 0) {
                    arma::mat tmp3 = pow(T0s1.row(j1),pow2[j2]);
                    T0s(i, j2 * n_pow1 + j1) = accu(tmp3);
                } else {
                    T0s(i, j2 * n_pow1 + j1) = max(abs(T0s1.row(j1)));
                }
            }
        }
    }

    Rcpp::List res;
    res["T0s"] =T0s;

    return(res);
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export()]]
arma::vec daSPU_calcT0 (arma::mat& CvSqrt,arma::mat& weight, arma::vec pow1, arma::vec pow2,  arma::vec Tsabs,SEXP pBigMat, int nperm) {

    //const int n = X1.n_rows;
    const int n_pow1 = pow1.size();
    const int n_pow2 = pow2.size();
    const int n_pow = n_pow1 * n_pow2;
    const int n_weight = weight.n_cols;

    const int k = CvSqrt.n_rows;
    // containers
    arma::mat T0s1(n_pow1,n_weight);
    T0s1.fill(0);

    XPtr<BigMatrix> xpMat(pBigMat);
    arma::mat T0s = arma::Mat<double> ( (double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false);

    for (int i = 0; i < nperm; i++) {
        arma::mat U00 = arma::randn(k,1);
        arma::mat U0 = CvSqrt * U00;

        for (int i2 = 0; i2 < n_weight; i2 ++) {
            arma::mat U0tmp = weight.col(i2) % U0;
            for (int j1 = 0; j1 < n_pow1; j1++) {
                if( pow1[j1] > 0) {
                    arma::vec tmp1 = pow(U0tmp,pow1[j1]);
                    double tmp2 = sum(tmp1);

                    if( tmp2 > 0 ) {
                        T0s1(j1,i2) = pow(std::abs(tmp2), 1/pow1[j1]);
                    } else {
                        T0s1(j1,i2) = -pow(std::abs(tmp2), 1/pow1[j1]);
                    }

                } else {
                    arma::vec tmp1 = abs(U0tmp);
                    T0s1(j1,i2) = max(tmp1);
                }
            }
        }

        for (int j1 = 0; j1 < n_pow1; j1++) {
            for (int j2 = 0; j2 < n_pow2; j2++) {
                if (pow2[j2] > 0) {
                    arma::mat tmp3 = pow(T0s1.row(j1),pow2[j2]);
                    T0s(i, j2 * n_pow1 + j1) = accu(tmp3);
                } else {
                    T0s(i, j2 * n_pow1 + j1) = max(abs(T0s1.row(j1)));
                }
            }
        }
    }

    //
    T0s = arma::abs(T0s);

    arma::vec minp0(nperm);
    arma::vec P0s(nperm);
    arma::vec pPerm0(n_pow + 1);
    double minP_tmp = 1.0;

    for(int k = 0; k < n_pow; k++) {

        // Calculate p-value
        arma::vec T0stmp = T0s.col(k);
        int tmp3 = 0;
        arma::vec rankarma  = avg_rank(T0stmp);

        for( int tt=0 ; tt < nperm ; tt++) {
            if( Tsabs(k)  <= T0stmp(tt) ) {
                tmp3++;
            }

            P0s(tt) = (double) rankarma(tt) / (double) nperm;
        }

        if(k == 0) {
            minp0 = P0s;
        } else {
            for( int ii = 0; ii < nperm; ii++) {
                if( minp0(ii) > P0s(ii) ) {
                    minp0(ii) = P0s(ii);
                }
            }
        }
        double tmp_pvalue = (double) tmp3 / (double) nperm;
        pPerm0(k) = tmp_pvalue;

        if (tmp_pvalue <= minP_tmp) {
            minP_tmp = tmp_pvalue;
        }

    }

    int count_pvalue = 0;
    for(int j=0; j < nperm; j++) {
        if( minP_tmp >= minp0(j) ) {
            count_pvalue = count_pvalue + 1;
        }
    }

    pPerm0(n_pow) = (double) (count_pvalue + 1) / (double) (nperm + 1);

    return pPerm0;
}

// [[Rcpp::export]]
void set_seed(unsigned int seed) {
    Rcpp::Environment base_env("package:base");
    Rcpp::Function set_seed_r = base_env["set.seed"];
    set_seed_r(seed);
}

// This function is taken from http://stackoverflow.com/questions/39153082/rcpp-rank-function-that-does-average-ties
class Comparator {
    private:
    const Rcpp::NumericVector& ref;

    bool is_na(double x) const
    {
        return Rcpp::traits::is_na<REALSXP>(x);
    }

    public:
    Comparator(const Rcpp::NumericVector& ref_)
    : ref(ref_)
    {}

    bool operator()(const int ilhs, const int irhs) const
    {
        double lhs = ref[ilhs], rhs = ref[irhs];
        if (is_na(lhs)) return false;
        if (is_na(rhs)) return true;
        return lhs < rhs;
    }
};

// [[Rcpp::export]]
Rcpp::NumericVector avg_rank2(Rcpp::NumericVector x)
{
    R_xlen_t sz = x.size();
    Rcpp::IntegerVector w = Rcpp::seq(0, sz - 1);
    std::sort(w.begin(), w.end(), Comparator(x));

    Rcpp::NumericVector r = Rcpp::no_init_vector(sz);
    for (R_xlen_t n, i = 0; i < sz; i += n) {
        n = 1;
        while (i + n < sz && x[w[i]] == x[w[i + n]]) ++n;
        for (R_xlen_t k = 0; k < n; k++) {
            r[w[i + k]] = i + (n + 1) / 2.;
        }
    }

    return r;
}

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::List aSPUsPathEngine2(Rcpp::List CH, Rcpp::List CHcovSq, arma::vec pow1, arma::vec pow2, int nGenes, int n_perm, int k, arma::vec nSNPs0, arma::vec nChrom0, arma::vec Ts2, int s) {
    const int n_ch = CH.size();
    const int n_pow1 = pow1.size();
    const int n_pow2 = pow2.size();

    arma::vec T0s(n_perm);
    arma::vec T0st(nGenes*n_pow1);
    arma::vec Ts2t(n_pow1*n_pow2);
    arma::vec pPerm0(n_pow1*n_pow2);
    arma::vec minp0(n_perm);
    arma::vec P0s(n_perm);

    // iterate for pow2
    for(int j2=0 ; j2 < n_pow2; j2++) {
        // iterate for pow1
        for(int j=0 ; j < n_pow1; j++) {

            // set seed to use same random numbers for same b's
            // This is necessary to use efficient memory
            set_seed(s);
            for(int b=0; b < n_perm; b++) {

                // Generate Score from null distribution
                Rcpp::NumericVector U00 = rnorm(k,0,1);
                arma::vec u0 = as<arma::vec>(U00);
                arma::vec U0(1);

                int SNPstart = 0;
                // iterate for chromosome
                for(int b2 = 0; b2 < n_ch ; b2++) {

                    // itreate for chromosome
                    if( b2 != 0) {
                        SNPstart = sum( nChrom0.subvec(0,b2-1) ) ;
                    }
                    int idx1 = SNPstart;
                    int idx2 = SNPstart+nChrom0(b2)-1;

                    arma::vec TT = as<arma::mat>(CHcovSq[b2])*u0.subvec(idx1, idx2) ;
                    U0 = join_cols(U0,TT) ;
                }

                arma::vec UU2 = U0.subvec(1,U0.size()-1);

                // iterate for genes
                SNPstart = 0;
                for(int iGene = 0 ; iGene < nGenes ; iGene++ ) {

                    // calculate starting and ending position of each gene from nSNPs0 vector
                    if( iGene != 0) {
                        SNPstart = sum( nSNPs0.subvec(0,iGene-1) ) ;
                    }
                    int idx1 = SNPstart;
                    int idx2 = SNPstart+nSNPs0(iGene)-1;

                    // calculate 1st level test statistic
                    if( pow1[j] > 0) {
                        arma::vec tmp1 = pow(UU2.subvec(idx1, idx2),pow1[j]);
                        double tmp2 = sum(tmp1);

                        if( tmp2 > 0 ) {
                            T0st(j*nGenes+iGene) = pow(std::abs(tmp2)/nSNPs0[iGene] , 1/pow1[j]);
                        } else {
                            T0st(j*nGenes+iGene) = -pow(std::abs(tmp2)/nSNPs0[iGene] , 1/pow1[j]);
                        }

                    } else {
                        arma::vec T0tp = abs(UU2.subvec(idx1, idx2));
                        T0st(j*nGenes+iGene) = max(abs(T0tp));
                    }
                }

                // calculate 2nd level test statistics
                if( pow2[j2] > 0) {
                    arma::vec tmp3 = pow(T0st.subvec(j*nGenes,(j+1)*nGenes-1), pow2[j2]);
                    double tmp4 = sum(tmp3);
                    T0s(b) = tmp4;
                } else {
                    T0s(b) = max( arma::abs(T0st.subvec(j*nGenes,(j+1)*nGenes-1)) ) ;
                }
            }

            // Calculate P-values
            int tmp3 = 0;
            arma::vec T0sabs = arma::abs(T0s);
            Rcpp::NumericVector a( T0sabs.begin(), T0sabs.end() );
            Rcpp::NumericVector ranka = avg_rank2(a);
            arma::vec rankarma = as<arma::vec>(ranka);

            for( int tt=0 ; tt < n_perm ; tt++) {
                if( std::abs(Ts2(j2*n_pow1 + j) ) <= std::abs(T0s(tt))) {
                    tmp3++;
                }

                P0s(tt) = (double) (n_perm - rankarma(tt) + 1) / (double) n_perm;
            }

            minp0 = P0s;

            if(j == 1) {
                for( int ii=0; ii < n_perm; ii++) {
                    minp0(ii) = P0s(ii);
                }
            } else {
                for( int ii=0; ii < n_perm; ii++) {
                    if( minp0(ii) > P0s(ii) ) {
                        minp0(ii) = P0s(ii);
                    }
                }
            }

            pPerm0(j2*n_pow1 + j) = (double) tmp3 / (double) n_perm;

        }
    }
    return Rcpp::List::create(Rcpp::Named("minp0") = minp0,
                              Rcpp::Named("pPerm0") = pPerm0,
                              Rcpp::Named("P0s") = P0s);
}


#ifndef STAN_MATH_OPENCL_DIAGONAL_MULTIPLY_HPP
#define STAN_MATH_OPENCL_DIAGONAL_MULTIPLY_HPP
#ifdef STAN_OPENCL
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/kernels/scalar_mul_diagonal.hpp>
#include <Eigen/Dense>

namespace stan {
namespace math {
/**
 * Multiplies the diagonal of a matrix on the OpenCL device with the specified
 * scalar.
 *
 * @param A input matrix
 * @param scalar scalar
 * @return copy of the input matrix with the diagonal multiplied by scalar
 */
inline matrix_cl diagonal_multiply(const matrix_cl& A, const double scalar) {
  matrix_cl B(A);
  if (B.size() == 0)
    return B;
  // For rectangular matrices
  int min_dim = B.rows();
  if (B.cols() < min_dim)
    min_dim = B.cols();
  try {
    opencl_kernels::scalar_mul_diagonal(cl::NDRange(min_dim), B.buffer(),
                                        scalar, B.rows(), min_dim);
  } catch (const cl::Error& e) {
    check_opencl_error("diagonal_multiply", e);
  }
  return B;
}
}  // namespace math
}  // namespace stan

#endif
#endif


//---------------------------------------------------------------------------//
//!
//! \file   Utility_InverseAreaConversionPolicy.hpp
//! \author Alex Robinson
//! \brief  Policy structs that define inverse area conversions
//!
//---------------------------------------------------------------------------//

#ifndef UTILITY_INVERSE_AREA_CONVERSION_POLICY_HPP
#define UTILITY_INVERSE_AREA_CONVERSION_POLICY_HPP

// Boost Includes
#include <boost/units/systems/cgs.hpp>

// FRENSIE Includes
#include "Utility_UnitConversionPolicyDecl.hpp"

namespace Utility{

//! The inverse area dimension tag
typedef boost::units::derived_dimension<boost::units::length_base_dimension,-2>::type InverseAreaDimension;

/*! \brief Policy struct for converting between inverse square Angstroms and
 * the native inverse area unit (1/cm^2)
 */
struct InverseSquareAngstromConversionPolicy : public BaseUnitConversionPolicy<InverseSquareAngstromConversionPolicy,InverseAreaDimension>
{
  //! Inverse square Angstrom per inverse square centimeter
  static inline double conversionFactor()
  { return 1e-16; }
};

/*! \brief Policy struct for converting between inverse square cm and
 * native inverse area unit (1/cm^2)
 */
struct InverseSquareCentimeterConversionPolicy : public BaseUnitConversionPolicy<InverseSquareCentimeterConversionPolicy, InverseAreaDimension>
{
  //! Inverse square centimeter per inverse square centimeter
  static inline double conversionFactor()
  { return 1.0; }
};

} // end Utility namespace

#endif // end UTILITY_INVERSE_AREA_CONVERSION_POLICY_HPP

//---------------------------------------------------------------------------//
// end Utility_InverseAreaConversionPolicy.hpp
//---------------------------------------------------------------------------//


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

#include "mcrl2/lps/detail/test_input.h"
#include "mcrl2/lps/find.h"
#include "mcrl2/lps/is_stochastic.h"
#include "mcrl2/lps/linearise.h"
#include "mcrl2/lps/parelm.h"
#include "mcrl2/lps/parse.h"
#include "mcrl2/lps/print.h"
#include "mcrl2/lps/stochastic_specification.h"
#include <boost/test/included/unit_test_framework.hpp>

using namespace mcrl2;
using namespace mcrl2::data;
using namespace mcrl2::lps;

BOOST_AUTO_TEST_CASE(test_empty_distribution)
{
  stochastic_distribution dist;
  std::cout << "empty dist = " << dist << std::endl;
  BOOST_CHECK(!dist.is_defined());
}

BOOST_AUTO_TEST_CASE(test_remove_stochastic_operators)
{
  std::string text =
    "act a;\n"
    "proc P = a.P;\n"
    "init P;"
    ;

  stochastic_specification src;
  parse_lps(text, src);
  BOOST_CHECK(!is_stochastic(src));

  specification dest = remove_stochastic_operators(src);
  std::cout << "dest = " << dest;
  BOOST_CHECK(lps::pp(src) == lps::pp(dest));
}

BOOST_AUTO_TEST_CASE(test_is_stochastic)
{
  std::string text =
    "act  throw: Bool;                       \n"
    "                                        \n"
    "proc P = dist b:Bool[1/2].throw(b) . P; \n"
    "                                        \n"
    "init P;                                 \n"
    ;
  stochastic_specification spec;
  parse_lps(text, spec);
  BOOST_CHECK(is_stochastic(spec));

  text =
    "act  throw: Bool;         \n"
    "                          \n"
    "proc P = throw(true) . P; \n"
    "                          \n"
    "init dist b:Bool[1/2] . P;\n"
    ;
  parse_lps(text, spec);
  BOOST_CHECK(is_stochastic(spec));
}

BOOST_AUTO_TEST_CASE(test_print)
{
  std::string text =
    "act  a: Bool;\n"
    "\n"
    "proc P(s3: Pos, p: Bool) =\n"
    "       (s3 == 1) ->\n"
    "         a(p) .\n"
    "         dist p: Bool[1 / 2] .\n"
    "         P(s3 = 2, p = true)\n"
    "     + delta;\n"
    "\n"
    "init dist p: Bool[1 / 2] . P(1, true);\n"
    ;
  stochastic_specification spec;
  parse_lps(text, spec);
  std::string result = lps::pp(spec);
  BOOST_CHECK_EQUAL(text, result);
}

// The following specification did not linearise, due to an infinite loop.
BOOST_AUTO_TEST_CASE(test_linearisation)
{
  std::string text =
    "act a:Bool;\n"
    "proc X=dist b:Bool[1/2].a(b).X;\n"
    "init X;\n"
    ;

  std::string result =
    "act  a: Bool;\n"
    "\n"
    "proc P(b1_X: Bool) =\n"
    "       a(b1_X) .\n"
    "         dist b1_X1: Bool[1 / 2] .\n"
    "         P(b1_X = b1_X1);\n"
    "\n"
    "init dist b1: Bool[1 / 2] . P(b1);\n"
    ;

  stochastic_specification spec=linearise(text);
  BOOST_CHECK_EQUAL(lps::pp(spec),result);
}

// This test checks whether multiple parameters in a stochastic operator are translated
// correctely.
BOOST_AUTO_TEST_CASE(test_multiple_stochastic_parameters)
{
  std::string text =
    "act a:Bool#Bool;\n"
    "proc X=dist b1,b2:Bool[if(b1,1/8,3/8)].a(b1,b2).X;\n"
    "init X;\n"
    ;

  std::string result =
    "act  a: Bool # Bool;\n"
    "\n"
    "proc P(b3_X,b4_X: Bool) =\n"
    "       a(b3_X, b4_X) .\n"
    "         dist b3_X1,b4_X1: Bool[if(b3_X1, 1 / 8, 3 / 8)] .\n"
    "         P(b3_X = b3_X1, b4_X = b4_X1);\n"
    "\n"
    "init dist b3,b4: Bool[if(b3, 1 / 8, 3 / 8)] . P(b3, b4);\n"
    ;

  stochastic_specification spec=linearise(text);
  BOOST_CHECK_EQUAL(lps::pp(spec),result);
}

// This test checks whether the outward distribution of dist operators is going
// correctely.
BOOST_AUTO_TEST_CASE(test_push_dist_outward)
{
  std::string text =
    "sort Coin = struct head_ | tail_;\n"
    "\n"
    "act throw:Coin;\n"
    "    success;\n"
    "\n"
    "proc X(head_seen:Bool) =  dist c:Coin[1/2].throw(c).\n"
    "                           ((c==head_ && head_seen) -> success.delta+\n"
    "                            (c==head_ && !head_seen) -> X(true)+\n"
    "                            (c==tail_) -> X(false));\n"
    "\n"
    "init X(false);\n"
    ;

  stochastic_specification spec=linearise(text);
}

BOOST_AUTO_TEST_CASE(test_parelm)
{
  stochastic_specification spec = linearise(lps::detail::ABP_SPECIFICATION());
  std::set<data::variable> v = lps::find_all_variables(spec);
  parelm(spec);
}

boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[])
{
  return nullptr;
}


/*
 *          Copyright Andrey Semashev 2007 - 2010.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   counter.hpp
 * \author Andrey Semashev
 * \date   01.05.2007
 *
 * The header contains implementation of the counter attribute.
 */

#if (defined(_MSC_VER) && _MSC_VER > 1000)
#pragma once
#endif // _MSC_VER > 1000

#ifndef BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_
#define BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/log/detail/prologue.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/basic_attribute_value.hpp>
#ifndef BOOST_LOG_NO_THREADS
#include <boost/detail/atomic_count.hpp>
#endif // BOOST_LOG_NO_THREADS

namespace boost {

namespace BOOST_LOG_NAMESPACE {

namespace attributes {

/*!
 * \class counter
 * \brief A class of an attribute that counts an integral value
 *
 * This type of attribute acts as a counter, that is, it returns a monotonously
 * changing value each time requested. The attribute value type can be specified
 * as a template parameter. However, the type must support basic arithmetic
 * operations, such as addition and substraction.
 */

#ifndef BOOST_LOG_NO_THREADS

template< typename T >
class counter :
    public attribute
{
public:
    //! A held counter type
    typedef T held_type;

private:
    //! Counter value type
    typedef basic_attribute_value< held_type > counter_value;

private:
    //! Initial value
    const held_type m_InitialValue;
    //! Step value
    const long m_Step;
    //! The counter
    boost::detail::atomic_count m_Counter;

public:
    /*!
     * Constructor
     *
     * \param initial Initial value of the counter
     * \param step Changing step of the counter. Each value acquired from the attribute
     *        will be greater than the previous one to this amount.
     */
    explicit counter(held_type const& initial = held_type(), long step = 1) :
        m_InitialValue(initial), m_Step(step), m_Counter(1)
    {
    }

    shared_ptr< attribute_value > get_value()
    {
        // TODO: a full featured atomic would do better here
        register long NextValue = --m_Counter;
        return boost::make_shared< counter_value >(m_InitialValue - static_cast< held_type >(NextValue * m_Step));
    }
};

#else // BOOST_LOG_NO_THREADS

template< typename T >
class counter :
    public attribute
{
public:
    //! A held counter type
    typedef T held_type;

private:
    //! Counter value type
    typedef basic_attribute_value< held_type > counter_value;

private:
    //! Counter value
    held_type m_Value;
    //! Step value
    const held_type m_Step;

public:
    /*!
     * Constructor
     *
     * \param initial Initial value of the counter
     * \param step Changing step of the counter. Each value acquired from the attribute
     *        will be greater than the previous one to this amount.
     */
    explicit counter(held_type const& initial = held_type(), long step = 1) :
        m_Value(initial), m_Step(step)
    {
    }

    shared_ptr< attribute_value > get_value()
    {
        m_Value += static_cast< held_type >(m_Step);
        return boost::make_shared< counter_value >(m_Value);
    }
};

#endif // BOOST_LOG_NO_THREADS

} // namespace attributes

} // namespace log

} // namespace boost

#endif // BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_


#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
  boost::gregorian::date d1(2009, 1, 30);
  boost::gregorian::date d2(2009, 10, 31);
  boost::gregorian::date_period dp(d1, d2);
  std::cout << dp.contains(d1) << std::endl;
  std::cout << dp.contains(d2) << std::endl;
}

Boost/The Boost C++ Libraries/src/10.2.8/main.cpp


#include <moja/hash.h>
#include <moja/types.h>

#include <boost/test/unit_test.hpp>

#include <unordered_map>

BOOST_AUTO_TEST_SUITE(HashingTests);

using namespace moja::hash;

BOOST_AUTO_TEST_CASE(core_hashing_TwangMix64) {
   moja::UInt64 i1 = 0x78a87873e2d31dafULL;
   moja::UInt64 i1_res = 3389151152926383528ULL;
   BOOST_CHECK_EQUAL(i1_res, twang_mix64(i1));
   BOOST_CHECK_EQUAL(i1, twang_unmix64(i1_res));

   moja::UInt64 i2 = 0x0123456789abcdefULL;
   moja::UInt64 i2_res = 3061460455458984563ull;
   BOOST_CHECK_EQUAL(i2_res, twang_mix64(i2));
   BOOST_CHECK_EQUAL(i2, twang_unmix64(i2_res));
}

namespace {
void checkTWang(uint64_t r) {
   moja::UInt64 result = twang_mix64(r);
   BOOST_CHECK_EQUAL(r, twang_unmix64(result));
}
}  // namespace

BOOST_AUTO_TEST_CASE(core_hashing_TwangUnmix64) {
   // We'll try (1 << i), (1 << i) + 1, (1 << i) - 1
   for (int i = 1; i < 64; i++) {
      checkTWang((1U << i) - 1);
      checkTWang(1U << i);
      checkTWang((1U << i) + 1);
   }
}

BOOST_AUTO_TEST_CASE(core_hashing_JenkinsRevMix32) {
   moja::UInt32 i1 = 3805486511ul;
   moja::UInt32 i1_res = 381808021ul;
   BOOST_CHECK_EQUAL(i1_res, jenkins_rev_mix32(i1));
   BOOST_CHECK_EQUAL(i1, jenkins_rev_unmix32(i1_res));

   moja::UInt32 i2 = 2309737967ul;
   moja::UInt32 i2_res = 1834777923ul;
   BOOST_CHECK_EQUAL(i2_res, jenkins_rev_mix32(i2));
   BOOST_CHECK_EQUAL(i2, jenkins_rev_unmix32(i2_res));
}

namespace {
void checkJenkins(moja::UInt32 r) {
   moja::UInt32 result = jenkins_rev_mix32(r);
   BOOST_CHECK_EQUAL(r, jenkins_rev_unmix32(result));
}
}  // namespace

BOOST_AUTO_TEST_CASE(core_hashing_JenkinsRevUnmix32) {
   // We'll try (1 << i), (1 << i) + 1, (1 << i) - 1
   for (int i = 1; i < 32; i++) {
      checkJenkins((1U << i) - 1);
      checkJenkins(1U << i);
      checkJenkins((1U << i) + 1);
   }
}

BOOST_AUTO_TEST_CASE(core_hashing_Hasher) {
   // Basically just confirms that things compile ok.
   std::unordered_map<moja::Int32, moja::Int32, moja::hasher<moja::Int32>> m;
   m.insert(std::make_pair(4, 5));
   BOOST_CHECK_EQUAL(m[4], 5);
}

// Not a full hasher since only handles one type.
class TestHasher {
  public:
   //	static size_t hash(const std::pair<int, int>& p) {
   // return p.first + p.second;
   //}
   size_t operator()(const std::pair<int, int>& p) const { return p.first + p.second; }
};

template <typename T, typename... Ts>
size_t hashCombineTest(const T& t, const Ts&... ts) {
   return hash_combine_generic(TestHasher{}, t, ts...);
}

BOOST_AUTO_TEST_CASE(core_hashing_Pair) {
   auto a = std::make_pair(1, 2);
   auto b = std::make_pair(3, 4);
   auto c = std::make_pair(1, 2);
   auto d = std::make_pair(2, 1);
   BOOST_CHECK_EQUAL(hash_combine(a), hash_combine(c));
   BOOST_CHECK_NE(hash_combine(b), hash_combine(c));
   BOOST_CHECK_NE(hash_combine(d), hash_combine(c));

   // With composition
   BOOST_CHECK_EQUAL(hash_combine(a, b), hash_combine(c, b));
   // Test order dependence
   BOOST_CHECK_NE(hash_combine(a, b), hash_combine(b, a));

   // Test with custom hasher
   BOOST_CHECK_EQUAL(hashCombineTest(a), hashCombineTest(c));
   // 3 + 4 != 1 + 2
   BOOST_CHECK_NE(hashCombineTest(b), hashCombineTest(c));
   // This time, thanks to a terrible hash function, these are equal
   BOOST_CHECK_EQUAL(hashCombineTest(d), hashCombineTest(c));
   // With composition
   BOOST_CHECK_EQUAL(hashCombineTest(a, b), hashCombineTest(c, b));
   // Test order dependence
   BOOST_CHECK_NE(hashCombineTest(a, b), hashCombineTest(b, a));
   // Again, 1 + 2 == 2 + 1
   BOOST_CHECK_EQUAL(hashCombineTest(a, b), hashCombineTest(d, b));
}

BOOST_AUTO_TEST_CASE(core_hashing_HashCombine) { BOOST_CHECK_NE(hash_combine(1, 2), hash_combine(2, 1)); }

BOOST_AUTO_TEST_CASE(core_hashing_Std_Tuple) {
   typedef std::tuple<int64_t, std::string, int32_t> tuple3;
   tuple3 t(42, "foo", 1);

   std::unordered_map<tuple3, std::string, moja::Hash> m;
   m[t] = "bar";
   BOOST_CHECK_EQUAL("bar", m[t]);
}

BOOST_AUTO_TEST_CASE(core_hashing_Enum_Type) {
   const auto hash = moja::Hash();

   enum class Enum32 : moja::Int32 { Foo, Bar };
   BOOST_CHECK_EQUAL(hash(static_cast<moja::Int32>(Enum32::Foo)), hash(Enum32::Foo));
   BOOST_CHECK_EQUAL(hash(static_cast<moja::Int32>(Enum32::Bar)), hash(Enum32::Bar));
   BOOST_CHECK_NE(hash(Enum32::Foo), hash(Enum32::Bar));

   std::unordered_map<Enum32, std::string, moja::Hash> m32;
   m32[Enum32::Foo] = "foo";
   BOOST_CHECK_EQUAL("foo", m32[Enum32::Foo]);

   enum class Enum64 : moja::Int64 { Foo, Bar };
   BOOST_CHECK_EQUAL(hash(static_cast<moja::Int64>(Enum64::Foo)), hash(Enum64::Foo));
   BOOST_CHECK_EQUAL(hash(static_cast<moja::Int64>(Enum64::Bar)), hash(Enum64::Bar));
   BOOST_CHECK_NE(hash(Enum64::Foo), hash(Enum64::Bar));

   std::unordered_map<Enum64, std::string, moja::Hash> m64;
   m64[Enum64::Foo] = "foo";
   BOOST_CHECK_EQUAL("foo", m64[Enum64::Foo]);
}

BOOST_AUTO_TEST_CASE(core_hashing_Pair_Moja_Hash) {
   typedef std::pair<moja::Int64, moja::Int32> pair2;
   pair2 p(42, 1);

   std::unordered_map<pair2, std::string, moja::Hash> m;
   m[p] = "bar";
   BOOST_CHECK_EQUAL("bar", m[p]);
}

BOOST_AUTO_TEST_CASE(core_hashing_Tuple_Moja_Hash) {
   typedef std::tuple<moja::Int64, moja::Int32, moja::Int32> tuple3;
   tuple3 t(42, 1, 1);

   std::unordered_map<tuple3, std::string, moja::Hash> m;
   m[t] = "bar";
   BOOST_CHECK_EQUAL("bar", m[t]);
}

namespace {
template <class T>
size_t hash_vector(const std::vector<T>& v) {
   return hash_range(v.begin(), v.end());
}
}  // namespace

BOOST_AUTO_TEST_CASE(core_hashing_HashRange) {
   // Not true at on windows:
   // BOOST_CHECK_EQUAL(hashVector<moja::Int32>({ 1, 2 }), hashVector<moja::Int16>({ 1, 2 }));
   BOOST_CHECK_NE(hash_vector<int>({2, 1}), hash_vector<int>({1, 2}));
   BOOST_CHECK_EQUAL(hash_vector<int>({}), hash_vector<float>({}));
}

BOOST_AUTO_TEST_CASE(core_hashing_Std_Tuple_Different_Hash) {
   typedef std::tuple<moja::Int64, std::string, moja::Int32> tuple3;
   tuple3 t1(42, "foo", 1);
   tuple3 t2(9, "bar", 3);
   tuple3 t3(42, "foo", 3);

   BOOST_CHECK_NE(std::hash<tuple3>()(t1), std::hash<tuple3>()(t2));
   BOOST_CHECK_NE(std::hash<tuple3>()(t1), std::hash<tuple3>()(t3));
}

BOOST_AUTO_TEST_CASE(core_hashing_Strings) {
   using namespace moja;

   std::string a1 = "10050517", b1 = "51107032", a2 = "10050518", b2 = "51107033", a3 = "10050519", b3 = "51107034",
               a4 = "10050525", b4 = "51107040";

   folly::Hash hash;
   BOOST_CHECK_EQUAL(hash(a1), hash(a1));
   BOOST_CHECK_EQUAL(hash(a2), hash(a2));
   BOOST_CHECK_EQUAL(hash(a3), hash(a3));
   BOOST_CHECK_EQUAL(hash(a4), hash(a4));

   BOOST_CHECK_NE(hash(a1), hash(b1));
   BOOST_CHECK_NE(hash(a2), hash(b2));
   BOOST_CHECK_NE(hash(a3), hash(b3));
   BOOST_CHECK_NE(hash(a4), hash(b4));
}

BOOST_AUTO_TEST_SUITE_END();


// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// 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/.

#include "main.h"

#include <Eigen/CXX11/Tensor>

static void test_default()
{
  Tensor<float, 1> vec(6);
  vec.setRandom();

  // Fixme: we should check that the generated numbers follow a uniform
  // distribution instead.
  for (int i = 1; i < 6; ++i) {
    VERIFY_IS_NOT_EQUAL(vec(i), vec(i-1));
  }
}

static void test_normal()
{
  Tensor<float, 1> vec(6);
  vec.setRandom<Eigen::internal::NormalRandomGenerator<float>>();

  // Fixme: we should check that the generated numbers follow a gaussian
  // distribution instead.
  for (int i = 1; i < 6; ++i) {
    VERIFY_IS_NOT_EQUAL(vec(i), vec(i-1));
  }
}

struct MyGenerator {
  MyGenerator() { }
  MyGenerator(const MyGenerator&) { }

  // Return a random value to be used.  "element_location" is the
  // location of the entry to set in the tensor, it can typically
  // be ignored.
  int operator()(Eigen::DenseIndex element_location, Eigen::DenseIndex /*unused*/ = 0) const {
    return static_cast<int>(3 * element_location);
  }

  // Same as above but generates several numbers at a time.
  internal::packet_traits<int>::type packetOp(
      Eigen::DenseIndex packet_location, Eigen::DenseIndex /*unused*/ = 0) const {
    const int packetSize = internal::packet_traits<int>::size;
    EIGEN_ALIGN_MAX int values[packetSize];
    for (int i = 0; i < packetSize; ++i) {
      values[i] = static_cast<int>(3 * (packet_location + i));
    }
    return internal::pload<typename internal::packet_traits<int>::type>(values);
  }
};

static void test_custom()
{
  Tensor<int, 1> vec(6);
  vec.setRandom<MyGenerator>();

  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(vec(i), 3*i);
  }
}

void test_cxx11_tensor_random()
{
  CALL_SUBTEST(test_default());
  CALL_SUBTEST(test_normal());
  CALL_SUBTEST(test_custom());
}


// Copyright Abel Sinkovics (abel@sinkovics.hu) 2013.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include "same_map.hpp"
#include "common.hpp"

#include <mpllibs/metamonad/pair.hpp>

#include <boost/test/unit_test.hpp>

#include <boost/mpl/map.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/assert.hpp>

BOOST_AUTO_TEST_CASE(test_same_map)
{
  using mpllibs::metamonad::pair;

  using boost::mpl::insert;
  using boost::mpl::map;

  // test_different_map
  BOOST_MPL_ASSERT((
    not_same_map<
      map<pair<int1, int13>, pair<int2, int4> >,
      map<pair<int2, int4>, pair<int13, int13> >
    >
  ));

  // test_smaller_map
  BOOST_MPL_ASSERT((
    not_same_map<
      map<pair<int1, int13>, pair<int2, int4> >,
      map<pair<int2, int4> >
    >
  ));

  // test_bigger_map
  BOOST_MPL_ASSERT((
    not_same_map<
      map<pair<int1, int13> >,
      map<pair<int2, int4>, pair<int1, int4> >
    >
  ));

  // test_same_map
  BOOST_MPL_ASSERT((
    same_map<
      map<pair<int1, int13>, pair<int2, int4> >,
      map<pair<int2, int4>, pair<int1, int13> >
    >
  ));

  // test_same_map_after_insert
  BOOST_MPL_ASSERT((
    same_map<map<pair<int1, int13> >, insert<map<>, pair<int1, int13> >::type>
  ));
}


#define BOOST_TEST_MODULE ls_solver_unit_tests

#include <boost/test/included/unit_test.hpp>
#include <armadillo>
#include "../src/analytical/linear/ls_solver.h"
#include "test_utils.cpp"
#include "../src/logging/easylogging++.h"

INITIALIZE_EASYLOGGINGPP

LSSolver solver;

BOOST_AUTO_TEST_CASE(test_common_cases)
{
    auto tester = SolverTester<LSSolver>(solver);
    tester.test_common();
}


/*
 * test_SYS_Simple.cpp
 *
 *  Created on: 2013-4-20
 *      Author: fasiondog
 */

#ifdef TEST_ALL_IN_ONE
    #include <boost/test/unit_test.hpp>
#else
    #define BOOST_TEST_MODULE test_hikyuu_trade_sys_suite
    #include <boost/test/unit_test.hpp>
#endif

#include <hikyuu/StockManager.h>
#include <hikyuu/trade_manage/crt/crtTM.h>
#include <hikyuu/trade_sys/portfolio/crt/PF_Simple.h>
#include <hikyuu/trade_sys/selector/crt/SE_Fixed.h>
#include <hikyuu/trade_sys/allocatefunds/crt/AF_EqualWeight.h>

#include <hikyuu/trade_sys/system/crt/SYS_Simple.h>
#include <hikyuu/trade_sys/signal/crt/SG_CrossGold.h>
#include <hikyuu/trade_sys/moneymanager/crt/MM_FixedCount.h>
#include <hikyuu/indicator/crt/EMA.h>

using namespace hku;

/**
 * @defgroup test_Portfolio test_Portfolio
 * @ingroup test_hikyuu_trade_sys_suite
 * @{
 */

/** @par 检测点 全部为delay模式系统实例，不调整持仓*/
BOOST_AUTO_TEST_CASE( test_PF_for_delay_and_no_adjust) {
    StockManager& sm = StockManager::instance();

    SYSPtr sys = SYS_Simple();
    sys->setSG(SG_CrossGold(OP(EMA(12)), OP(EMA(26))));
    sys->setMM(MM_FixedCount(100));
    SYSPtr pro_sys = sys->clone(false, false);

    TMPtr tm = crtTM(Datetime(199001010000L), 500000);
    SEPtr se = SE_Fixed();
    AFPtr af = AF_EqualWeight();
    PFPtr pf = PF_Simple(tm, se, af);

    KQuery query = KQueryByDate(Datetime(201101010000L), Null<Datetime>(),
                               KQuery::DAY);

    /** @arg */
    sys->setTM(tm->clone());
    sys->run(sm["sz000001"], query);
    sys->getTM()->tocsv(sm.tmpdir());

    se->addStock(sm["sz000001"], pro_sys);
    pf->run(query);
    tm->name("PF");
    tm->tocsv(sm.tmpdir());

    TradeRecordList tr1 = sys->getTM()->getTradeList();
    TradeRecordList tr2 = tm->getTradeList();
    BOOST_CHECK(tr1.size() == tr2.size());

    std::cout << tr1.size() << std::endl;
    std::cout << tr2.size() << std::endl;

}

/** @} */


//          Copyright Carl Philipp Reh 2009 - 2016.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#ifndef FCPPT_MPL_MAX_VALUE_HPP_INCLUDED
#define FCPPT_MPL_MAX_VALUE_HPP_INCLUDED

#include <fcppt/preprocessor/disable_gcc_warning.hpp>
#include <fcppt/preprocessor/pop_warning.hpp>
#include <fcppt/preprocessor/push_warning.hpp>
#include <fcppt/config/external_begin.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/max_element.hpp>
#include <boost/mpl/transform.hpp>
#include <fcppt/config/external_end.hpp>

namespace fcppt
{
namespace mpl
{

FCPPT_PP_PUSH_WARNING
FCPPT_PP_DISABLE_GCC_WARNING(-Weffc++)

/**
\brief Calculates the maximum value in a sequence using a metafunction

\ingroup fcpptmpl

Calculates the maximum value in \a Sequence according to \a MetaFunction. \a
MetaFunction will be invoked on every type in \a Sequence and the maximum value
of them will be returned.

\snippet mpl/various.cpp mpl_max_value

\tparam Sequence An MPL sequence

\tparam MetaFunction A metafunction transforming every type in the sequence
into an MPL integral constant
*/
template<
	typename Sequence,
	typename MetaFunction
>
struct max_value
:
boost::mpl::deref<
	typename boost::mpl::max_element<
		typename boost::mpl::transform<
			Sequence,
			MetaFunction
		>::type
	>::type
>::type
{
};

FCPPT_PP_POP_WARNING

}
}

#endif


/******************************************************************************
 * Copyright 2019 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

#include "../TestEnvironment.hpp"

#include <rw/loaders/WorkCellLoader.hpp>
#include <rw/math/Q.hpp>
#include <rw/math/Random.hpp>
#include <rw/models/WorkCell.hpp>
#include <rw/trajectory/Path.hpp>
#include <rw/trajectory/TrajectoryFactory.cpp>

#include <gtest/gtest.h>

#if !defined(__GNUC__) || BOOST_VERSION >= 106400 || __GNUC__ >= 7 ||                   \
    (__GNUC__ == 6 && __GNUC_MINOR__ >= 1) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 4) || \
    (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 && __GNUC_PATCHLEVEL__ >= 4)
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <sstream>
#endif

using namespace rw::math;
using namespace rw::models;
using namespace rw::kinematics;
using namespace rw::loaders;
using namespace rw::trajectory;
using rw::trajectory::QPath;

TEST (BoostSerialization, Path)
{
    QPath path (5);

    for (std::size_t i = 0; i < path.size (); ++i) {
        std::size_t size = Random::ranI (2, 15);
        path[i]          = Q (size);

        for (std::size_t k = 0; k < size; ++k) {
            path[i][k] = Random::ran (-10, 10);
        }
    }
    EXPECT_EQ (std::size_t (5), path.size ());

#if !defined(__GNUC__) || BOOST_VERSION >= 106400 || __GNUC__ >= 7 ||                   \
    (__GNUC__ == 6 && __GNUC_MINOR__ >= 1) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 4) || \
    (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 && __GNUC_PATCHLEVEL__ >= 4)
    std::stringstream stream;
    boost::archive::text_oarchive oa (stream);
    oa << path;

    // Use boost to load class data
    boost::archive::text_iarchive ia (stream);
    QPath loadedpath;
    ia >> loadedpath;

    EXPECT_EQ (path.size (), loadedpath.size ());
    for (std::size_t i = 0; i < std::min (path.size (), loadedpath.size ()); ++i) {
        EXPECT_EQ (path[i], loadedpath[i]);
    }
#endif
}
TEST (PathTest, simpleQPath)
{
    QPath path;
    Q q (7);
    q (0) = 1;
    path.push_back (q);
    q (0) = 2;
    path.push_back (q);
    q (0) = 3;
    path.push_back (q);
    int index = 1;
    for (Q q : path) {
        EXPECT_EQ (q (0), index);
        index++;
    }
}

TEST (PathTest, simpleTransform3DPath)
{
    Transform3DPath path;
    Transform3D<> t;
    t (0, 0) = 1;
    path.push_back (t);
    t (0, 0) = 2;
    path.push_back (t);
    t (0, 0) = 3;
    path.push_back (t);

    int index = 1;
    for (Transform3D< double > t : path) {
        EXPECT_EQ (t (0, 0), index);
        index++;
    }
}
TEST (PathTest, simpleStatePath)
{
    StatePath statepath;
    WorkCell::Ptr workcell = WorkCellLoader::Factory::load (TestEnvironment::testfilesDir () +
                                                            "MultiRobotDemo/Scene.wc.xml");
    EXPECT_FALSE (workcell.isNull ());
    Device::Ptr dev      = workcell->getDevices ().front ();
    const State defstate = workcell->getDefaultState ();

    // Test StatePath and the possibility of creating
    {
        StatePath statepath;
        State state = defstate;

        statepath.push_back (state);
        Q q = dev->getQ (state);
        for (size_t i = 0; i < q.size (); i++)
            q (i) = 0.5;
        dev->setQ (q, state);
        statepath.push_back (state);
        for (size_t i = 0; i < q.size (); i++)
            q (i) = -1;
        dev->setQ (q, state);
        statepath.push_back (state);

        StateTrajectory::Ptr statetrajectory =
            TrajectoryFactory::makeLinearTrajectoryUnitStep (statepath);
        State s0 = statetrajectory->x (0);
        q        = dev->getQ (s0);
        EXPECT_EQ (q (0), 0);

        State s05 = statetrajectory->x (0.5);
        q         = dev->getQ (s05);
        EXPECT_EQ (q (0), 0.25);

        State s1 = statetrajectory->x (1);
        q        = dev->getQ (s1);
        EXPECT_EQ (q (0), 0.5);

        State s15 = statetrajectory->x (1.5);
        q         = dev->getQ (s15);
        std::cout << "q = " << q << std::endl;
        EXPECT_EQ (q (0), -0.25);

        State s2 = statetrajectory->x (2);
        q        = dev->getQ (s2);
        EXPECT_EQ (q (0), -1);
    }

    // Test StatePath and the possibility of creating
    {
        TimedStatePath timedStatePath;
        WorkCell::Ptr workcell = WorkCellLoader::Factory::load (TestEnvironment::testfilesDir () +
                                                                "MultiRobotDemo/Scene.wc.xml");
        EXPECT_FALSE (workcell.isNull ());

        Device::Ptr dev = workcell->getDevices ().front ();
        State state     = workcell->getDefaultState ();
        timedStatePath.push_back (Timed< State > (0, state));

        Q q = dev->getQ (state);
        for (size_t i = 0; i < q.size (); i++)
            q (i) = 0.5;
        dev->setQ (q, state);
        timedStatePath.push_back (Timed< State > (12, state));

        for (size_t i = 0; i < q.size (); i++)
            q (i) = -1;
        dev->setQ (q, state);
        timedStatePath.push_back (Timed< State > (24, state));

        StateTrajectory::Ptr statetrajectory =
            TrajectoryFactory::makeLinearTrajectory (timedStatePath);
        State s0 = statetrajectory->x (0);
        q        = dev->getQ (s0);
        std::cout << "q(0) = " << q << std::endl;
        EXPECT_EQ (q (0), 0);

        State s3 = statetrajectory->x (3);
        q        = dev->getQ (s3);
        std::cout << "q(3) = " << q << std::endl;
        EXPECT_EQ (q (0), 0.125);

        State s1 = statetrajectory->x (12);
        q        = dev->getQ (s1);
        EXPECT_EQ (q (0), 0.5);

        State s15 = statetrajectory->x (18);
        q         = dev->getQ (s15);
        std::cout << "q(18) = " << q << std::endl;
        EXPECT_EQ (q (0), -0.25);

        State s2 = statetrajectory->x (24);
        q        = dev->getQ (s2);
        EXPECT_EQ (q (0), -1);
    }
}


//==================================================================================================
/**
  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_COMMON_SCALAR_FUNCTION_SQR_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SCALAR_FUNCTION_SQR_HPP_INCLUDED

#include <boost/simd/constant/sqrtvalmax.hpp>
#include <boost/simd/constant/valmax.hpp>
#include <boost/simd/function/abs.hpp>
#include <boost/simd/function/sqr.hpp>
#include <boost/simd/function/saturated.hpp>
#include <boost/simd/detail/dispatch/function/overload.hpp>
#include <boost/config.hpp>

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

  BOOST_DISPATCH_OVERLOAD ( sqr_
                          , (typename A0)
                          , bd::cpu_
                          , bs::saturated_tag
                          , bd::scalar_< bd::int_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator()(const saturated_tag &,  A0 a0) const BOOST_NOEXCEPT
    {
      return saturated_(abs)(a0) > Sqrtvalmax<A0>() ? Valmax<A0>() : sqr(a0);
    }
  };

  BOOST_DISPATCH_OVERLOAD ( sqr_
                          , (typename A0)
                          , bd::cpu_
                          , bs::saturated_tag
                          , bd::scalar_< bd::uint_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator()(const saturated_tag &, A0 a0) const BOOST_NOEXCEPT
    {
      return a0 > Sqrtvalmax<A0>() ? Valmax<A0>() : sqr(a0);
    }
  };

  BOOST_DISPATCH_OVERLOAD ( sqr_
                          , (typename A0)
                          , bd::cpu_
                          , bs::saturated_tag
                          , bd::scalar_< bd::floating_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() (const saturated_tag &, A0 a0) const BOOST_NOEXCEPT
    {
      return sqr(a0);
    }
  };

   BOOST_DISPATCH_OVERLOAD ( sqr_
                          , (typename A0)
                          , bd::cpu_
                          , bd::scalar_< bd::arithmetic_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( A0  a0) const BOOST_NOEXCEPT
    {
      return a0*a0;
    }
  };
} } }

#endif


// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// 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/.
#include "unproject.h"
#include "model_proj_viewport.h"
#include "../unproject.h"
#include "gl.h"

#include <Eigen/Dense>
#include <Eigen/LU>

IGL_INLINE void igl::opengl2::unproject(
  const double winX,
  const double winY,
  const double winZ,
  double* objX,
  double* objY,
  double* objZ)
{
  Eigen::Vector3d obj;
  igl::opengl2::unproject(Eigen::Vector3d(winX,winY,winZ),obj);
  *objX = obj(0);
  *objY = obj(1);
  *objZ = obj(2);
}

template <typename Derivedwin, typename Derivedobj>
IGL_INLINE void igl::opengl2::unproject(
  const Eigen::PlainObjectBase<Derivedwin> & win,
  Eigen::PlainObjectBase<Derivedobj> & obj)
{
  const auto ret = igl::opengl2::unproject(win);
  obj = ret.template cast<typename Derivedobj::Scalar>();
}

template <typename Derivedwin>
IGL_INLINE Derivedwin igl::opengl2::unproject(
  const Eigen::PlainObjectBase<Derivedwin> & win)
{
  using namespace Eigen;
  typedef typename Derivedwin::Scalar Scalar;
  Matrix4d MV,P;
  Vector4d VPd;
  model_proj_viewport(MV,P,VPd);
  Vector3d wind = win.template cast<double>();
  Vector3d objd = igl::unproject(wind,MV,P,VPd);
  return objd.template cast<Scalar>();
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::opengl2::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
template void igl::opengl2::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
template Eigen::Matrix<float, 3, 1, 0, 3, 1> igl::opengl2::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::opengl2::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
template void igl::opengl2::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
#endif


//  (C) Copyright Jeremy Siek 2002.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/pending/disjoint_sets.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/cstdlib.hpp>

template < typename DisjointSet > struct test_disjoint_set
{
    static void do_test()
    {
        // The following tests are pretty lame, just a basic sanity check.
        // Industrial strength tests still need to be written.

#if !defined(__MWERKS__) || __MWERKS__ > 0x3003
        std::size_t elts[]
#else
        std::size_t elts[4]
#endif
            = { 0, 1, 2, 3 };

        const int N = sizeof(elts) / sizeof(*elts);

        DisjointSet ds(N);

        ds.make_set(elts[0]);
        ds.make_set(elts[1]);
        ds.make_set(elts[2]);
        ds.make_set(elts[3]);

        BOOST_TEST(ds.find_set(0) != ds.find_set(1));
        BOOST_TEST(ds.find_set(0) != ds.find_set(2));
        BOOST_TEST(ds.find_set(0) != ds.find_set(3));
        BOOST_TEST(ds.find_set(1) != ds.find_set(2));
        BOOST_TEST(ds.find_set(1) != ds.find_set(3));
        BOOST_TEST(ds.find_set(2) != ds.find_set(3));

        ds.union_set(0, 1);
        ds.union_set(2, 3);
        BOOST_TEST(ds.find_set(0) != ds.find_set(3));
        int a = ds.find_set(0);
        BOOST_TEST(a == ds.find_set(1));
        int b = ds.find_set(2);
        BOOST_TEST(b == ds.find_set(3));

        ds.link(a, b);
        BOOST_TEST(ds.find_set(a) == ds.find_set(b));
        BOOST_TEST(1 == ds.count_sets(elts, elts + N));

        ds.normalize_sets(elts, elts + N);
        ds.compress_sets(elts, elts + N);
        BOOST_TEST(1 == ds.count_sets(elts, elts + N));
    }
};

int main(int, char*[])
{
    using namespace boost;
    {
        typedef disjoint_sets_with_storage< identity_property_map,
            identity_property_map, find_with_path_halving >
            ds_type;
        test_disjoint_set< ds_type >::do_test();
    }
    {
        typedef disjoint_sets_with_storage< identity_property_map,
            identity_property_map, find_with_full_path_compression >
            ds_type;
        test_disjoint_set< ds_type >::do_test();
    }
    return boost::report_errors();
}


// Copyright (c) by respective owners including Yahoo!, Microsoft, and
// individual contributors. All rights reserved. Released under a BSD (revised)
// license as described in the file LICENSE.

#include "reductions/cb/details/large_action_space.h"
#include "test_common.h"
#include "vw/core/rand48.h"
#include "vw/core/rand_state.h"
#include "vw/core/reductions/cb/cb_explore_adf_common.h"
#include "vw/core/reductions/cb/cb_explore_adf_large_action_space.h"
#include "vw/core/vw.h"

#include <boost/test/unit_test.hpp>

using internal_action_space =
    VW::cb_explore_adf::cb_explore_adf_base<VW::cb_explore_adf::cb_explore_adf_large_action_space>;

void check_matrix_multiplication(
    VW::workspace& vw, internal_action_space* action_space, const VW::multi_ex& examples, uint64_t d)
{
  // assuming no shared features or interactions at this point since doing manual calculations by re-using the raw
  // unprocessed example

  auto num_actions = examples.size();
  // gather the feature indexes

  for (size_t action_index = 0; action_index < num_actions; action_index++)
  {
    auto* ex = examples[action_index];

    std::vector<feature_index> ft_indexes;
    // test sanity - test assumes no shared features
    BOOST_CHECK_EQUAL(!CB::ec_is_example_header(*ex), true);
    for (auto ns : ex->indices)
    {
      for (auto ft_index : ex->feature_space[ns].indices) { ft_indexes.push_back(ft_index); }
    }

    std::vector<weight> ft_weights;
    for (auto ft_index : ft_indexes) { ft_weights.push_back(vw.weights.dense_weights[ft_index]); }

    uint64_t seed = vw.get_random_state()->get_current_state();

    // checking the multiplication of matrix A of vw action weights dim(#actions x #features) which is a sparse
    // matrix, with the random matrix with Gaussian entries of dim(#features x d)
    for (uint64_t gaussian_col = 0; gaussian_col < d; gaussian_col++)
    {
      float dot_product = 0;
      for (auto ft_index : ft_indexes)
      {
        auto gaussian_row = ft_index;
        auto combined_index = gaussian_row + gaussian_col + seed;
        auto lazyg_cell = merand48_boxmuller(combined_index);
        auto Action_matrix_cell_weight = vw.weights.dense_weights[ft_index];
        dot_product += Action_matrix_cell_weight * lazyg_cell;
      }
      BOOST_CHECK_EQUAL(dot_product, action_space->explore.Q(action_index, gaussian_col));
    }
  }
}

BOOST_AUTO_TEST_CASE(creation_of_Q_with_lazy_gaussian)
{
  auto d = 2;
  auto& vw = *VW::initialize("--cb_explore_adf --large_action_space --max_actions " + std::to_string(d) + " --quiet",
      nullptr, false, nullptr, nullptr);

  {
    VW::multi_ex examples;

    examples.push_back(VW::read_example(vw, "0:1.0:0.5 | 1 2 3"));

    vw.learn(examples);
  }

  std::vector<std::string> e_r;
  vw.l->get_enabled_reductions(e_r);
  if (std::find(e_r.begin(), e_r.end(), "cb_explore_adf_large_action_space") == e_r.end())
  { BOOST_FAIL("cb_explore_adf_large_action_space not found in enabled reductions"); }

  VW::LEARNER::multi_learner* learner =
      as_multiline(vw.l->get_learner_by_name_prefix("cb_explore_adf_large_action_space"));

  auto action_space = (internal_action_space*)learner->get_internal_type_erased_data_pointer_test_use_only();

  BOOST_CHECK_EQUAL(action_space != nullptr, true);

  {
    VW::multi_ex examples;

    examples.push_back(VW::read_example(vw, "0:1.0:0.5 | 1 2 3"));

    vw.predict(examples);

    action_space->explore.generate_Q(examples);

    check_matrix_multiplication(vw, action_space, examples, d);

    // check that feature values do not affect the matrix manipulation as they are not part of it
    // push new example but since we did not run predict, Q should be the same
    examples.clear();
    examples.push_back(VW::read_example(vw, "0:1.0:0.5 | 1:100 2:100 3:100"));
    check_matrix_multiplication(vw, action_space, examples, d);
  }
}


/****************************************************************************
 * Copyright (c) 2021 by the Picasso authors                                *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the Picasso library. Picasso is distributed under a *
 * BSD 3-clause license. For the licensing terms see the LICENSE file in    *
 * the top-level directory.                                                 *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#ifndef PICASSO_ADAPTIVEMESH_HPP
#define PICASSO_ADAPTIVEMESH_HPP

#include <Cajita.hpp>

#include <Kokkos_Core.hpp>

#include <boost/property_tree/ptree.hpp>

#include <memory>

#include <mpi.h>

namespace Picasso
{
//---------------------------------------------------------------------------//
/*!
  \class AdaptiveMesh
  \brief Logically uniform Cartesian mesh with adaptive node locations.
 */
template <class MemorySpace>
class AdaptiveMesh
{
  public:
    using cajita_mesh = Cajita::UniformMesh<double>;

    using memory_space = MemorySpace;

    using local_grid = Cajita::LocalGrid<cajita_mesh>;

    using node_array = Cajita::Array<double, Cajita::Node,
                                     Cajita::UniformMesh<double>, MemorySpace>;

    static constexpr std::size_t num_space_dim = 3;

    // Construct an adaptive mesh from the problem bounding box and a property
    // tree.
    template <class ExecutionSpace>
    AdaptiveMesh( const boost::property_tree::ptree& ptree,
                  const Kokkos::Array<double, 6>& global_bounding_box,
                  const int minimum_halo_cell_width, MPI_Comm comm,
                  const ExecutionSpace& exec_space )
    {
        build( ptree, global_bounding_box, minimum_halo_cell_width, comm,
               exec_space );
    }

    // Constructor that uses the default ExecutionSpace for this MemorySpace.
    AdaptiveMesh( const boost::property_tree::ptree& ptree,
                  const Kokkos::Array<double, 6>& global_bounding_box,
                  const int minimum_halo_cell_width, MPI_Comm comm )
    {
        using exec_space = typename memory_space::execution_space;

        build( ptree, global_bounding_box, minimum_halo_cell_width, comm,
               exec_space{} );
    }

  private:
    template <class ExecutionSpace>
    void build( const boost::property_tree::ptree& ptree,
                const Kokkos::Array<double, 6>& global_bounding_box,
                const int minimum_halo_cell_width, MPI_Comm comm,
                const ExecutionSpace& exec_space )
    {
        _minimum_halo_width = minimum_halo_cell_width;

        // Get the mesh parameters.
        const auto& mesh_params = ptree.get_child( "mesh" );

        // Get the global number of cells and cell sizes in each direction.
        std::array<int, 3> global_num_cell;
        Kokkos::Array<double, 3> cell_size;
        if ( mesh_params.count( "cell_size" ) )
        {
            if ( mesh_params.get_child( "cell_size" ).size() != 3 )
                throw std::runtime_error(
                    "3 entries required for mesh.cell_size" );

            int d = 0;
            for ( auto& element : mesh_params.get_child( "cell_size" ) )
            {
                cell_size[d] = element.second.get_value<double>();
                global_num_cell[d] = std::rint(
                    ( global_bounding_box[d + 3] - global_bounding_box[d] ) /
                    cell_size[d] );
                ++d;
            }
        }
        else if ( mesh_params.count( "global_num_cell" ) )
        {
            if ( mesh_params.get_child( "global_num_cell" ).size() != 3 )
                throw std::runtime_error(
                    "3 entries required for mesh.global_num_cell" );

            int d = 0;
            for ( auto& element : mesh_params.get_child( "global_num_cell" ) )
            {
                global_num_cell[d] = element.second.get_value<int>();
                cell_size[d] =
                    ( global_bounding_box[d + 3] - global_bounding_box[d] ) /
                    global_num_cell[d];
                ++d;
            }
        }

        // Create global mesh.
        std::array<double, 3> global_low_corner = { 0.0, 0.0, 0.0 };
        std::array<double, 3> global_high_corner = {
            static_cast<double>( global_num_cell[0] ),
            static_cast<double>( global_num_cell[1] ),
            static_cast<double>( global_num_cell[2] ) };

        // Get the periodicity.
        std::array<bool, 3> periodic;
        {
            if ( mesh_params.get_child( "periodic" ).size() != 3 )
                throw std::runtime_error(
                    "3 entries required for mesh.periodic" );

            int d = 0;
            for ( auto& element : mesh_params.get_child( "periodic" ) )
            {
                periodic[d] = element.second.get_value<bool>();
                ++d;
            }
        }

        // For dimensions that are not periodic we pad by the minimum halo
        // cell width to allow for projections outside of the domain.
        for ( int d = 0; d < 3; ++d )
        {
            if ( !periodic[d] )
            {
                global_num_cell[d] += 2 * _minimum_halo_width;
                global_low_corner[d] -= _minimum_halo_width;
                global_high_corner[d] += _minimum_halo_width;
            }
        }

        // Create the global mesh.
        auto global_mesh = Cajita::createUniformGlobalMesh(
            global_low_corner, global_high_corner, global_num_cell );

        // Create the partitioner.
        const auto& part_params = mesh_params.get_child( "partitioner" );
        std::shared_ptr<Cajita::BlockPartitioner<3>> partitioner;
        if ( part_params.get<std::string>( "type" ).compare( "uniform_dim" ) ==
             0 )
        {
            partitioner = std::make_shared<Cajita::DimBlockPartitioner<3>>();
        }
        else if ( part_params.get<std::string>( "type" ).compare( "manual" ) ==
                  0 )
        {
            if ( part_params.get_child( "ranks_per_dim" ).size() != 3 )
                throw std::runtime_error(
                    "3 entries required for mesh.partitioner.ranks_per_dim " );

            std::array<int, 3> ranks_per_dim;
            int d = 0;
            for ( auto& element : part_params.get_child( "ranks_per_dim" ) )
            {
                ranks_per_dim[d] = element.second.get_value<int>();
                ++d;
            }
            partitioner = std::make_shared<Cajita::ManualBlockPartitioner<3>>(
                ranks_per_dim );
        }

        // Build the global grid.
        auto global_grid = Cajita::createGlobalGrid( comm, global_mesh,
                                                     periodic, *partitioner );

        // Get the halo cell width. If the user does not assign one then it is
        // assumed the minimum halo cell width will be used.
        auto halo_cell_width = std::max(
            _minimum_halo_width, mesh_params.get<int>( "halo_cell_width", 0 ) );

        // Build the local grid.
        _local_grid = Cajita::createLocalGrid( global_grid, halo_cell_width );

        // Create the nodes.
        buildNodes( cell_size, exec_space );
    }

  public:
    // Get the minimum required numober of cells in the halo.
    int minimumHaloWidth() const { return _minimum_halo_width; }

    // Get the local grid.
    std::shared_ptr<local_grid> localGrid() const { return _local_grid; }

    // Get the mesh node coordinates.
    std::shared_ptr<node_array> nodes() const { return _nodes; }

    // Build the mesh nodes.
    template <class ExecutionSpace>
    void buildNodes( const Kokkos::Array<double, 3>& cell_size,
                     const ExecutionSpace& exec_space )
    {
        // Create both owned and ghosted nodes so we don't have to gather
        // initially.
        auto node_layout =
            Cajita::createArrayLayout( _local_grid, 3, Cajita::Node() );
        _nodes = Cajita::createArray<double, MemorySpace>( "mesh_nodes",
                                                           node_layout );
        auto node_view = _nodes->view();
        auto local_mesh =
            Cajita::createLocalMesh<ExecutionSpace>( *_local_grid );
        auto local_space = _local_grid->indexSpace(
            Cajita::Ghost(), Cajita::Node(), Cajita::Local() );
        Kokkos::parallel_for(
            "Picasso::AdaptiveMesh::CreateNodes",
            Cajita::createExecutionPolicy( local_space, exec_space ),
            KOKKOS_LAMBDA( const int i, const int j, const int k ) {
                node_view( i, j, k, 0 ) =
                    local_mesh.lowCorner( Cajita::Ghost(), 0 ) +
                    i * cell_size[0];
                node_view( i, j, k, 1 ) =
                    local_mesh.lowCorner( Cajita::Ghost(), 1 ) +
                    j * cell_size[1];
                node_view( i, j, k, 2 ) =
                    local_mesh.lowCorner( Cajita::Ghost(), 2 ) +
                    k * cell_size[2];
            } );
    }

  public:
    int _minimum_halo_width;
    std::shared_ptr<local_grid> _local_grid;
    std::shared_ptr<node_array> _nodes;
};

//---------------------------------------------------------------------------//
// Static type checker.
template <class>
struct is_adaptive_mesh_impl : public std::false_type
{
};

template <class MemorySpace>
struct is_adaptive_mesh_impl<AdaptiveMesh<MemorySpace>> : public std::true_type
{
};

template <class T>
struct is_adaptive_mesh
    : public is_adaptive_mesh_impl<typename std::remove_cv<T>::type>::type
{
};

//---------------------------------------------------------------------------//
// Creation functions.
template <class MemorySpace, class ExecSpace>
auto createAdaptiveMesh( MemorySpace, const boost::property_tree::ptree& ptree,
                         const Kokkos::Array<double, 6>& global_bounding_box,
                         const int minimum_halo_cell_width, MPI_Comm comm,
                         ExecSpace exec_space )
{
    return std::make_shared<AdaptiveMesh<MemorySpace>>(
        ptree, global_bounding_box, minimum_halo_cell_width, comm, exec_space );
}

template <class MemorySpace>
auto createAdaptiveMesh( MemorySpace, const boost::property_tree::ptree& ptree,
                         const Kokkos::Array<double, 6>& global_bounding_box,
                         const int minimum_halo_cell_width, MPI_Comm comm )
{
    return std::make_shared<AdaptiveMesh<MemorySpace>>(
        ptree, global_bounding_box, minimum_halo_cell_width, comm );
}

//---------------------------------------------------------------------------//

} // end namespace Picasso

#endif // end PICASSO_ADAPTIVEMESH_HPP