//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <nt2/trigonometric/include/functions/rem_pio2_straight.hpp>
#include <boost/fusion/tuple.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/sdk/meta/as_floating.hpp>
#include <nt2/sdk/unit/tests/ulp.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>
#include <nt2/sdk/unit/module.hpp>

#include <nt2/include/constants/pio_2.hpp>
#include <nt2/include/constants/pio_4.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/constants/zero.hpp>

NT2_TEST_CASE_TPL ( rem_pio2_straight_real__1_0,  NT2_REAL_TYPES)
{

  using nt2::rem_pio2_straight;
  using nt2::tag::rem_pio2_straight_;
  typedef typename nt2::meta::as_integer<T>::type iT;

  NT2_TEST_TYPE_IS( (typename boost::dispatch::meta::call<rem_pio2_straight_(T)>::type)
                  , (std::pair<iT,T>)
                  );

  {
    T r1;
    NT2_TEST_EQUAL( rem_pio2_straight(nt2::Pio_2<T>(), r1), nt2::One<iT>());
    NT2_TEST_ULP_EQUAL( r1, nt2::Zero<T>(), 0.5);
    NT2_TEST_EQUAL( rem_pio2_straight(nt2::Pio_4<T>(), r1), nt2::One<iT>());
    NT2_TEST_ULP_EQUAL( r1, -nt2::Pio_4<T>(), 0.5);
  }
}


//==================================================================================================
/**
  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)
**/
//==================================================================================================
#include <boost/simd/function/frexp.hpp>
#include <boost/simd/function/toint.hpp>
#include <boost/simd/function/pedantic.hpp>
#include <boost/simd/constant/nbmantissabits.hpp>
#include <boost/simd/constant/halfeps.hpp>
#include <scalar_test.hpp>

namespace bs = boost::simd;

STF_CASE_TPL("Check basic behavior of pedantic_(frexp)", STF_IEEE_TYPES)
{
  STF_EXPR_IS( (bs::pedantic_(bs::frexp)(T(0))), (std::pair<T,T>) );

  auto p = bs::pedantic_(bs::frexp)(T(1));
  STF_EQUAL(p.first  , T(0.5));
  STF_EQUAL(p.second , T(1));
}

STF_CASE_TPL("Check behavior of pedantic_(frexp) on Zero", STF_IEEE_TYPES)
{
  auto r = bs::pedantic_(bs::frexp)(T(0));

  STF_EQUAL (r.first , T(0));
  STF_EQUAL (r.second, T(0));
  STF_EQUAL (ldexp(r.first,bs::toint(r.second)), T(0));
}

STF_CASE_TPL("Check behavior of pedantic_(frexp) on Valmax", STF_IEEE_TYPES)
{
  auto r = bs::pedantic_(bs::frexp)(bs::Valmax<T>());

  STF_ULP_EQUAL (r.first , T(1)-bs::Halfeps<T>(), 1);
  STF_EQUAL     (r.second, bs::Limitexponent<T>());
  STF_EQUAL     (ldexp(r.first,bs::toint(r.second)),bs::Valmax<T>());
}

#ifndef BOOST_SIMD_NO_INVALID
#include <boost/simd/constant/nan.hpp>

STF_CASE_TPL("Check behavior of pedantic_(frexp) on NaN", STF_IEEE_TYPES)
{
  auto r = bs::pedantic_(bs::frexp)(bs::Nan<T>());

  STF_IEEE_EQUAL(r.first , bs::Nan<T>());
  STF_EQUAL     (r.second, T(0));
  STF_IEEE_EQUAL(ldexp(r.first,bs::toint(r.second)), bs::Nan<T>());
}
#endif

#ifndef BOOST_SIMD_NO_INFINITIES
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/minf.hpp>

STF_CASE_TPL("Check behavior of pedantic_(frexp) on infinites", STF_IEEE_TYPES)
{
  auto r = bs::pedantic_(bs::frexp)(bs::Inf<T>());
  auto q = bs::pedantic_(bs::frexp)(bs::Minf<T>());

  STF_IEEE_EQUAL(r.first , bs::Inf<T>());
  STF_EQUAL     (r.second, T(0));
  STF_IEEE_EQUAL(ldexp(r.first,bs::toint(r.second)), bs::Inf<T>());

  STF_IEEE_EQUAL(q.first , bs::Minf<T>());
  STF_EQUAL     (q.second, T(0));
  STF_IEEE_EQUAL(ldexp(q.first,bs::toint(q.second)), bs::Minf<T>());
}
#endif

#ifndef BOOST_SIMD_NO_DENORMALS
#include <boost/simd/detail/constant/minexponent.hpp>
#include <boost/simd/constant/mindenormal.hpp>

STF_CASE_TPL("Check behavior of pedantic_(frexp) on denormals", STF_IEEE_TYPES)
{
  auto r = bs::pedantic_(bs::frexp)(bs::Mindenormal<T>());

  STF_ULP_EQUAL (r.first, T(0.5), 1);
  STF_EQUAL     (r.second, bs::Minexponent<T>()-bs::Nbmantissabits<T>()+1);
  STF_EQUAL     (ldexp(r.first,bs::toint(r.second)),bs::Mindenormal<T>());
}
#endif


// Copyright 2015-2018 Hans Dembinski
//
// 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)

//[ guide_indexed_access

#include <boost/format.hpp>
#include <boost/histogram.hpp>
#include <cassert>
#include <iostream>
#include <numeric> // for std::accumulate
#include <sstream>

using namespace boost::histogram;

int main() {
  // make histogram with 2 x 2 = 4 bins (not counting under-/overflow bins)
  auto h = make_histogram(axis::regular<>(2, -1.0, 1.0), axis::regular<>(2, 2.0, 4.0));

  h(weight(1), -0.5, 2.5); // bin index 0, 0
  h(weight(2), -0.5, 3.5); // bin index 0, 1
  h(weight(3), 0.5, 2.5);  // bin index 1, 0
  h(weight(4), 0.5, 3.5);  // bin index 1, 1

  // use the `indexed` range adaptor to iterate over all bins;
  // it is not only more convenient but also faster than a hand-crafted loop!
  std::ostringstream os;
  for (auto&& x : indexed(h)) {
    // x is a special accessor object
    const auto i = x.index(0); // current index along first axis
    const auto j = x.index(1); // current index along second axis
    const auto b0 = x.bin(0);  // current bin interval along first axis
    const auto b1 = x.bin(1);  // current bin interval along second axis
    const auto v = *x;         // "dereference" to get the bin value
    os << boost::format("%i %i [%2i, %i) [%2i, %i): %i\n") % i % j % b0.lower() %
              b0.upper() % b1.lower() % b1.upper() % v;
  }

  std::cout << os.str() << std::flush;

  assert(os.str() == "0 0 [-1, 0) [ 2, 3): 1\n"
                     "1 0 [ 0, 1) [ 2, 3): 3\n"
                     "0 1 [-1, 0) [ 3, 4): 2\n"
                     "1 1 [ 0, 1) [ 3, 4): 4\n");

  // `indexed` skips underflow and overflow bins by default, but can be called
  // with the second argument `coverage::all` to walk over all bins
  std::ostringstream os2;
  for (auto&& x : indexed(h, coverage::all)) {
    os2 << boost::format("%2i %2i: %i\n") % x.index(0) % x.index(1) % *x;
  }

  std::cout << os2.str() << std::flush;

  assert(os2.str() == "-1 -1: 0\n"
                      " 0 -1: 0\n"
                      " 1 -1: 0\n"
                      " 2 -1: 0\n"

                      "-1  0: 0\n"
                      " 0  0: 1\n"
                      " 1  0: 3\n"
                      " 2  0: 0\n"

                      "-1  1: 0\n"
                      " 0  1: 2\n"
                      " 1  1: 4\n"
                      " 2  1: 0\n"

                      "-1  2: 0\n"
                      " 0  2: 0\n"
                      " 1  2: 0\n"
                      " 2  2: 0\n");
}

//]


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
/*!
 * \file
**/
#ifndef BOOST_SIMD_CONSTANT_CONSTANTS_NBMANTISSABITS_HPP_INCLUDED
#define BOOST_SIMD_CONSTANT_CONSTANTS_NBMANTISSABITS_HPP_INCLUDED

#include <boost/simd/include/functor.hpp>
#include <boost/simd/sdk/meta/int_c.hpp>
#include <boost/simd/sdk/constant/constant.hpp>

/*!
 * \ingroup boost_simd_constant
 * \defgroup boost_simd_constant_nbmantissabits Nbmantissabits
 *
 * \par Description
 * Constant Nbmantissabits, The number of mantissa bits of a floating point number,
 * i.e. 53 for double and 24 for float.
 * \par
 * The value of this constant is type dependant. This means that for different
 * types it does not represent the same mathematical number.
 *
 * \par Header file
 *
 * \code
 * #include <nt2/include/functions/nbmantissabits.hpp>
 * \endcode
 *
 *
 * \synopsis
 *
 * \code
 * namespace boost::simd
 * {
 *   template <class T,class A0>
 *     meta::call<tag::nbmantissabits_(A0)>::type
 *     Nbmantissabits();
 * }
 * \endcode
 *
 *
 * \param T template parameter of Nbmantissabits
 *
 * \return type T value
 *
 *
**/

namespace boost { namespace simd
{
  namespace tag
  {
    /*!
     * \brief Define the tag Nbmantissabits of functor Nbmantissabits
     *        in namespace boost::simd::tag for toolbox boost.simd.constant
    **/
    struct Nbmantissabits : ext::pure_constant_<Nbmantissabits>
    {
      template<class Target, class Dummy=void>
      struct  apply : meta::int_c < typename Target::type
                                  , sizeof(typename Target::type)*CHAR_BIT
                                  >
      {};
    };

    template<class T, class Dummy>
    struct  Nbmantissabits::apply<boost::dispatch::meta::single_<T>,Dummy>
          : meta::int_c<boost::simd::int32_t,23> {};

    template<class T, class Dummy>
    struct  Nbmantissabits::apply<boost::dispatch::meta::double_<T>,Dummy>
          : meta::int_c<boost::simd::int64_t,52> {};
  }

  BOOST_SIMD_CONSTANT_IMPLEMENTATION(boost::simd::tag::Nbmantissabits, Nbmantissabits)
} }

#include <boost/simd/sdk/constant/common.hpp>

#endif


/* boost random/exponential_distribution.hpp header file
 *
 * Copyright Jens Maurer 2000-2001
 * Copyright Steven Watanabe 2011
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id: exponential_distribution.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $
 *
 * Revision history
 *  2001-02-18  moved to individual header files
 */

#ifndef BOOST_RANDOM_EXPONENTIAL_DISTRIBUTION_HPP
#define BOOST_RANDOM_EXPONENTIAL_DISTRIBUTION_HPP

#include <boost/config/no_tr1/cmath.hpp>
#include <iosfwd>
#include <boost/assert.hpp>
#include <boost/limits.hpp>
#include <boost/random/detail/config.hpp>
#include <boost/random/detail/operators.hpp>
#include <boost/random/uniform_01.hpp>

namespace boost {
namespace random {

/**
 * The exponential distribution is a model of \random_distribution with
 * a single parameter lambda.
 *
 * It has \f$\displaystyle p(x) = \lambda e^{-\lambda x}\f$
 */
template<class RealType = double>
class exponential_distribution
{
public:
    typedef RealType input_type;
    typedef RealType result_type;

    class param_type
    {
    public:

        typedef exponential_distribution distribution_type;

