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

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

 * See LICENSE for the license information

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

/**
 * @file    DoglegOptimizer.cpp
 * @brief
 * @author  Richard Roberts
 * @date   Feb 26, 2012
 */

#include <gtsam/nonlinear/DoglegOptimizer.h>
#include <gtsam/nonlinear/DoglegOptimizerImpl.h>
#include <gtsam/linear/GaussianBayesTree.h>
#include <gtsam/linear/GaussianBayesNet.h>
#include <gtsam/linear/GaussianFactorGraph.h>
#include <gtsam/linear/VectorValues.h>

#include <boost/algorithm/string.hpp>

using namespace std;

namespace gtsam {

/* ************************************************************************* */
DoglegParams::VerbosityDL DoglegParams::verbosityDLTranslator(const std::string &verbosityDL) const {
  std::string s = verbosityDL;  boost::algorithm::to_upper(s);
  if (s == "SILENT") return DoglegParams::SILENT;
  if (s == "VERBOSE") return DoglegParams::VERBOSE;

  /* default is silent */
  return DoglegParams::SILENT;
}

/* ************************************************************************* */
std::string DoglegParams::verbosityDLTranslator(VerbosityDL verbosityDL) const {
  std::string s;
  switch (verbosityDL) {
  case DoglegParams::SILENT:  s = "SILENT"; break;
  case DoglegParams::VERBOSE: s = "VERBOSE"; break;
  default:                    s = "UNDEFINED"; break;
  }
  return s;
}

/* ************************************************************************* */
void DoglegOptimizer::iterate(void) {

  // Linearize graph
  GaussianFactorGraph::shared_ptr linear = graph_.linearize(state_.values);

  // Pull out parameters we'll use
  const bool dlVerbose = (params_.verbosityDL > DoglegParams::SILENT);

  // Do Dogleg iteration with either Multifrontal or Sequential elimination
  DoglegOptimizerImpl::IterationResult result;

  if ( params_.isMultifrontal() ) {
    GaussianBayesTree bt = *linear->eliminateMultifrontal(*params_.ordering, params_.getEliminationFunction());
    VectorValues dx_u = bt.optimizeGradientSearch();
    VectorValues dx_n = bt.optimize();
    result = DoglegOptimizerImpl::Iterate(state_.Delta, DoglegOptimizerImpl::ONE_STEP_PER_ITERATION,
      dx_u, dx_n, bt, graph_, state_.values, state_.error, dlVerbose);
  }
  else if ( params_.isSequential() ) {
    GaussianBayesNet bn = *linear->eliminateSequential(*params_.ordering, params_.getEliminationFunction());
    VectorValues dx_u = bn.optimizeGradientSearch();
    VectorValues dx_n = bn.optimize();
    result = DoglegOptimizerImpl::Iterate(state_.Delta, DoglegOptimizerImpl::ONE_STEP_PER_ITERATION,
      dx_u, dx_n, bn, graph_, state_.values, state_.error, dlVerbose);
  }
  else if ( params_.isIterative() ) {
    throw runtime_error("Dogleg is not currently compatible with the linear conjugate gradient solver");
  }
  else {
    throw runtime_error("Optimization parameter is invalid: DoglegParams::elimination");
  }

  // Maybe show output
  if(params_.verbosity >= NonlinearOptimizerParams::DELTA) result.dx_d.print("delta");

  // Create new state with new values and new error
  state_.values = state_.values.retract(result.dx_d);
  state_.error = result.f_error;
  state_.Delta = result.Delta;
  ++state_.iterations;
}

/* ************************************************************************* */
DoglegParams DoglegOptimizer::ensureHasOrdering(DoglegParams params, const NonlinearFactorGraph& graph) const {
  if(!params.ordering)
    params.ordering = Ordering::COLAMD(graph);
  return params;
}

} /* namespace gtsam */


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

  @copyright 2016 NumScale SAS

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

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

 /*!

    @ingroup group-operator
    Function object implementing is_equal capabilities

    Returns @ref True or @ref False
    according x and y are equal or not.

    Infix notation can be used with operator '=='

    @par Semantic:

    @code
    auto r = is_equal(x,y);
    @endcode

    or

    @code
    auto r = x == y;
    @endcode

    @see  is_not_equal, is_eqz, is_equal_with_equal_nans

  **/
  as_logical_t<T0> is_equal(T0 const& x, T1 const& y);
} }
#endif

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

#endif


//=======================================================================
// Copyright 2017 Felix Salfelder
//
// 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/graph/minimum_degree_ordering.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/test/minimal.hpp>
#include <boost/typeof/typeof.hpp>
#include <vector>
#include <map>

typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> G;

int test_main(int argc, char** argv)
{
    size_t n = 10;
    G g(n);

    std::vector<int> inverse_perm(n, 0);
    std::vector<int> supernode_sizes(n, 1);
    BOOST_AUTO(id, boost::get(boost::vertex_index, g));
    std::vector<int> degree(n, 0);
    std::map<int,int> io;
    std::map<int,int> o;

    boost::minimum_degree_ordering(
        g
      , boost::make_iterator_property_map(degree.begin(), id, degree[0])
      , boost::make_assoc_property_map(io)
      , boost::make_assoc_property_map(o)
      , boost::make_iterator_property_map(
            supernode_sizes.begin()
          , id
          , supernode_sizes[0]
        )
      , 0
      , id
    );

    for (int k = 0; k < n; ++k)
    {
        BOOST_CHECK(o[io[k]] == k);
    }

    return 0;
}


/*
 * Copyright 2014-2017, Andrea Del Prete, Rohan Budhiraja LAAS-CNRS
 *
 */

#ifndef __sot_torque_control_TorqueOffsetEstimator_H__
#define __sot_torque_control_TorqueOffsetEstimator_H__
/* --------------------------------------------------------------------- */
/* --- API ------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

#if defined(WIN32)
#if defined(torque_offset_estimator_EXPORTS)
#define TORQUEOFFSETESTIMATOR_EXPORT __declspec(dllexport)
#else
#define TORQUEOFFSETESTIMATOR_EXPORT __declspec(dllimport)
#endif
#else
#define TORQUEOFFSETESTIMATOR_EXPORT
#endif

//#define VP_DEBUG 1        /// enable debug output
//#define VP_DEBUG_MODE 20

/* --------------------------------------------------------------------- */
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */

#include <boost/circular_buffer.hpp>
#include <Eigen/StdVector>

/*Motor model*/
#include <pinocchio/multibody/model.hpp>
#include <pinocchio/parsers/urdf.hpp>
#include <pinocchio/algorithm/rnea.hpp>
#include <pinocchio/algorithm/kinematics.hpp>

/* HELPER */
#include <dynamic-graph/signal-helper.h>
#include <sot/core/matrix-geometry.hh>
#include <sot/core/robot-utils.hh>
#include <sot/core/stop-watch.hh>

/*Motor model*/
#include <sot/torque_control/motor-model.hh>

namespace dynamicgraph {
namespace sot {
namespace torque_control {

class TORQUEOFFSETESTIMATOR_EXPORT TorqueOffsetEstimator : public ::dynamicgraph::Entity {
  DYNAMIC_GRAPH_ENTITY_DECL();

 public: /* --- SIGNALS --- */
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  typedef int dummy;
  typedef std::vector<Eigen::VectorXd, Eigen::aligned_allocator<Eigen::VectorXd> > stdAlignedVector;

  /** --- CONSTRUCTOR ---- */
  TorqueOffsetEstimator(const std::string& name);
  void init(const std::string& urdfFile, const Eigen::Matrix4d& _m_torso_X_imu, const double& gyro_epsilon,
            const std::string& ffJointName, const std::string& torsoJointName);
  void computeOffset(const int& nIterations, const double& epsilon);

  virtual void display(std::ostream& os) const;

  DECLARE_SIGNAL_IN(base6d_encoders, dynamicgraph::Vector);
  DECLARE_SIGNAL_IN(accelerometer, dynamicgraph::Vector);
  DECLARE_SIGNAL_IN(gyroscope, dynamicgraph::Vector);
  DECLARE_SIGNAL_IN(jointTorques, dynamicgraph::Vector);
  DECLARE_SIGNAL_INNER(collectSensorData, dummy);
  DECLARE_SIGNAL_OUT(jointTorquesEstimated, dynamicgraph::Vector);

 protected:
  RobotUtilShrPtr m_robot_util;
  pinocchio::Model m_model;  /// Pinocchio robot model
  pinocchio::Data* m_data;   /// Pinocchio robot data
  int n_iterations;          // Number of iterations to consider
  double epsilon;
  double gyro_epsilon;

  pinocchio::JointIndex ffIndex, torsoIndex;  // Index of the free-flyer and torso frames
  Eigen::VectorXd jointTorqueOffsets;
  pinocchio::SE3 m_torso_X_imu;  // Definition of the imu in the chest frame.

  // stdAlignedVector encSignals;
  // stdAlignedVector accSignals;
  // stdAlignedVector gyrSignals;
  // stdAlignedVector tauSignals;

  // stdAlignedVector stdVecJointTorqueOffsets;

  void sendMsg(const std::string& msg, MsgType t = MSG_TYPE_INFO, const char* = "", int = 0) {
    logger_.stream(t) << ("[" + name + "] " + msg) << '\n';
  }

 private:
  enum { PRECOMPUTATION, INPROGRESS, COMPUTED } sensor_offset_status;

  // void calculateSensorOffsets();
  int current_progress;
};  // class TorqueOffsetEstimator

}  // namespace torque_control
}  // namespace sot
}  // namespace dynamicgraph

#endif  // #ifndef __sot_torque_control_TorqueOffsetEstimator_H__


//==============================================================================
//         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
//==============================================================================
#ifndef BOOST_SIMD_IEEE_FUNCTIONS_EXPONENTBITS_HPP_INCLUDED
#define BOOST_SIMD_IEEE_FUNCTIONS_EXPONENTBITS_HPP_INCLUDED
#include <boost/simd/include/functor.hpp>
#include <boost/dispatch/include/functor.hpp>

