#include <celero/Celero.h>

#include <string>
#include <random>
#include <limits>

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

#include <pcg_random.hpp>

///
/// This is the main(int argc, char** argv) for the entire celero program.
/// You can write your own, or use this macro to insert the standard one into the project.
///
CELERO_MAIN

constexpr int g_samples = 10;
constexpr int g_iterations = 1000;
constexpr int g_loop = 10000;

// mt19937
std::mt19937 rng_mt19937;

std::uniform_int_distribution<int> distribution_int(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
std::uniform_int_distribution<long> distribution_long(std::numeric_limits<long>::min(), std::numeric_limits<long>::max());

auto random_mt19937_int() noexcept
{
	return distribution_int(rng_mt19937);
}

auto random_mt19937_long() noexcept
{
	return distribution_long(rng_mt19937);
}

// taus88
boost::random::taus88 rng_taus88;
boost::random::uniform_int_distribution<int> dist_taus88_int(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
boost::random::uniform_int_distribution<long> dist_taus88_long(std::numeric_limits<long>::min(), std::numeric_limits<long>::max());

int random_taus88_int() noexcept
{
	return dist_taus88_int(rng_taus88);
}
long random_taus88_long() noexcept
{
	return dist_taus88_long(rng_taus88);
}

// PCG
pcg32 pcg;

auto random_pcg_int() noexcept
{
	return distribution_int(pcg);
}

auto random_pcg_long() noexcept
{
	return distribution_long(pcg);
}

// WELL512
// http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
/* initialize state to random bits */
static unsigned long state[16];
/* init should also reset this to 0 */
static unsigned int well_index = 0;
/* return 32 bit random number */
unsigned long WELLRNG512(void)
{
	unsigned long a, b, c, d;
	a = state[well_index];
	c = state[(well_index + 13) & 15];
	b = a^c ^ (a << 16) ^ (c << 15);
	c = state[(well_index + 9) & 15];
	c ^= (c >> 11);
	a = state[well_index] = b^c;
	d = a ^ ((a << 5) & 0xDA442D24UL);
	well_index = (well_index + 15) & 15;
	a = state[well_index];
	state[well_index] = a^b^d ^ (a << 2) ^ (b << 18) ^ (c << 28);
	return state[well_index];
}

// intel fastrand
// https://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor
static unsigned int g_fastrand_seed;
inline int fastrand() {
	g_fastrand_seed = (214013 * g_fastrand_seed + 2531011);
	return (g_fastrand_seed >> 16) & 0x7FFF;
}

// xorshift+
// https://en.wikipedia.org/wiki/Xorshift
/* The state must be seeded so that it is not everywhere zero. */
uint64_t s[2];

uint64_t xorshift128plus(void) {
	uint64_t x = s[0];
	uint64_t const y = s[1];
	s[0] = y;
	x ^= x << 23; // a
	s[1] = x ^ y ^ (x >> 17) ^ (y >> 26); // b, c
	return s[1] + y;
}

//#define DONT_OPTIMIIZE

// int
BASELINE(int, rand, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(rand());
#else
		rand();
#endif
}

BENCHMARK(int, mt19937, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(random_mt19937_int());
#else
		random_mt19937_int();
#endif
}

BENCHMARK(int, WELL512, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(static_cast<int>(WELLRNG512()));// using long
#else
		static_cast<int>(WELLRNG512());// using long
#endif
}

BENCHMARK(int, taus88, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(random_taus88_int());
#else
		random_taus88_int();
#endif
}

BENCHMARK(int, intel_fastrand, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(fastrand());
#else
		fastrand();
#endif
}

BENCHMARK(int, xorshiftplus, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(static_cast<int>(xorshift128plus()));// using uint64_t
#else
		static_cast<int>(xorshift128plus());
#endif
}

BENCHMARK(int, pcg, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(random_pcg_int());
#else
		random_pcg_int();
#endif
}

// long
BASELINE(long, rand, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway((static_cast<long>(rand()) << (sizeof(int) * 8 - 1)) | rand());
#else
		(static_cast<long>(rand()) << (sizeof(int) * 8 - 1)) | rand();
#endif
}

BENCHMARK(long, mt19937, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(random_mt19937_long());
#else
		random_mt19937_long();
#endif
}

BENCHMARK(long, WELL512, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(WELLRNG512());
#else
		WELLRNG512();
#endif
}

BENCHMARK(long, taus88, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(random_taus88_long());
#else
		random_taus88_long();
#endif
}

BENCHMARK(long, intel_fastrand, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway((static_cast<long>(fastrand()) << (sizeof(int) * 8 - 1)) | fastrand());
#else
		(static_cast<long>(fastrand()) << (sizeof(int) * 8 - 1)) | fastrand();
#endif
}

BENCHMARK(long, xorshiftplus, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(xorshift128plus());
#else
		xorshift128plus();
#endif
}

BENCHMARK(long, pcg, g_samples, g_iterations)
{
	for (size_t i = 0; i < g_loop; ++i)
#ifdef DONT_OPTIMIIZE
		celero::DoNotOptimizeAway(random_pcg_long());
#else
		random_pcg_long();
#endif
}


#pragma once

#include <vector>
#include <Eigen/Dense>
#include <iostream>

#include <ros/ros.h>

#include "utils/utility_functions.hpp"

namespace hdi_plan {
class ChompTrajectory {
public:
	ChompTrajectory(const std::vector<Eigen::Vector3d>& trajectory_points, const double start_time, const double end_time, const double discretization, const double speed);
	ChompTrajectory(const Eigen::Vector3d& start_point, const Eigen::Vector3d& end_point);
	~ChompTrajectory();

	Eigen::MatrixXd get_trajectory() const {
		return this->trajectory_;
	}

	int get_num_points() const {
		return this->num_points_;
	};

	int get_num_points_diff() const {
		return this->num_points_diff_;
	};

	int get_num_points_free() const {
		return this->num_points_free_;
	};

	int get_start_extra() const {
		return this->start_extra_;
	};

	int get_end_extra() const {
		return this->end_extra_;
	};

	int get_start_index() const {
		return this->start_index_;
	};

	int get_end_index() const {
		return this->end_index_;
	};

	int get_duration() const {
		return this->duration_;
	};

	double get_discretization() const {
		return this->discretization_;
	}

	Eigen::Vector3d get_position_by_index(int index) const {
		Eigen::Vector3d position(this->trajectory_(index + this->start_extra_, 0),
					        this->trajectory_(index + this->start_extra_, 1),
					        this->trajectory_(index + this->start_extra_, 2));
		return position;
	};

	Eigen::MatrixXd::ColXpr get_joint_trajectory(int joint) {
		return this->trajectory_.col(joint);
	}

	Eigen::MatrixXd::RowXpr get_point_trajectory(int point) {
		return this->trajectory_.row(point);
	}

	Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic> get_free_trajectory_block(){
		return this->trajectory_.block(start_index_, 0, this->num_points_free_, this->num_joints_);
	}

	void add_increments_to_trajectory(Eigen::MatrixXd::ColXpr increment, int joint_number, double scale);

	double calculate_time_by_index(int index);
private:
	double start_time_;
	double end_time_;

	std::vector<Eigen::Vector3d> trajectory_points_;
	Eigen::MatrixXd trajectory_;
	double duration_;
	double duration_diff_;
	int num_points_;
	int num_points_diff_;
	int num_points_free_;
	int num_joints_{3};
	double discretization_{0.5}; // every interval is 0.5s
	double speed_{1.0};
	std::vector<int> group_number_;
	std::vector<int> group_number_add_;
	std::vector<Eigen::Vector3d> discretized_points_;

	int start_index_origin;
	int end_index_origin_;
	int start_index_;
	int end_index_;
	int start_extra_{0};
	int end_extra_{0};
	void calculate_duration_and_points_num_for_full_trajectory();
	void update_trajectory_for_diff();
	void fill_trajectory();
	void fill_discretized_points();
	Eigen::Vector3d calculate_position_by_index(int index);
	void set_start_time();
};

}


//==================================================================================================
/*!
  @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_NEGATE_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_NEGATE_HPP_INCLUDED

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

 /*!

    @ingroup group-ieee
    Function object implementing negate capabilities

    Retuns the first element multiplied by the @ref sign of the second.

    @par Semantic:

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

    is similar to:

    @code
    auto r =  x*sign(y);
    @endcode

    @par Note
    If y is @ref Zero the result is zero. This can be avoided using
    @ref negatenz or @ref copysign.

    @see sign, negatenz, copysign,  Mzero,  is_positive, is_negative

  **/
  Value negate(Value const & x, Value const& y);
} }
#endif

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