        /**
         * Constructs parameters with a given lambda.
         *
         * Requires: lambda > 0
         */
        param_type(RealType lambda_arg = RealType(1.0))
          : _lambda(lambda_arg) { BOOST_ASSERT(_lambda > RealType(0)); }

        /** Returns the lambda parameter of the distribution. */
        RealType lambda() const { return _lambda; }

        /** Writes the parameters to a @c std::ostream. */
        BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
        {
            os << parm._lambda;
            return os;
        }

        /** Reads the parameters from a @c std::istream. */
        BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
        {
            is >> parm._lambda;
            return is;
        }

        /** Returns true if the two sets of parameters are equal. */
        BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
        { return lhs._lambda == rhs._lambda; }

        /** Returns true if the two sets of parameters are different. */
        BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)

    private:
        RealType _lambda;
    };

    /**
     * Constructs an exponential_distribution with a given lambda.
     *
     * Requires: lambda > 0
     */
    explicit exponential_distribution(RealType lambda_arg = RealType(1.0))
      : _lambda(lambda_arg) { BOOST_ASSERT(_lambda > RealType(0)); }

    /**
     * Constructs an exponential_distribution from its parameters
     */
    explicit exponential_distribution(const param_type& parm)
      : _lambda(parm.lambda()) {}

    // compiler-generated copy ctor and assignment operator are fine

    /** Returns the lambda parameter of the distribution. */
    RealType lambda() const { return _lambda; }

    /** Returns the smallest value that the distribution can produce. */
    RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const
    { return RealType(0); }
    /** Returns the largest value that the distribution can produce. */
    RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const
    { return (std::numeric_limits<RealType>::infinity)(); }

    /** Returns the parameters of the distribution. */
    param_type param() const { return param_type(_lambda); }
    /** Sets the parameters of the distribution. */
    void param(const param_type& parm) { _lambda = parm.lambda(); }

    /**
     * Effects: Subsequent uses of the distribution do not depend
     * on values produced by any engine prior to invoking reset.
     */
    void reset() { }

    /**
     * Returns a random variate distributed according to the
     * exponential distribution.
     */
    template<class Engine>
    result_type operator()(Engine& eng) const
    {
        using std::log;
        return -result_type(1) /
            _lambda * log(result_type(1)-uniform_01<RealType>()(eng));
    }

    /**
     * Returns a random variate distributed according to the exponential
     * distribution with parameters specified by param.
     */
    template<class Engine>
    result_type operator()(Engine& eng, const param_type& parm) const
    {
        return exponential_distribution(parm)(eng);
    }

    /** Writes the distribution to a std::ostream. */
    BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, exponential_distribution, ed)
    {
        os << ed._lambda;
        return os;
    }

    /** Reads the distribution from a std::istream. */
    BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, exponential_distribution, ed)
    {
        is >> ed._lambda;
        return is;
    }

    /**
     * Returns true iff the two distributions will produce identical
     * sequences of values given equal generators.
     */
    BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(exponential_distribution, lhs, rhs)
    { return lhs._lambda == rhs._lambda; }

    /**
     * Returns true iff the two distributions will produce different
     * sequences of values given equal generators.
     */
    BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(exponential_distribution)

private:
    result_type _lambda;
};

} // namespace random

using random::exponential_distribution;

} // namespace boost

#endif // BOOST_RANDOM_EXPONENTIAL_DISTRIBUTION_HPP


/*
 dparallel_recursion: distributed parallel_recursion skeleton
 Copyright (C) 2015-2020 Millan A. Martinez, Basilio B. Fraguela, Jose C. Cabaleiro. Universidade da Coruna

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

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

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

///
/// \file     topsorts_dstack.cpp
/// \author   Millan A. Martinez  <millan.alvarez@udc.es>
/// \author   Basilio B. Fraguela <basilio.fraguela@udc.es>
/// \author   Jose C. Cabaleiro   <jc.cabaleiro@usc.es>
///

#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <vector>
#include <numeric>
#include <algorithm>
#include <boost/serialization/vector.hpp>
#include <dparallel_recursion/dparallel_stack_recursion.h>

using namespace dpr;

int nthreads = 4;
int *A = nullptr; /* holds acyclic digraph compatible with 1,2,...,n */

struct Problem {

  static int SZ;

  std::vector<int> value_;
  std::vector<int> children_;

  //If root is false, it generates the default empty problem []
  //If root is true, it generates the root problem 1 2 3 ... SZ
  Problem(const bool root = false) {
    if (root) {
      value_.resize(SZ);
      std::iota(value_.begin(), value_.end(), 1);
    }
  }

  // copy constructor
  Problem(const std::vector<int>& v) :
  value_(v)
  { }

  //move constructor
  Problem(std::vector<int>&& v) :
  value_(std::move(v))
  { }

  /*
  //print current problem
  void print() const noexcept {
    printf("[");
    for(const auto& v : value_) printf(" %d", v);
    printf(" ]\n");
  }
  */

  bool empty() const noexcept { return value_.empty(); }

  // Requires i in 0..(SZ-1)
  Problem adj(const int i) const noexcept {
    auto copy = value_;
    std::swap(copy[i], copy[i+1]);
    return copy;
  }

//  Problem f() const noexcept
//  { int i = 1;
//
//    while( (i < SZ) && (value_[i-1] < value_[i]) ) {
//      i++;
//    }
//
//    if (i == SZ) {
//      return Problem();
//    } else {
//      return adj(i - 1);
//    }
//  }

  bool reverse(const int s, const int i) const noexcept {
    return (i <= (s - 1)) || ( (i == (s + 1)) && (s <= (SZ-3)) && (value_[s] < value_[s+2]) );
  }

  void fill_nchildren() {
    if (!empty()) { //dismiss empty problems
      // findindex
      int idx;
      for(idx = 0; (idx < (SZ-1)) && (value_[idx] < value_[idx+1]); idx++);
      for (int i = 0; i < (SZ-1); i++) {
        if(A[value_[i] * SZ + value_[i+1] - SZ - 1] != 1) {
          if (reverse(idx, i)) {
            children_.push_back(i);
          }
        }
      }
    }
  }

//  void fill_nchildren() {
//    if (!empty()) { //dismiss empty problems
//      for (int i = 0; i < (SZ-1); i++) { // implements "reverse"
//        if(A[value_[i] * SZ + value_[i+1] - SZ - 1] != 1) {
//          const auto w = adj(i); // This problem cannot have w == null/empty
//          if (value_ == w.f().value_) {
//            children_.push_back(i);
//          }
//        }
//      }
//    }
//  }

  // Generate the i-th child problem, i in [0..(nchildren()-1)]
  // Does not test whether that child should exist!
  Problem child(const int i) const noexcept { return adj(children_[i]); }

  size_t nchildren() const noexcept { return children_.size(); }

  template<typename Archive>
  void serialize(Archive &ar, const unsigned int) {
    ar & value_ & children_;
  }

};

int Problem::SZ = 9;

struct MyInfo : public Arity<UNKNOWN> {

  static bool is_base(const Problem& p) { return !p.nchildren(); }

  static int num_children(const Problem& p) { return p.nchildren(); }

  static Problem child(int i, const Problem& p) { return p.child(i); }

  //static bool do_parallel(const Problem& p) { ... }
};

struct MyBody : public EmptyBody<Problem, size_t, true> {

  static void pre(Problem& p) { p.fill_nchildren(); }

  static size_t base(const Problem& p) { return 1; }

  static size_t non_base(const Problem& p) { return base(p); }

//  static size_t post(const Problem& p, const size_t* v) {
//    return std::accumulate(v, v + p.nchildren(), (size_t)1);
//  }

  static void post(const size_t& r, size_t& rr) {
    rr += r;
  }

};

//BOOST_IS_BITWISE_SERIALIZABLE(Problem);

int main(int argc, char** argv)
{
  int rank;
  int nprocs;
  int chunkSize = 4;
  int chunksToSteal = dpr::CHUNKS_TO_STEAL_DEFAULT;
  unsigned int pollingInterval = dpr::POLLING_INTERVAL_DEFAULT;
  int stackSize = 100;
  int threads_request_policy = dpr::THREAD_MPI_STEAL_POLICY_DEFAULT;
  int mpi_workrequest_limits = dpr::MPI_WORKREQUEST_LIMITS_DEFAULT;
  int trp_predict_workcount = dpr::TRP_PREDICT_WORKCOUNT_DEFAULT;
  int partitioner = 0;
  int m;

  if (getenv("OMP_NUM_THREADS"))
    nthreads = atoi(getenv("OMP_NUM_THREADS"));

  if (argc > 1) {
    chunkSize = atoi(argv[1]);
  }

  if (argc > 2) {
    chunksToSteal = atoi(argv[2]);
  }

  if (argc > 3) {
    pollingInterval = atoi(argv[3]);
  }

  if (argc > 4) {
    threads_request_policy = atoi(argv[4]);
  }

  if (argc > 5) {
    stackSize = atoi(argv[5]);
  }

  if (argc > 6) {
    partitioner = atoi(argv[6]);
  }

  if (argc > 7) {
    mpi_workrequest_limits = atoi(argv[7]);
  }

  if (argc > 8) {
    trp_predict_workcount = atoi(argv[8]);
  }

  dpr_stack_init(argc, argv, nprocs, rank, nthreads, chunksToSteal, pollingInterval, stackSize, threads_request_policy, mpi_workrequest_limits, trp_predict_workcount);

  if (rank == 0) {
    printf("\nEnter number of vertices and edges:");

    scanf("%d %d", &Problem::SZ, &m);
    MPI_Bcast(&Problem::SZ, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&m, 1, MPI_INT, 0, MPI_COMM_WORLD);
    printf("\nEnter %d edge(s) as pairs i j, i<j : \n", m);
    //printf("%d %d\n", Problem::SZ, m);
    A = (int *)calloc(Problem::SZ * Problem::SZ, sizeof(int));

    for(int k=1; k<=m; k++) {
      int i, j;
      scanf("%d %d", &i, &j);
      MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD);
      MPI_Bcast(&j, 1, MPI_INT, 0, MPI_COMM_WORLD);
      if (i >= j) {
        printf ("\nEdge must have form i<j");
        return 0;
      }
      A[(i - 1) * Problem::SZ + (j - 1)] = 1;
      //printf("%d %d\n", i, j);
    }

    printf("Nprocs=%d threads=%d sz=%d chunkSize=%d stackSize=%d chunksToSteal=%d pollingI=%d trp=%d partitioner=%d mpiWrLimits=%d trpPredWc=%d\n", nprocs, nthreads, Problem::SZ, chunkSize, stackSize, chunksToSteal, pollingInterval, threads_request_policy, partitioner, mpi_workrequest_limits, trp_predict_workcount);
  } else {
    MPI_Bcast(&Problem::SZ, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&m, 1, MPI_INT, 0, MPI_COMM_WORLD);

    A = (int *)calloc(Problem::SZ * Problem::SZ, sizeof(int));

    for(int k=1; k<=m; k++) {
      int i, j;
      MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD);
      MPI_Bcast(&j, 1, MPI_INT, 0, MPI_COMM_WORLD);
      if (i >= j) {
        return 0;
      }
      A[(i - 1) * Problem::SZ + (j - 1)] = 1;
      //printf("%d %d\n", i, j);
    }
  }

  Problem input(true);

  const auto t0 = std::chrono::steady_clock::now();

  size_t result;
  if (partitioner == 2) {
    result = dparallel_stack_recursion<size_t> (input, MyInfo(), MyBody(), chunkSize, dpr::partitioner::automatic(), dpr::ReplicatedInput);
  } else {
    result = dparallel_stack_recursion<size_t> (input, MyInfo(), MyBody(), chunkSize, dpr::partitioner::simple(), dpr::ReplicatedInput);
  }

  const auto t1 = std::chrono::steady_clock::now();
  double time = std::chrono::duration<double>(t1 - t0).count();

  if (rank == 0) {
    printf("Result: %zu\nTime: %lf\n", result, time);
  }

  free(A);

  MPI_Finalize();

  return 0;
}