namespace boost { namespace simd { namespace tag
  {
   /*!
     @brief exponentbits generic tag

     Represents the exponentbits function in generic contexts.

     @par Models:
        Hierarchy
   **/
    struct exponentbits_ : ext::elementwise_<exponentbits_>
    {
      /// @brief Parent hierarchy
      typedef ext::elementwise_<exponentbits_> parent;
      template<class... Args>
      static BOOST_FORCEINLINE BOOST_AUTO_DECLTYPE dispatch(Args&&... args)
      BOOST_AUTO_DECLTYPE_BODY( dispatching_exponentbits_( ext::adl_helper(), static_cast<Args&&>(args)... ) )
    };
  }
  namespace ext
  {
   template<class Site>
   BOOST_FORCEINLINE generic_dispatcher<tag::exponentbits_, Site> dispatching_exponentbits_(adl_helper, boost::dispatch::meta::unknown_<Site>, ...)
   {
     return generic_dispatcher<tag::exponentbits_, Site>();
   }
   template<class... Args>
   struct impl_exponentbits_;
  }
  /*!
    Returns the exponent bits of the floating input as an integer value.
    the other bits (sign and mantissa) are just masked.
    This function is not defined on integral types.

    @par Semantic:

    @code
    as_integer<T> r = exponentbits(x);
    @endcode

    is similar to

    @code
    as_integer<T> r = x&Exponentmask<T>();
    @endcode

    @param a0

    @return a value of the integral type associated to the input
  **/
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::exponentbits_, exponentbits, 1)
} }

#endif


/*ckwg +29
 * Copyright 2013-2018 by Kitware, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither name of Kitware, Inc. nor the names of any contributors may be used
 *    to endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * \file
 * \brief Implementation of \link kwiver::vital::camera_rpc
 * camera_rpc \endlink class
 */

#include <vital/types/camera_rpc.h>
#include <vital/io/eigen_io.h>
#include <Eigen/Geometry>

#include <iomanip>

namespace kwiver {
namespace vital {

camera_rpc
::camera_rpc()
  : m_logger( kwiver::vital::get_logger( "vital.camera_rpc" ) )
{
}

/// Project a 3D point into a 2D image point
vector_2d
camera_rpc
::project( const vector_3d& pt ) const
{
  // Normalize points
  vector_3d norm_pt = ( pt - world_offset() ).cwiseQuotient( world_scale() );

  // Calculate polynomials
  vector_4d polys = this->rpc_coeffs()*this->power_vector(norm_pt);
  vector_2d image_pt( polys[0] / polys[1], polys[2] / polys[3]);

  // Un-normalize
  return image_pt.cwiseProduct( image_scale() ) + image_offset();
}

/// Project a 2D image point to a 3D point in space
vector_3d
camera_rpc
::back_project( const vector_2d& image_pt, double elev ) const
{
  // Normalize image point
  vector_2d norm_pt =
    ( image_pt - image_offset() ).cwiseQuotient( image_scale() );
  auto norm_elev = ( elev - world_offset()[2] ) / world_scale()[2];

  // Use a first order approximation to the RPC to initialize.
  // This sets all non-linear terms of the RPC to zero and then forms
  // a least squares solution to invert the mapping.
  matrix_2x2d A;
  vector_3d rslt( 0., 0., norm_elev );
  vector_2d b;

  A.block<1, 2>( 0, 0 ) = rpc_coeffs().block<1, 2>( 0, 1 )
                           - norm_pt[0] * rpc_coeffs().block<1, 2>( 1, 1 );
  A.block<1, 2>( 1, 0 ) = rpc_coeffs().block<1, 2>( 2, 1 );
                           - norm_pt[1] * rpc_coeffs().block<1, 2>( 3, 1 );

  b[0] = ( rpc_coeffs()( 1, 0 ) + norm_elev*rpc_coeffs()( 1, 3 ) )*norm_pt[0]
         - ( rpc_coeffs()( 0, 0 ) + norm_elev*rpc_coeffs()( 0, 3 ) );
  b[1] = ( rpc_coeffs()( 3, 0 ) + norm_elev*rpc_coeffs()( 3, 3 ) )*norm_pt[1]
         - ( rpc_coeffs()( 2, 0 ) + norm_elev*rpc_coeffs()( 2, 3 ) );

  rslt.head(2) = A.colPivHouseholderQr().solve( b );

  // Apply gradient descendent until convergence. Should converge
  // in a few interations.
  for ( int i = 0; i < 10; ++i )
  {
    matrix_2x2d J;
    vector_2d pt;

    this->jacobian( rslt, J, pt );

    vector_2d step = J.colPivHouseholderQr().solve( norm_pt - pt );
    rslt.head( 2 ) += step;
    if ( step.cwiseAbs().maxCoeff() < 1.e-16 )
    {
      break;
    }
  }

  return rslt.cwiseProduct( this->world_scale() ) + this->world_offset();
}

Eigen::Matrix<double, 20, 1>
camera_rpc
::power_vector( const vector_3d& pt )
{
  // Form the monomials in homogeneous form
  double w  = 1.0;
  double x = pt.x();
  double y = pt.y();
  double z = pt.z();

  double xx = x * x;
  double xy = x * y;
  double xz = x * z;
  double yy = y * y;
  double yz = y * z;
  double zz = z * z;
  double xxx = xx * x;
  double xxy = xx * y;
  double xxz = xx * z;
  double xyy = xy * y;
  double xyz = xy * z;
  double xzz = xz * z;
  double yyy = yy * y;
  double yyz = yy * z;
  double yzz = yz * z;
  double zzz = zz * z;

  // Fill in vector
  Eigen::Matrix<double, 20, 1> retVec;
  retVec << w, x, y, z, xy, xz, yz, xx, yy, zz,
            xyz, xxx, xyy, xzz, xxy, yyy, yzz, xxz, yyz, zzz;
  return retVec;
}

void
simple_camera_rpc
::update_partial_deriv() const
{
  std::vector<int> dx_ind = { 1, 7, 4, 5, 14 ,17 ,10, 11, 12, 13 };
  std::vector<int> dy_ind = { 2, 4, 8, 6, 12, 10, 18, 14, 15, 16 };
  for ( int i = 0; i < 10; ++i )
  {
    double pwr = 1.0;
    if ( i == 1 || i == 4 || i == 5 )
    {
      pwr = 2.;
    }
    else if ( i == 7 )
    {
      pwr = 3.;
    }
    dx_coeffs_.block<4, 1>( 0, i ) =
      pwr * rpc_coeffs().block<4, 1>( 0, dx_ind[i] );
    pwr = 1.0;
    if ( i == 2 || i == 4 || i == 6 )
    {
      pwr = 2.;
    }
    else if ( i == 8 )
    {
      pwr = 3.;
    }
    dy_coeffs_.block<4, 1>( 0, i ) =
      pwr * rpc_coeffs().block<4, 1>( 0, dy_ind[i] );
  }
}

void
simple_camera_rpc
::jacobian( const vector_3d& pt, matrix_2x2d& J, vector_2d& norm_pt ) const
{
  Eigen::Matrix<double, 20, 1> pv = this->power_vector( pt );
  vector_4d ply = this->rpc_coeffs() * pv;
  vector_4d dx_ply = this->dx_coeffs_ * pv.head(10);
  vector_4d dy_ply = this->dy_coeffs_ * pv.head(10);

  J( 0, 0 ) = ( ply[1] * dx_ply[0] - ply[0] * dx_ply[1] ) / ( ply[1] * ply[1] );
  J( 0, 1 ) = ( ply[1] * dy_ply[0] - ply[0] * dy_ply[1] ) / ( ply[1] * ply[1] );
  J( 1, 0 ) = ( ply[3] * dx_ply[2] - ply[2] * dx_ply[3] ) / ( ply[3] * ply[3] );
  J( 1, 1 ) = ( ply[3] * dy_ply[2] - ply[2] * dy_ply[3] ) / ( ply[3] * ply[3] );

  norm_pt << ply[0] / ply[1], ply[2] / ply[3];
}

} } // end namespace


/**
 * \file dcs/math/stats/distribution/any_distribution.hpp
 *
 * \brief Generic class for probability distributions with runtime polymorphism
 * support.
 *
 * \author Marco Guazzone (marco.guazzone@gmail.com)
 *
 *

 *
 * Copyright 2009 Marco Guazzone (marco.guazzone@gmail.com)
 *
 * 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.
 */

#ifndef DCS_MATH_STATS_DISTRIBUTION_ANY_DISTRIBUTION_HPP
#define DCS_MATH_STATS_DISTRIBUTION_ANY_DISTRIBUTION_HPP

#include <boost/smart_ptr.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/utility/enable_if.hpp>
#include <dcs/debug.hpp>
#include <dcs/math/random/any_generator.hpp>
#include <dcs/math/random/base_generator.hpp>
#include <dcs/math/random/generator_traits.hpp>
#include <dcs/math/random/uniform_01_adaptor.hpp>
#include <dcs/math/stats/distribution/base_distribution.hpp>
#include <dcs/math/stats/distribution/distribution_adaptor.hpp>
#include <dcs/math/stats/distribution/distribution_traits.hpp>
#include <dcs/type_traits/add_reference.hpp>
#include <dcs/type_traits/remove_reference.hpp>
#include <dcs/util/holder.hpp>
//#include <iosfwd>