#endif


#ifndef STAN_MATH_TORSTEN_LINODE_HPP
#define STAN_MATH_TORSTEN_LINODE_HPP

#include <Eigen/Dense>
#include <stan/math/torsten/ev_manager.hpp>
#include <boost/math/tools/promotion.hpp>
#include <stan/math/torsten/ev_solver.hpp>
#include <stan/math/torsten/to_array_2d.hpp>
#include <stan/math/torsten/pmx_linode_model.hpp>
#include <stan/math/torsten/pmx_check.hpp>
#include <stan/math/prim/err/check_square.hpp>
#include <vector>

namespace torsten {

  namespace {
    template<typename T>
    using torsten_matrix_dyn_t = Eigen::Matrix<T,-1,-1>;
  }

/**
 * Computes the predicted amounts in each compartment at each event
 * for a compartment model, described by a linear system of ordinary
 * differential equations. Uses the stan::math::matrix_exp
 * function.
 *
 * @tparam T0 type of scalar for time of events.
 * @tparam T1 type of scalar for amount at each event.
 * @tparam T2 type of scalar for rate at each event.
 * @tparam T3 type of scalar for inter-dose inteveral at each event.
 * @tparam T4 type of scalar for matrix describing linear ODE system.
 * @tparam T5 type of scalars for bio-variability parameters.
 * @tparam T6 type of scalars for tlag parameters
 * @param[in] time times of events
 * @param[in] amt amount at each event
 * @param[in] rate rate at each event
 * @param[in] ii inter-dose interval at each event
 * @param[in] evid event identity:
 *                    (0) observation
 *                    (1) dosing
 *                    (2) other
 *                    (3) reset
 *                    (4) reset AND dosing
 * @param[in] cmt compartment number at each event
 * @param[in] addl additional dosing at each event
 * @param[in] ss steady state approximation at each event (0: no, 1: yes)
 * between time-points
 * @param[in] system square matrix describing the linear system of ODEs
 * @param[in] bio-variability at each event
 * @param[in] lag times at each event
 * @return a matrix with predicted amount in each compartment
 * at each event.
 */
template <typename T0, typename T1, typename T2, typename T3,
          typename T4, typename T5, typename T6>
stan::matrix_return_t<T0, T1, T2, T3, T4, T5, T6>
pmx_solve_linode(const std::vector<T0>& time,
                 const std::vector<T1>& amt,
                 const std::vector<T2>& rate,
                 const std::vector<T3>& ii,
                 const std::vector<int>& evid,
                 const std::vector<int>& cmt,
                 const std::vector<int>& addl,
                 const std::vector<int>& ss,
                 const std::vector< Eigen::Matrix<T4, -1, -1> >& system,
                 const std::vector<std::vector<T5> >& biovar,
                 const std::vector<std::vector<T6> >& tlag) {
  using std::vector;
  using Eigen::Dynamic;
  using Eigen::Matrix;
  using boost::math::tools::promote_args;

  static const char* function("pmx_solve_linode");
  for (size_t i = 0; i < system.size(); i++)
    stan::math::check_square(function, "system matrix", system[i]);
  int nCmt = system[0].cols();

  using ER = NONMENEventsRecord<T0, T1, T2, T3>;
  using EM = EventsManager<ER, NonEventParameters<T0, T4, torsten_matrix_dyn_t, std::tuple<T5, T6> >>;
  const ER events_rec(nCmt, time, amt, rate, ii, evid, cmt, addl, ss);

  Matrix<typename EM::T_scalar, Dynamic, Dynamic> pred =
    Matrix<typename EM::T_scalar, Dynamic, Dynamic>::Zero(events_rec.num_event_times(), EM::nCmt(events_rec));

  using model_type = torsten::PMXLinODEModel<typename EM::T_par>;
  EventSolver<model_type, EM> pr;
  pr.pred(0, events_rec, pred, dsolve::PMXAnalyiticalIntegrator(), system, biovar, tlag, nCmt);
  return pred;
}

/**
 * Overload function to allow user to pass a matrix for
 * system.
 */
template <typename T0, typename T1, typename T2, typename T3,
          typename T4, typename T_biovar, typename T_tlag>
stan::matrix_return_t<T0, T1, T2, T3, T4, T_biovar, T_tlag>
pmx_solve_linode(const std::vector<T0>& time,
                 const std::vector<T1>& amt,
                 const std::vector<T2>& rate,
                 const std::vector<T3>& ii,
                 const std::vector<int>& evid,
                 const std::vector<int>& cmt,
                 const std::vector<int>& addl,
                 const std::vector<int>& ss,
                 const Eigen::Matrix<T4, -1, -1>& system,
                 const std::vector<T_biovar>& biovar,
                 const std::vector<T_tlag>& tlag) {
  std::vector<Eigen::Matrix<T4, -1, -1> > system_{system};
  auto biovar_ = torsten::to_array_2d(biovar);
  auto tlag_ = torsten::to_array_2d(tlag);

  return pmx_solve_linode(time, amt, rate, ii, evid, cmt, addl, ss,
                          system_, biovar_, tlag_);
}

/**
 * Overload function to allow user to pass a matrix for
 * system.
 */
template <typename T0, typename T1, typename T2, typename T3,
          typename T4, typename T_biovar, typename T_tlag,
          typename = require_any_not_std_vector_t<T_biovar, T_tlag> >
stan::matrix_return_t<T0, T1, T2, T3, T4, T_biovar, T_tlag>
pmx_solve_linode(const std::vector<T0>& time,
                 const std::vector<T1>& amt,
                 const std::vector<T2>& rate,
                 const std::vector<T3>& ii,
                 const std::vector<int>& evid,
                 const std::vector<int>& cmt,
                 const std::vector<int>& addl,
                 const std::vector<int>& ss,
                 const std::vector< Eigen::Matrix<T4, -1, -1> >& system,
                 const std::vector<T_biovar>& biovar,
                 const std::vector<T_tlag>& tlag) {
  auto biovar_ = torsten::to_array_2d(biovar);
  auto tlag_ = torsten::to_array_2d(tlag);

  return pmx_solve_linode(time, amt, rate, ii, evid, cmt, addl, ss,
                          system, biovar_, tlag_);
}