#pragma once
#include <cmath>
#include <algorithm>
#include <limits>
#include <Eigen/Geometry>
#include <boost/optional.hpp>
#include "BaryCoordT.hh"
#include "util.hh"
#include "RangeAdaptor.hh"

namespace kt84 {
    namespace eigen_util {
        template <typename TMatrix>
        inline auto range_elements(TMatrix& m) -> RangeAdaptor<decltype(m.data())> {
            return make_RangeAdaptor(m.data(), m.data() + m.size());
        }
        template <typename TVector, typename TScalar>
        inline void push_back(TVector& v, TScalar s) {
            int n = v.size();
            v.conservativeResize(n + 1);
            v[n] = s;
        }
        template <typename TVector>
        inline void erase_at(TVector& v, int index) {
            int n = v.size();
            auto tmp(v);
            v.resize(n - 1);
            v << tmp.head(index), tmp.tail(n - 1 - index);
        }
        template <typename TVector>
        inline void swap_xy(TVector& v) {
            std::swap(v.x(), v.y());
        }
        template <typename TAlignedBox>
        inline void bbox_add_margin(TAlignedBox& bbox, double ratio, bool is_margin_square = false) {
            if (is_margin_square) {
                typedef typename TAlignedBox::VectorType VectorType;
                VectorType margin = VectorType::Ones();
                margin *= bbox.diagonal().norm() * ratio;
                bbox.max() += margin;
                bbox.min() -= margin;
            } else {
                bbox.extend((1 + ratio) * bbox.max() - ratio * bbox.min());
                bbox.extend((1 + ratio) * bbox.min() - ratio * bbox.max());
            }
        }
        inline Eigen::Vector2d bbox_bilinear(const Eigen::AlignedBox2d& bbox, double tx, double ty) {            // (0, 0) corresponds to bbox.min, (1, 1) corresponds to bbox.max
            double x = (1 - tx) * bbox.min().x() + tx * bbox.max().x();
            double y = (1 - ty) * bbox.min().y() + ty * bbox.max().x();
            return Eigen::Vector2d(x, y);
        }
        inline Eigen::Vector3d bbox_trilinear(const Eigen::AlignedBox3d& bbox, double tx, double ty, double tz) {            // (0, 0, 0) corresponds to bbox.min, (1, 1, 1) corresponds to bbox.max
            double x = (1 - tx) * bbox.min().x() + tx * bbox.max().x();
            double y = (1 - ty) * bbox.min().y() + ty * bbox.max().x();
            double z = (1 - tz) * bbox.min().z() + tz * bbox.max().z();
            return Eigen::Vector3d(x, y, z);
        }
        inline Eigen::Vector3d orientation_color(Eigen::Vector3d d) {
            auto cx = d.x() > 0 ? Eigen::Vector3d(1, 0, 0) : Eigen::Vector3d(0, 1, 1);
            auto cy = d.y() > 0 ? Eigen::Vector3d(0, 1, 0) : Eigen::Vector3d(1, 0, 1);
            auto cz = d.z() > 0 ? Eigen::Vector3d(0, 0, 1) : Eigen::Vector3d(1, 1, 0);
            d /= std::abs<double>(d.sum());
            d = d.cwiseAbs();
            return d.x() * cx + d.y() * cy + d.z() * cz;
        }
        inline Eigen::Vector3d heat_color(double t) {
            // t     | 0    | 0.25 | 0.5   | 0.75   | 1   |
            // color | blue | cyan | green | yellow | red |
            t = util::clamp(t, 0., 1.);
            Eigen::Vector3d colors[5] = {
                Eigen::Vector3d(0, 0, 1),
                Eigen::Vector3d(0, 1, 1),
                Eigen::Vector3d(0, 1, 0),
                Eigen::Vector3d(1, 1, 0),
                Eigen::Vector3d(1, 0, 0)
            };
            int i = t < 0.25 ? 0 : t < 0.5 ? 1 : t < 0.75 ? 2 : 3;
            double s = (t - i * 0.25) * 4;
            return (1 - s) * colors[i] + s * colors[i + 1];
        }
        template <int N>
        inline int closest_axis(const Eigen::Matrix<double, N, 1, 0, N, 1>& v) {
            int result = -1;
            double v_abs_max = 0;
            for (int i = 0; i < N; ++i) {
                double v_abs = std::abs(v[i]);
                if (v_abs_max < v_abs) {
                    v_abs_max = v_abs;
                    result = i;
                }
            }
            return result;
        }
        inline Eigen::Vector2d compute_gradient(const Eigen::Vector2d& x0, const Eigen::Vector2d& x1, const Eigen::Vector2d& x2, double y0, double y1, double y2) {
            /*
                a.x0 + b = y0
                a.x1 + b = y1
                a.x2 + b = y2
                -->
                a.(x1 - x0) = y1 - y0
                a.(x2 - x0) = y2 - y0
                -->
                |(x1 - x0)^T| * a = |y1 - y0|
                |(x2 - x0)^T|       |y2 - y0|
            */
            Eigen::Matrix2d A;
            A << Eigen::RowVector2d(x1 - x0),
                 Eigen::RowVector2d(x2 - x0);
            return A.inverse() * Eigen::Vector2d(y1 - y0, y2 - y0);
        }
        inline Eigen::Vector3d compute_gradient(const Eigen::Vector3d& x0, const Eigen::Vector3d& x1, const Eigen::Vector3d& x2, const Eigen::Vector3d& x3, double y0, double y1, double y2, double y3) {
            /*
                a.x0 + b = y0
                a.x1 + b = y1
                a.x2 + b = y2
                a.x3 + b = y3
                -->
                a.(x1 - x0) = y1 - y0
                a.(x2 - x0) = y2 - y0
                a.(x3 - x0) = y3 - y0
                -->
                |(x1 - x0)^T|       |y1 - y0|
                |(x2 - x0)^T| * a = |y2 - y0|
                |(x3 - x0)^T|       |y3 - y0|
            */
            Eigen::Matrix3d A;
            A << Eigen::RowVector3d(x1 - x0),
                 Eigen::RowVector3d(x2 - x0),
                 Eigen::RowVector3d(x3 - x0);
            return A.inverse() * Eigen::Vector3d(y1 - y0, y2 - y0, y3 - y0);
        }
        inline Eigen::Vector3d compute_gradient(const Eigen::Vector3d& x0, const Eigen::Vector3d& x1, const Eigen::Vector3d& x2, double y0, double y1, double y2) {
            /*
                Compute gradient restricted to the tangent vectors on the triangle x0-x1-x2.
                a.x0 + b = y0
                a.x1 + b = y1
                a.x2 + b = y2
                a.n      = 0                (n: normal)
                -->
                a.(x1 - x0) = y1 - y0
                a.(x2 - x0) = y2 - y0
                a.n         = 0
                -->
                |(x1 - x0)^T|       |y1 - y0|
                |(x2 - x0)^T| * a = |y2 - y0|
                | n       ^T|       |0      |
            */
            Eigen::Matrix3d A;
            A << Eigen::RowVector3d(x1 - x0),
                 Eigen::RowVector3d(x2 - x0),
                 Eigen::RowVector3d((x1 - x0).cross(x2 - x0));
            return A.inverse() * Eigen::Vector3d(y1 - y0, y2 - y0, 0);
        }
        inline Eigen::Vector2d rotate90(const Eigen::Vector2d& xy) { return Eigen::Vector2d(-xy[1], xy[0]); }
        inline double angle(const Eigen::Vector2d& d0, const Eigen::Vector2d& d1) { return std::atan2(rotate90(d0).dot(d1), d0.dot(d1)); }
        inline double angle(const Eigen::Vector3d& d0, const Eigen::Vector3d& d1) { return std::acos(d0.normalized().dot(d1.normalized())); }
        template <class T>
        inline void orthonormalize(const T& unit, T& p) {
            p -= unit.dot(p) * unit;
            p.normalize();
        }
        template <class T>
        inline bool project_to_line(const T& line_v0, const T& line_v1, const T& point, Eigen::Vector2d& t) {
            /*
                x0 := line_v0
                x1 := line_v1
                y := point
                compute t (which sums up to one) such that
                    | t[0] * x0 + t[1] * x1 - y |^2
                is minimized.
                ---------------------
                u := t[1]
                (1 - u) * x0 + u * x1 =~ y
                u =~ (y - x0).dot(x1 - x0) / (x1 - x0).squaredNorm()
            */

            double r = (line_v1 - line_v0).squaredNorm();
            if (r == 0)
                // degenerate
                return false;

            t[1] = (point - line_v0).dot(line_v1 - line_v0) / r;
            t[0] = 1 - t[1];

            return true;
        }

        template <class T>
        inline bool project_to_triangle(const T& triangle_v0, const T& triangle_v1, const T& triangle_v2, const T& point, Eigen::Vector3d& t) {
            /*
                x0 := triangle_v0
                x1 := triangle_v1
                x2 := triangle_v2
                y := point
                compute t (which sums up to one) such that
                    | t[0] * x0 + t[1] * x1 + t[2] * x2 - y |^2
                is minimized.
                ---------------------
                u := t[1]
                v := t[2]
                (1 - u - v) * x0 + u * x1 + v * x2 =~ y
                (x1-x0, x2-x0) * |u| =~ y-x0
                                 |v|
                |u| =~ |(x1-x0).squaredNorm(), (x1-x0).dot(x2-x0)   |^-1 * | (x1-x0).dot(y-x0) |
                |v|    |(x1-x0).dot(x2-x0)   , (x2-x0).squaredNorm()|      | (x2-x0).dot(y-x0) |
            */

            T d01 = triangle_v1 - triangle_v0;
            T d02 = triangle_v2 - triangle_v0;
            T d0p = point       - triangle_v0;
            Eigen::Matrix2d M;
            M <<
                d01.squaredNorm(), d01.dot(d02),
                d01.dot(d02)     , d02.squaredNorm();
            if (M.determinant() == 0)
                // degenerate
                return false;

            Eigen::Vector2d b;
            b <<
                d01.dot(d0p),
                d02.dot(d0p);

            Eigen::Vector2d uv = ((Eigen::Matrix2d)M.inverse()) * b;

            t[0] = 1 - uv[0] - uv[1];
            t[1] = uv[0];
            t[2] = uv[1];

            return true;
        }

        template <class T>
        inline boost::optional<double> distance_to_line(const T& line_v0, const T& line_v1, const T& point, bool do_clamp = false) {
            Eigen::Vector2d t;
            if (!project_to_line(line_v0, line_v1, point, t))
                // degenrate case
                return boost::none;

            if (do_clamp) {
                t[0] = util::clamp(t[0], 0.0, 1.0);
                t[1] = 1 - t[0];
            }

            return (t[0] * line_v0 + t[1] * line_v1 - point).norm();
        }