namespace dcs { namespace math { namespace stats {

//namespace detail {
//
///**
// * \brief Interface for the \c ProbabilityDistribution concept.
// *
// * \tparam RealT The type used for real numbers.
// *
// * \author Marco Guazzone (marco.guazzone@gmail.com)
// */
//template <typename ValueT>
//class concept_distribution
//{
//	public: typedef ValueT value_type;
//
//	//virtual value_type rand(::dcs::math::random::any_generator<value_type>& rng) const = 0;
//
//	//[TODO]
//	public: template <typename UniformRandomGeneratorT>
//		value_type rand(UniformRandomGeneratorT& rng) const
//	{
//		return do_rand(
//			::dcs::math::random::make_any_generator<UniformRandomGeneratorT&>(rng)
//		);
//	}
//	//[/TODO]
//
//
//	public: virtual ::std::ostream& print(::std::ostream& os) const = 0;
//
//
//	//virtual ::std::pair<any_iterator,any_iterator> params() = 0;
//	//virtual ::std::pair<any_iterator const,any_iterator const> params() const = 0;
//	virtual ~concept_distribution() { }
//
//
//	//[TODO]
//	private: virtual value_type do_rand(::dcs::math::random::any_generator<value_type>& rng) const = 0;
//	//private: virtual ::std::ostream& print(::std::ostream& os) const = 0;
//	//[/TODO]
//};

//template < typename DistributionT, typename DistributionTraitsT=distribution_traits<DistributionT> >
//class model_distribution: public concept_distribution<typename DistributionTraitsT::value_type>
//{
//	private: typedef DistributionT distribution_type;
//	public: typedef typename ::dcs::type_traits::add_reference<distribution_type>::type reference_distribution_type;
//	public: typedef typename ::dcs::type_traits::add_reference<typename ::dcs::type_traits::add_const<distribution_type>::type>::type const_reference_distribution_type;
//	public: typedef typename DistributionTraitsT::value_type value_type;
//
//
//	public: model_distribution(const_reference_distribution_type dist)
//		: dist_(dist)
//	{
//		// empty
//	}
//
//
//	public: ::std::ostream& print(::std::ostream& os) const
//	{
//		os << dist_;
//		return os;
//	}
//
//
//	private: value_type do_rand(::dcs::math::random::any_generator<value_type>& rng) const
//	{
//		return dist_.rand(rng);
//	}
//
//
//	public: distribution_type dist_;
//};
//
//} // Namespace detail

/**
 * \brief Generic random number generator.
 * \tparam ValueT The type of real numbers.
 *
 * This class is useful when one does not know at compile-time the type of
 * the random probability distribution that is to be used or when one needs to
 * create a container of non-homogeneous randon probability distributions.
 * Thus, this class realizes a runtime version of the \c ProbabilityDistribution
 * concept; this is accomplished by using the type-erasure technique,
 * which adds a one more level of indirection.
 *
 * \author Marco Guazzone (marco.guazzone@gmail.com)
 */
template <typename ValueT>
class any_distribution
{
	public: typedef ValueT value_type;

	public: any_distribution() { }

	public: template <typename DistributionT>
		any_distribution(DistributionT const& dist)
		: ptr_dist_(new distribution_adaptor<DistributionT>(dist))
	{
		// empty
	}

	public: template <typename DistributionT>
		any_distribution(::dcs::util::holder<DistributionT> const& wrap_dist)
		: ptr_dist_(new distribution_adaptor<DistributionT>(wrap_dist.get()))
	{
		// empty
	}

	// Compiler-generated copy ctor and copy assignement are fine.

	public: template <typename DistributionT>
		void distribution(DistributionT dist)
	{
		ptr_dist_ = ::boost::make_shared< distribution_adaptor<DistributionT> >(dist);
	}

	//@{ ProbabilityDistribution concept implementation

//	public: value_type rand(::dcs::math::random::any_generator<value_type>& rng) const
//	{
//		return ptr_dist_->rand(rng);
//	}

	public: template <typename UniformRandomGeneratorT>
		value_type rand(UniformRandomGeneratorT& rng) const
	{
		// pre: distribution pointer must be a valid pointer
		DCS_DEBUG_ASSERT( ptr_dist_ );

//		::dcs::math::random::uniform_01_adaptor<UniformRandomGeneratorT&,value_type> u01_rng = ::dcs::math::random::uniform_01_adaptor<UniformRandomGeneratorT&,value_type>(rng);
//		return ptr_dist_->rand(u01_rng);
		return ptr_dist_->rand(rng);
		//return ptr_dist_->rand(rng);
//			::dcs::math::random::make_any_generator<UniformRandomGeneratorT&>(rng)
//		);
	}

//	public: template <typename UniformRandomGeneratorT>
//		typename ::boost::disable_if<
//			::boost::is_base_of<
//				::dcs::math::random::base_generator<
//					typename ::dcs::math::random::generator_traits<UniformRandomGeneratorT>::result_type
//				>,
//				UniformRandomGeneratorT
//			>,
//			value_type
//		>::type rand(UniformRandomGeneratorT& rng) const
//	{
////		::dcs::math::random::uniform_01_adaptor<UniformRandomGeneratorT&,value_type> u01_rng = ::dcs::math::random::uniform_01_adaptor<UniformRandomGeneratorT&,value_type>(rng);
////		return ptr_dist_->rand(u01_rng);
//		return ptr_dist_->rand(rng);
//		//return ptr_dist_->rand(rng);
////			::dcs::math::random::make_any_generator<UniformRandomGeneratorT&>(rng)
////		);
//	}

//	public: value_type rand(::dcs::math::random::base_generator<value_type>& rng) const
//	{
//		::dcs::math::random::uniform_01_adaptor< ::dcs::math::random::base_generator<value_type>&,value_type > u01_rng = ::dcs::math::random::uniform_01_adaptor< ::dcs::math::random::base_generator<value_type>&,value_type >(rng);
//		return ptr_dist_->rand(u01_rng);
//	}

//	public: template <typename T>
//		value_type rand(::dcs::math::random::base_generator<T>& rng) const
//	{
////		//::dcs::math::random::uniform_01_adaptor< ::dcs::math::random::base_generator<T>&,value_type > u01_rng = ::dcs::math::random::uniform_01_adaptor< ::dcs::math::random::base_generator<T>&,value_type >(rng);
////		typedef ::dcs::math::random::base_generator<T> base_generator_type;
////		typedef ::dcs::math::random::uniform_01_adaptor<base_generator_type&, valua_type> adapted_generator_type;
////		adapted_generator_type u01_rng(rng);
////
////		return ptr_dist_->rand(u01_rng);
//		return ptr_dist_->rand(rng);
//	}

//	public: template <
//				typename CharT,
//				typename CharTraits
//			>
//		::std::basic_ostream<CharT,CharTraits>& print(::std::basic_ostream<CharT,CharTraits>& os) const
//	{
////		return ptr_dist_->print(os);
//		os << *ptr_dist_;
//		return os;
//	}

	//@} ProbabilityDistribution concept implementation

	private: ::boost::shared_ptr< base_distribution<value_type> > ptr_dist_; // shared_ptr needed in order to keep alive the pointer during object copying
};

template <
	typename DistributionT,
	typename DistributionTraitsT=distribution_traits<DistributionT>
>
struct make_any_distribution_type
{
	typedef any_distribution<typename DistributionTraitsT::value_type> type;
};

namespace detail {

template <
	typename DistributionT,
	typename DistributionTraitsT=distribution_traits<DistributionT>
>
struct make_any_distribution_impl;

template <typename DistributionT, typename DistributionTraitsT>
struct make_any_distribution_impl
{
	typedef typename make_any_distribution_type<DistributionT,DistributionTraitsT>::type any_distribution_type;

	static any_distribution_type apply(DistributionT& dist)
	{
		return any_distribution_type(dist);
	}
};

template <typename DistributionT, typename DistributionTraitsT>
struct make_any_distribution_impl<DistributionT&,DistributionTraitsT>
{
	typedef typename make_any_distribution_type<DistributionT,DistributionTraitsT>::type any_distribution_type;

	static any_distribution_type apply(DistributionT& dist)
	{
		::dcs::util::holder<DistributionT&> wrap_distribution(dist);
		return any_distribution_type(wrap_distribution);
	}
};

template <typename RealT>
struct make_any_distribution_impl< any_distribution<RealT> >
{
	typedef any_distribution<RealT> any_distribution_type;

//	static any_distribution_type& apply(any_distribution_type& dist)
//	{
//		return dist;
//	}
//
//	static any_distribution_type const& apply(any_distribution_type const& dist)
//	{
//		return dist;
//	}

	static any_distribution_type apply(any_distribution_type const& dist)
	{
		return dist;
	}
};

template <typename RealT>
struct make_any_distribution_impl< any_distribution<RealT>& >
{
	typedef any_distribution<RealT> any_distribution_type;

	static any_distribution_type& apply(any_distribution_type& dist)
	{
		return dist;
	}
};

} // Namespace detail

template <typename DistributionT>
inline typename make_any_distribution_type<DistributionT>::type make_any_distribution(DistributionT dist)
{
	return detail::make_any_distribution_impl<DistributionT>::apply(dist);
}

//template <typename RealT, typename UniformRandomGeneratorT>
//inline RealT rand(any_distribution<RealT> const& dist, UniformRandomGeneratorT& rng)
//{
//	return dist.rand(rng);
//}

}}} // Namespace dcs::math::stats

#endif // DCS_MATH_STATS_DISTRIBUTION_ANY_DISTRIBUTION_HPP


#ifndef BOOST_QVM_QUAT_VEC_OPERATIONS_HPP_INCLUDED
#define BOOST_QVM_QUAT_VEC_OPERATIONS_HPP_INCLUDED

// Copyright 2008-2022 Emil Dotchevski and Reverge Studios, Inc.

// 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/qvm/quat_traits.hpp>
#include <boost/qvm/deduce_vec.hpp>
#include <boost/qvm/inline.hpp>
#include <boost/qvm/enable_if.hpp>