  // old version by using transpose
template <typename T0, typename T1, typename T2, typename T3,
          typename T4, typename T5, typename T6>
stan::matrix_return_t<T0, T1, T2, T3, T4, T5, T6>
linOdeModel(const std::vector<T0>& time,
            const std::vector<T1>& amt,
            const std::vector<T2>& rate,
            const std::vector<T3>& ii,
            const std::vector<int>& evid,
            const std::vector<int>& cmt,
            const std::vector<int>& addl,
            const std::vector<int>& ss,
            const std::vector< Eigen::Matrix<T4, Eigen::Dynamic, Eigen::Dynamic> >& system,
            const std::vector<std::vector<T5> >& biovar,
            const std::vector<std::vector<T6> >& tlag) {
  auto x = pmx_solve_linode(time, amt, rate, ii, evid, cmt, addl, ss, system, biovar, tlag);
  return x.transpose();
}

template <typename T0, typename T1, typename T2, typename T3,
          typename T4, typename T_biovar, typename T_tlag>
stan::matrix_return_t<T0, T1, T2, T3, T4, T_biovar, T_tlag>
linOdeModel(const std::vector<T0>& time,
                 const std::vector<T1>& amt,
                 const std::vector<T2>& rate,
                 const std::vector<T3>& ii,
                 const std::vector<int>& evid,
                 const std::vector<int>& cmt,
                 const std::vector<int>& addl,
                 const std::vector<int>& ss,
                 const Eigen::Matrix<T4, -1, -1>& system,
                 const std::vector<T_biovar>& biovar,
                 const std::vector<T_tlag>& tlag) {
  auto x = pmx_solve_linode(time, amt, rate, ii, evid, cmt, addl, ss, system, biovar, tlag);
  return x.transpose();
}

  template <typename T0, typename T1, typename T2, typename T3,
            typename T4, typename T_biovar, typename T_tlag,
            typename = require_any_not_std_vector_t<T_biovar, T_tlag> >
  stan::matrix_return_t<T0, T1, T2, T3, T4, T_biovar, T_tlag>
  linOdeModel(const std::vector<T0>& time,
              const std::vector<T1>& amt,
              const std::vector<T2>& rate,
              const std::vector<T3>& ii,
              const std::vector<int>& evid,
              const std::vector<int>& cmt,
              const std::vector<int>& addl,
              const std::vector<int>& ss,
              const std::vector< Eigen::Matrix<T4, -1, -1> >& system,
              const std::vector<T_biovar>& biovar,
              const std::vector<T_tlag>& tlag) {
    auto x = pmx_solve_linode(time, amt, rate, ii, evid, cmt, addl, ss,
                            system, biovar, tlag);
    return x.transpose();
  }

}
#endif


#ifndef qlex_svi_interpolation_hpp
#define qlex_svi_interpolation_hpp

#include <ql/utilities/null.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <ql/math/interpolation.hpp>
#include <ql/math/optimization/method.hpp>
#include <ql/math/optimization/simplex.hpp>
#include <ql/math/optimization/levenbergmarquardt.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/math/optimization/projectedcostfunction.hpp>
#include <ql/math/optimization/constraint.hpp>
#include <ql/math/randomnumbers/haltonrsg.hpp>

#include <termstructures/volatility/svi.hpp>

#include <boost/make_shared.hpp>
#include <boost/assign/list_of.hpp>

using namespace QuantLib;

namespace QLExtension {

namespace detail {
	class SVICoeffHolder {
	public:
		SVICoeffHolder(const Time t, const Real &forward, std::vector<Real> params)
			: t_(t), forward_(forward), params_(params),
			weights_(std::vector<Real>()), error_(Null<Real>()),
			maxError_(Null<Real>()), SVIEndCriteria_(EndCriteria::None) {
			QL_REQUIRE(t > 0.0, "expiry time must be positive: " << t
				<< " not allowed");
		}
		virtual ~SVICoeffHolder() {}

		/*! Expiry, Forward */
		Real t_;
		const Real forward_;
		/*! Parameters */
		std::vector<Real> params_;
		std::vector<Real> weights_;
		/*! Interpolation results */
		Real error_, maxError_;
		EndCriteria::Type SVIEndCriteria_;
	};