        template <class T>
        inline boost::optional<double> distance_to_triangle(const T& triangle_v0, const T& triangle_v1, const T& triangle_v2, const T& point, bool do_clamp = false) {
            Eigen::Vector3d t;
            if (!project_to_triangle(triangle_v0, triangle_v1, triangle_v2, point, t))
                // degenrate case
                return boost::none;

            if (do_clamp && t[0] < 0 || t[1] < 0 || t[2] < 0) {
                double d0 = *distance_to_line(triangle_v0, triangle_v1, point, true);
                double d1 = *distance_to_line(triangle_v1, triangle_v2, point, true);
                double d2 = *distance_to_line(triangle_v2, triangle_v0, point, true);
                return util::min(d0, d1, d2);
            }

            return (t[0] * triangle_v0 + t[1] * triangle_v1 + t[2] * triangle_v2 - point).norm();
        }
        inline double triangle_area(const Eigen::Vector2d& v0, const Eigen::Vector2d& v1, const Eigen::Vector2d& v2) {
            Eigen::Vector2d d1 = v1 - v0;
            Eigen::Vector2d d2 = v2 - v0;
            return d1.x() * d2.y() - d1.y() * d2.x();
        }
        inline double triangle_area(const Eigen::Vector3d& v0, const Eigen::Vector3d& v1, const Eigen::Vector3d& v2) {
            Eigen::Vector3d d1 = v1 - v0;
            Eigen::Vector3d d2 = v2 - v0;
            return d1.cross(d2).norm() / 2;
        }
        template <class T>
        inline bool intersection(const T& line0_p0, const T& line0_p1, const T& line1_p0, const T& line1_p1, double& line0_coordinate, double& line1_coordinate) {
            /*
                notation:
                    v0 := line0_p0
                    v1 := line0_p1
                    w0 := line1_p0
                    w1 := line1_p1
                    s  := line0_coordinate
                    t  := line1_coordinate
                seek for (s, t) which minimizes:
                    |(1 - s) * v0 + s * v1 - (1 - t) * w0 - t * w1|^2
                least square sense:
                    | v1-v0, -w1+w0 | * |s| =~ -v0+w0
                                        |t|
            */
            T d0 = line0_p1 - line0_p0;
            T d1 = line1_p1 - line1_p0;
            T e  = line1_p0 - line0_p0;
            double d0d0 = d0.squaredNorm();
            double d0d1 = d0.dot(d1);
            double d1d1 = d1.squaredNorm();
            Eigen::Matrix2d A;
            A <<
                d0d0, -d0d1,
                -d0d1, d1d1;

            if (A.determinant() == 0)
                // two lines are parallel
                return false;

            Eigen::Vector2d b(d0.dot(e), -d1.dot(e));
            Eigen::Vector2d st = ((Eigen::Matrix2d)A.inverse()) * b;

            line0_coordinate = st[0];
            line1_coordinate = st[1];
            return true;
        }
        template <typename T>
        inline std::vector<T> eigen_vectorx_to_std_vector(const Eigen::Matrix<T, -1, 1>& eigen_vectorx) {
            int n = eigen_vectorx.rows();
            std::vector<T> result(n);
            for (int i = 0; i < n; ++i)
                result[i] = eigen_vectorx[i];
            return result;
        }
        template <typename T>
        inline Eigen::Matrix<T, -1, 1> std_vector_to_eigen_vectorx(const std::vector<T>& std_vector) {
            int n = std_vector.size();
            Eigen::Matrix<T, -1, 1> result = Eigen::Matrix<T, -1, 1>::Zero(n);
            for (int i = 0; i < n; ++i)
                result[i] = std_vector[i];
            return result;
        }
        template <typename TVector>
        inline int max_axis(const TVector& v) {
            int index_max = -1;
            typename TVector::Scalar value_max = -std::numeric_limits<typename TVector::Scalar>::max();
            for (int i = 0; i < v.size(); ++i) {
                if (value_max < v[i]) {
                    value_max = v[i];
                    index_max = i;
                }
            }
            return index_max;
        }
        template <typename TVector>
        inline int min_axis(const TVector& v) {
            int index_min = -1;
            typename TVector::Scalar value_min = std::numeric_limits<typename TVector::Scalar>::max();
            for (int i = 0; i < v.size(); ++i) {
                if (value_min < v[i]) {
                    value_min = v[i];
                    index_min = i;
                }
            }
            return index_min;
        }
        template <typename TVector>
        inline void rotate(TVector& v) {
            TVector tmp(v);
            int n = v.size();
            for (int i = 0; i < n; ++i)
                v[i] = tmp[(i + 1) % n];
        }
        template <typename TVector>
        inline void reverse(TVector& v) {
            TVector tmp(v);
            int n = v.size();
            for (int i = 0; i < n; ++i)
                v[i] = tmp[n - 1 - i];
        }
    }
}


#ifndef _PARSER_H_
#define _PARSER_H_

#include <boost/regex.hpp>
#include <string>
#include <unordered_map>
#include <vector>
class Parser {
  using operator_map = std::unordered_map<int, std::vector<char>>;

 public:
  int max_op_m;
  boost::regex re_number_m, re_operator_m;
  std::unordered_map<int, boost::regex> re_operands_m;

  Parser(operator_map m = operator_map({{0, {'+', '*'}}}), int max_op = 0,
         std::string num = "\\d+", std::string op = "[^\\d]");

  int64_t operate(const int64_t &a, const int64_t &b, const char &op);

  std::string extract_parenthesis(std::string &line);

  int64_t compute_expression(std::string line);

  int64_t evaluate(std::string line);
};

#endif


///
/// \file vandermonde_matrix.hpp
///
#ifndef MXPFIT_VANDERMONDE_MATRIX_HPP
#define MXPFIT_VANDERMONDE_MATRIX_HPP

#include <cassert>

#include <Eigen/Core>

#include <mxpfit/matrix_free_gemv.hpp>

namespace mxpfit
{

///
/// ### VandermondeMatrix
///
/// Expression of a rectangular column Vandermonde matrix.
///
/// \tparam T  Scalar type of matrix elements
///
/// This class represents a \f$ m \times n \f$ column Vandermonde matrix of
/// the form
///
/// \f[
///   \bm{V}(\bm{t}) = \left[ \begin{array}{cccc}
///     1         & 1         & \dots  & 1         \\
///     t_{1}^{}  & t_{2}^{}  & \dots  & t_{n}^{}  \\
///     \vdots    & \vdots    & \ddots & \vdots    \\
///     t_{1}^{m} & t_{2}^{m} & \dots  & t_{n}^{m} \\
///   \end{array} \right].
/// \f]
///
/// This class represents a Vandermonde matrix expression from the given number
/// of rows, \f$ m, \f$ and a vector expression for the coefficients of the
/// second row, \f$(t_1,t_2,\dots,t_n).\f$ If the given vector expression is
/// l-value, this class wraps the existing vector expression, otherwise storage
/// for coefficients are allocated.
///
/// This class also provides the interface for matrix-vector multiplication
/// compatible to `MatrixFreeGEMV`. For this purpose, the class also allocate
/// internal a vector of size \f$n\f$ as working space.
///

template <typename T>
class VandermondeMatrix
{
public:
    using Scalar          = T;
    using RealScalar      = typename Eigen::NumTraits<T>::Real;
    using StorageIndex    = Eigen::Index;
    using Index           = Eigen::Index;
    using CoeffsVector    = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
    using CoeffsVectorRef = Eigen::Ref<const CoeffsVector>;
    using PlainObject = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;

private:
    Index m_rows;
    mutable CoeffsVector m_workspace;
    CoeffsVectorRef m_coeffs;

public:
    /// Default constructor: create an empty matrix
    VandermondeMatrix()
        : m_rows(),
          m_workspace(),
          m_coeffs(m_workspace) // need to initialize Eigen::Ref object
    {
    }

    ///
    /// Create a Vandermonde matrix from number of rows and coefficients of the
    /// first row.
    ///
    template <typename InputType>
    VandermondeMatrix(Index nrows, const InputType& coeffs)
        : m_rows(nrows), m_workspace(coeffs.size()), m_coeffs(coeffs)
    {
        EIGEN_STATIC_ASSERT_VECTOR_ONLY(InputType);
    }

    /// Copy constructor
    VandermondeMatrix(const VandermondeMatrix& other)
        : m_rows(other.m_rows),
          m_workspace(other.m_workspace),
          m_coeffs(other.m_coeffs)
    {
    }

    /// Default destructor
    ~VandermondeMatrix()
    {
    }

    /// Delete assignment operator as a consequence that Eigen::Ref is
    /// non-assignable
    VandermondeMatrix& operator=(const VandermondeMatrix& other) = delete;

    /// \return the number of rows
    Index rows() const
    {
        return m_rows;
    }

    /// \return the number of columns
    Index cols() const
    {
        return m_coeffs.size();
    }

    /// Set elements of Vandermonde matrix
    template <typename Derived>
    void setMatrix(Index nrows, const Eigen::EigenBase<Derived>& coeffs)
    {
        EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
        m_rows = nrows;
        if (m_workspace.size() != coeffs.size())
        {
            m_workspace.resize(coeffs.size());
        }
        m_coeffs.~CoeffsVectorRef();
        ::new (&m_coeffs) CoeffsVectorRef(coeffs.derived());
    }

    void setMatrix(Index nrows, const CoeffsVectorRef& coeffs)
    {
        m_rows = nrows;
        if (&(coeffs.derived()) != &m_coeffs)
        {
            if (m_workspace.size() != coeffs.size())
            {
                m_workspace.resize(coeffs.size());
            }
            m_coeffs.~CoeffsVectorRef();
            ::new (&m_coeffs) CoeffsVectorRef(coeffs);
        }
    }

    ///
    /// \return A const reference to the coefficients of the second row
    ///
    const CoeffsVectorRef& coeffs() const
    {
        return m_coeffs;
    }

    ///
    /// \return The same Vandermonde matrix in dense form.
    ///
    PlainObject toDenseMatrix() const
    {
        PlainObject ret(rows(), cols());
        for (Index j = 0; j < cols(); ++j)
        {
            auto x = m_coeffs(j);
            auto v = Scalar(1);
            ret(0, j) = v;
            for (Index i = 1; i < rows(); ++i)
            {
                v *= x;
                ret(i, j) = v;
            }
        }
        return ret;
    }

    /// Compute matrix-vector product of the form `dst += alpha * A * rhs`
    template <typename Dest, typename RHS>
    void apply(Dest& dst, const Eigen::MatrixBase<RHS>& rhs, Scalar alpha) const
    {
        apply_impl(dst, rhs, alpha, coeffs());
    }

    /// Compute matrix-vector product of the form
    /// `dst += alpha * A.conjugate() * rhs`
    template <typename Dest, typename RHS>
    void applyConjugate(Dest& dst, const Eigen::MatrixBase<RHS>& rhs,
                        Scalar alpha) const
    {
        apply_impl(dst, rhs, alpha, coeffs().conjugate());
    }

    /// Compute matrix-vector product of the form
    /// `dst += alpha * A.transpose() * rhs`
    template <typename Dest, typename RHS>
    void applyTranspose(Dest& dst, const Eigen::MatrixBase<RHS>& rhs,
                        Scalar alpha) const
    {
        apply_transpose_impl(dst, rhs, alpha, coeffs());
    }