namespace boost { namespace qvm {

template <class A,class B>
BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    is_quat<A>::value &&
    is_vec<B>::value && vec_traits<B>::dim==3,
    deduce_vec2<A,B,3> >::type
operator*( A const & a, B const & b )
    {
    typedef typename deduce_vec2<A,B,3>::type R;
    typedef typename quat_traits<A>::scalar_type TA;
    typedef typename vec_traits<B>::scalar_type TB;
    TA const aa = quat_traits<A>::template read_element<0>(a);
    TA const ab = quat_traits<A>::template read_element<1>(a);
    TA const ac = quat_traits<A>::template read_element<2>(a);
    TA const ad = quat_traits<A>::template read_element<3>(a);
    TA const t2 = aa*ab;
    TA const t3 = aa*ac;
    TA const t4 = aa*ad;
    TA const t5 = -ab*ab;
    TA const t6 = ab*ac;
    TA const t7 = ab*ad;
    TA const t8 = -ac*ac;
    TA const t9 = ac*ad;
    TA const t10     = -ad*ad;
    TB const bx = vec_traits<B>::template read_element<0>(b);
    TB const by = vec_traits<B>::template read_element<1>(b);
    TB const bz = vec_traits<B>::template read_element<2>(b);
    R r;
    vec_traits<R>::template write_element<0>(r) = 2*((t8+t10)*bx + (t6-t4)*by + (t3+t7)*bz) + bx;
    vec_traits<R>::template write_element<1>(r) = 2*((t4+t6)*bx + (t5+t10)*by + (t9-t2)*bz) + by;
    vec_traits<R>::template write_element<2>(r) = 2*((t7-t3)*bx + (t2+t9)*by + (t5+t8)*bz) + bz;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

} }

#endif


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

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

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

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

#include "toplevelfixture.hpp"
// clang-format off
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
// clang-format on
#include <ql/currencies/america.hpp>
#include <ql/math/interpolations/linearinterpolation.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/nullcalendar.hpp>
#include <qle/indexes/commodityindex.hpp>
#include <qle/pricingengines/analyticcashsettledeuropeanengine.hpp>
#include <qle/termstructures/pricecurve.hpp>

using namespace boost::unit_test_framework;
using namespace QuantLib;
using namespace QuantExt;
using std::fixed;
using std::map;
using std::setprecision;
using std::string;
using std::vector;

namespace bdata = boost::unit_test::data;

namespace {

// Create a flat yield term structure where DF(0, t) = exp (-r * t)
Handle<YieldTermStructure> flatYts(Rate r) {
    return Handle<YieldTermStructure>(boost::make_shared<FlatForward>(0, NullCalendar(), r, Actual365Fixed()));
}

// Create a process for the tests
boost::shared_ptr<GeneralizedBlackScholesProcess> getProcess(Rate spot, Volatility vol, Rate r, Rate q) {

    // Set up the term structures
    Handle<Quote> spotQuote(boost::make_shared<SimpleQuote>(spot));
    Handle<YieldTermStructure> rTs = flatYts(r);
    Handle<YieldTermStructure> qTs = flatYts(q);
    Handle<BlackVolTermStructure> volTs(boost::make_shared<BlackConstantVol>(0, NullCalendar(), vol, Actual365Fixed()));

    // Return the process
    return boost::make_shared<GeneralizedBlackScholesProcess>(spotQuote, qTs, rTs, volTs);
}

// Create a dummy price term structure
Handle<PriceTermStructure> priceTs() {
    vector<Period> tenors{ 0 * Days, 1 * Years };
    vector<Real> prices{ 60.0, 69.0 };
    return Handle<PriceTermStructure>(
        boost::make_shared<InterpolatedPriceCurve<Linear> >(tenors, prices, Actual365Fixed(), USDCurrency()));
}

// Return a map containing all of the CashSettledEuropeanOption results
map<string, Real> results(const CashSettledEuropeanOption& option) {

    map<string, Real> mp;

    mp["npv"] = option.NPV();
    mp["delta"] = option.delta();
    mp["deltaForward"] = option.deltaForward();
    mp["elasticity"] = option.elasticity();
    mp["gamma"] = option.gamma();
    mp["theta"] = option.theta();
    mp["thetaPerDay"] = option.thetaPerDay();
    mp["vega"] = option.vega();
    mp["rho"] = option.rho();
    mp["dividendRho"] = option.dividendRho();
    mp["strikeSensitivity"] = option.strikeSensitivity();
    mp["itmCashProbability"] = option.itmCashProbability();

    return mp;
}

// Check option values on or after expiry date
void checkOptionValues(CashSettledEuropeanOption& option, Rate r, Real exercisePrice, Real tolerance = 1e-12) {

    // Discount factor from payment and time to payment date.
    auto yts = flatYts(r);
    DiscountFactor df_tp = yts->discount(option.paymentDate());
    Time tp = yts->timeFromReference(option.paymentDate());
    BOOST_TEST_MESSAGE("Discount factor from payment is: " << fixed << setprecision(12) << df_tp);

    // Value at exercise
    Real valueAtExpiry = (*option.payoff())(exercisePrice);

    // Check the results after manual exercise.
    map<string, Real> cashSettledResults = results(option);
    BOOST_REQUIRE(cashSettledResults.count("npv") == 1);
    for (const auto& kv : cashSettledResults) {
        BOOST_TEST_CONTEXT("With result " << kv.first) {
            BOOST_TEST_MESSAGE("Value for " << kv.first << " with cash settlement is: " << fixed << setprecision(12)
                                            << kv.second);
            if (kv.first == "npv") {
                BOOST_CHECK_SMALL(kv.second - df_tp * valueAtExpiry, tolerance);
            } else if (kv.first == "rho") {
                BOOST_CHECK_SMALL(kv.second + tp * cashSettledResults.at("npv"), tolerance);
            } else if (kv.first == "theta") {
                if (tp > 0.0 && !close(tp, 0.0)) {
                    BOOST_CHECK_SMALL(kv.second + std::log(df_tp) / tp * cashSettledResults.at("npv"), tolerance);
                } else {
                    BOOST_CHECK(close(kv.second, 0.0));
                }
            } else if (kv.first == "thetaPerDay") {
                if (cashSettledResults.count("theta") == 0) {
                    BOOST_ERROR("Expected results to contain a value for theta");
                    continue;
                } else {
                    BOOST_CHECK_SMALL(kv.second - cashSettledResults.at("theta") / 365.0, tolerance);
                }
            } else {
                BOOST_CHECK(close(kv.second, 0.0));
            }
        }
    }
}

} // namespace

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

BOOST_AUTO_TEST_SUITE(AnalyticCashSettledEuropeanEngineTest)

vector<Real> strikes{ 55, 58, 62, 65 };
vector<Option::Type> optionTypes{ Option::Type::Call, Option::Type::Put };

BOOST_DATA_TEST_CASE(testOptionBeforeExpiry, bdata::make(strikes) * bdata::make(optionTypes), strike, optionType) {

    BOOST_TEST_MESSAGE("Testing cash settled option pricing before expiry...");

    Settings::instance().evaluationDate() = Date(3, Jun, 2020);

    // Create cash settled option instrument
    Date expiry(3, Sep, 2020);
    Date payment(7, Sep, 2020);
    bool automaticExercise = false;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Value the option accounting for cash settlement and store all results
    option.setPricingEngine(engine);
    map<string, Real> cashSettledResults = results(option);

    // Value the option ignoring cash settlement
    engine = boost::make_shared<AnalyticEuropeanEngine>(getProcess(spot, vol, r, q));
    option.setPricingEngine(engine);
    map<string, Real> theoreticalResults = results(option);

    // Discount factor from payment to expiry.
    auto yts = flatYts(r);
    DiscountFactor df_te_tp = yts->discount(payment) / yts->discount(expiry);
    BOOST_TEST_MESSAGE("Discount factor from payment to expiry is: " << fixed << setprecision(12) << df_te_tp);

    // Check the results
    Real tolerance = 1e-12;
    BOOST_REQUIRE_EQUAL(cashSettledResults.size(), theoreticalResults.size());
    BOOST_REQUIRE(cashSettledResults.count("npv") == 1);
    BOOST_REQUIRE(theoreticalResults.count("npv") == 1);
    for (const auto& kv : cashSettledResults) {

        BOOST_TEST_CONTEXT("With result " << kv.first) {

            auto it = theoreticalResults.find(kv.first);
            BOOST_CHECK(it != theoreticalResults.end());

            // If there is no matching result in theoreticalResults, skip to next result.
            if (it == theoreticalResults.end())
                continue;

            // Check the result is as expected by comparing to the results that do not account for delayed payment.
            Real theorResult = it->second;
            BOOST_TEST_MESSAGE("Value for " << kv.first << " with cash settlement is: " << fixed << setprecision(12)
                                            << kv.second);
            BOOST_TEST_MESSAGE("Value for " << kv.first << " ignoring cash settlement is: " << fixed << setprecision(12)
                                            << theorResult);

            // Most results should be of the form cashSettledResult = DF(t_e, t_p) * theoreticalResult.
            // There are some exceptions dealt with below.
            if (close(theorResult, 0.0)) {
                BOOST_CHECK(close(kv.second, 0.0));
            } else if (kv.first == "elasticity" || kv.first == "itmCashProbability") {
                BOOST_CHECK(close(kv.second, theorResult));
            } else if (kv.first == "rho") {
                Time delta_te_tp = yts->timeFromReference(payment) - yts->timeFromReference(expiry);
                Real expRho = df_te_tp * (theorResult - delta_te_tp * theoreticalResults.at("npv"));
                BOOST_TEST_MESSAGE("Value for expected rho is: " << fixed << setprecision(12) << expRho);
                BOOST_CHECK(close(kv.second, expRho));
            } else {
                BOOST_CHECK_SMALL(kv.second / theorResult - df_te_tp, tolerance);
            }
        }
    }
}

BOOST_DATA_TEST_CASE(testOptionManualExerciseAfterExpiry, bdata::make(strikes) * bdata::make(optionTypes), strike,
                     optionType) {

    BOOST_TEST_MESSAGE("Testing cash settled manual exercise option pricing after expiry...");

    Settings::instance().evaluationDate() = Date(4, Sep, 2020);

    // Create cash settled option instrument
    Date expiry(3, Sep, 2020);
    Date payment(7, Sep, 2020);
    bool automaticExercise = false;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Value the option accounting for cash settlement and store all results
    option.setPricingEngine(engine);
    map<string, Real> cashSettledResults = results(option);

    // Option has not been manually exercised so all results should be zero.
    for (const auto& kv : cashSettledResults) {
        BOOST_TEST_CONTEXT("With result " << kv.first) { BOOST_CHECK(close(kv.second, 0.0)); }
    }

    // Manually exercise the option with an expiry value of 59.
    Real exercisePrice = 59.00;
    option.exercise(exercisePrice);

    // Check the updated results
    checkOptionValues(option, r, exercisePrice);
}

// Values for includeReferenceDateEvents in tests.
vector<bool> irdes{ true, false };

BOOST_DATA_TEST_CASE(testOptionManualExerciseOnExpiry,
                     bdata::make(strikes) * bdata::make(optionTypes) * bdata::make(irdes), strike, optionType, irde) {

    BOOST_TEST_MESSAGE("Testing cash settled manual exercise option on expiry date...");

    // Should work for either setting of includeReferenceDateEvents.
    Settings::instance().includeReferenceDateEvents() = irde;

    // Create cash settled option instrument
    Date expiry(3, Sep, 2020);
    Settings::instance().evaluationDate() = expiry;
    Date payment(7, Sep, 2020);
    bool automaticExercise = false;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Set the pricing engine
    option.setPricingEngine(engine);

    // We are on the expiry date but have not exercised the option. Expect the valuation to proceed and hence
    // the value to be based off the market spot price.
    checkOptionValues(option, r, spot);

    // Manually exercise the option with an expiry value of 59.
    Real exercisePrice = 59.00;
    option.exercise(exercisePrice);

    // Check the updated option values.
    checkOptionValues(option, r, exercisePrice);
}

BOOST_DATA_TEST_CASE(testOptionManualExerciseOnPayment, bdata::make(strikes) * bdata::make(optionTypes), strike,
                     optionType) {

    BOOST_TEST_MESSAGE("Testing cash settled manual exercise option on payment date...");

    // Create cash settled option instrument
    Date expiry(3, Sep, 2020);
    Date payment(7, Sep, 2020);
    Settings::instance().evaluationDate() = payment;
    bool automaticExercise = false;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Set the pricing engine
    option.setPricingEngine(engine);

    // Manually exercise the option with an expiry value of 59.
    Real exercisePrice = 59.00;
    option.exercise(exercisePrice);

    // Set include reference date events to true so that the option is not considered expired.
    Settings::instance().includeReferenceDateEvents() = true;

    // Check the option values against expected values.
    checkOptionValues(option, r, exercisePrice);

    // Set include reference date events to false so that the option is considered expired.
    // Must recalculate for the setting to take effect.
    Settings::instance().includeReferenceDateEvents() = false;
    option.recalculate();

    // Check that all the values are zero, i.e. the expired state.
    map<string, Real> cashSettledResults = results(option);
    for (const auto& kv : cashSettledResults) {
        BOOST_TEST_CONTEXT("With result " << kv.first) { BOOST_CHECK(close(kv.second, 0.0)); }
    }
}

BOOST_DATA_TEST_CASE(testOptionAutomaticExerciseAfterExpiry, bdata::make(strikes) * bdata::make(optionTypes), strike,
                     optionType) {

    BOOST_TEST_MESSAGE("Testing cash settled automatic exercise option pricing after expiry...");

    Settings::instance().evaluationDate() = Date(4, Sep, 2020);

    // Create index to be used in option.
    Date expiry(3, Sep, 2020);
    NullCalendar fixingCalendar;
    boost::shared_ptr<Index> index =
        boost::make_shared<CommodityFuturesIndex>("TEST", expiry, fixingCalendar, priceTs());

    // Add the expiry date fixing for the index.
    Real exercisePrice = 59.00;
    index->addFixing(expiry, exercisePrice);

    // Create cash settled option instrument
    Date payment(7, Sep, 2020);
    bool automaticExercise = true;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise, index);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Set the pricing engine
    option.setPricingEngine(engine);