	template <class I1, class I2>
	class SVIInterpolationImpl : public Interpolation::templateImpl<I1, I2>,
								 public SVICoeffHolder
	{
	public:
		SVIInterpolationImpl(
			const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, Time t,
			const Real &forward, std::vector<Real> params, bool vegaWeighted,
			const boost::shared_ptr<EndCriteria> &endCriteria,
			const boost::shared_ptr<OptimizationMethod> &optMethod,
			const Real errorAccept, const bool useMaxError, const Size maxGuesses)
			: Interpolation::templateImpl<I1, I2>(xBegin, xEnd, yBegin),
			SVICoeffHolder(t, forward, params),
			endCriteria_(endCriteria), optMethod_(optMethod),
			errorAccept_(errorAccept), useMaxError_(useMaxError),
			maxGuesses_(maxGuesses),  vegaWeighted_(vegaWeighted) {
				// if no optimization method or endCriteria is provided, we provide one
				if (!optMethod_)
					optMethod_ = boost::shared_ptr<OptimizationMethod>(
					new LevenbergMarquardt(1e-8, 1e-8, 1e-8));
				// optMethod_ = boost::shared_ptr<OptimizationMethod>(new
				//    Simplex(0.01));
				if (!endCriteria_) {
					endCriteria_ = boost::shared_ptr<EndCriteria>(
						new EndCriteria(60000, 100, 1e-8, 1e-8, 1e-8));
				}
				// equal weighted
				this->weights_ = std::vector<Real>(xEnd - xBegin, 1.0 / (xEnd - xBegin));
				completed_ = false;
			}

		// Optimization
		void update() {
			// we must update weights if it is vegaWeighted
			if (vegaWeighted_) {
				// std::vector<Real>::const_iterator x = this->xBegin_;
				// std::vector<Real>::const_iterator y = this->yBegin_;
				// std::vector<Real>::iterator w = weights_.begin();
				this->weights_.clear();
				Real weightsSum = 0.0;
				for (Size i = 0; i<Size(this->xEnd_ - this->xBegin_); ++i) {
					Real stdDev = std::sqrt((this->yBegin_[i]) * (this->yBegin_[i]) * this->t_);
					this->weights_.push_back(
						blackFormulaStdDevDerivative(this->xBegin_[i], forward_, stdDev));
					weightsSum += this->weights_.back();
				}
				// weight normalization
				std::vector<Real>::iterator w = this->weights_.begin();
				for (; w != this->weights_.end(); ++w)
					*w /= weightsSum;
			}

			try {
				SVIError costFunction(this);
				Constraint constraint = SVIConstraint();

				Array guess(params_.size());
				for (Size i = 0; i < params_.size(); i++)
				{
					guess[i] = this->params_[i];
				}
				Size iterations = 0;
				Real tmpInterpolationError;
				EndCriteria::Type tmpEndCriteria;
				do {
					Problem problem(costFunction, constraint, guess);
					tmpEndCriteria = optMethod_->minimize(problem, *endCriteria_);
					guess = problem.currentValue();
					tmpInterpolationError = useMaxError_ ? interpolationMaxError()
						: interpolationError();

					switch (tmpEndCriteria) {
					case EndCriteria::None:
					case EndCriteria::MaxIterations:
					case EndCriteria::Unknown:
						completed_ = false;
						break;
					default:
						completed_ = true;
					}
				} while (++iterations < maxGuesses_ &&
					tmpInterpolationError > errorAccept_);

				for (Size i = 0; i < guess.size(); ++i)
					this->params_[i] = guess[i];

				this->error_ = interpolationError();
				this->maxError_ = interpolationMaxError();
			}
			catch (const std::exception& e)
			{
				QL_FAIL("error in SVI calibration: " << e.what());
			}
		}

		Real value(Real x) const {
			QL_REQUIRE(x > 0.0, "strike must be positive: " << io::rate(x)
				<< " not allowed");
			return sviVolatility(x, forward_, t_, params_[0], params_[1], params_[2], params_[3], params_[4]);
		}

		Real primitive(Real) const { QL_FAIL("SVI primitive not implemented"); }
		Real derivative(Real) const { QL_FAIL("SVI derivative not implemented"); }
		Real secondDerivative(Real) const {
			QL_FAIL("SVI secondDerivative not implemented");
		}

		// calculate total squared weighted difference (L2 norm)
		Real interpolationSquaredError() const {
			Real error, totalError = 0.0;
			//std::vector<Real>::const_iterator x = this->xBegin_;
			//std::vector<Real>::const_iterator y = this->yBegin_;
			// std::vector<Real>::const_iterator w = this->weights_.begin();
			for (Size i = 0; i<Size(this->xEnd_ - this->xBegin_); ++i) {
				error = (value(this->xBegin_[i]) - this->yBegin_[i]);
				totalError += error * error * (this->weights_[i]);
			}
			return totalError;
		}

		// calculate weighted differences
		Disposable<Array> interpolationErrors(const Array &) const {
			Array results(Size(this->xEnd_ - this->xBegin_));
			//std::vector<Real>::const_iterator x = this->xBegin_;
			//std::vector<Real>::const_iterator y = this->yBegin_;
			//std::vector<Real>::const_iterator w = this->weights_.begin();
			Array::iterator r = results.begin();
			for (Size i = 0; i < Size(this->xEnd_ - this->xBegin_); i++)
			{
				*r = (value(this->xBegin_[i]) - this->yBegin_[i]) * std::sqrt(this->weights_[i]);
			}
			return results;
		}

		Real interpolationError() const {
			Size n = this->xEnd_ - this->xBegin_;
			Real squaredError = interpolationSquaredError();
			return std::sqrt(n * squaredError / (n - 1));
		}

		Real interpolationMaxError() const {
			Real error, maxError = QL_MIN_REAL;
			I1 i = this->xBegin_;
			I2 j = this->yBegin_;
			for (; i != this->xEnd_; ++i, ++j) {
				error = std::fabs(value(*i) - *j);
				maxError = std::max(maxError, error);
			}
			return maxError;
		}
	public:
		boost::shared_ptr<EndCriteria> endCriteria_;
		boost::shared_ptr<OptimizationMethod> optMethod_;
		const Real errorAccept_;
		const bool useMaxError_;
		const Size maxGuesses_;
		bool vegaWeighted_;
		bool completed_;
		NoConstraint constraint_;

	private:
		class SVIError : public CostFunction {
		public:
			SVIError(SVIInterpolationImpl *svi) : svi_(svi) {}

			// calculate total squared weighted difference
			Real value(const Array &x) const {
				for (Size i = 0; i < svi_->params_.size(); i++)
				{
					svi_->params_[i] = x[i];
				}

				return svi_->interpolationSquaredError();
			}

			Disposable<Array> values(const Array &x) const {
				for (Size i = 0; i < svi_->params_.size(); i++)
				{
					svi_->params_[i] = x[i];
				}

				return svi_->interpolationErrors(x);
			}

		private:
			SVIInterpolationImpl *svi_;
		};

		class SVIConstraint : public Constraint {
		private:
			class Impl : public Constraint::Impl {
			public:
				bool test(const Array& params) const {
					if (params[1] < 0)
						return false;
					if (std::fabs(params[2]) >= 1)
						return false;
					if (params[4] <= 0)
						return false;
					//if (params[0] + params[1] * params[4] * std::sqrt(1-params[2]*params[2]) < 0)
					//	return false;

					return true;
				}
			};
		public:
			SVIConstraint()
				: Constraint(boost::shared_ptr<Constraint::Impl>(
				new SVIConstraint::Impl)) {}
		};
	};
}	// end of namespace detail