    /// Compute matrix-vector product of the form
    /// `dst += alpha * A.adjoint() * rhs`
    template <typename Dest, typename RHS>
    void applyAdjoint(Dest& dst, const Eigen::MatrixBase<RHS>& rhs,
                      Scalar alpha) const
    {
        apply_transpose_impl(dst, rhs, alpha, coeffs().conjugate());
    }

private:
    template <typename Dest, typename RHS, typename CoeffsV>
    void apply_impl(Dest& dst, const Eigen::MatrixBase<RHS>& rhs, Scalar alpha,
                    const Eigen::MatrixBase<CoeffsV>& coeffs) const
    {
        EIGEN_STATIC_ASSERT_VECTOR_ONLY(Dest);
        EIGEN_STATIC_ASSERT_VECTOR_ONLY(RHS);

        assert(dst.size() == rows());
        assert(rhs.size() == cols());

        if (alpha == Scalar(/*zero*/))
        {
            return;
        }

        m_workspace = rhs.derived();

        dst(0) += alpha * m_workspace.sum();
        for (Index i = 1; i < rows(); ++i)
        {
            m_workspace.array() *= coeffs.array();
            dst(i) += alpha * m_workspace.sum();
        }
    }

    template <typename Dest, typename RHS, typename CoeffsV>
    void apply_transpose_impl(Dest& dst, const Eigen::MatrixBase<RHS>& rhs,
                              Scalar alpha,
                              const Eigen::MatrixBase<CoeffsV>& coeffs) const
    {
        EIGEN_STATIC_ASSERT_VECTOR_ONLY(Dest);
        EIGEN_STATIC_ASSERT_VECTOR_ONLY(RHS);

        assert(dst.size() == cols());
        assert(rhs.size() == rows());

        for (Index i = 0; i < cols(); ++i)
        {
            auto x = coeffs(i);
            // Evaluate polynomial using Honer's method
            auto s = Scalar();
            for (Index j = 0; j < rows(); ++j)
            {
                s = s * x + rhs(rows() - j - 1);
            }

            dst(i) += alpha * s;
        }
    }
};

} // namespace mxpfit

#endif /* MXPFIT_VANDERMONDE_MATRIX_HPP */


//---------------------------------------------------------------------------//
//!
//! \file   tstMomentumConversion.cpp
//! \author Alex Robinson
//! \brief  The momentum conversion unit tests
//!
//---------------------------------------------------------------------------//

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

// Trilinos Includes
#include <Teuchos_UnitTestHarness.hpp>

// FRENSIE Includes
#include "Utility_MomentumUnits.hpp"
#include "Utility_RawPhysicalConstants.hpp"

using namespace Utility::Units;
using boost::units::quantity;

//---------------------------------------------------------------------------//
// Tests
//---------------------------------------------------------------------------//
// Check that the momentum units can be converted
TEUCHOS_UNIT_TEST( MomentumConversion, convert )
{
  quantity<AtomicMomentum> atomic_momentum_q( 1.0*mec_momentum );

  quantity<MeCMomentum> mec_momentum_q( 1.0*atomic_momentum );

  TEST_FLOATING_EQUALITY(
		atomic_momentum_q.value(),
		Utility::RawPhysicalConstants::inverse_fine_structure_constant,
		1e-15 );
  TEST_FLOATING_EQUALITY(
			mec_momentum_q.value(),
			Utility::RawPhysicalConstants::fine_structure_constant,
			1e-15 );
}

//---------------------------------------------------------------------------//
// end tstMomentumConversion.cpp
//---------------------------------------------------------------------------//


//=======================================================================
// Copyright (c) 2014 Piotr Smulewicz
//
// 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 k_center_test.cpp
 * @brief
 * @author Piotr Smulewicz
 * @version 1.0
 * @date 2014-01-28
 */

#include "test_utils/test_result_check.hpp"
#include "greedy/k_center/in_balls.hpp"

#include "paal/data_structures/metric/basic_metrics.hpp"
#include "paal/greedy/k_center/k_center.hpp"
#include "paal/utils/irange.hpp"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(KCenter) {
    std::size_t const NUM_CENTERS = 3;
    std::size_t const NUM_ITEMS = 6;
    const double OPTIMAL = 1;
    const double APPROXIMATION_RATIO = 2;
    auto metric = [](int a, int b) { return 0.1 + abs(a - b) * 0.9; };
    auto items = paal::irange(NUM_ITEMS);
    std::vector<int> centers;
    // solution
    double radius = paal::greedy::kCenter(metric, NUM_CENTERS, items.begin(),
                                          items.end(), back_inserter(centers));
    LOGLN("Radius " << radius);
    LOGLN("Centers:");
    LOG_COPY_RANGE_DEL(centers, " ");
    LOGLN("");
    BOOST_CHECK_EQUAL(centers.size(), NUM_CENTERS);
    check_result(radius, OPTIMAL, APPROXIMATION_RATIO);
    paal::in_balls(items, centers, metric, radius);
}


#ifndef CLUSTER_H
#define CLUSTER_H 1

#include <set>
#include <vector>
#include <STD/Iostream.hpp>

//#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>

namespace Clustering{

  typedef double Coord;            // a coordinate
  typedef double Distance;         // distance
  typedef unsigned int Dimensions; // how many dimensions
  typedef unsigned int PointId;    // the id of this point
  typedef unsigned int ClusterId;  // the id of this cluster

  typedef std::vector<Coord> Point;    // a point (a centroid)
  typedef std::vector<Point> Points;   // collection of points

  typedef std::set<PointId> SetPoints; // set of points

  // ClusterId -> (PointId, PointId, PointId, .... )
  typedef std::vector<SetPoints> ClustersToPoints;
  // PointId -> ClusterId
  typedef std::vector<ClusterId> PointsToClusters;
  // coll of centroids
  typedef std::vector<Point> Centroids;

  //
  // Dump a point
  //
  std::ostream& operator << (std::ostream& os, Point& p);

  //
  // distance between two points
  //
  Distance distance(const Point & x, const Point & y);

  //
  // Dump collection of Points
  //
  std::ostream& operator << (std::ostream& os, Points& cps);

  //
  // Dump a Set of points
  //
  std::ostream& operator << (std::ostream& os, SetPoints & sp);

  //
  // Dump centroids
  //
  std::ostream& operator << (std::ostream& os, Centroids & cp);

  //
  // Dump ClustersToPoints
  //
  std::ostream& operator << (std::ostream& os, ClustersToPoints & cp);

  //
  // Dump ClustersToPoints
  //
  std::ostream& operator << (std::ostream& os, PointsToClusters & pc);

  //
  // This class stores all the points available in the model
  //
  class PointsSpace{

    //
    // Dump collection of points
    //
    friend std::ostream& operator << (std::ostream& os, PointsSpace & ps){

      PointId i = 0;
      BOOST_FOREACH(Points::value_type p, ps.points__){
	os << "point["<<i++<<"]=" << p << std::endl;
      }
      return os;
    };

  public:

    PointsSpace(PointId num_points, Dimensions num_dimensions)
      : num_points__(num_points), num_dimensions__(num_dimensions)
    {init_points();};

    inline const PointId getNumPoints() const {return num_points__;}
    inline const PointId getNumDimensions() const {return num_dimensions__;}
    inline const Point& getPoint(PointId pid) const { return points__[pid];}
    inline void setPoint(PointId pid, int dim, double val) { points__.at(pid).at(dim) = val;}

  private:
    //
    // Init collection of points
    //
    void init_points();

    PointId num_points__;
    Dimensions num_dimensions__;
    Points points__;
  };

  //
  //  This class represents a cluster
  //
  class Clusters {

  private:

    ClusterId num_clusters__;    // number of clusters
    PointsSpace& ps__;           // the point space
    Dimensions num_dimensions__; // the dimensions of vectors
    PointId num_points__;        // total number of points
    ClustersToPoints clusters_to_points__;
    PointsToClusters points_to_clusters__;
    Centroids centroids__;

    //
    // Zero centroids
    //
    void zero_centroids();

    //
    // Zero centroids
    //
    void compute_centroids();

    //
    // Initial partition points among available clusters
    //
    void initial_partition_points();

  public:

    //const ClustersToPoints & getClusters() const { return clusters_to_points__; }
    const Centroids & getCentroids() const { return centroids__; }
    //
    // Dump ClustersToPoints
    //
    friend std::ostream& operator << (std::ostream& os, Clusters & cl){

      ClusterId cid = 0;
      BOOST_FOREACH(ClustersToPoints::value_type set, cl.clusters_to_points__){
	os << "Cluster["<<cid<<"]=(";
	BOOST_FOREACH(SetPoints::value_type pid, set){
	  Point p = cl.ps__.getPoint(pid);
	  os << "(" << p << ")";
	}
	os << ")" << std::endl;
	cid++;
      }
      return os;
    }

    Clusters(ClusterId num_clusters, PointsSpace & ps)
      : num_clusters__(num_clusters), ps__(ps),
	num_dimensions__(ps.getNumDimensions()),
	num_points__(ps.getNumPoints()),
	points_to_clusters__(num_points__, 0){

      ClusterId i = 0;
      Dimensions dim;
      for (; i < num_clusters; i++){
	Point point;   // each centroid is a point
	for (dim=0; dim<num_dimensions__; dim++)
	  point.push_back(0.0);
	SetPoints set_of_points;

	// init centroids
	centroids__.push_back(point);

	// init clusterId -> set of points
	clusters_to_points__.push_back(set_of_points);
	// init point <- cluster
      }
      /*
      std::cout << "Centroids"
		<<std::endl<< centroids__;
      std::cout << "PointsToClusters"
		<<std::endl<< points_to_clusters__;
      std::cout << "ClustersToPoints"
		<<std::endl<< clusters_to_points__;
      */
    };

    //
    // k-means
    //
    void k_means (void);
  };

};

#endif


/*=============================================================================
    Copyright (c) 2001-2003 Daniel Nuffer
    http://spirit.sourceforge.net/

    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)
=============================================================================*/
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_ast.hpp>
#include <boost/assert.hpp>

#include <iostream>
#include <stack>
#include <functional>
#include <string>

// This example shows how to use an AST and tree_iter_node instead of
// tree_val_node
////////////////////////////////////////////////////////////////////////////
using namespace std;
using namespace BOOST_SPIRIT_CLASSIC_NS;

typedef char const*         iterator_t;
typedef tree_match<iterator_t, node_iter_data_factory<> >
    parse_tree_match_t;

typedef parse_tree_match_t::tree_iterator iter_t;

typedef ast_match_policy<iterator_t, node_iter_data_factory<> > match_policy_t;
typedef scanner<iterator_t, scanner_policies<iter_policy_t, match_policy_t> > scanner_t;
typedef rule<scanner_t> rule_t;

//  grammar rules
rule_t expression, term, factor, integer;

////////////////////////////////////////////////////////////////////////////
long evaluate(parse_tree_match_t hit);
long eval_expression(iter_t const& i);
long eval_term(iter_t const& i);
long eval_factor(iter_t const& i);
long eval_integer(iter_t const& i);

long evaluate(parse_tree_match_t hit)
{
    return eval_expression(hit.trees.begin());
}