    // Check the option values against expected values.
    checkOptionValues(option, r, exercisePrice);
}

BOOST_DATA_TEST_CASE(testOptionAutomaticExerciseOnExpiry,
                     bdata::make(strikes) * bdata::make(optionTypes) * bdata::make(irdes), strike, optionType, irde) {

    BOOST_TEST_MESSAGE("Testing cash settled automatic exercise option pricing on expiry...");

    // Should work for either setting of includeReferenceDateEvents.
    Settings::instance().includeReferenceDateEvents() = irde;

    // Create index to be used in option.
    Date expiry(3, Sep, 2020);
    Settings::instance().evaluationDate() = expiry;
    NullCalendar fixingCalendar;
    Handle<PriceTermStructure> pts = priceTs();
    boost::shared_ptr<Index> index = boost::make_shared<CommodityFuturesIndex>("TEST", expiry, fixingCalendar, pts);

    // Create cash settled option instrument
    Date payment(7, Sep, 2020);
    bool automaticExercise = true;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise, index);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Set the pricing engine
    option.setPricingEngine(engine);

    // We have not added a fixing for the index so it will be projected of the the price term structure above to
    // give the payoff. So, we use that value here in our check initially.
    Real ptsPrice = pts->price(0.0);
    checkOptionValues(option, r, ptsPrice);

    // Add an expiry date fixing for the index.
    Real exercisePrice = 59.00;
    index->addFixing(expiry, exercisePrice);

    // Check the updated values
    checkOptionValues(option, r, exercisePrice);
}