	//! %SVI smile interpolation between discrete volatility points.
	class SVIInterpolation : public Interpolation {
	public:
		template <class I1, class I2>
		SVIInterpolation(const I1 &xBegin,  // x = strikes
			const I1 &xEnd,
			const I2 &yBegin,  // y = volatilities
			Time t,            // option expiry
			const Real& forward,
			Real a,
			Real b,
			Real rho,
			Real m,
			Real sigma,
			bool vegaWeighted = true,
			const boost::shared_ptr<EndCriteria>& endCriteria
			= boost::shared_ptr<EndCriteria>(),
			const boost::shared_ptr<OptimizationMethod>& optMethod
			= boost::shared_ptr<OptimizationMethod>(),
			const Real errorAccept = 0.0020,
			const bool useMaxError = false,
			const Size maxGuesses = 1) {

			impl_ = boost::shared_ptr<Interpolation::Impl>(
				new detail::SVIInterpolationImpl<I1, I2>(
				xBegin, xEnd, yBegin, t, forward,
				boost::assign::list_of(a)(b)(rho)(m)(sigma),
				vegaWeighted, endCriteria, optMethod, errorAccept, useMaxError,
				maxGuesses));
			coeffs_ = boost::dynamic_pointer_cast<
				detail::SVICoeffHolder >(impl_);
		}
		Real expiry()  const { return coeffs_->t_; }
		Real forward() const { return coeffs_->forward_; }
		Real a()   const { return coeffs_->params_[0]; }
		Real b()    const { return coeffs_->params_[1]; }
		Real rho()      const { return coeffs_->params_[2]; }
		Real m()     const { return coeffs_->params_[3]; }
		Real sigma()     const { return coeffs_->params_[4]; }
		Real rmsError() const { return coeffs_->error_; }
		Real maxError() const { return coeffs_->maxError_; }
		const std::vector<Real>& interpolationWeights() const {
			return coeffs_->weights_;
		}
		EndCriteria::Type endCriteria() { return coeffs_->SVIEndCriteria_; }

	private:
		boost::shared_ptr<detail::SVICoeffHolder> coeffs_;
	};
}	// end of namespace QLExtension

#endif


//Link to Boost
 #define BOOST_TEST_DYN_LINK

//VERY IMPORTANT - include this last
#include <boost/test/unit_test.hpp>

#include <sstream>
#include <iostream>
#include <vector>
#include <cmath>
#include <boost/timer.hpp>
#include "test.h"
#include "../ConformalBlock.h"

struct Scalar4ptTestData
{
public:
    // spacetime dimension.
    float_type d;

    // the value of Delta1 - Delta 2.
    float_type dlt12;

    // the value of Delta3 - Delta 4.
    float_type dlt34;
};

std::ostream& operator<< (std::ostream& out, const Scalar4ptTestData& data) {
  out << '{';
  out << "d=" << data.d << ", dlt12=" << data.dlt12 << ", dlt34=" << data.dlt34;
  out << '}';
  return out;
}

vector<Scalar4ptTestData> CreateScalar4ptTestData(int size, bool evenD = false, bool intDelta = false) {
    vector<Scalar4ptTestData> ret(size);
    for (int i = 0; i < size; i++) {
        if (evenD) {
                ret[i].d = (float_type)(2 * randomint(1, 4));
            } else {
                ret[i].d = (float_type)(2 * randomint(1, 4) + 1);
            }
        if (intDelta) {
                ret[i].dlt12 = -randomint(0, 4);
                ret[i].dlt34 = -randomint(0, 4);
            } else {
                ret[i].dlt12 = -random(0.0, 4.0);
                ret[i].dlt34 = -random(0.0, 4.0);
            }
    }

    return ret;
}

struct ScalarCBTestData
{
public:
    // scaling dimension of the interchange operator.
    double delta;

    // spin of the interchange opertor.
    int l;

    // radial coordinate r.
    double r;

    // eta = cos[theta]
    double eta;

    // order of r to compute
    int order;
};

std::ostream& operator<< (std::ostream& out, const ScalarCBTestData& data) {
  out << '{';
  out << "delta=" << data.delta << ", l=" << data.l << ", r=" << data.r << ", eta=" << data.eta << ", order=" << data.order;
  out << '}';
  return out;
}

vector<ScalarCBTestData> CreateScalarCBTestData(int size) {
    vector<ScalarCBTestData> ret(size);
    for (int i = 0; i < size; i++) {
        ret[i].l = randomint(0, 10);

        // TODO: apply unitary bound?
        ret[i].delta = random(0.0, 4.0) + ret[i].l - 2;
        ret[i].r = random(0.0, 0.2);
        ret[i].eta = random(0.0, 1.0);
        ret[i].order = randomint(10, 16);
    }

    return ret;
}

// test suite1: odd d and floating delta12 and delta34
BOOST_FIXTURE_TEST_SUITE(ScalarCB_suite1, SimpleTestFixture, * utf::label("ScalarCB"))