long eval_expression(iter_t const& i)
{
    cout << "In eval_expression. i->value = " <<
        string(i->value.begin(), i->value.end()) <<
        " i->children.size() = " << i->children.size() << endl;

    cout << "ID: " << i->value.id().to_long() << endl;

    if (i->value.id() == integer.id())
    {
        BOOST_ASSERT(i->children.size() == 0);
        return strtol(i->value.begin(), 0, 10);
    }
    else if (i->value.id() == factor.id())
    {
        // factor can only be unary minus
        BOOST_ASSERT(*i->value.begin() == '-');
        return - eval_expression(i->children.begin());
    }
    else if (i->value.id() == term.id())
    {
        if (*i->value.begin() == '*')
        {
            BOOST_ASSERT(i->children.size() == 2);
            return eval_expression(i->children.begin()) *
                eval_expression(i->children.begin()+1);
        }
        else if (*i->value.begin() == '/')
        {
            BOOST_ASSERT(i->children.size() == 2);
            return eval_expression(i->children.begin()) /
                eval_expression(i->children.begin()+1);
        }
        else
            BOOST_ASSERT(0);
    }
    else if (i->value.id() == expression.id())
    {
        if (*i->value.begin() == '+')
        {
            BOOST_ASSERT(i->children.size() == 2);
            return eval_expression(i->children.begin()) +
                eval_expression(i->children.begin()+1);
        }
        else if (*i->value.begin() == '-')
        {
            BOOST_ASSERT(i->children.size() == 2);
            return eval_expression(i->children.begin()) -
                eval_expression(i->children.begin()+1);
        }
        else
            BOOST_ASSERT(0);
    }
    else
        BOOST_ASSERT(0); // error

   return 0;
}

////////////////////////////////////////////////////////////////////////////
int
main()
{
    BOOST_SPIRIT_DEBUG_RULE(integer);
    BOOST_SPIRIT_DEBUG_RULE(factor);
    BOOST_SPIRIT_DEBUG_RULE(term);
    BOOST_SPIRIT_DEBUG_RULE(expression);
    //  Start grammar definition
    integer     =   leaf_node_d[ lexeme_d[ (!ch_p('-') >> +digit_p) ] ];
    factor      =   integer
                |   inner_node_d[ch_p('(') >> expression >> ch_p(')')]
                |   (root_node_d[ch_p('-')] >> factor);
    term        =   factor >>
                    *(  (root_node_d[ch_p('*')] >> factor)
                      | (root_node_d[ch_p('/')] >> factor)
                    );
    expression  =   term >>
                    *(  (root_node_d[ch_p('+')] >> term)
                      | (root_node_d[ch_p('-')] >> term)
                    );
    //  End grammar definition

    cout << "/////////////////////////////////////////////////////////\n\n";
    cout << "\t\tThe simplest working calculator...\n\n";
    cout << "/////////////////////////////////////////////////////////\n\n";
    cout << "Type an expression...or [q or Q] to quit\n\n";

    string str;
    while (getline(cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        const char* str_begin = str.c_str();
        const char* str_end = str.c_str();
        while (*str_end)
            ++str_end;

        scanner_t scan(str_begin, str_end);

        parse_tree_match_t hit = expression.parse(scan);

        if (hit && str_begin == str_end)
        {
#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
            // dump parse tree as XML
            std::map<rule_id, std::string> rule_names;
            rule_names[&integer] = "integer";
            rule_names[&factor] = "factor";
            rule_names[&term] = "term";
            rule_names[&expression] = "expression";
            tree_to_xml(cout, hit.trees, str.c_str(), rule_names);
#endif

            // print the result
            cout << "parsing succeeded\n";
            cout << "result = " << evaluate(hit) << "\n\n";
        }
        else
        {
            cout << "parsing failed\n";
        }
    }

    cout << "Bye... :-) \n\n";
    return 0;
}


#include "../secp256k1/include/MultiExponent.h"

#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>

BOOST_AUTO_TEST_CASE(multiexponentation_test)
{
    std::vector<int> sizes = {1, 4, 20, 57,136, 235, 1260, 4420, 7880, 16050, 10, 100, 1000, 5000};

    for(unsigned int j = 0; j < sizes.size(); ++j){
        int size = sizes[j];
        std::vector<secp_primitives::GroupElement> gens;
        std::vector<secp_primitives::Scalar> scalars;

        secp_primitives::GroupElement r;
        gens.resize(size);
        scalars.resize(size);
        for (int i = 0; i < size; ++i) {
            gens[i].randomize();
            scalars[i].randomize();

            r += gens[i] * scalars[i];
        }

        secp_primitives::MultiExponent multiexponent(gens, scalars);
        secp_primitives::GroupElement result = multiexponent.get_multiple();

        BOOST_CHECK_EQUAL(r,result);
    }
}


#pragma once
#include <iostream>

#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <unsupported/Eigen/NonLinearOptimization>
//#include <unsupported/Eigen/LevenbergMarquardt>

// LM minimize for the model y = a w + b x + c y + d z
//typedef std::vector<Eigen::Vector4d,Eigen::aligned_allocator<Eigen::Vector4d> > Point4DVector;
typedef std::vector<Eigen::Vector4d > Point4DVector;
typedef std::vector<Eigen::Vector3d > Point3DVector;
typedef std::vector<Eigen::Matrix3d > Matrix3DVector;
typedef std::vector<Eigen::Matrix4d > Matrix4DVector;
typedef std::vector<Eigen::Affine3d > Affine3DVector;
typedef std::vector<Eigen::Affine3f > Affine3fVector;

typedef std::vector<Eigen::Vector3d > Vector3dVector;
typedef std::vector<Eigen::Quaterniond > QuaterniondVector;

typedef Eigen::Matrix<double,7,1> Vector7d ;
typedef std::vector<Vector7d > Vector7dVector;

// Generic functor
template<typename _Scalar, int NX = Eigen::Dynamic, int NY = Eigen::Dynamic>
struct Functor
{
typedef _Scalar Scalar;
enum {
    InputsAtCompileTime = NX,
    ValuesAtCompileTime = NY
};
typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;

int m_inputs, m_values;

Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}

int inputs() const { return m_inputs; }
int values() const { return m_values; }

};

void NormalizeQ(Eigen::Quaterniond &Q);
void Affine3d_From_Qt( Eigen::Affine3d& T_a2b, Eigen::Quaterniond Q_a2b,Eigen::Vector3d t_a2b );
void Affine3d_To_Vector( const Eigen::Affine3d& T,Eigen::Matrix<double,16,1>& V );
void Vector_To_Affine3d(  const Eigen::VectorXd& V ,Eigen::Affine3d& T);

struct Q_bc_Functor : Functor<double>
{
  int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
  {
      // 0  = w * p[0] + x * p[1] + y * p[2] + z * p[3]
    for(unsigned int i = 0; i < this->Mct_sub_Mb.size(); ++i)
      {
      fvec(i) = this->Mct_sub_Mb[i](0) * x(0) + this->Mct_sub_Mb[i](1) * x(1) +
              this->Mct_sub_Mb[i](2) * x(2) + this->Mct_sub_Mb[i](3) * x(3) +
              (pow( x(0),2 ) + pow( x(1),2 ) + pow( x(2),2 ) + pow( x(3),2 ) - 1)*1;
      }
    return 0;
  }

  Point4DVector Mct_sub_Mb;

  int inputs() const { return 2; } // There are two parameters of the model
  int values() const { return this->Mct_sub_Mb.size(); } // The number of observations
};

struct Q_bc_FunctorNumericalDiff : Eigen::NumericalDiff<Q_bc_Functor> {};

struct T_bc_Functor : Functor<double>
{
    Eigen::VectorXd t_temp_N;
    Eigen::MatrixXd R_temp_N;

    int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
    {
        fvec = t_temp_N - R_temp_N * x;
        return 0;
    }
    int inputs() const { return 2; } // There are two parameters of the model
    int values() const { return t_temp_N.rows(); } // The number of observations
};
struct T_bc_FunctorNumericalDiff : Eigen::NumericalDiff<T_bc_Functor> {};

Point4DVector GeneratePoints(const Eigen::MatrixXd M);

struct T_rw_Functor : Functor<double>
{
    QuaterniondVector Q_r2w_V;
    Vector3dVector t_r2w_V;
    int operator()(const Eigen::VectorXd &Q_t_r2w, Eigen::VectorXd &fvec) const
    {
        for(int i=0;i<Q_r2w_V.size();i++)
        {
            fvec(i*7+0) = Q_r2w_V.at(i).x() - Q_t_r2w(0);
            fvec(i*7+1) = Q_r2w_V.at(i).y() - Q_t_r2w(1);
            fvec(i*7+2) = Q_r2w_V.at(i).z() - Q_t_r2w(2);
            fvec(i*7+3) = Q_r2w_V.at(i).w() - Q_t_r2w(3);

            for(int j=0;j<3;j++)
            {
                fvec(i*7+4+j) = t_r2w_V.at(i)(j) - Q_t_r2w(j+4);
            }
        }
    }
    int inputs() const { return 2; } // There are two parameters of the model
    int values() const { return Q_r2w_V.size()*7; } // The number of observations
};
struct T_rw_FunctorNumericalDiff : Eigen::NumericalDiff<T_rw_Functor> {};

struct InCal_Functor : Functor<double>
{
    Affine3DVector T_w2b_V,T_r2c_V;
    int operator()(const Eigen::VectorXd &T_In, Eigen::VectorXd &fvec) const
    {
//        Eigen::Quaterniond Q_r2w( T_In(3),T_In(0),T_In(1),T_In(2) ) ,Q_b2c( T_In(3+7),T_In(0+7),T_In(1+7),T_In(2+7) );
//        Eigen::Vector3d t_r2w( T_In(4),T_In(5),T_In(6) ) ,t_b2c( T_In(4+7),T_In(5+7),T_In(6+7) );

        Eigen::Affine3d T_r2w,T_c2b;
//        Affine3d_From_Qt(T_r2w,Q_r2w,t_r2w);
//        Affine3d_From_Qt(T_b2c,Q_b2c,t_b2c);
        Eigen::VectorXd V_r2w,V_c2b;
        V_r2w = T_In.block<16,1>(0,0);
        V_c2b = T_In.block<16,1>(16,0);

        Vector_To_Affine3d(V_r2w,T_r2w);
        Vector_To_Affine3d(V_c2b,T_c2b);

        for(int i=0;i<T_w2b_V.size();i++)
        {
            Eigen::Affine3d T_r2b_1 = T_c2b * T_r2c_V.at(i);
            Eigen::Affine3d T_r2b_2 = T_w2b_V.at(i) * T_r2w;

            Eigen::Matrix4d T_err = T_r2b_1.matrix() - T_r2b_2.matrix();

//            Eigen::Affine3d T_r2r =  T_r2b_1.inverse() * T_r2b_2;
//            Eigen::Matrix4d T_err = T_r2r.matrix() - Eigen::Affine3d::Identity().matrix();

            for(int j=0;j<4;j++)
            {
                for(int k=0;k<4;k++)
                {
                    fvec(i*16+j*4+k) = T_err(j,k);
                }
            }
        }
    }
    int inputs() const { return 2; } // There are two parameters of the model
    int values() const { return T_w2b_V.size()*16; } // The number of observations
};
struct Incal_FunctorNumericalDiff : Eigen::NumericalDiff<InCal_Functor> {};

int Cal_Q_bc(Eigen::MatrixXf M,Eigen::VectorXf& xf);
int Cal_T_bc(Eigen::VectorXf t_temp_N,Eigen::MatrixXf R_temp_N,Eigen::VectorXf& t_b2c);
int InstallCalib_LM( Eigen::Affine3f &T_b2c,  Eigen::Affine3f &T_r2w, Affine3fVector& T_r2c_V,Affine3fVector& T_w2b_V);
int Cal_T_rw(Eigen::Affine3f& T_r2w,Affine3fVector& T_r2w_V_f);