BOOST_DATA_TEST_CASE(testOptionAutomaticExerciseOnPayment, bdata::make(strikes) * bdata::make(optionTypes), strike,
                     optionType) {

    BOOST_TEST_MESSAGE("Testing cash settled automatic exercise option pricing on payment date...");

    // Create index to be used in option.
    Date expiry(3, Sep, 2020);
    NullCalendar fixingCalendar;
    boost::shared_ptr<Index> index =
        boost::make_shared<CommodityFuturesIndex>("TEST", expiry, fixingCalendar, priceTs());

    // Add the expiry date fixing for the index.
    Real exercisePrice = 59.00;
    index->addFixing(expiry, exercisePrice);

    // Create cash settled option instrument
    Date payment(7, Sep, 2020);
    Settings::instance().evaluationDate() = payment;
    bool automaticExercise = true;
    CashSettledEuropeanOption option(optionType, strike, expiry, payment, automaticExercise, index);

    // Create engine that accounts for cash settlement.
    Rate spot = 60.00;
    Volatility vol = 0.30;
    Rate r = 0.02;
    Rate q = 0.01;
    boost::shared_ptr<PricingEngine> engine =
        boost::make_shared<AnalyticCashSettledEuropeanEngine>(getProcess(spot, vol, r, q));

    // Set the pricing engine
    option.setPricingEngine(engine);

    // Set include reference date events to true so that the option is not considered expired.
    Settings::instance().includeReferenceDateEvents() = true;

    // Check the option values against expected values.
    checkOptionValues(option, r, exercisePrice);

    // Set include reference date events to false so that the option is considered expired.
    // Must recalculate for the setting to take effect.
    Settings::instance().includeReferenceDateEvents() = false;
    option.recalculate();

    // Check that all the values are zero, i.e. the expired state.
    map<string, Real> cashSettledResults = results(option);
    for (const auto& kv : cashSettledResults) {
        BOOST_TEST_CONTEXT("With result " << kv.first) { BOOST_CHECK(close(kv.second, 0.0)); }
    }
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


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

  @copyright 2015 NumScale SAS
  @copyright 2015 J.T.Lapreste

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

#include <boost/simd/function/definition/sech.hpp>
#include <boost/simd/arch/common/generic/function/sech.hpp>

#endif


///////////////////////////////////////////////////////////////////////////////
// statistics::survival::data::random::default_batch.hpp                     //
//                                                                           //
//  Copyright 2009 Erwann Rogard. 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_STATISTICS_SURVIVAL_DATA_RANDOM_DEFAULT_BATCH_HPP_ER_2009
#define BOOST_STATISTICS_SURVIVAL_DATA_RANDOM_DEFAULT_BATCH_HPP_ER_2009
#include <boost/random/gen_to_random.hpp>
#include <boost/functional/clock.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/functional/visitor.hpp>
#include <boost/iterator/range_cycle.hpp>
#include <boost/random/ref_distribution.hpp>
#include <boost/statistics/survival/data/random/batch.hpp>

namespace boost{
namespace statistics{
namespace survival{
namespace data{
namespace random{

    // Same as batch, but
    // x is drawn cyclically from a fixed set of values, referred to
    // as "x_values", and the clock produces times at fixed intervals.
    template<
        typename T,
        typename M,
        typename P,
        typename Rx,    // Range // Covariate values
        typename I = typename meta::random_input<M>::type
    >
    class meta_default_batch{
        // Covariates
        typedef range_cycle<>                                   meta_;
        typedef typename meta_::apply<Rx>::type                 cycle_;
        typedef typename functional::visitor<cycle_>            gcov_;
        public:
        typedef boost::random::gen_to_random<gcov_,I>           rcov_;
        private:
        // Necessary in combination with cycle
        typedef boost::random::ref_distribution<rcov_&>         ref_rcov_;
        typedef shared_ptr<rcov_> shared_;

        // Clock
        typedef functional::clock<T>                            gc_;
        typedef boost::random::gen_to_random<gc_,I>             rc_;

        public:
        typedef std::size_t                                     size_type;
        typedef gc_                                             clock_type;

        typedef batch<T,M,P,rc_,ref_rcov_,I>  type;

        typedef typename type::model_parameter_ mp_;

        static rcov_ rcov(
            Rx& x_values,             // Not const Rx&? TODO see range_cycle
            size_type offset,
            size_type n

        ){
            return rcov_(
                gcov_(
                    meta_::make(x_values,offset,n)
                )
            );
        }

        // rcov above must be called from outside.
        static type make(
            mp_ mp,
            const clock_type& c,
            rcov_& rcov
        ){
            return type(
                mp,
                rc_(c),
                ref_rcov_(
                    rcov
                )
            );
        }

    };

}// random
}// data
}// survival
}// statistics
}// boost

#endif


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

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  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_SIMD_FUNCTION_RSHL_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_RSHL_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>

#include <boost/simd/meta/hierarchy/simd.hpp>
#include <boost/simd/function/simd/if_else.hpp>
#include <boost/simd/function/simd/is_gtz.hpp>
#include <boost/simd/function/simd/shift_left.hpp>
#include <boost/simd/function/simd/shr.hpp>
#include <boost/simd/function/simd/unary_minus.hpp>

#ifndef NDEBUG
#include <boost/simd/function/simd/max.hpp>
#include <boost/simd/constant/zero.hpp>
#endif

namespace boost { namespace simd { namespace ext
{
   namespace bd = boost::dispatch;
   namespace bs = boost::simd;
   BOOST_DISPATCH_OVERLOAD(rshl_
                          , (typename A0, typename A1, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::arithmetic_<A0>, X>
                          , bd::generic_<bd::integer_<A1>>
                          )
   {
      BOOST_FORCEINLINE A0 operator()( const A0& a0, const  A1&  a1) const BOOST_NOEXCEPT
      {
        #ifndef NDEBUG
        return if_else(is_gtz(a1), shift_left(a0, max(Zero<A1>(), a1)), shr(a0, max(Zero<A1>(), -a1)));
        #else
        return if_else(is_gtz(a1), shift_left(a0, a1), shr(a0, -a1));
        #endif
      }
   };

   BOOST_DISPATCH_OVERLOAD(rshl_
                          , (typename A0, typename A1, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::arithmetic_<A0>, X>
                          , bd::generic_<bd::unsigned_<A1>>
                          )
   {
     BOOST_FORCEINLINE A0 operator()( const A0& a0, const  A1&  a1) const BOOST_NOEXCEPT
     {
       return shift_left(a0, a1);
     }
   };
} } }

#endif


#pragma once

#include <memory>

#include <boost/dynamic_bitset.hpp>

#include "abstract_cardinality_estimator.hpp"
#include "operators/operator_scan_predicate.hpp"
#include "statistics/statistics_objects/abstract_histogram.hpp"

namespace opossum {

template <typename T>
class AbstractHistogram;
template <typename T>
class GenericHistogram;
template <typename T>
class AttributeStatistics;
class AliasNode;
class ProjectionNode;
class AggregateNode;
class ValidateNode;
class PredicateNode;
class JoinNode;
class UnionNode;
class LimitNode;

/**
 * Hyrise's default, statistics-based cardinality estimator
 */
class CardinalityEstimator : public AbstractCardinalityEstimator {
 public:
  std::shared_ptr<AbstractCardinalityEstimator> new_instance() const override;

  Cardinality estimate_cardinality(const std::shared_ptr<const AbstractLQPNode>& lqp) const override;
  std::shared_ptr<TableStatistics> estimate_statistics(const std::shared_ptr<const AbstractLQPNode>& lqp) const;

  /**
   * Per-node-type estimation functions
   * @{
   */
  static std::shared_ptr<TableStatistics> estimate_alias_node(
      const AliasNode& alias_node, const std::shared_ptr<TableStatistics>& input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_projection_node(
      const ProjectionNode& projection_node, const std::shared_ptr<TableStatistics>& input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_aggregate_node(
      const AggregateNode& aggregate_node, const std::shared_ptr<TableStatistics>& input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_validate_node(
      const ValidateNode& validate_node, const std::shared_ptr<TableStatistics>& input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_predicate_node(
      const PredicateNode& predicate_node, const std::shared_ptr<TableStatistics>& input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_join_node(
      const JoinNode& join_node, const std::shared_ptr<TableStatistics>& left_input_table_statistics,
      const std::shared_ptr<TableStatistics>& right_input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_union_node(
      const UnionNode& union_node, const std::shared_ptr<TableStatistics>& left_input_table_statistics,
      const std::shared_ptr<TableStatistics>& right_input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_limit_node(
      const LimitNode& limit_node, const std::shared_ptr<TableStatistics>& input_table_statistics);
  /** @} */

  /**
   * Filter estimations
   * @{
   */

  /**
   * Estimate a simple scanning predicate. This function analyses the given predicate and dispatches the actual
   * estimation algorithm.
   */
  static std::shared_ptr<TableStatistics> estimate_operator_scan_predicate(
      const std::shared_ptr<TableStatistics>& input_table_statistics, const OperatorScanPredicate& predicate);

  /**
   * Estimation of an equi scan between two histograms. Estimating equi scans without correlation information is
   * impossible, so this function is restricted to computing an upper bound of the resulting histogram.
   */
  template <typename T>
  static std::shared_ptr<GenericHistogram<T>> estimate_column_vs_column_equi_scan_with_histograms(
      const AbstractHistogram<T>& left_histogram, const AbstractHistogram<T>& right_histogram);
  /** @} */

  /**
   * Join estimations
   * @{
   */
  static std::shared_ptr<TableStatistics> estimate_inner_equi_join(const ColumnID left_column_id,
                                                                   const ColumnID right_column_id,
                                                                   const TableStatistics& left_input_table_statistics,
                                                                   const TableStatistics& right_input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_semi_join(const ColumnID left_column_id,
                                                             const ColumnID right_column_id,
                                                             const TableStatistics& left_input_table_statistics,
                                                             const TableStatistics& right_input_table_statistics);

  static std::shared_ptr<TableStatistics> estimate_cross_join(const TableStatistics& left_input_table_statistics,
                                                              const TableStatistics& right_input_table_statistics);
  template <typename T>
  static std::shared_ptr<GenericHistogram<T>> estimate_inner_equi_join_with_histograms(
      const AbstractHistogram<T>& left_histogram, const AbstractHistogram<T>& right_histogram);

  /**
   * Given two HistogramBins with equal bounds and the specified height and distinct counts, estimate the number of
   * matches and distinct values for an equi-inner join of these two bins using a principle-of-inclusion estimation.
   * @return {estimated_height, estimated_distinct_count}
   */
  static std::pair<HistogramCountType, HistogramCountType> estimate_inner_equi_join_of_bins(
      const float left_height, const float left_distinct_count, const float right_height,
      const float right_distinct_count);

  /** @} */

  /**
   * Helper
   * @{
   */
  static std::shared_ptr<TableStatistics> prune_column_statistics(
      const std::shared_ptr<TableStatistics>& table_statistics, const std::vector<ColumnID>& pruned_column_ids);

  /** @} */
};
}  // namespace opossum


#include <stan/math/rev.hpp>
#include <boost/mp11.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/rev/functor/test_fixture_ode.hpp>
#include <test/unit/math/rev/functor/test_fixture_dae_chem.hpp>
#include <test/unit/math/rev/functor/dae_test_functors.hpp>

/**
 *
 * Use same solver functor type for both w & w/o tolerance control
 */
template <typename solve_type, typename... Ts>
using ode_test_tuple = std::tuple<solve_type, solve_type, Ts...>;

/**
 * Outer product of test types
 */
using chemical_kinetics_sens_test_types = boost::mp11::mp_product<
    ode_test_tuple, ::testing::Types<dae_functor>,
    ::testing::Types<double>,  // t
    ::testing::Types<double,
                     stan::math::var_value<double> >,  // yy
    ::testing::Types<double,
                     stan::math::var_value<double> >,    // yp
    ::testing::Types<stan::math::var_value<double> > >;  // theta

TYPED_TEST_SUITE_P(chemical_kinetics_test);
TYPED_TEST_P(chemical_kinetics_test, value) { this->test_value(0.0); }
TYPED_TEST_P(chemical_kinetics_test, sens) { this->test_sens(0.0); }
REGISTER_TYPED_TEST_SUITE_P(chemical_kinetics_test, value, sens);
INSTANTIATE_TYPED_TEST_SUITE_P(StanDAE, chemical_kinetics_test,
                               chemical_kinetics_sens_test_types);


#ifndef STAN_MCMC_HMC_HAMILTONIANS_DIAG_E_METRIC_HPP
#define STAN_MCMC_HMC_HAMILTONIANS_DIAG_E_METRIC_HPP

#include <stan/callbacks/logger.hpp>
#include <stan/mcmc/hmc/hamiltonians/base_hamiltonian.hpp>
#include <stan/mcmc/hmc/hamiltonians/diag_e_point.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/normal_distribution.hpp>

namespace stan {
  namespace mcmc {

    // Euclidean manifold with diagonal metric
    template <class Model, class BaseRNG>
    class diag_e_metric: public base_hamiltonian<Model, diag_e_point, BaseRNG> {
    public:
      explicit diag_e_metric(const Model& model)
        : base_hamiltonian<Model, diag_e_point, BaseRNG>(model) {}

      double T(diag_e_point& z) {
        return 0.5 * z.p.dot( z.inv_e_metric_.cwiseProduct(z.p) );
      }

      double tau(diag_e_point& z) {
        return T(z);
      }

      double phi(diag_e_point& z) {
        return this->V(z);
      }

      double dG_dt(diag_e_point& z, callbacks::logger& logger) {
        return 2 * T(z) - z.q.dot(z.g);
      }

      Eigen::VectorXd dtau_dq(diag_e_point& z, callbacks::logger& logger) {
        return Eigen::VectorXd::Zero(this->model_.num_params_r());
      }

      Eigen::VectorXd dtau_dp(diag_e_point& z) {
        return z.inv_e_metric_.cwiseProduct(z.p);
      }

      Eigen::VectorXd dphi_dq(diag_e_point& z, callbacks::logger& logger) {
        return z.g;
      }

      void sample_p(diag_e_point& z, BaseRNG& rng) {
        boost::variate_generator<BaseRNG&, boost::normal_distribution<> >
          rand_diag_gaus(rng, boost::normal_distribution<>());

        for (int i = 0; i < z.p.size(); ++i)
          z.p(i) = rand_diag_gaus() / sqrt(z.inv_e_metric_(i));
      }
    };

  }  // mcmc
}  // stan
#endif


//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
//
// 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)
//
// Official repository: https://github.com/cppalliance/json
//

#ifndef BOOST_JSON_DETAIL_IMPL_OBJECT_IMPL_HPP
#define BOOST_JSON_DETAIL_IMPL_OBJECT_IMPL_HPP

#include <boost/json/detail/digest.hpp>
#include <boost/json/detail/object_impl.hpp>

BOOST_JSON_NS_BEGIN
namespace detail {

constexpr
std::size_t
object_impl::
max_size() noexcept
{
    // max_size depends on the address model
    using min = std::integral_constant<std::size_t,
        (std::size_t(-1) - sizeof(table)) /
            (sizeof(value_type) + sizeof(index_t))>;
    return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
        min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
}

void
object_impl::
remove(
    index_t& head,
    value_type& p) noexcept
{
    auto const i = index_of(p);
    if(head == i)
    {
        head = next(p);
        return;
    }
    auto* pn = &next(get(head));
    while(*pn != i)
        pn = &next(get(*pn));
    *pn = next(p);
}

auto
object_impl::
bucket_sizes() noexcept ->
    bucket_size_array&
{
    // Taken from Boost.Intrusive and Boost.MultiIndex code,
    // thanks to Ion Gaztanaga and Joaquin M Lopez Munoz.
    static constexpr std::size_t list[34] =
    {
        0,

        3,                     7,
        11,                    17,
        29,                    53,
        97,                    193,
        389,                   769,
        1543,                  3079,
        6151,                  12289,
        24593,                 49157,
        98317,                 196613,
        393241,                786433,
        1572869,               3145739,
        6291469,               12582917,
        25165843,              50331653,
        100663319,             201326611,
        402653189,             805306457,
        1610612741,
        BOOST_JSON_MAX_STRUCTURED_SIZE,
        // catch anything that exceeds max_size
        std::size_t(-1)
    };
    return list;
}

std::size_t
object_impl::
bucket_index(
    std::size_t hash,
    std::size_t index) noexcept
{
    // Suggested by Joaquin M Lopez Munoz
    // https://github.com/CPPAlliance/json/issues/115
    switch(index)
    {
        default:
        case  0: return 0;
        case  1: return hash % bucket_sizes()[1];
        case  2: return hash % bucket_sizes()[2];
        case  3: return hash % bucket_sizes()[3];
        case  4: return hash % bucket_sizes()[4];
        case  5: return hash % bucket_sizes()[5];
        case  6: return hash % bucket_sizes()[6];
        case  7: return hash % bucket_sizes()[7];
        case  8: return hash % bucket_sizes()[8];
        case  9: return hash % bucket_sizes()[9];
        case 10: return hash % bucket_sizes()[10];
        case 11: return hash % bucket_sizes()[11];
        case 12: return hash % bucket_sizes()[12];
        case 13: return hash % bucket_sizes()[13];
        case 14: return hash % bucket_sizes()[14];
        case 15: return hash % bucket_sizes()[15];
        case 16: return hash % bucket_sizes()[16];
        case 17: return hash % bucket_sizes()[17];
        case 18: return hash % bucket_sizes()[18];
        case 19: return hash % bucket_sizes()[19];
        case 20: return hash % bucket_sizes()[20];
        case 21: return hash % bucket_sizes()[21];
        case 22: return hash % bucket_sizes()[22];
        case 23: return hash % bucket_sizes()[23];
        case 24: return hash % bucket_sizes()[24];
        case 25: return hash % bucket_sizes()[25];
        case 26: return hash % bucket_sizes()[26];
        case 27: return hash % bucket_sizes()[27];
        case 28: return hash % bucket_sizes()[28];
        case 29: return hash % bucket_sizes()[29];
        case 30: return hash % bucket_sizes()[30];
        case 31: return hash % bucket_sizes()[31];
        case 32: return hash % bucket_sizes()[32];
    }
}

auto
object_impl::
bucket(string_view key) const noexcept ->
    index_t&
{
    auto const hash = digest(key);
    return bucket_begin()[bucket_index(
        hash, tab_->prime_index)];
}

auto
object_impl::
bucket(std::size_t hash) const noexcept ->
    index_t&
{
    return bucket_begin()[bucket_index(
        hash, tab_->prime_index)];
}

auto
object_impl::
begin() const noexcept ->
    value_type*
{
    if(! tab_)
        return nullptr;
    return reinterpret_cast<
        value_type*>(tab_ + 1);
}

auto
object_impl::
end() const noexcept ->
    value_type*
{
    return begin() + size();
}

auto
object_impl::
get(index_t i) const noexcept ->
    value_type&
{
    BOOST_ASSERT(i != null_index);
    return (reinterpret_cast<
        value_type*>(tab_ + 1))[i];
}

auto
object_impl::
index_of(value_type const& p) const noexcept ->
    index_t
{
    return static_cast<index_t>(
        &p - reinterpret_cast<
            value_type const*>(tab_ + 1));
}

auto
object_impl::
bucket_begin() const noexcept ->
    index_t*
{
    return reinterpret_cast<
        index_t*>(
            begin() + capacity());
}

std::size_t
object_impl::
digest(string_view key) const noexcept
{
    return detail::digest(
        key.data(), key.size(), salt());
}

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

auto
object_impl::
next(value_type& e) noexcept ->
    index_t&
{
    return value_access::next(e);
}

auto
object_impl::
next(value_type const& e) noexcept ->
    index_t
{
    return value_access::next(e);
}

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

unchecked_object::
~unchecked_object()
{
    if( data_ &&
        ! sp_.is_not_counted_and_deallocate_is_trivial())
    {
        value* p = data_;
        while(size_--)
        {
            p[0].~value();
            p[1].~value();
            p += 2;
        }
    }
}

} // detail
BOOST_JSON_NS_END

#endif


// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the deep learning tools from the
    dlib C++ Library.  I'm assuming you have already read the dnn_mnist_ex.cpp
    example.  So in this example program I'm going to go over a number of more
    advanced parts of the API, including:
        - Using multiple GPUs
        - Training on large datasets that don't fit in memory
        - Defining large networks
        - Accessing and configuring layers in a network
*/

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

using namespace std;
using namespace dlib;

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

// Let's start by showing how you can conveniently define large networks.  The
// most important tool for doing this are C++'s alias templates.  These let us
// define new layer types that are combinations of a bunch of other layers.
// These will form the building blocks for more complex networks.

// So let's begin by defining the building block of a residual network (see
// Figure 2 in Deep Residual Learning for Image Recognition by He, Zhang, Ren,
// and Sun).  You can see a few things in this statement.  The most obvious is
// that we have combined a bunch of layers into the name "base_res".  You can
// also see the use of the tag1 layer.  This layer doesn't do any computation.
// It exists solely so other layers can refer to it.  In this case, the
// add_prev1 layer looks for the tag1 layer and will take the tag1 output and
// add it to the input of the add_prev1 layer.  This combination allows us to
// implement skip and residual style networks.
template <int stride, typename SUBNET>
using base_res  = relu<add_prev1<bn_con<con<8,3,3,1,1,relu<bn_con<con<8,3,3,stride,stride,tag1<SUBNET>>>>>>>>;

// Let's also define the same block but with all the batch normalization layers
// replaced with affine transform layers.  We will use this type of construction
// when testing our networks.
template <int stride, typename SUBNET>
using base_ares = relu<add_prev1<affine<con<8,3,3,1,1,relu<affine<con<8,3,3,stride,stride,tag1<SUBNET>>>>>>>>;

// And of course we can define more alias templates based on previously defined
// alias templates.  The _down versions downsample the inputs by a factor of 2
// while the res and ares layer types don't.
template <typename SUBNET> using res       = base_res<1,SUBNET>;
template <typename SUBNET> using res_down  = base_res<2,SUBNET>;
template <typename SUBNET> using ares      = base_ares<1,SUBNET>;
template <typename SUBNET> using ares_down = base_ares<2,SUBNET>;

// Now that we have these convenient aliases, we can define a residual network
// without a lot of typing.  Note the use of a repeat layer.  This special layer
// type allows us to type repeat<9,res<SUBNET>> instead of
// res<res<res<res<res<res<res<res<res<SUBNET>>>>>>>>>.  It will also prevent
// the compiler from complaining about super deep template nesting when creating
// large networks.
const unsigned long number_of_classes = 10;
using net_type = loss_multiclass_log<fc<number_of_classes,
                            avg_pool<11,11,11,11,
                            res<res<res<res_down<
                            repeat<9,res, // repeat this layer 9 times
                            res_down<
                            res<
                            input<matrix<unsigned char>>
                            >>>>>>>>>>;

// And finally, let's define a residual network building block that uses
// parametric ReLU units instead of regular ReLU.
template <typename SUBNET>
using pres  = prelu<add_prev1<bn_con<con<8,3,3,1,1,prelu<bn_con<con<8,3,3,1,1,tag1<SUBNET>>>>>>>>;

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

int main(int argc, char** argv) try
{
    if (argc != 2)
    {
        cout << "This example needs the MNIST dataset to run!" << endl;
        cout << "You can get MNIST from http://yann.lecun.com/exdb/mnist/" << endl;
        cout << "Download the 4 files that comprise the dataset, decompress them, and" << endl;
        cout << "put them in a folder.  Then give that folder as input to this program." << endl;
        return 1;
    }

    std::vector<matrix<unsigned char>> training_images;
    std::vector<unsigned long> training_labels;
    std::vector<matrix<unsigned char>> testing_images;
    std::vector<unsigned long> testing_labels;
    load_mnist_dataset(argv[1], training_images, training_labels, testing_images, testing_labels);

    // dlib uses cuDNN under the covers.  One of the features of cuDNN is the
    // option to use slower methods that use less RAM or faster methods that use
    // a lot of RAM.  If you find that you run out of RAM on your graphics card
    // then you can call this function and we will request the slower but more
    // RAM frugal cuDNN algorithms.
    set_dnn_prefer_smallest_algorithms();

    // Create a network as defined above.  This network will produce 10 outputs
    // because that's how we defined net_type.  However, fc layers can have the
    // number of outputs they produce changed at runtime.
    net_type net;
    // So if you wanted to use the same network but override the number of
    // outputs at runtime you can do so like this:
    net_type net2(num_fc_outputs(15));

    // Now, let's imagine we wanted to replace some of the relu layers with
    // prelu layers.  We might do it like this:
    using net_type2 = loss_multiclass_log<fc<number_of_classes,
                                avg_pool<11,11,11,11,
                                pres<res<res<res_down< // 2 prelu layers here
                                tag4<repeat<9,pres,    // 9 groups, each containing 2 prelu layers
                                res_down<
                                res<
                                input<matrix<unsigned char>>
                                >>>>>>>>>>>;

    // prelu layers have a floating point parameter.  If you want to set it to
    // something other than its default value you can do so like this:
    net_type2 pnet(prelu_(0.2),
                   prelu_(0.25),
                   repeat_group(prelu_(0.3),prelu_(0.4)) // Initialize all the prelu instances in the repeat
                                                         // layer.  repeat_group() is needed to group the
                                                         // things that are part of repeat's block.
                   );
    // As you can see, a network will greedily assign things given to its
    // constructor to the layers inside itself.  The assignment is done in the
    // order the layers are defined, but it will skip layers where the
    // assignment doesn't make sense.

    // Now let's print the details of the pnet to the screen and inspect it.
    cout << "The pnet has " << pnet.num_layers << " layers in it." << endl;
    cout << pnet << endl;
    // These print statements will output this (I've truncated it since it's
    // long, but you get the idea):
    /*
        The pnet has 125 layers in it.
        layer<0>      loss_multiclass_log
        layer<1>      fc       (num_outputs=10)
        layer<2>      avg_pool (nr=11, nc=11, stride_y=11, _stride_x=11)
        layer<3>      prelu    (initial_param_value=0.2)
        layer<4>      add_prev
        layer<5>      bn_con
        layer<6>      con      (num_filters=8, nr=3, nc=3, stride_y=1, stride_x=1)
        layer<7>      prelu    (initial_param_value=0.25)
        layer<8>      bn_con
        layer<9>      con      (num_filters=8, nr=3, nc=3, stride_y=1, stride_x=1)
        layer<10>     tag1
        ...
        layer<33>     con      (num_filters=8, nr=3, nc=3, stride_y=2, stride_x=2)
        layer<34>     tag1
        layer<35>     tag4
        layer<36>     prelu    (initial_param_value=0.3)
        layer<37>     add_prev
        layer<38>     bn_con
        ...
        layer<114>    con      (num_filters=8, nr=3, nc=3, stride_y=2, stride_x=2)
        layer<115>    tag1
        layer<116>    relu
        layer<117>    add_prev
        layer<118>    bn_con
        layer<119>    con      (num_filters=8, nr=3, nc=3, stride_y=1, stride_x=1)
        layer<120>    relu
        layer<121>    bn_con
        layer<122>    con      (num_filters=8, nr=3, nc=3, stride_y=1, stride_x=1)
        layer<123>    tag1
        layer<124>    input<matrix>
    */

    // Now that we know the index numbers for each layer, we can access them
    // individually using layer<index>(pnet).  For example, to access the output
    // tensor for the first prelu layer we can say:
    layer<3>(pnet).get_output();
    // Or to print the prelu parameter for layer 7 we can say:
    cout << "prelu param: "<< layer<7>(pnet).layer_details().get_initial_param_value() << endl;

    // We can also access layers by their type.  This next statement finds the
    // first tag1 layer in pnet, and is therefore equivalent to calling
    // layer<10>(pnet):
    layer<tag1>(pnet);
    // The tag layers don't do anything at all and exist simply so you can tag
    // parts of your network and access them by layer<tag>().  You can also
    // index relative to a tag.  So for example, to access the layer immediately
    // after tag4 you can say:
    layer<tag4,1>(pnet); // Equivalent to layer<35+1>(pnet).

    // Or to access the layer 2 layers after tag4:
    layer<tag4,2>(pnet);
    // Tagging is a very useful tool for making complex network structures.  For
    // example, the add_prev1 layer is implemented internally by using a call to
    // layer<tag1>().

    // Ok, that's enough talk about defining and inspecting networks.  Let's
    // talk about training networks!

    // The dnn_trainer will use SGD by default, but you can tell it to use
    // different solvers like adam.
    dnn_trainer<net_type,adam> trainer(net,adam(0.001));
    // Also, if you have multiple graphics cards you can tell the trainer to use
    // them together to make the training faster.  For example, replacing the
    // above constructor call with this one would cause it to use GPU cards 0
    // and 1.
    //dnn_trainer<net_type,adam> trainer(net,adam(0.001), {0,1});

    trainer.be_verbose();
    trainer.set_synchronization_file("mnist_resnet_sync", std::chrono::seconds(100));
    // While the trainer is running it keeps an eye on the training error.  If
    // it looks like the error hasn't decreased for the last 2000 iterations it
    // will automatically reduce the step size by 0.1.  You can change these
    // default parameters to some other values by calling these functions.  Or
    // disable them entirely by setting the shrink amount to 1.
    trainer.set_iterations_without_progress_threshold(2000);
    trainer.set_step_size_shrink_amount(0.1);

    // Now, what if your training dataset is so big it doesn't fit in RAM?  You
    // make mini-batches yourself, any way you like, and you send them to the
    // trainer by repeatedly calling trainer.train_one_step().
    //
    // For example, the loop below stream MNIST data to out trainer.
    std::vector<matrix<unsigned char>> mini_batch_samples;
    std::vector<unsigned long> mini_batch_labels;
    dlib::rand rnd(time(0));
    // Loop until the trainer's automatic shrinking has shrunk the step size by
    // 1e-3.  For the default shrinks amount of 0.1 this means stop after it
    // shrinks it 3 times.
    while(trainer.get_step_size() >= 1e-3)
    {
        mini_batch_samples.clear();
        mini_batch_labels.clear();

        // make a 128 image mini-batch
        while(mini_batch_samples.size() < 128)
        {
            auto idx = rnd.get_random_32bit_number()%training_images.size();
            mini_batch_samples.push_back(training_images[idx]);
            mini_batch_labels.push_back(training_labels[idx]);
        }

        trainer.train_one_step(mini_batch_samples, mini_batch_labels);
    }

    // When you call train_one_step(), the trainer will do its processing in a
    // separate thread.  This allows the main thread to work on loading data
    // while the trainer is busy executing the mini-batches in parallel.
    // However, this also means we need to wait for any mini-batches that are
    // still executing to stop before we mess with the net object.  Calling
    // get_net() performs the necessary synchronization.
    trainer.get_net();

    net.clean();
    serialize("mnist_res_network.dat") << net;

    // Now we have a trained network.  However, it has batch normalization
    // layers in it.  As is customary, we should replace these with simple
    // affine layers before we use the network.  This can be accomplished by
    // making a network type which is identical to net_type but with the batch
    // normalization layers replaced with affine.  For example:
    using test_net_type = loss_multiclass_log<fc<number_of_classes,
                                avg_pool<11,11,11,11,
                                ares<ares<ares<ares_down<
                                repeat<9,res,
                                ares_down<
                                ares<
                                input<matrix<unsigned char>>
                                >>>>>>>>>>;
    // Then we can simply assign our trained net to our testing net.
    test_net_type tnet = net;
    // Or if you only had a file with your trained network you could deserialize
    // it directly into your testing network.
    deserialize("mnist_res_network.dat") >> tnet;

    // And finally, we can run the testing network over our data.

    std::vector<unsigned long> predicted_labels = tnet(training_images);
    int num_right = 0;
    int num_wrong = 0;
    for (size_t i = 0; i < training_images.size(); ++i)
    {
        if (predicted_labels[i] == training_labels[i])
            ++num_right;
        else
            ++num_wrong;

    }
    cout << "training num_right: " << num_right << endl;
    cout << "training num_wrong: " << num_wrong << endl;
    cout << "training accuracy:  " << num_right/(double)(num_right+num_wrong) << endl;

    predicted_labels = tnet(testing_images);
    num_right = 0;
    num_wrong = 0;
    for (size_t i = 0; i < testing_images.size(); ++i)
    {
        if (predicted_labels[i] == testing_labels[i])
            ++num_right;
        else
            ++num_wrong;

    }
    cout << "testing num_right: " << num_right << endl;
    cout << "testing num_wrong: " << num_wrong << endl;
    cout << "testing accuracy:  " << num_right/(double)(num_right+num_wrong) << endl;

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


#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <boost/program_options.hpp>

#include "msa.hpp"
#include "model.hpp"
#include "MCseq.hpp"
#include "OptParam.hpp"
#include "AnaTraj.hpp"
using namespace std;

namespace po = boost::program_options;

int main(int argc, char *argv[])
{
  po::options_description desc("Allowed options");
  desc.add_options()
    ("help,h","produce help message")
    ("in,i", po::value<string>(), "set input file (multiple FASTA)")
    ("dos", po::value<string>(), "WL DOS file")
    ("param,p", po::value<string>(), "input LGM parameter file")
    ("param_out", po::value<string>(), "output LGM parameter file")
    ("logbase,l", po::value<string>(), "basename for log files")
    ("temp", po::value<double>(), "Temperature")
    ("mu_len", po::value<double>(), "Mu_len")
    ("ftraj", po::value<string>(), "trajectory file to be analyzed")
    ("feigen", po::value<string>(), "eigen components file.")
    ("seed", po::value<int>(), "random seed")
    ;

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

  if(vm.count("help")) {
    cerr << desc << endl;
    return 1;
  }
  string logbase = "ana";
  if(vm.count("logbase")) {
    logbase = vm["logbase"].as<string>();
  }
  cerr << "# LOGBASE= " << logbase << endl;

  if(vm.count("in")) {
    cerr << "Input file was set to " << vm["in"].as<string>() << endl;
    string infile = vm["in"].as<string>();
    Msa msa(infile);
    Model model(msa);
    int nseq = model.get_num_seq();
    if(vm.count("param")) {
      model.read_parameters(vm["param"].as<string>());
    } else {
      cerr << "Specify the parameter file!" << endl;
      exit(1);
    }

    MCseq mcs(model);

    if(vm.count("seed")) {
      mcs.set_seed(vm["seed"].as<int>());
      cerr << "random seed= " << (vm["seed"].as<int>()) << endl;;
    }
    if(vm.count("dos")) {
      mcs.STATS_MULTICANONICAL = true;
      mcs.read_DOS(vm["dos"].as<string>(), true);
    } else {
      mcs.STATS_MULTICANONICAL = false;
      cerr << "Trajectory treated as CANONICAL." << endl;
    }
    double temp = 1.0;
    if(vm.count("temp")) {
      temp = vm["temp"].as<double>();
    }
    mcs.set_temperature(temp);
    cerr << "Temperature= " << temp << endl;

    AnaTraj atraj(model);
    string ftraj;
    if(vm.count("ftraj")) {
      ftraj = vm["ftraj"].as<string>();
      cerr << "# Trajectory file: " <<  ftraj << endl;
      atraj.set_trajectory_file(ftraj);
    }

    double Mu_len = 0;
    if(vm.count("mu_len")) {
      Mu_len = vm["mu_len"].as<double>();
    }
    cerr << "Mu_len= " << Mu_len << endl;
    model.set_mu_len(Mu_len);

    int Nseqs=0;
    mcs.init_stats(model);
    mcs.stats_full_nonbonded = false;
    const clock_t begin_time = clock();
    cerr << "# Sampling from Trajectory file " << endl;
    vector<double> weights;
    while(atraj.pick_seq(model, mcs)) {
      const double w = mcs.count_stats(model, true);
      weights.push_back(w);
      Nseqs++;
      if(Nseqs % 100000 == 0) cerr << Nseqs << " sequences processed." << endl;
    }
    atraj.unset_trajectory_file();
    cerr << "total weight= " << mcs.WeightTotal << endl;
    mcs.finish_stats(model);
    const clock_t end_time = clock();

    if(vm.count("feigen")) {
      const string feigen = vm["feigen"].as<string>();
      cerr << "# Eigen-components file: " <<  feigen << endl;
      atraj.read_eigen_components(feigen);
    }
    const int nseqs = weights.size();
    for(int i = 0; i != nseqs; ++i) {
      weights[i] /= mcs.WeightTotal;
    }
    vector<int> inds = PCA_project_seqs(atraj, cout, 10000, weights);
    atraj.set_trajectory_file(ftraj);
    int ind=0;
    while(atraj.pick_seq(model, mcs)) {
      if(std::binary_search (inds.begin(), inds.end(), ind)) {
	cerr << "weight " << ind << "\t" << weights[ind] << endl;
	darray1 p = atraj.pca_project(mcs);
	cout << p[0] << "\t"
	     << p[1] << "\t"
	     << p[2] << "\t"
	     << mcs.Energy << "\t"
	     << weights[ind] << endl;
      }
      ++ind;
    }
    atraj.unset_trajectory_file();
  }
  return 0;
}