BOOST_DATA_TEST_CASE(RI_dDelta12_test, CreateScalar4ptTestData(TCNumber, false, false) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    float_type actual = r.RI_dDelta12(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RI_dDelta34_test, CreateScalar4ptTestData(TCNumber, false, false) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    float_type actual = r.RI_dDelta34(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);

    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RII_dDelta12_test, CreateScalar4ptTestData(TCNumber, false, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta12(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RII_dDelta34_test, CreateScalar4ptTestData(TCNumber, false, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta34(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta12_test, CreateScalar4ptTestData(TCNumber, false, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta12(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta34_test, CreateScalar4ptTestData(TCNumber, false, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta34(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(dDelta_test,
    CreateScalar4ptTestData(TCNumber, false, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    float_type actual = cb.dDelta(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb.evaluate(sc.delta + inc, sc.l, sc.r, sc.eta, sc.order) - cb.evaluate(sc.delta - inc, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta12_test,
    CreateScalar4ptTestData(TCNumber, false, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12 - inc, rc.dlt34);
    ConformalBlockScalars cb2(rc.d, rc.dlt12 + inc, rc.dlt34);
    float_type actual = cb.dDelta12(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta34_test,
    CreateScalar4ptTestData(TCNumber, false, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12, rc.dlt34 - inc);
    ConformalBlockScalars cb2(rc.d, rc.dlt12, rc.dlt34 + inc);
    float_type actual = cb.dDelta34(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_AUTO_TEST_SUITE_END()

// test suite2: odd d and integer delta12 and delta34
BOOST_FIXTURE_TEST_SUITE(ScalarCB_suite2, SimpleTestFixture, * utf::label("ScalarCB"))

BOOST_DATA_TEST_CASE(RI_dDelta12_test, CreateScalar4ptTestData(TCNumber, false, true) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    float_type actual = r.RI_dDelta12(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RI_dDelta34_test, CreateScalar4ptTestData(TCNumber, false, true) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    float_type actual = r.RI_dDelta34(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);

    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RII_dDelta12_test, CreateScalar4ptTestData(TCNumber, false, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta12(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RII_dDelta34_test, CreateScalar4ptTestData(TCNumber, false, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta34(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta12_test, CreateScalar4ptTestData(TCNumber, false, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta12(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta34_test, CreateScalar4ptTestData(TCNumber, false, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta34(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(dDelta_test,
    CreateScalar4ptTestData(TCNumber, false, true) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    float_type actual = cb.dDelta(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb.evaluate(sc.delta + inc, sc.l, sc.r, sc.eta, sc.order) - cb.evaluate(sc.delta - inc, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta12_test,
    CreateScalar4ptTestData(TCNumber, false, true) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12 - inc, rc.dlt34);
    ConformalBlockScalars cb2(rc.d, rc.dlt12 + inc, rc.dlt34);
    float_type actual = cb.dDelta12(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta34_test,
    CreateScalar4ptTestData(TCNumber, false, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12, rc.dlt34 - inc);
    ConformalBlockScalars cb2(rc.d, rc.dlt12, rc.dlt34 + inc);
    float_type actual = cb.dDelta34(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_AUTO_TEST_SUITE_END()

// test suite3: even d and floating delta12 and delta34
BOOST_FIXTURE_TEST_SUITE(ScalarCB_suite3, SimpleTestFixture, * utf::label("ScalarCB"))

BOOST_DATA_TEST_CASE(RI_dDelta12_test, CreateScalar4ptTestData(TCNumber, true, false) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    float_type actual = r.RI_dDelta12(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RI_dDelta34_test, CreateScalar4ptTestData(TCNumber, true, false) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    float_type actual = r.RI_dDelta34(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);

    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RII_dDelta12_test, CreateScalar4ptTestData(TCNumber, true, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta12(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RII_dDelta34_test, CreateScalar4ptTestData(TCNumber, true, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta34(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta12_test, CreateScalar4ptTestData(TCNumber, true, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta12(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta34_test, CreateScalar4ptTestData(TCNumber, true, false) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta34(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(dDelta_test,
    CreateScalar4ptTestData(TCNumber, true, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    float_type actual = cb.dDelta(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb.evaluate(sc.delta + inc, sc.l, sc.r, sc.eta, sc.order) - cb.evaluate(sc.delta - inc, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta12_test,
    CreateScalar4ptTestData(TCNumber, true, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12 - inc, rc.dlt34);
    ConformalBlockScalars cb2(rc.d, rc.dlt12 + inc, rc.dlt34);
    float_type actual = cb.dDelta12(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta34_test,
    CreateScalar4ptTestData(TCNumber, false, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12, rc.dlt34 - inc);
    ConformalBlockScalars cb2(rc.d, rc.dlt12, rc.dlt34 + inc);
    float_type actual = cb.dDelta34(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_AUTO_TEST_SUITE_END()

// test suite4: even d and integer delta12 and delta34
BOOST_FIXTURE_TEST_SUITE(ScalarCB_suite4, SimpleTestFixture, * utf::label("ScalarCB"))

BOOST_DATA_TEST_CASE(RI_dDelta12_test, CreateScalar4ptTestData(TCNumber, true, true) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    float_type actual = r.RI_dDelta12(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RI_dDelta34_test, CreateScalar4ptTestData(TCNumber, true, true) ^ bdata::xrange(1, 1 + TCNumber), rc, n)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    float_type actual = r.RI_dDelta34(n);
    float_type expect = (r2.RI(n) - r1.RI(n)) / (2 * inc);

    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(RII_dDelta12_test, CreateScalar4ptTestData(TCNumber, true, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta12(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RII_dDelta34_test, CreateScalar4ptTestData(TCNumber, true, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= l; n++) {
        float_type actual = r.RII_dDelta34(l, n);
        float_type expect = (r2.RII(l, n) - r1.RII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta12_test, CreateScalar4ptTestData(TCNumber, true, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12 - inc, rc.dlt34);
    RCoefficients r2(rc.d, rc.dlt12 + inc, rc.dlt34);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta12(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(RIII_dDelta34_test, CreateScalar4ptTestData(TCNumber, true, true) ^ bdata::xrange(1, 1 + TCNumber), rc, l)
{
    RCoefficients r(rc.d, rc.dlt12, rc.dlt34);
    RCoefficients r1(rc.d, rc.dlt12, rc.dlt34 - inc);
    RCoefficients r2(rc.d, rc.dlt12, rc.dlt34 + inc);

    for (int n = 1; n <= TCNumber; n++) {
        float_type actual = r.RIII_dDelta34(l, n);
        float_type expect = (r2.RIII(l, n) - r1.RIII(l, n)) / (2 * inc);
        MY_FLOAT_EQUAL(actual, expect, tol);
    }
}

BOOST_DATA_TEST_CASE(dDelta_test,
    CreateScalar4ptTestData(TCNumber, true, true) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    float_type actual = cb.dDelta(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb.evaluate(sc.delta + inc, sc.l, sc.r, sc.eta, sc.order) - cb.evaluate(sc.delta - inc, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta12_test,
    CreateScalar4ptTestData(TCNumber, true, true) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12 - inc, rc.dlt34);
    ConformalBlockScalars cb2(rc.d, rc.dlt12 + inc, rc.dlt34);
    float_type actual = cb.dDelta12(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_DATA_TEST_CASE(dDelta34_test,
    CreateScalar4ptTestData(TCNumber, false, false) ^ CreateScalarCBTestData(TCNumber), rc, sc)
{
    ConformalBlockScalars cb(rc.d, rc.dlt12, rc.dlt34);
    ConformalBlockScalars cb1(rc.d, rc.dlt12, rc.dlt34 - inc);
    ConformalBlockScalars cb2(rc.d, rc.dlt12, rc.dlt34 + inc);
    float_type actual = cb.dDelta34(sc.delta, sc.l, sc.r, sc.eta, sc.order);
    float_type expect = (cb2.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order) - cb1.evaluate(sc.delta, sc.l, sc.r, sc.eta, sc.order)) / (2 * inc);
    MY_FLOAT_EQUAL(actual, expect, tol);
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(conformalblock_suite)

// test the accuracy of the functions. The test data comes from a failure of bootstrap run.
BOOST_AUTO_TEST_CASE(Accuracy_test, * utf::label("ScalarCB.accuracy"))
{
    vector<float_type> dims = vector<float_type>({0.509292, 1.37473, 2.23385, 3.20297});
    float_type dlt12 = dims[0] - dims[3];
    float_type dlt34 = dims[0] - dims[3];
    float_type delta = dims[0];
    cpx_t rho = Z2rho(cpx_t(1-0.41671, -0.0386725));
    float_type r = abs(rho);
    float_type eta = cos(arg(rho));

    ConformalBlockScalars cb(3, dlt12, dlt34);
    float_type value1 = cb.evaluate(delta, 0, r, eta, 12);
    float_type value2 = cb.evaluate(delta, 0, r, eta, 13);
    MY_FLOAT_EQUAL(value1, value2, 1e-6);

    value1 = cb.dDelta(delta, 0, r, eta, 12);
    value2 = cb.dDelta(delta, 0, r, eta, 13);
    MY_FLOAT_EQUAL(value1, value2, 1e-6);

    value1 = cb.dDelta12(delta, 0, r, eta, 12);
    value2 = cb.dDelta12(delta, 0, r, eta, 13);
    MY_FLOAT_EQUAL(value1, value2, 1e-6);

    value1 = cb.dDelta34(delta, 0, r, eta, 12);
    value2 = cb.dDelta34(delta, 0, r, eta, 13);
    MY_FLOAT_EQUAL(value1, value2, 1e-6);
}

BOOST_AUTO_TEST_CASE(ConformalBlock_Performance_test, * utf::label("ScalarCB.perf"))
{
    vector<float_type> dims = vector<float_type>({0.509292, 1.37473, 2.23385, 3.20297});
    float_type dlt12 = dims[0] - dims[3];
    float_type dlt34 = dims[0] - dims[3];
    float_type delta = dims[0];
    cpx_t rho1 = Z2rho(cpx_t(1-0.41671, -0.0386725));
    float_type r1 = abs(rho1);
    float_type eta1 = cos(arg(rho1));

    cpx_t rho2 = Z2rho(cpx_t(0.598759,0.00609649));
    float_type r2 = abs(rho2);
    float_type eta2 = cos(arg(rho2));

    ConformalBlockScalars cb(3, dlt12, dlt34);
    int count = 100;

    boost::timer stopwatch;
    for (int i = 0; i < count; i++) {
        cb.evaluate(delta, 0, r1, eta1, 12);
        cb.evaluate(delta, 0, r2, eta2, 12);
    }

    std::cout << "Performance: calling ScalarCB.evaluate " << 2 * count << " times takes " << stopwatch.elapsed() << " seconds." << std::endl;

    stopwatch.restart();

    for (int i = 0; i < count; i++) {
        cb.dDelta(delta, 0, r1, eta1, 12);
        cb.dDelta(delta, 0, r2, eta2, 12);
    }

    std::cout << "Performance: calling ScalarCB.dDelta " << 2 * count << " times takes " << stopwatch.elapsed() << " seconds." << std::endl;

    stopwatch.restart();

    for (int i = 0; i < count; i++) {
        cb.dDelta12(delta, 0, r1, eta1, 12);
        cb.dDelta12(delta, 0, r2, eta2, 12);
    }

    std::cout << "Performance: calling ScalarCB.dDelta12 " << 2 * count << " times takes " << stopwatch.elapsed() << " seconds." << std::endl;

    stopwatch.restart();
}

//Name your test cases for what they test
BOOST_AUTO_TEST_CASE(evaluate_test, * boost::unit_test::tolerance(boost::test_tools::fpc::percent_tolerance(0.001)))
{
    int d = 4;
    int l = 6;
    int order = 7;
    float_type dlt12 = 0.0;
    float_type dlt34 = 0.0;
    float_type r = 0.124;
    float_type Pi = acos(-1.0);
    float_type eta = cos(Pi/3);
    float_type dlt = 8.3;
    ConformalBlockScalars cb(d, dlt12, dlt34);
    float_type res = cb.evaluate(dlt, l, r, eta, order);
    // the expacted value obtained from mathematica program
#if CONFORMAL_BLOCK_NORMALIZATION == 1
    float_type exp = 4.327452890496684 * 1e-9;
#else
    float_type exp = 0.0000470163;
#endif

    BOOST_TEST(res == exp);
}

BOOST_AUTO_TEST_SUITE_END()


/* Boost test/cmp_header.hpp header file
 *
 * Copyright 2003 Guillaume Melquiond
 *
 * 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/numeric/interval/interval.hpp>
#include <boost/numeric/interval/checking.hpp>
#include <boost/numeric/interval/compare.hpp>
#include <boost/numeric/interval/policies.hpp>
#include <boost/core/lightweight_test.hpp>
#include "bugs.hpp"

struct empty_class {};

typedef boost::numeric::interval_lib::policies
          <empty_class, boost::numeric::interval_lib::checking_base<int> >
  my_policies;

typedef boost::numeric::interval<int, my_policies> I;

#define BOOST_C_EXN(e) \
  BOOST_TEST_THROWS(e, boost::numeric::interval_lib::comparison_error)


/*
 * parser_byte.hpp
 *
 *  Created on: 19.02.2016
 *      Author: mgresens
 */

#pragma once

#include <boost/spirit/home/x3/binary.hpp>

namespace hessian {
namespace parser {

typedef std::int_fast8_t byte_t;

const auto byte_rule = [](const byte_t from, const byte_t to)
{
	const auto check = [from, to](auto& ctx)
	{
		const byte_t value = x3::_attr(ctx);
		x3::_val(ctx) = value;
		x3::_pass(ctx) = from <= value && value <= to;
	};

	return x3::byte_ [check];
};

template <typename T, size_t N>
class calc_action
{
public:
	calc_action(const T offset) : _offset(offset) {}

	template <typename C>
	void operator()(C& ctx) const
	{
		using boost::fusion::at_c;
		const T b1 = at_c<0>(x3::_attr(ctx));
		const T b0 = at_c<1>(x3::_attr(ctx));
		x3::_val(ctx) = ((b1 - _offset) << N) + b0;
	};

private:
	T _offset;
};

template <typename T>
struct calc_action<T, 0>
{
public:
	calc_action(const T offset) : _offset(offset) {}

	template <typename C>
	void operator()(C& ctx) const
	{
		const T b0 = x3::_attr(ctx);
		x3::_val(ctx) = b0 - _offset;
	}

private:
	T _offset;
};

}
}


/*
// Copyright (c) 2000-2009, Texas Engineering Experiment Station (TEES), a
// component of the Texas A&M University System.

// All rights reserved.

// The information and source code contained herein is the exclusive
// property of TEES and may not be disclosed, examined or reproduced
// in whole or in part without explicit written authorization from TEES.
*/

#include <stapl/array.hpp>
#include <stapl/algorithm.hpp>
#include <stapl/utility/do_once.hpp>
#include <boost/lexical_cast.hpp>

typedef unsigned long long ulong_type;

///////////////////////////////////////////////////////////////////////////////
/// @brief Determines whether a number is divisible by 3 or 5. If this
///        condition is true, the number that was tested will be
///        returned. Otherwise, 0 will be returned.
///////////////////////////////////////////////////////////////////////////////
struct three_five_divisor
{
  typedef ulong_type result_type;
  template<typename T>
  ulong_type operator()(T const& i)
  {
    if ((i % 3) == 0 || (i % 5) == 0)
      return i;

    return 0;
  }
};

stapl::exit_code stapl_main(int argc, char** argv)
{
  ulong_type num = boost::lexical_cast<ulong_type> (argv[1]);

  // Creates a non-storage view in counting order from 1 to num.
  auto vw = stapl::counting_view<ulong_type>(num, 1);

  // Maps three_five_divisor functor to set numbers in the view that are not
  //   divisible by 3 or 5 to 0. Then stapl::plus is called to add the numbers
  //   in the view.
  ulong_type total = stapl::map_reduce(
    three_five_divisor(), stapl::plus<ulong_type>(), vw
  );

  // Prints the total sum.
  stapl::do_once ([&] {
    std::cout << "The total is: " << total << std::endl;
  });

  return EXIT_SUCCESS;
}


// Trees.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define BOOST_TEST_MAIN
#include <boost\test\unit_test.hpp>
#include "binary_tree_builder.h"
#include "binary_search_tree.h"
#include <iostream>
#include <functional>

void build_test_tree(trees::binary_tree_builder<int> &tree) {
	tree.put_left(4).move_left().put_left(1).put_right(6);
	tree.move_up().put_right(12).move_right();
	tree.put_left(11).put_right(20);
	tree.move_left().put_left(11);
}

BOOST_AUTO_TEST_CASE( pre_order_Traversal_Check ){
	trees::binary_tree_builder<int> tree(10);
	build_test_tree(tree);
	std::vector<int> check{ 10,4,1,6,12,11,11,20 };
	auto pre_ordered = trees::pre_order<int>(tree);
	BOOST_CHECK(check == pre_ordered);
}

BOOST_AUTO_TEST_CASE(in_order_Traversal_Check){
	trees::binary_tree_builder<int> tree(10);
	build_test_tree(tree);
	std::vector<int> check{ 1,4,6,10,11,11,12,20 };
	auto in_ordered = trees::in_order<int>(tree);
	BOOST_CHECK(check == in_ordered);
}

BOOST_AUTO_TEST_CASE(post_order_Traversal_Check) {
	trees::binary_tree_builder<int> tree(10);
	build_test_tree(tree);
	std::vector<int> check{ 1,6,4,11,11,20,12,10 };
	auto post_ordered = trees::post_order<int>(tree);
	BOOST_CHECK(check == post_ordered);
}

BOOST_AUTO_TEST_CASE(binary_search_ordering_test) {
	trees::binary_search_tree<int> search_tree;
	search_tree.insert(10).insert(5).insert(15).insert(20).insert(21).insert(20);
	std::vector<int> check{ 5,10,15,20,21 };
	auto sorted = trees::in_order<int>(search_tree);
	BOOST_CHECK(check == sorted);
}

BOOST_AUTO_TEST_CASE(binary_search_tree_find_success) {
	trees::binary_search_tree<int> search_tree;
	search_tree.insert(10).insert(5).insert(15).insert(20).insert(21).insert(20);

	BOOST_CHECK(search_tree.contains(5));
}

BOOST_AUTO_TEST_CASE(binary_search_tree_find_failure) {
	trees::binary_search_tree<int> search_tree;
	search_tree.insert(10).insert(5).insert(15).insert(20).insert(21).insert(20);

	BOOST_CHECK(!search_tree.contains(1));
}

BOOST_AUTO_TEST_CASE(binary_search_tree_delete_root) {
	trees::binary_search_tree<int> search_tree;
	search_tree.insert(10).insert(5).insert(15).insert(20).insert(21).insert(20);
	search_tree.remove(10);
	std::vector<int> check{ 5,15,20,21 };
	auto sorted = trees::in_order<int>(search_tree);
	BOOST_CHECK(check == sorted);
}

BOOST_AUTO_TEST_CASE(binary_search_tree_delete_only_node) {
	trees::binary_search_tree<int> search_tree;
	search_tree.insert(10);
	search_tree.remove(10);
	auto sorted = trees::in_order<int>(search_tree);
	BOOST_CHECK_EQUAL(sorted.size(), 0);
}

BOOST_AUTO_TEST_CASE(binary_search_tree_delete_one_of_two) {
	trees::binary_search_tree<int> search_tree;
	search_tree.insert(10).insert(5);
	search_tree.remove(10);
	std::vector<int> check{ 5 };
	auto sorted = trees::in_order<int>(search_tree);
	BOOST_CHECK(check == sorted);
}


// Copyright 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_custom_accumulators_simple

#include <boost/format.hpp>
#include <boost/histogram.hpp>
#include <cassert>
#include <iostream>
#include <sstream>

int main() {
  using namespace boost::histogram;

  // A custom accumulator which tracks the maximum of the samples.
  // It must have a call operator that accepts the argument of the `sample` function.
  struct maximum {
    // return value is ignored, so we use void
    void operator()(double x) {
      if (x > value) value = x;
    }
    double value = 0; // value is public and initialized to zero
  };

  // Create 1D histogram that uses the custom accumulator.
  auto h = make_histogram_with(dense_storage<maximum>(), axis::integer<>(0, 2));
  h(0, sample(1.0)); // sample goes to first cell
  h(0, sample(2.0)); // sample goes to first cell
  h(1, sample(3.0)); // sample goes to second cell
  h(1, sample(4.0)); // sample goes to second cell

  std::ostringstream os;
  for (auto&& x : indexed(h)) {
    os << boost::format("index %i maximum %.1f\n") % x.index() % x->value;
  }
  std::cout << os.str() << std::flush;
  assert(os.str() == "index 0 maximum 2.0\n"
                     "index 1 maximum 4.0\n");
}

//]