/*
Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/)
Copyright 2017-2019 University of Huddersfield.
Licensed under the BSD-3 License.
See license.md file in the project root for full license information.
This project has received funding from the European Research Council (ERC)
under the European Union’s Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/

#pragma once

#include "../util/FluidEigenMappings.hpp"
#include "../util/NNFuncs.hpp"
#include "../util/NNLayer.hpp"
#include "../../data/FluidDataSet.hpp"
#include "../../data/FluidIndex.hpp"
#include "../../data/FluidTensor.hpp"
#include "../../data/TensorTypes.hpp"
#include <Eigen/Core>
#include <random>

namespace fluid {
namespace algorithm {

class MLP
{
  using ArrayXd = Eigen::ArrayXd;
  using ArrayXXd = Eigen::ArrayXXd;

public:
  explicit MLP() = default;
  ~MLP() = default;

  void init(index inputSize, index outputSize,
            FluidTensor<index, 1> hiddenSizes, index hiddenAct, index outputAct)
  {
    mLayers.clear();
    std::vector<index> sizes = {inputSize};
    std::vector<index> activations = {};
    for (auto&& s : hiddenSizes)
    {
      sizes.push_back(s);
      activations.push_back(hiddenAct);
    }
    sizes.push_back(outputSize);
    activations.push_back(outputAct);
    for (index i = 0; i < asSigned(sizes.size() - 1); i++)
    {
      mLayers.push_back(NNLayer(sizes[asUnsigned(i)], sizes[asUnsigned(i + 1)],
                                activations[asUnsigned(i)]));
    }
    for (auto&& l : mLayers) l.init();
    mInitialized = true;
    mTrained = false;
  }

  void getParameters(index layer, RealMatrixView W, RealVectorView b,
                     index& layerType) const
  {
    using namespace _impl;
    W = asFluid(mLayers[asUnsigned(layer)].getWeights());
    b = asFluid(mLayers[asUnsigned(layer)].getBiases());
    layerType = mLayers[asUnsigned(layer)].getActType();
  }

  void setParameters(index layer, RealMatrixView W, RealVectorView b,
                     index layerType)
  {
    using namespace Eigen;
    using namespace std;
    using namespace _impl;
    MatrixXd weights = asEigen<Matrix>(W);
    VectorXd biases = asEigen<Matrix>(b);
    mLayers[asUnsigned(layer)].init(weights, biases, layerType);
  }

  void clear()
  {
    for (auto&& l : mLayers) l.init();
    mInitialized = false;
    mTrained = false;
  }

  double loss(ArrayXXd pred, ArrayXXd out)
  {
    assert(pred.rows() == out.rows());
    return (pred - out).square().sum() / out.rows();
  }

  void process(RealMatrixView in, RealMatrixView out, index startLayer,
               index endLayer)
  {
    using namespace _impl;
    using namespace Eigen;
    ArrayXXd input = asEigen<Eigen::Array>(in);
    ArrayXXd output = ArrayXXd::Zero(out.rows(), out.cols());
    forward(input, output, startLayer, endLayer);
    out = asFluid(output);
  }

  void processFrame(RealVectorView in, RealVectorView out, index startLayer,
                    index endLayer)
  {
    using namespace _impl;
    using namespace Eigen;
    ArrayXd  tmpIn = asEigen<Eigen::Array>(in);
    ArrayXXd input(1, tmpIn.size());
    input.row(0) = tmpIn;
    ArrayXXd output = ArrayXXd::Zero(1, out.size());
    forward(input, output, startLayer, endLayer);
    ArrayXd tmpOut = output.row(0);
    out = asFluid(tmpOut);
  }

  void forward(Eigen::Ref<ArrayXXd> in, Eigen::Ref<ArrayXXd> out)
  {
    forward(in, out, 0, asSigned(mLayers.size()));
  }

  void forward(Eigen::Ref<ArrayXXd> in, Eigen::Ref<ArrayXXd> out,
               index startLayer, index endLayer)
  {
    if (startLayer >= asSigned(mLayers.size()) ||
        endLayer > asSigned(mLayers.size()))
      return;
    if (startLayer < 0 || endLayer <= 0) return;
    ArrayXXd input = in;
    ArrayXXd output;
    for (index i = startLayer; i < endLayer; i++)
    {
      auto&& l = mLayers[asUnsigned(i)];
      output = ArrayXXd::Zero(input.rows(), l.outputSize());
      l.forward(input, output);
      input = output;
    }
    out = output;
  }

  void backward(Eigen::Ref<ArrayXXd> out)
  {
    index    nRows = out.rows();
    ArrayXXd chain =
        ArrayXXd::Zero(nRows, mLayers[mLayers.size() - 1].inputSize());
    mLayers[mLayers.size() - 1].backward(out, chain);
    for (index i = asSigned(mLayers.size() - 2); i >= 0; i--)
    {
      ArrayXXd tmp = ArrayXXd::Zero(nRows, mLayers[asUnsigned(i)].inputSize());
      mLayers[asUnsigned(i)].backward(chain, tmp);
      chain = tmp;
    }
  }

  void update(double learningRate, double momentum)
  {
    for (auto&& l : mLayers) l.update(learningRate, momentum);
  }

  index size() const { return asSigned(mLayers.size()); }
  bool  trained() const { return mTrained; }
  void  setTrained(bool val) { mTrained = val; }
  index initialized() const { return mInitialized; }

  // 0 = size of the input, 1 = output size of first hidden
  index outputSize(index layer) const
  {
    if (layer == 0) return mLayers[0].inputSize();
    if (layer < 0 || layer > asSigned(mLayers.size())) return 0;
    return mLayers[asUnsigned(layer - 1)].outputSize();
  }

  index inputSize(index layer) const
  {
    return (layer >= asSigned(mLayers.size()) || layer < 0)
               ? 0
               : mLayers[asUnsigned(layer)].inputSize();
  }

  index dims() const
  {
    return mLayers.size() == 0 ? 0 : mLayers[0].inputSize();
  }

  std::vector<NNLayer> mLayers;
  bool                 mInitialized{false};
  bool                 mTrained{false};
};
} // namespace algorithm
} // namespace fluid


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

#ifndef BOOST_ASTRONOMY_COORDINATE_ARITHMETIC_HPP
#define BOOST_ASTRONOMY_COORDINATE_ARITHMETIC_HPP

#include <type_traits>

#include <boost/units/quantity.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/arithmetic/cross_product.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/algorithms/transform.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/units/conversion.hpp>

#include <boost/astronomy/coordinate/base_representation.hpp>
#include <boost/astronomy/coordinate/cartesian_representation.hpp>

namespace boost { namespace astronomy { namespace coordinate {

namespace bg = boost::geometry;
namespace bu = boost::units;

//!Returns the cross product of representation1 and representation2
template
<
    template<typename ...> class Representation1,
    template<typename ...> class Representation2,
    typename ...Args1,
    typename ...Args2
>
auto cross
(
    Representation1<Args1...> const& representation1,
    Representation2<Args2...> const& representation2
)
{
    /*!both the coordinates/vector are first converted into
    cartesian coordinate system then cross product of both cartesian
    vectors is converted into requested type and returned*/

    /*checking types if it is not subclass of
    base_representaion then compile time erorr is generated*/
    //BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
    //    <
    //        boost::astronomy::coordinate::base_representation,
    //        Representation1<Args1...>
    //    >::value),
    //    "First argument type is expected to be a representation class");
    //BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
    //    <
    //        boost::astronomy::coordinate::base_representation,
    //        Representation2<Args2...>
    //    >::value),
    //    "Second argument type is expected to be a representation class");

    /*converting both coordinates/vector into cartesian system*/

    typedef Representation1<Args1...> representation1_type;
    typedef Representation2<Args2...> representation2_type;

    bg::model::point
    <
        typename std::conditional
        <
            sizeof(typename representation2_type::type) >=
                sizeof(typename representation1_type::type),
            typename representation2_type::type,
            typename representation1_type::type
        >::type,
        3,
        bg::cs::cartesian
    > tempPoint1, tempPoint2, result;

    bg::transform(representation1.get_point(), tempPoint1);
    bg::transform(representation2.get_point(), tempPoint2);

    bg::set<0>(result, (bg::get<1>(tempPoint1)*bg::get<2>(tempPoint2)) -
        ((bg::get<2>(tempPoint1)*
        bu::conversion_factor(typename representation1_type::quantity3::unit_type(),
        typename representation1_type::quantity2::unit_type()))*
        (bg::get<1>(tempPoint2)*
        bu::conversion_factor(typename representation2_type::quantity2::unit_type(),
        typename representation2_type::quantity3::unit_type()))));

    bg::set<1>(result, (bg::get<2>(tempPoint1)*bg::get<0>(tempPoint2)) -
        ((bg::get<0>(tempPoint1)*
        bu::conversion_factor(typename representation1_type::quantity1::unit_type(),
        typename representation1_type::quantity3::unit_type()))*
        (bg::get<2>(tempPoint2)*
        bu::conversion_factor(typename representation2_type::quantity3::unit_type(),
        typename representation2_type::quantity1::unit_type()))));

    bg::set<2>(result, (bg::get<0>(tempPoint1)*bg::get<1>(tempPoint2)) -
        ((bg::get<1>(tempPoint1)*
        bu::conversion_factor(typename representation1_type::quantity2::unit_type(),
        typename representation1_type::quantity1::unit_type()))*
        (bg::get<0>(tempPoint2)*
        bu::conversion_factor(typename representation2_type::quantity1::unit_type(),
        typename representation2_type::quantity2::unit_type()))));

    return Representation1
        <
            typename representation1_type::type,
            bu::quantity<typename bu::multiply_typeof_helper
            <
                typename representation1_type::quantity2::unit_type,
                typename representation2_type::quantity3::unit_type>::type
            >,
            bu::quantity<typename bu::multiply_typeof_helper
            <
                typename representation1_type::quantity3::unit_type,
                typename representation2_type::quantity1::unit_type>::type
            >,
            bu::quantity<typename bu::multiply_typeof_helper
            <
                typename representation1_type::quantity1::unit_type,
                typename representation2_type::quantity2::unit_type>::type
            >
        >(result);
}

//! Returns dot product of representation1 and representation2
template<typename Representation1, typename Representation2>
auto dot(Representation1 const& representation1, Representation2 const& representation2)
{
    /*!both the coordinates/vector are first converted into
    cartesian coordinate system then dot product of both cartesian
    product is converted into requested type and returned*/

    /*converting both coordinates/vector into cartesian system*/
    bg::model::point
    <
        typename std::conditional
        <
            sizeof(typename Representation2::type) >=
                sizeof(typename Representation1::type),
            typename Representation2::type,
            typename Representation1::type
        >::type,
        3,
        bg::cs::cartesian
    > tempPoint1, tempPoint2;

    auto cartesian1 = make_cartesian_representation(representation1);
    auto cartesian2 = make_cartesian_representation(representation2);

    typedef decltype(cartesian1) cartesian1_type;
    typedef decltype(cartesian2) cartesian2_type;

    bg::set<0>(tempPoint1, cartesian1.get_x().value());
    bg::set<1>(tempPoint1,
        static_cast<typename cartesian1_type::quantity1>(cartesian1.get_y()).value());
    bg::set<2>(tempPoint1,
        static_cast<typename cartesian1_type::quantity1>(cartesian1.get_z()).value());

    bg::set<0>(tempPoint2, cartesian2.get_x().value());
    bg::set<1>(tempPoint2,
        static_cast<typename cartesian2_type::quantity1>(cartesian2.get_y()).value());
    bg::set<2>(tempPoint2,
        static_cast<typename cartesian2_type::quantity1>(cartesian2.get_z()).value());

    return bg::dot_product(tempPoint1, tempPoint2) *
        typename cartesian1_type::quantity1::unit_type() *
        typename cartesian2_type::quantity1::unit_type();
}

//! Returns magnitude of the cartesian vector
template
<
    typename CoordinateType,
    typename XQuantity,
    typename YQuantity,
    typename ZQuantity
>
auto magnitude
(
    cartesian_representation
    <
        CoordinateType,
        XQuantity,
        YQuantity,
        ZQuantity
    > const& vector
)
{
    CoordinateType result = 0;
    bg::model::point
    <
        CoordinateType,
        3,
        bg::cs::cartesian
    > tempPoint;

    bg::set<0>(tempPoint, vector.get_x().value());
    bg::set<1>(tempPoint, static_cast<XQuantity>(vector.get_y()).value());
    bg::set<2>(tempPoint, static_cast<XQuantity>(vector.get_z()).value());

    result += std::pow(bg::get<0>(tempPoint), 2) +
        std::pow(bg::get<1>(tempPoint), 2) +
        std::pow(bg::get<2>(tempPoint), 2);

    return std::sqrt(result) * typename XQuantity::unit_type();
}

//! Returns magnitude of the vector other than cartesian
template <typename Coordinate>
auto magnitude(Coordinate const& vector)
{
    return bg::get<2>(vector.get_point()) * typename Coordinate::quantity3::unit_type();
}

//! Returns the unit vector of vector given
template <typename ...Args>
cartesian_representation<Args...>
unit_vector(cartesian_representation<Args...> const& vector)
{
    bg::model::point
    <
        typename cartesian_representation<Args...>::type,
        3,
        bg::cs::cartesian
    > tempPoint;
    auto mag = magnitude(vector); //magnitude of vector

    //performing calculations to find unit vector
    bg::set<0>(tempPoint, vector.get_x().value() / mag.value());
    bg::set<1>(tempPoint,
        vector.get_y().value() /
        static_cast<typename cartesian_representation<Args...>::quantity2>(mag).value());
    bg::set<2>(tempPoint,
        vector.get_z().value() /
        static_cast<typename cartesian_representation<Args...>::quantity3>(mag).value());

    return cartesian_representation<Args...>(tempPoint);
}

//! Returns unit vector of given vector other than Cartesian
template <typename Coordinate>
auto unit_vector(Coordinate const& vector)
{
    Coordinate tempVector;

    tempVector.set_lat(vector.get_lat());
    tempVector.set_lon(vector.get_lon());
    tempVector.set_dist(1.0 * typename Coordinate::quantity3::unit_type());

    return tempVector;
}

//! Returns sum of representation1 and representation2
template<typename Representation1, typename Representation2>
Representation1 sum
(
    Representation1 const& representation1,
    Representation2 const& representation2
)
{
    /*!both the coordinates/vector are first converted into
    cartesian coordinate system then sum of both cartesian
    vectors is converted into the type of first argument and returned*/

    /*checking types if it is not subclass of
    base_representaion then compile time erorr is generated*/
    //BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
    //    <
    //        boost::astronomy::coordinate::base_representation,
    //        Representation1
    //    >::value),
    //    "First argument type is expected to be a representation class");
    //BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
    //    <
    //        boost::astronomy::coordinate::base_representation,
    //        Representation2
    //    >::value),
    //    "Second argument type is expected to be a representation class");

    /*converting both coordinates/vector into cartesian system*/
    bg::model::point
    <
        typename std::conditional
        <
            sizeof(typename Representation2::type) >=
                sizeof(typename Representation1::type),
            typename Representation2::type,
            typename Representation1::type
        >::type,
        3,
        bg::cs::cartesian
    > result;

    auto cartesian1 = make_cartesian_representation(representation1);
    auto cartesian2 = make_cartesian_representation(representation2);

    typedef decltype(cartesian1) cartesian1_type;

    //performing calculation to find the sum
    bg::set<0>(result, (cartesian1.get_x().value() +
        static_cast<typename cartesian1_type::quantity1>(cartesian2.get_x()).value()));
    bg::set<1>(result, (cartesian1.get_y().value() +
        static_cast<typename cartesian1_type::quantity2>(cartesian2.get_y()).value()));
    bg::set<2>(result, (cartesian1.get_z().value() +
        static_cast<typename cartesian1_type::quantity3>(cartesian2.get_z()).value()));

    return Representation1(result);
}

//! Returns mean of representation1 and representation2
template<typename Representation1, typename Representation2>
Representation1 mean
(
    Representation1 const& representation1,
    Representation2 const& representation2
)
{

    /*!both the coordinates/vector are first converted into
    cartesian coordinate system then mean of both cartesian
    vectors is converted into the type of first argument and returned*/

    /*checking return type if it is not subclass of
    base_representaion then compile time erorr is generated*/
    //BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
    //    <boost::astronomy::coordinate::base_representation, ReturnType>::value),
    //    "return type is expected to be a representation class");

    /*converting both coordinates/vector into cartesian system*/
    bg::model::point
    <
        typename std::conditional
        <
            sizeof(typename Representation2::type) >=
                sizeof(typename Representation1::type),
            typename Representation2::type,
            typename Representation1::type
        >::type,
        3,
        bg::cs::cartesian
    > result;

    auto cartesian1 = make_cartesian_representation(representation1);
    auto cartesian2 = make_cartesian_representation(representation2);

    typedef decltype(cartesian1) cartesian1_type;

    //performing calculation to find the mean
    bg::set<0>(result, (cartesian1.get_x().value() +
        static_cast<typename cartesian1_type::quantity1>(cartesian2.get_x()).value())/2);
    bg::set<1>(result, (cartesian1.get_y().value() +
        static_cast<typename cartesian1_type::quantity2>(cartesian2.get_y()).value())/2);
    bg::set<2>(result, (cartesian1.get_z().value() +
        static_cast<typename cartesian1_type::quantity3>(cartesian2.get_z()).value())/2);

    return Representation1(result);
}

}}} // namespace boost::astronomy::coordinate
#endif // !BOOST_ASTRONOMY_COORDINATE_ARITHMETIC_HPP


// Copyright (c) 2014-2020 The Virie Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <cstddef>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/program_options.hpp>

#include "common/util.h"
#include "string_tools.h"
#include "common/command_line.h"
#include "currency_core/currency_config.h"
#include "currency_core/difficulty.h"

#define COUNT_GENERATE 2000
#define DEFAULT_TEST_DIFFICULTY_TARGET        120

#define NEXT_DIFFICULTY_ALGO(A,B,C) currency::next_difficulty(A,B,C)

namespace fs = boost::filesystem;

bool generate(const std::string& file_name, uint64_t count = COUNT_GENERATE)
{
  struct powers_t
  {
    uint64_t step;
    uint64_t power;
  };

  const std::vector<powers_t> table_powers{ {100, 10}, {500, 1000}, {1000, 10000}, {1500, 100000}, {~0ull, 10} };

  std::vector<std::uint64_t> times;
  times.reserve(DIFFICULTY_WINDOW + 1);
  times.push_back(0);

  std::vector<currency::wide_difficulty_type> diffs;;
  diffs.reserve(DIFFICULTY_WINDOW + 1);
  diffs.push_back(DIFFICULTY_STARTER);

  uint64_t time = 100;
  TRY_ENTRY();
    std::srand(unsigned(std::time(0)));
    fs::ofstream fo;
    fo.open(file_name);

    fo << times.front() << "\t" << diffs.front() << std::endl;
    for (uint64_t i = 0; i < count; ++i)
    {
      currency::wide_difficulty_type w_diff = NEXT_DIFFICULTY_ALGO(times, diffs, DEFAULT_TEST_DIFFICULTY_TARGET);
      currency::difficulty_type diff = w_diff.convert_to<uint64_t>();

      fo << time << "\t" << diff << std::endl;

      times.push_back(time);
      w_diff += diffs.front();
      diffs.insert(diffs.begin(), w_diff);

      while (times.size() > DIFFICULTY_WINDOW)
        times.erase(times.begin());

      while (diffs.size() > DIFFICULTY_WINDOW)
        diffs.pop_back();

      const uint64_t power_limit = std::find_if(std::begin(table_powers), std::end(table_powers), [i](const powers_t& e) -> bool
      {
        return i < e.step;
      }) -> power;

      const uint64_t power_rand = power_limit + std::rand() * power_limit / 5 / RAND_MAX; //  rnd = 20%
      const uint64_t l = 120 * diff / power_rand;
      time += l + 1;

    }
  CATCH_ENTRY("generate to: " << file_name, false);
  std::cout << "Generated to: " << file_name << std::endl;
  return true;
}

namespace po = boost::program_options;

namespace
{
  const command_line::arg_descriptor<bool> arg_generate = {"generate", "Generate table"};
  const command_line::arg_descriptor<std::string> arg_file_name = {"file", "File name", "data.txt"};
}

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

  epee::string_tools::set_module_name_and_folder(argv[0]);
  epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_4);
  epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_4);

  po::options_description desc_options("Allowed options");
  command_line::add_arg(desc_options, command_line::arg_help);
  command_line::add_arg(desc_options, arg_generate);
  command_line::add_arg(desc_options, arg_file_name);

  po::variables_map vm;

  bool r = command_line::handle_error_helper(desc_options, [&]()
  {
    po::store(po::parse_command_line(argc, argv, desc_options), vm);
    if (command_line::has_arg(vm, command_line::arg_help))
    {
      std::cout << desc_options << std::endl;
      return false;
    }
    po::notify(vm);
    return true;
  });
  if (!r)
    return EXIT_FAILURE;

  const std::string file_name = command_line::get_arg(vm, arg_file_name);
  if (command_line::has_arg(vm, arg_generate))
    return generate(file_name) ? EXIT_SUCCESS : EXIT_FAILURE;

  std::vector<uint64_t> timestamps;
  timestamps.reserve(DIFFICULTY_WINDOW + 1);
  std::vector<currency::wide_difficulty_type> wide_cumulative_difficulties;
  wide_cumulative_difficulties.reserve(DIFFICULTY_WINDOW + 1);

  TRY_ENTRY();
    fs::ifstream data(file_name);
    data.exceptions(std::fstream::badbit);
    data.clear(data.rdstate());
    uint64_t timestamp, difficulty;
    currency::wide_difficulty_type wide_cumulative_difficulty = 0;
    for (size_t n = 0; data >> timestamp >> difficulty; ++n)
    {
      currency::wide_difficulty_type wide_res = NEXT_DIFFICULTY_ALGO(timestamps, wide_cumulative_difficulties, DEFAULT_TEST_DIFFICULTY_TARGET);
      if (wide_res.convert_to<uint64_t>() != difficulty) {
        std::cout << "Wrong wide difficulty for block " << n << std::endl
                  << "Expected: " << difficulty << std::endl
                  << "Found: " << wide_res << std::endl;
        return EXIT_FAILURE;
      }

      timestamps.push_back(timestamp);
      if (timestamps.size() > DIFFICULTY_WINDOW)
        timestamps.erase(timestamps.begin());

      wide_cumulative_difficulties.insert(wide_cumulative_difficulties.begin(), wide_cumulative_difficulty += difficulty);
      if (wide_cumulative_difficulties.size() > DIFFICULTY_WINDOW)
        wide_cumulative_difficulties.pop_back();
    }
    if (!data.eof())
      data.clear(std::fstream::badbit);
  CATCH_ENTRY("difficulty test from: " << file_name, EXIT_FAILURE);

  std::cout << "TEST SUCCESS" << std::endl;
  return EXIT_SUCCESS;
}


#include <boost/math/special_functions/ellint_2.hpp>