/* boost random/uniform_smallint.hpp header file
 *
 * Copyright Jens Maurer 2000-2001
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id: uniform_smallint.hpp 60755 2010-03-22 00:45:06Z steven_watanabe $
 *
 * Revision history
 *  2001-04-08  added min<max assertion (N. Becker)
 *  2001-02-18  moved to individual header files
 */

#ifndef BOOST_RANDOM_UNIFORM_SMALLINT_HPP
#define BOOST_RANDOM_UNIFORM_SMALLINT_HPP

#include <cassert>
#include <iostream>
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/static_assert.hpp>
#include <boost/random/detail/config.hpp>
#include <boost/random/uniform_01.hpp>
#include <boost/detail/workaround.hpp>

namespace boost {

// uniform integer distribution on a small range [min, max]

/**
 * The distribution function uniform_smallint models a \random_distribution.
 * On each invocation, it returns a random integer value uniformly distributed
 * in the set of integer numbers {min, min+1, min+2, ..., max}. It assumes
 * that the desired range (max-min+1) is small compared to the range of the
 * underlying source of random numbers and thus makes no attempt to limit
 * quantization errors.
 *
 * Let rout=(max-min+1) the desired range of integer numbers, and
 * let rbase be the range of the underlying source of random
 * numbers. Then, for the uniform distribution, the theoretical probability
 * for any number i in the range rout will be pout(i) =
 * 1/rout. Likewise, assume a uniform distribution on rbase for
 * the underlying source of random numbers, i.e. pbase(i) =
 * 1/rbase. Let pout_s(i) denote the random
 * distribution generated by @c uniform_smallint. Then the sum over all
 * i in rout of (pout_s(i)/pout(i) - 1)2
 * shall not exceed rout/rbase2
 * (rbase mod rout)(rout -
 * rbase mod rout).
 *
 * The template parameter IntType shall denote an integer-like value type.
 *
 * Note: The property above is the square sum of the relative differences
 * in probabilities between the desired uniform distribution
 * pout(i) and the generated distribution pout_s(i).
 * The property can be fulfilled with the calculation
 * (base_rng mod rout), as follows: Let r = rbase mod
 * rout. The base distribution on rbase is folded onto the
 * range rout. The numbers i < r have assigned (rbase
 * div rout)+1 numbers of the base distribution, the rest has
 * only (rbase div rout). Therefore,
 * pout_s(i) = ((rbase div rout)+1) /
 * rbase for i < r and pout_s(i) = (rbase
 * div rout)/rbase otherwise. Substituting this in the
 * above sum formula leads to the desired result.
 *
 * Note: The upper bound for (rbase mod rout)
 * (rout - rbase mod rout) is
 * rout2/4.  Regarding the upper bound for the
 * square sum of the relative quantization error of
 * rout3/(4*rbase2), it
 * seems wise to either choose rbase so that rbase >
 * 10*rout2 or ensure that rbase is
 * divisible by rout.
 */
template<class IntType = int>
class uniform_smallint
{
public:
  typedef IntType input_type;
  typedef IntType result_type;

  /**
   * Constructs a @c uniform_smallint. @c min and @c max are the
   * lower and upper bounds of the output range, respectively.
   */
  explicit uniform_smallint(IntType min_arg = 0, IntType max_arg = 9)
    : _min(min_arg), _max(max_arg)
  {
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
    // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope
    BOOST_STATIC_ASSERT(std::numeric_limits<IntType>::is_integer);
#endif
 }

  result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; }
  result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; }
  void reset() { }

  template<class Engine>
  result_type operator()(Engine& eng)
  {
    typedef typename Engine::result_type base_result;
    base_result _range = static_cast<base_result>(_max-_min)+1;
    base_result _factor = 1;

    // LCGs get bad when only taking the low bits.
    // (probably put this logic into a partial template specialization)
    // Check how many low bits we can ignore before we get too much
    // quantization error.
    base_result r_base = (eng.max)() - (eng.min)();
    if(r_base == (std::numeric_limits<base_result>::max)()) {
      _factor = 2;
      r_base /= 2;
    }
    r_base += 1;
    if(r_base % _range == 0) {
      // No quantization effects, good
      _factor = r_base / _range;
    } else {
      // carefully avoid overflow; pessimizing here
      for( ; r_base/_range/32 >= _range; _factor *= 2)
        r_base /= 2;
    }

    return static_cast<result_type>(((eng() - (eng.min)()) / _factor) % _range + _min);
  }

#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
  template<class CharT, class Traits>
  friend std::basic_ostream<CharT,Traits>&
  operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_smallint& ud)
  {
    os << ud._min << " " << ud._max;
    return os;
  }

  template<class CharT, class Traits>
  friend std::basic_istream<CharT,Traits>&
  operator>>(std::basic_istream<CharT,Traits>& is, uniform_smallint& ud)
  {
    is >> std::ws >> ud._min >> std::ws >> ud._max;
    return is;
  }
#endif

private:

  result_type _min;
  result_type _max;
};

} // namespace boost

#endif // BOOST_RANDOM_UNIFORM_SMALLINT_HPP


#include <boost/test/unit_test.hpp>
#include <gmp.h>

#include "runtime/header.h"

extern "C" {
mpz_ptr hook_INT_tmod(mpz_t, mpz_t);
mpz_ptr hook_INT_emod(mpz_t, mpz_t);
mpz_ptr hook_INT_add(mpz_t, mpz_t);
mpz_ptr hook_INT_and(mpz_t, mpz_t);
mpz_ptr hook_INT_mul(mpz_t, mpz_t);
mpz_ptr hook_INT_sub(mpz_t, mpz_t);
mpz_ptr hook_INT_tdiv(mpz_t, mpz_t);
mpz_ptr hook_INT_ediv(mpz_t, mpz_t);
mpz_ptr hook_INT_shl(mpz_t, mpz_t);
mpz_ptr hook_INT_shr(mpz_t, mpz_t);
mpz_ptr hook_INT_pow(mpz_t, mpz_t);
mpz_ptr hook_INT_xor(mpz_t, mpz_t);
mpz_ptr hook_INT_or(mpz_t, mpz_t);
mpz_ptr hook_INT_max(mpz_t, mpz_t);
mpz_ptr hook_INT_min(mpz_t, mpz_t);
mpz_ptr hook_INT_powmod(mpz_t, mpz_t, mpz_t);
mpz_ptr hook_INT_bitRange(mpz_t, mpz_t, mpz_t);
mpz_ptr hook_INT_signExtendBitRange(mpz_t, mpz_t, mpz_t);
mpz_ptr hook_INT_not(mpz_t);
mpz_ptr hook_INT_abs(mpz_t);
mpz_ptr hook_INT_log2(mpz_t);
mpz_ptr hook_INT_rand(mpz_t);
bool hook_INT_le(mpz_t, mpz_t);
bool hook_INT_lt(mpz_t, mpz_t);
bool hook_INT_eq(mpz_t, mpz_t);
bool hook_INT_ne(mpz_t, mpz_t);
bool hook_INT_ge(mpz_t, mpz_t);
bool hook_INT_gt(mpz_t, mpz_t);
block *hook_INT_srand(mpz_t);

mpz_ptr move_int(mpz_t i) {
  mpz_ptr result = (mpz_ptr)malloc(sizeof(__mpz_struct));
  *result = *i;
  return result;
}

void add_hash64(void *, uint64_t) { }

uint32_t getTagForSymbolName(const char *) {
  return 0;
}

void *koreAllocAlwaysGC(size_t size) {
  return malloc(size);
}
}

BOOST_AUTO_TEST_SUITE(IntTest)

BOOST_AUTO_TEST_CASE(tmod) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_tmod(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 1), 0);
  mpz_set_si(a, -7);
  mpz_clear(result);
  free(result);
  result = hook_INT_tmod(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -1), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(b, 0);
  BOOST_CHECK_THROW(hook_INT_tmod(a, b), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(emod) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_emod(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 1), 0);
  mpz_set_si(a, -7);
  mpz_clear(result);
  free(result);
  result = hook_INT_emod(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, 2), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(b, 0);
  BOOST_CHECK_THROW(hook_INT_emod(a, b), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(add) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_add(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 10), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(le) {
  mpz_t a, b;
  bool result;
  mpz_init_set_ui(a, 2);
  mpz_init_set_ui(b, 3);
  result = hook_INT_le(a, b);
  BOOST_CHECK(result);
  result = false;
  mpz_set_si(a, 3);
  result = hook_INT_le(a, b);
  BOOST_CHECK(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(eq) {
  mpz_t a, b;
  bool result;
  mpz_init_set_ui(a, 2);
  mpz_init_set_ui(b, 3);
  result = hook_INT_eq(a, b);
  BOOST_CHECK(!result);
  result = false;
  mpz_set_si(a, 3);
  result = hook_INT_eq(a, b);
  BOOST_CHECK(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(ne) {
  mpz_t a, b;
  bool result;
  mpz_init_set_ui(a, 2);
  mpz_init_set_ui(b, 3);
  result = hook_INT_ne(a, b);
  BOOST_CHECK(result);
  result = true;
  mpz_set_si(a, 3);
  result = hook_INT_ne(a, b);
  BOOST_CHECK(!result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(bitwise_and) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 13);
  mpz_init_set_ui(b, 3);
  result = hook_INT_and(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 1), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(mul) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_mul(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 21), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(sub) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_sub(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 4), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(tdiv) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_tdiv(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 2), 0);
  mpz_set_si(b, -3);
  mpz_clear(result);
  free(result);
  result = hook_INT_tdiv(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -2), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(b, 0);
  BOOST_CHECK_THROW(hook_INT_tdiv(a, b), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(ediv) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_ediv(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 2), 0);
  mpz_set_si(a, -7);
  mpz_set_si(b, -3);
  mpz_clear(result);
  free(result);
  result = hook_INT_ediv(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, 3), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(b, 0);
  BOOST_CHECK_THROW(hook_INT_ediv(a, b), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(shl) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_shl(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 56), 0);
  mpz_set_si(b, -3);
  mpz_clear(result);
  free(result);
  BOOST_CHECK_THROW(hook_INT_shl(a, b), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(lt) {
  mpz_t a, b;
  bool result;
  mpz_init_set_ui(a, 2);
  mpz_init_set_ui(b, 3);
  result = hook_INT_lt(a, b);
  BOOST_CHECK(result);
  result = true;
  mpz_set_si(a, 3);
  result = hook_INT_lt(a, b);
  BOOST_CHECK(!result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(ge) {
  mpz_t a, b;
  bool result;
  mpz_init_set_ui(a, 4);
  mpz_init_set_ui(b, 3);
  result = hook_INT_ge(a, b);
  BOOST_CHECK(result);
  result = false;
  mpz_set_si(a, 3);
  result = hook_INT_ge(a, b);
  BOOST_CHECK(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(shr) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 21);
  mpz_init_set_ui(b, 3);
  result = hook_INT_shr(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 2), 0);
  mpz_set_si(b, -3);
  mpz_clear(result);
  free(result);
  BOOST_CHECK_THROW(hook_INT_shr(a, b), std::invalid_argument);
  mpz_set_ui(b, 1);
  mpz_mul_2exp(b, b, 64);
  result = hook_INT_shr(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(a, -21);
  result = hook_INT_shr(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -1), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(gt) {
  mpz_t a, b;
  bool result;
  mpz_init_set_ui(a, 4);
  mpz_init_set_ui(b, 3);
  result = hook_INT_gt(a, b);
  BOOST_CHECK(result);
  result = true;
  mpz_set_si(a, 3);
  result = hook_INT_gt(a, b);
  BOOST_CHECK(!result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(pow) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  mpz_init_set_ui(b, 3);
  result = hook_INT_pow(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 343), 0);
  mpz_set_si(b, -3);
  mpz_clear(result);
  free(result);
  BOOST_CHECK_THROW(hook_INT_pow(a, b), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(powmod) {
  mpz_t a, b, mod;
  mpz_ptr result;
  mpz_init_set_ui(a, 5);
  mpz_init_set_ui(b, 2);
  mpz_init_set_ui(mod, 3);
  result = hook_INT_powmod(a, b, mod);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 1), 0);
  mpz_set_si(b, -3);
  mpz_clear(result);
  free(result);
  result = hook_INT_powmod(a, b, mod);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 2), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(mod, 5);
  BOOST_CHECK_THROW(hook_INT_powmod(a, b, mod), std::invalid_argument);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(bitwise_xor) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 13);
  mpz_init_set_ui(b, 3);
  result = hook_INT_xor(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 14), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(bitwise_or) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 13);
  mpz_init_set_ui(b, 3);
  result = hook_INT_or(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 15), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(bitwise_not) {
  mpz_t a;
  mpz_ptr result;
  mpz_init_set_ui(a, 7);
  result = hook_INT_not(a);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -8), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
}

BOOST_AUTO_TEST_CASE(abs) {
  mpz_t a;
  mpz_ptr result;
  mpz_init_set_si(a, -7);
  result = hook_INT_abs(a);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, 7), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
}

BOOST_AUTO_TEST_CASE(max) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 2);
  mpz_init_set_ui(b, 3);
  result = hook_INT_max(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 3), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(b, 2);
  result = hook_INT_max(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 2), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(min) {
  mpz_t a, b;
  mpz_ptr result;
  mpz_init_set_ui(a, 2);
  mpz_init_set_ui(b, 3);
  result = hook_INT_min(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 2), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(a, 3);
  result = hook_INT_min(a, b);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 3), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
  mpz_clear(b);
}

BOOST_AUTO_TEST_CASE(log2) {
  mpz_t a;
  mpz_ptr result;
  mpz_init_set_ui(a, 0);
  BOOST_CHECK_THROW(hook_INT_log2(a), std::invalid_argument);
  mpz_set_ui(a, 256);
  result = hook_INT_log2(a);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 8), 0);
  mpz_set_ui(a, 255);
  mpz_clear(result);
  free(result);
  result = hook_INT_log2(a);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 7), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(a);
}

BOOST_AUTO_TEST_CASE(bitRange) {
  mpz_t i, off, len;
  mpz_ptr result;
  mpz_init_set_ui(i, 127);
  mpz_init_set_ui(off, 0);
  mpz_init_set_ui(len, 8);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 127), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 255);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 255), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 128);
  mpz_set_ui(off, 1);
  mpz_set_ui(len, 7);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 64), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 129);
  mpz_set_ui(len, 5);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 1);
  mpz_mul_2exp(i, i, 256);
  mpz_sub_ui(i, i, 1);
  mpz_set_ui(off, 1);
  mpz_mul_2exp(off, off, 64);
  mpz_set_ui(len, 1);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 128);
  mpz_set_ui(off, 0);
  mpz_set_ui(len, 0);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(len, -1);
  BOOST_CHECK_THROW(hook_INT_bitRange(i, off, len), std::invalid_argument);
  mpz_set_ui(len, 8);
  mpz_set_si(off, -1);
  BOOST_CHECK_THROW(hook_INT_bitRange(i, off, len), std::invalid_argument);
  mpz_set_ui(off, 1);
  mpz_mul_2exp(off, off, 64);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(i, -128);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 255), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 0x8040201008040201);
  mpz_set_ui(off, 256);
  mpz_set_ui(len, 8);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_str(
      i,
      "-71056704293871788966541103783220878172235088814392126358492723927577357"
      "355120458894410533635294234972718488758941394468447352968280152612380545"
      "3895275517072855048781056",
      10);
  mpz_set_ui(off, 32);
  mpz_set_ui(len, 8);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 12), 0);
  mpz_clear(result);
  free(result);
  mpz_set_str(
      i,
      "697754608693466068295273213726275558775348389513141500672185545754018175"
      "72291616476873517904722261084304426432566930777772989164244884679414200"
      "0",
      10);
  mpz_set_ui(off, 64);
  mpz_set_ui(len, 8);
  result = hook_INT_bitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 56), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(i);
  mpz_clear(off);
  mpz_clear(len);
}

BOOST_AUTO_TEST_CASE(signExtendBitRange) {
  mpz_t i, off, len;
  mpz_ptr result;
  mpz_init_set_ui(i, 255);
  mpz_init_set_ui(off, 0);
  mpz_init_set_ui(len, 8);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -1), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 127);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 127), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 128);
  mpz_set_ui(off, 1);
  mpz_set_ui(len, 7);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -64), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 129);
  mpz_set_ui(len, 5);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 1);
  mpz_mul_2exp(i, i, 256);
  mpz_sub_ui(i, i, 1);
  mpz_set_ui(off, 1);
  mpz_mul_2exp(off, off, 64);
  mpz_set_ui(len, 1);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, -0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_ui(i, 128);
  mpz_set_ui(off, 0);
  mpz_set_ui(len, 0);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(len, -1);
  BOOST_CHECK_THROW(
      hook_INT_signExtendBitRange(i, off, len), std::invalid_argument);
  mpz_set_ui(len, 8);
  mpz_set_si(off, -1);
  BOOST_CHECK_THROW(
      hook_INT_signExtendBitRange(i, off, len), std::invalid_argument);
  mpz_set_ui(off, 1);
  mpz_mul_2exp(off, off, 64);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 0), 0);
  mpz_clear(result);
  free(result);
  mpz_set_si(i, -128);
  result = hook_INT_signExtendBitRange(i, off, len);
  BOOST_CHECK_EQUAL(mpz_cmp_si(result, -1), 0);
  mpz_clear(result);
  free(result);
  mpz_clear(i);
  mpz_clear(off);
  mpz_clear(len);
}

BOOST_AUTO_TEST_CASE(rand) {
  mpz_t seed;
  mpz_init_set_ui(seed, 1);
  mpz_t upperBound;
  mpz_init_set_ui(upperBound, 100);
  BOOST_CHECK_EQUAL((uintptr_t)hook_INT_srand(seed), 1);
  mpz_ptr result = hook_INT_rand(upperBound);
  BOOST_CHECK_EQUAL(mpz_cmp_ui(result, 59), 0);
}

BOOST_AUTO_TEST_SUITE_END()


#include <vi/ea.h>

#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>

#include <cstdio>
#include <iostream>
#include <random>
#include <string>

// Merciful C++ gods, please absolve me of these sins

#define BUILD_SYSTEM(PARENT_SELECTION, ADULT_SELECTION) \
    vi::ea::build_system( \
        std::default_random_engine{std::random_device{}()}, \
        vi::ea::dynamic_int_vector_creator{ \
            variables["L"].as<unsigned>(), \
            variables["L"].as<unsigned>(), \
            std::uniform_int_distribution<unsigned>{0U, variables["S"].as<unsigned>() - 1U}}, \
        PARENT_SELECTION, \
        vi::ea::reproduction::sexual{ \
            variables["mutation_rate"].as<double>(), \
            variables["crossover_rate"].as<double>(), \
            variables["crossover_points"].as<unsigned>()}, \
        ADULT_SELECTION, \
        variables["population_size"].as<unsigned>(), \
        [=] (const auto& genotype) \
        { \
            unsigned collisions = 0; \
            const auto d_max = variables.count("local") ? 0 : genotype.size() - 3; \
            for (int d = 0; d <= d_max; ++d) \
            { \
                collisions += evaluate_surprising_sequence_collisions(genotype, variables["S"].as<unsigned>(), d); \
            } \
            return 1.0 / (1.0 + static_cast<double>(collisions)); \
        })

namespace po = boost::program_options;
po::variables_map variables{};

bool solution_found = false;

template <typename system_type>
void run_system(system_type&& system)
{
    unsigned generation;
    double fitness_mean, fitness_std_dev;
    typename system_type::individual_type const* best_individual;

    const auto early_stop = variables.count("stop") > 0;

    while (true)
    {
        std::tie(generation, fitness_mean, fitness_std_dev, best_individual) = system.stats();

        std::printf("%d %f %f %f %s\n",
                    generation,
                    best_individual->fitness,
                    fitness_mean,
                    fitness_std_dev,
                    boost::lexical_cast<std::string>(best_individual->genotype).c_str());

        if (early_stop and best_individual->fitness == 1.0 or generation >= variables["generations"].as<unsigned>())
        {
            break;
        }

        system.evolve();
    }
}

std::vector<bool> tags{};

unsigned evaluate_surprising_sequence_collisions(
    const std::vector<unsigned>& sentence, const unsigned s, const unsigned d)
{
    tags.resize(s * s);
    std::fill(tags.begin(), tags.end(), false);

    unsigned collisions = 0;

    for (std::size_t i = 0; i != sentence.size() - d - 1; ++i)
    {
        const auto offset = s * sentence[i] + sentence[i + d + 1];
        if (tags[offset])
        {
            ++collisions;
        }
        else
        {
            tags[offset] = true;
        }
    }

    return collisions;
}

int main(int argc, char** argv)
{
    try
    {
        po::options_description description{"Options"};
        description.add_options()
            ("L", po::value<unsigned>()->default_value(40), "Surprising string length")
            ("S", po::value<unsigned>()->default_value(40), "Surprising string symbol set size")
            ("adult_selection", po::value<std::string>()->default_value("full"), "Adult selection (full/mixed/over)")
            ("child_count", po::value<unsigned>()->default_value(150), "Child count used in mixed/over adult selection")
            ("crossover_points", po::value<unsigned>()->default_value(1), "Crossover points")
            ("crossover_rate", po::value<double>()->default_value(1.0), "Crossover rate")
            ("epsilon", po::value<double>()->default_value(0.1), "Tournament probability of selecting random winner")
            ("generations", po::value<unsigned>()->default_value(1000), "Generation count")
            ("global", "Global surprising sequence")
            ("group_size", po::value<unsigned>()->default_value(10), "Tournament group size")
            ("local", "Local surprising sequence")
            ("mutation_rate", po::value<double>()->default_value(0.001), "Mutation rate")
            ("parent_selection", po::value<std::string>()->default_value("proportionate"), "Parent selection (proportionate/rank/sigma/tournament)")
            ("population_size", po::value<unsigned>()->default_value(100), "Population size")
            ("rank_max", po::value<double>()->default_value(1.5), "Rank selection pressure ('max')")
            ("stop", "Stop on first encountered solution");

        po::store(po::parse_command_line(argc, argv, description), variables);

        if (variables.count("global") == 0 and variables.count("local") == 0)
        {
            std::cerr << "error: use --global or --local switch" << std::endl;
            return EXIT_FAILURE;
        }

        const auto adult_selection  = variables["adult_selection"].as<std::string>();
        const auto parent_selection = variables["parent_selection"].as<std::string>();

        if (adult_selection == "full" and parent_selection == "proportionate")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::fitness_proportionate{},
                vi::ea::adult_selection::full_generational_replacement{}));
        }
        else if (adult_selection == "full" and parent_selection == "rank")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::rank{variables["rank_max"].as<double>()},
                vi::ea::adult_selection::full_generational_replacement{}));
        }
        else if (adult_selection == "full" and parent_selection == "sigma")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::sigma{},
                vi::ea::adult_selection::full_generational_replacement{}));
        }
        else if (adult_selection == "full" and parent_selection == "tournament")
        {
            auto parent_selection = vi::ea::parent_selection::tournament{
                variables["group_size"].as<unsigned>(),
                variables["epsilon"].as<double>()};

            run_system(BUILD_SYSTEM(parent_selection, vi::ea::adult_selection::full_generational_replacement{}));
        }
        else if (adult_selection == "mixed" and parent_selection == "proportionate")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::fitness_proportionate{},
                vi::ea::adult_selection::generational_mixing{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "mixed" and parent_selection == "rank")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::rank{variables["rank_max"].as<double>()},
                vi::ea::adult_selection::generational_mixing{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "mixed" and parent_selection == "sigma")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::sigma{},
                vi::ea::adult_selection::generational_mixing{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "mixed" and parent_selection == "tournament")
        {
            auto parent_selection = vi::ea::parent_selection::tournament{
                variables["group_size"].as<unsigned>(),
                variables["epsilon"].as<double>()};

            run_system(BUILD_SYSTEM(
                parent_selection,
                vi::ea::adult_selection::generational_mixing{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "over" and parent_selection == "proportionate")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::fitness_proportionate{},
                vi::ea::adult_selection::overproduction{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "over" and parent_selection == "rank")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::rank{variables["rank_max"].as<double>()},
                vi::ea::adult_selection::overproduction{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "over" and parent_selection == "sigma")
        {
            run_system(BUILD_SYSTEM(
                vi::ea::parent_selection::sigma{},
                vi::ea::adult_selection::overproduction{variables["child_count"].as<unsigned>()}));
        }
        else if (adult_selection == "over" and parent_selection == "tournament")
        {
            auto parent_selection = vi::ea::parent_selection::tournament{
                variables["group_size"].as<unsigned>(),
                variables["epsilon"].as<double>()};

            run_system(BUILD_SYSTEM(
                parent_selection,
                vi::ea::adult_selection::overproduction{variables["child_count"].as<unsigned>()}));
        }
    }
    catch (const po::error& error)
    {
        std::cerr << "error: " << error.what() << std::endl;
        return EXIT_FAILURE;
    }

    return solution_found ? 1 : 0;
}


/*=============================================================================
Copyright (c) 2016 Paul W. Bible

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 ACCUMULATORS
#define ACCUMULATORS

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/covariance.hpp>
#include <boost/accumulators/statistics/variance.hpp>
#include <boost/accumulators/statistics/variates/covariate.hpp>

//! The Accumulators namespace provides min, max, and average accumulators to the broader code base.
/*!
	This namespace defines accumulator types from boost. Also provided are specific extactors
	that will return the accumulator's current value.
*/
namespace Accumulators{

	//to be able to call Accumulators::covariate1 instread of boost::accumulators::covariate1
	using namespace boost::accumulators;

	//typedefs
	/*! MinAccumulator
	\brief A helper type wrapping boost accumulators.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats< boost::accumulators::tag::min >  > MinAccumulator;

	/*! MaxAccumulator
	\brief A helper type wrapping boost accumulators.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats< boost::accumulators::tag::max >  > MaxAccumulator;

	/*! MeanAccumulator
	\brief A helper type wrapping boost accumulators.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats<	boost::accumulators::tag::mean > > MeanAccumulator;

	/*! MeanAccumulator
	\brief A helper type wrapping boost accumulators.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats<	boost::accumulators::tag::mean > > MeanAccumulator;

	/*! SimpleAccumulator
	\brief A helper type wrapping min, max, and mean accumulators.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats<
			boost::accumulators::tag::max,
			boost::accumulators::tag::min,
			boost::accumulators::tag::mean > > SimpleAccumulator;

	/*! CovarianceAccumulator
	\brief A helper type wrapping the covariance accumulator.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats<
		    boost::accumulators::tag::covariance<double,
			  boost::accumulators::tag::covariate1> > > CovarianceAccumulator;

	/*! VarianceAccumulator
	\brief A helper type wrapping the variance accumulator.
	*/
	typedef boost::accumulators::accumulator_set< double,
		boost::accumulators::stats<
		    boost::accumulators::tag::variance> > VarianceAccumulator;

	//extractors
	/*! extractMin
	\brief A helper helper function to extract the min.
	*/
	inline double extractMin(const MinAccumulator &acc){
		return  boost::accumulators::min(acc);
	}

	/*! extractMax
	\brief A helper helper function to extract the max.
	*/
	inline double extractMax(const MaxAccumulator &acc){
		return  boost::accumulators::max(acc);
	}

	/*! extractMean
	\brief A helper helper function to extract the mean.
	*/
	inline double extractMean(const MeanAccumulator &acc){
		return  boost::accumulators::mean(acc);
	}

	/*! extractMin
	\brief An overlaoded helper helper function to extract the min.
	*/
	inline double extractMin(const SimpleAccumulator &acc){
		return  boost::accumulators::min(acc);
	}

	/*! extractMax
	\brief An overlaoded helper helper function to extract the max.
	*/
	inline double extractMax(const SimpleAccumulator &acc){
		return  boost::accumulators::max(acc);
	}

	/*! extractMean
	\brief An overlaoded helper helper function to extract the mean.
	*/
	inline double extractMean(const SimpleAccumulator &acc){
		return  boost::accumulators::mean(acc);
	}

	/*! extractCovariance
	\brief A helper helper function to extract the covariance.
	*/
	inline double extractCovariance(const CovarianceAccumulator &acc){
		return  boost::accumulators::covariance(acc);
	}

	/*! extractVariance
	\brief A helper helper function to extract the variance.
	*/
	inline double extractVariance(const VarianceAccumulator &acc){
		return  boost::accumulators::variance(acc);
	}

	/*! extractVariance
	\brief A helper helper function to extract the variance.
	*/
	inline double extractSD(const VarianceAccumulator &acc){
		return  sqrt(boost::accumulators::variance(acc));
	}

};
#endif


// Boost.Geometry (aka GGL, Generic Geometry Library)
//
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Projection example 1, direct

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/extensions/algorithms/parse.hpp>

#include <boost/geometry/extensions/gis/latlong/latlong.hpp>
#include <boost/geometry/extensions/gis/projections/parameters.hpp>
#include <boost/geometry/extensions/gis/projections/proj/robin.hpp>

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

    // Initialize projection parameters
    projections::parameters par = projections::init("+ellps=WGS84 +units=m");

    // Construct a Robinson projection, using specified point types
    // (This delivers a projection without virtual methods. Note that in p02 example
    //  the projection is created using a factory, which delivers a projection with virtual methods)
    typedef model::ll::point<degree> point_ll_deg;
    typedef model::d2::point_xy<double> point_xy;
    projections::robin_spheroid<point_ll_deg, point_xy> prj(par);

    // Define Amsterdam / Barcelona in decimal degrees / degrees/minutes
    point_ll_deg amsterdam = parse<point_ll_deg>("52.4N", "5.9E");
    point_ll_deg barcelona = parse<point_ll_deg>("41 23'N", "2 11'E");

    point_xy pa, pb;

    // Now do the projection. "Forward" means from latlong to meters.
    // (Note that a map projection might fail. This is not 'exceptional'.
    // Therefore the forward function does not throw but returns false)
    if (prj.forward(amsterdam, pa) && prj.forward(barcelona, pb))
    {
        std::cout << "Amsterdam: " << wkt(pa) << std::endl << "Barcelona: " << wkt(pb) << std::endl;

        std::cout << "Distance (unprojected):" << distance(amsterdam, barcelona) / 1000.0 << " km" << std::endl;
        std::cout << "Distance (  projected):" << distance(pa, pb) / 1000.0 << " km" << std::endl;

        // Do the inverse projection. "Inverse" means from meters to latlong
        // It also might fail or might not exist, not all projections
        // have their inverse implemented
        point_ll_deg a1;
        if (prj.inverse(pa, a1))
        {
            std::cout << "Amsterdam (original): " << wkt(amsterdam)  << std::endl
                << "Amsterdam (projected, and back):" << wkt(a1) << std::endl;
            std::cout << "Distance a-a': " << distance(amsterdam, a1) << " meter" << std::endl;
        }
    }

    return 0;
}


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

int main( int argc , char* argv[ ] ) {
   using namespace boost::gregorian ;

   int year =  std::atoi( argv[ 1 ] ) ;
   for ( int i = 1 ; i < 13 ; i++ ) {
      try {
	 date d( year , i , 1  ) ;
	 d = d.end_of_month( ) ;
	 day_iterator d_itr ( d ) ;
	 while ( d_itr->day_of_week( ) != Sunday ) {
	    --d_itr ;
	 }
	 std::cout << to_simple_string ( *d_itr ) << std::endl ;
      } catch ( bad_year by ) {
	  std::cout << "Terminated because of " << by.what( ) << "\n" ;
      }
   }
   return 0 ;
}


/*
 * rng/uniform_rng.hpp --
 *
 * This file is part of nettcl2d application.
 *
 * Copyright (c) 2012 Andrey V. Nakin <andrey.nakin@gmail.com>
 * All rights reserved.
 *
 * See the file "COPYING" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 */

#ifndef UNIFORM_RNG_HPP_
#define UNIFORM_RNG_HPP_

#include <boost/random/uniform_real.hpp>
#include <boost/random/linear_congruential.hpp>
#include "../calc/abstract_rng.hpp"

namespace rng {

	class Uniform : public AbstractRng {

		typedef boost::rand48 Generator;

		virtual double doGenerate() {
			return distr(generator);
		}

		virtual void doSeed(long seedValue) {
			generator.seed(static_cast<uint64_t>(seedValue));
		}

		virtual phlib::Cloneable* doClone() const {
			return new Uniform(mean, range);
		}

	public:

		Uniform(const double mean, const double range) :
			mean(mean), range(range),
			generator(static_cast<uint64_t>(12345L)),
			distr(mean - 0.5 * range, range > 0.0 ? mean + 0.5 * range : mean + 1.0e-6) {}

	private:

		const double mean;
		const double range;
		Generator generator;
		boost::uniform_real<double> distr;

	};

}

#endif /* UNIFORM_RNG_HPP_ */


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

int main()
{
  boost::gregorian::date d1(2008, 1, 31);
  boost::gregorian::date d2(2008, 8, 31);
  boost::gregorian::date_duration dd = d2 - d1;
  std::cout << dd.days() << std::endl;
}

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


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
Copyright (C) 2014 StatPro Italia srl
Copyright (C) 2015 CompatibL

This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/

QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

// Based on piecewisezerospreadedtermstructure.cpp from Quantlib/test-suite.

#ifndef cl_adjoint_test_zero_spreaded_term_structure_impl_hpp
#define cl_adjoint_test_zero_spreaded_term_structure_impl_hpp
#pragma once

#include "adjointzerospreadedtermstructuretest.hpp"
#include "utilities.hpp"
#include "adjointtestutilities.hpp"
#include "adjointtestbase.hpp"
#include <ql/termstructures/yield/piecewisezerospreadedtermstructure.hpp>
#include <ql/termstructures/yield/zerocurve.hpp>
#include <ql/indexes/iborindex.hpp>
#include <ql/termstructures/yield/ratehelpers.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/math/interpolations/all.hpp>
#include <boost/make_shared.hpp>

using namespace QuantLib;
using namespace boost::unit_test_framework;

#define OUTPUT_FOLDER_NAME "AdjointPiecwZeroSprTermStruct"

namespace
{
    enum
    {
#if defined CL_GRAPH_GEN
        // Number of points for dependency plots.
        pointNo = 100,
        // Number of points for performance plot.
        iterNo = 100,
        // Step for portfolio size for performance testing .
        step = 1,
        // Defines performance accuracy. Its value is a minimum number
        // of calling of O(1) complexity methods per one performance test.
        iterNumFactor = 1000,
#else
        // Number of points for dependency plots.
        pointNo = 10,
        // Number of points for performance plot.
        iterNo = 10,
        // Step for portfolio size for performance testing .
        step = 1,
        // Defines performance accuracy. Its value is a minimum number
        // of calling of O(1) complexity methods per one performance test.
        iterNumFactor = 1
#endif
    };

    std::vector<double> getDoubleVector(Size size)
    {
        std::vector<double> vec =
        {
            0.04, 0.09, 0.12, 0.06, 0.05, 0.19, 0.52, 0.66, 0.45, 0.82, 0.73, 0.33, 0.82
            , 0.66, 0.39, 0.74, 0.58, 0.55, 0.36, 0.91, 0.11, 0.24, 0.5, 0.22, 0.43, 0.5
            , 0.99, 0.64, 0.58, 0.35, 0.46, 0.86, 0.71, 0.23, 0.3, 0.07, 0.03, 0.82, 0.12
            , 0.55, 0.82, 0.95, 0.11, 0.91, 0.16, 0.73, 0.24, 0.96, 0.31, 0.32, 0.46, 0.88
            , 0.71, 0.03, 0.55, 0.58, 0.1, 0.63, 0.23, 0.02, 0.62, 0.7, 0.37, 0.21, 0.19
            , 0.13, 0.2, 0.46, 0.41, 0.9, 0.99, 0.01, 0.73, 0.19, 0.2, 0.58, 0.59, 0.83
            , 0.1, 0.85, 0.76, 0.9, 0.49, 0.01, 0.65, 0.99, 0.5, 0.63, 0.52, 0.43, 0.79
            , 0.49, 0.69, 0.01, 0.44, 0.22, 0.64, 0.88, 0.83, 0.35, 0.54, 0.16, 0.91, 0.18
            , 0.35, 0.45, 0.26, 0.48, 0.67, 0.94, 0.03, 0.22, 0.64, 0.88, 0.83, 0.35, 0.64
        };
        return std::vector<double>(vec.begin(), vec.begin() + size);
    }

    std::vector<Integer> getIntegerVector(Size size)
    {
        std::vector<Integer> vec = {
            18, 51, 98, 120, 170, 201, 296, 297, 315, 383, 394, 460, 504, 588, 620, 691, 753
            , 776, 781, 806, 904, 993, 1062, 1107, 1126, 1196, 1199, 1236, 1301, 1347, 1382
            , 1475, 1486, 1539, 1576, 1664, 1740, 1793, 1799, 1837, 1906, 1942, 1982, 2070
            , 2089, 2115, 2138, 2196, 2210, 2244, 2293, 2368, 2425, 2445, 2494, 2572, 2588, 2674
            , 2770, 2790, 2792, 2802, 2810, 2903, 2973, 2990, 3032, 3108, 3193, 3196, 3289
            , 3346, 3349, 3356, 3415, 3468, 3492, 3538, 3578, 3635, 3664, 3760, 3781, 3875
            , 3930, 4025, 4047, 4072, 4150, 4216, 4295, 4388, 4441, 4521, 4572, 4594, 4615, 4692
            , 4766, 4778, 4834, 4856, 4895, 4936, 4965, 4995, 5012, 5096, 5145, 5185, 5215, 5305
        };
        return std::vector<Integer>(vec.begin(), vec.begin() + size);
    }

    struct RateDependence
    {
        static std::deque<std::string > get_columns()
        {
            static std::deque<std::string > columns =
            {
                "Rate", ""
            };

            return columns;
        }

        template <typename stream_type>
        friend inline stream_type&
            operator << (stream_type& stm, RateDependence& v)
        {
                stm << v.inputRate_
                    << ";" << v.interpolatedZeroRate_ << std::endl;

                return stm;
            }

        Real inputRate_;
        Real interpolatedZeroRate_;
    };

    struct Interpol
    {
        Interpol() :
        calendar_(TARGET())
        , settlementDays_(2)
        , today_(Date(9, June, 2009))
        , compounding_(Continuous)
        , dayCount_(Actual360())
        , settlementDate_(calendar_.advance(today_, settlementDays_, Days))
        {
            Settings::instance().evaluationDate() = today_;
        }

        virtual Date setInterpolationDate() = 0;

        virtual void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates) = 0;

        virtual boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                                , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
                                                                                = 0;
        virtual std::string getName() = 0;

        Calendar calendar_;
        Natural settlementDays_;
        DayCounter dayCount_;
        Compounding compounding_;
        Date today_;
        Date settlementDate_;

        SavedSettings backup_;

    };

    struct FlatInterpolLeft : Interpol
    {
        FlatInterpolLeft()
        {
        }

        Date setInterpolationDate() { return calendar_.advance(today_, 6, Months); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(2);
            spreadDates.resize(2);
            for (Size i = 0; i < 2; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.01*i + 0.02));
                spreadDates[i] = calendar_.advance(today_, 7 * i + 8, Months);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<PiecewiseZeroSpreadedTermStructure>(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "FlatInterpolationLeft"; }

    };

    struct FlatInterpolRight : Interpol
    {
        FlatInterpolRight() {}

        Date setInterpolationDate() { return calendar_.advance(today_, 6, Months); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(2);
            spreadDates.resize(2);
            for (Size i = 0; i < 2; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.01*i + 0.02));
                spreadDates[i] = calendar_.advance(today_, 7 * i + 8, Months);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            boost::shared_ptr<ZeroYieldStructure> sprTermStructure =
                boost::make_shared<PiecewiseZeroSpreadedTermStructure>(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
            sprTermStructure->enableExtrapolation();
            return sprTermStructure;
        }

        std::string getName() { return "FlatInterpolationRight"; }
    };

    struct LinearInterpolMultipleSpreads : Interpol
    {
        LinearInterpolMultipleSpreads() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 120, Days); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(4);
            spreadDates.resize(4);
            for (Size i = 0; i < 4; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.005*i + 0.02));
            }
            for (Size i = 0; i < 2; i++)
            {
                spreadDates[i] = calendar_.advance(today_, 3 * i + 3, Months);
                spreadDates[i + 2] = calendar_.advance(today_, 10 * i + 30, Months);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<PiecewiseZeroSpreadedTermStructure>(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "LinearInterpolationMultipleSpreads"; }
    };

    struct LinearInterpol : Interpol
    {
        LinearInterpol() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 120, Days); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(2);
            spreadDates.resize(2);
            for (Size i = 0; i < 2; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.01*i + 0.02));
                spreadDates[i] = calendar_.advance(today_, 50 * i + 100, Days);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<InterpolatedPiecewiseZeroSpreadedTermStructure<Linear> >(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "LinearInterpolation"; }
    };

    struct ForwardFlatInterpol : Interpol
    {
        ForwardFlatInterpol() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 100, Days); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(2);
            spreadDates.resize(2);
            for (Size i = 0; i < 2; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.01*i + 0.02));
                spreadDates[i] = calendar_.advance(today_, 185 * i + 75, Days);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<InterpolatedPiecewiseZeroSpreadedTermStructure<ForwardFlat> >(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "ForwardFlatInterpolation"; }
    };

    struct BackwardFlatInterpol : Interpol
    {
        BackwardFlatInterpol() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 110, Days); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(3);
            spreadDates.resize(3);
            for (Size i = 0; i < 3; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.01*i + 0.02));
                spreadDates[i] = calendar_.advance(today_, 100 * (i + 1), Days);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<InterpolatedPiecewiseZeroSpreadedTermStructure<BackwardFlat> >(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "BackwardFlatInterpolation"; }
    };

    struct DefaultInterpol : Interpol
    {
        DefaultInterpol() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 100, Days); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(2, Handle<Quote>(boost::make_shared<SimpleQuote>(0.02)));
            spreadDates.resize(2);
            for (Size i = 0; i < 2; i++)
            {
                spreadDates[i] = calendar_.advance(today_, 75 * (i + 1), Days);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<PiecewiseZeroSpreadedTermStructure>(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "DefaultInterpolation"; }
    };

    struct SetInterpolFactory : Interpol
    {
        SetInterpolFactory() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 11, Months); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(3);
            spreadDates.resize(3);
            for (Size i = 0; i < 3; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.02 + i*pow(-1, i)*0.01));
                spreadDates[i] = calendar_.advance(today_, 8 * (i + 1), Months);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            Cubic factory = Cubic(CubicInterpolation::Spline, false);
            return boost::make_shared<InterpolatedPiecewiseZeroSpreadedTermStructure<Cubic> >(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates, compounding_,
                NoFrequency, dayCount_, factory);
        }

        std::string getName() { return "SetInterpolationFactory"; }
    };

    struct QuoteChanging : Interpol
    {
        QuoteChanging() {}

        Date setInterpolationDate() { return  calendar_.advance(today_, 120, Days); }

        void setSpreads(std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            spreads.resize(2);
            spreadDates.resize(2);
            for (Size i = 0; i < 2; i++)
            {
                spreads[i] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.01*i + 0.02));
                spreadDates[i] = calendar_.advance(today_, 50 * i + 100, Days);
            }
        }

        boost::shared_ptr<ZeroYieldStructure> createSpreadedTermStructure(boost::shared_ptr<YieldTermStructure>& termStructure
                                                                          , std::vector<Handle<Quote> >& spreads, std::vector<Date>& spreadDates)
        {
            return boost::make_shared<InterpolatedPiecewiseZeroSpreadedTermStructure<BackwardFlat> >(
                Handle<YieldTermStructure>(termStructure),
                spreads, spreadDates);
        }

        std::string getName() { return "QuoteChanging"; }
    };

    template <class InterpolationType>
    struct TestData
    {
        struct Test
        : cl::AdjointTest<Test>
        {
            explicit Test(Size size, TestData* data)
            : AdjointTest()
            , data_(data)
            , size_(size)
            , rates_(size)
            , resRates_(1)
            , spreads_()
            , spreadDates_()
            , interpolationDate_()
            {
                setLogger(&data_->outPerform_);
                std::vector<double> ratesDouble_ = getDoubleVector(size_);

                for (Size i = 0; i < size_; i++)
                {
                    rates_[i] = Real(ratesDouble_[i]);
                }
            }

            Size indepVarNumber() { return size_; }

            Size depVarNumber() { return 1; }

            Size minPerfIteration() { return iterNumFactor; }

            void recordTape()
            {
                cl::Independent(rates_);
                calculateResRates(rates_, resRates_);
                f_ = std::make_unique<cl::tape_function<double>>(rates_, resRates_);
            }

            void calculateResRates(std::vector<Real> rates, std::vector<Real>& resRates)
            {
                resRates.resize(1);
                data_->type_.setSpreads(spreads_, spreadDates_);
                interpolationDate_ = data_->type_.setInterpolationDate();
                boost::shared_ptr<YieldTermStructure> termStructure = createTermStructure(rates);
                boost::shared_ptr<ZeroYieldStructure> spreadedTermStructure =
                    data_->type_.createSpreadedTermStructure(termStructure, spreads_, spreadDates_);

                Time t = data_->type_.dayCount_.yearFraction(data_->type_.today_, interpolationDate_);

                resRates[0] = spreadedTermStructure->zeroRate(t, data_->type_.compounding_);
            }

            void resetSpreads(std::vector<Real> rates, std::vector<Real>& resRates)
            {
                resRates.resize(1);
                data_->type_.setSpreads(spreads_, spreadDates_);
                interpolationDate_ = data_->type_.setInterpolationDate();
                spreads_[1] = Handle<Quote>(boost::make_shared<SimpleQuote>(0.025));
                boost::shared_ptr<YieldTermStructure> termStructure = createTermStructure(rates);
                boost::shared_ptr<ZeroYieldStructure> spreadedTermStructure =
                    data_->type_.createSpreadedTermStructure(termStructure, spreads_, spreadDates_);

                Time t = data_->type_.dayCount_.yearFraction(data_->type_.today_, interpolationDate_);

                resRates[0] = spreadedTermStructure->zeroRate(t, data_->type_.compounding_);
            }

            boost::shared_ptr<YieldTermStructure> createTermStructure(std::vector<Real>& rates)
            {
                std::vector<Integer> ts = getIntegerVector(size_ - 1);
                std::vector<Date> dates(size_);
                dates[0] = data_->type_.settlementDate_;
                for (Size i = 0; i < size_ - 1; ++i)
                {
                    dates[i + 1] = data_->type_.calendar_.advance(data_->type_.today_, ts[i], Days);
                }
                return boost::make_shared<ZeroCurve>(dates, rates, data_->type_.dayCount_);
            };

            void calcAnalytical()
            {
                double h = 1e-4;
                std::vector<Real> resRight(1), resLeft(1);
                analyticalResults_.resize(size_);
                for (Size i = 0; i < size_; i++)
                {
                    rates_[i] += h;
                    calculateResRates(rates_, resRight);
                    rates_[i] -= 2 * h;
                    calculateResRates(rates_, resLeft);
                    rates_[i] += h;
                    analyticalResults_[i] = (resRight[0] - resLeft[0]) / (2 * h);
                }
            }

            Size size_;
            std::vector<cl::tape_double> rates_;
            std::vector<cl::tape_double> resRates_;
            std::vector<Handle<Quote> > spreads_;
            std::vector<Date> spreadDates_;
            Date interpolationDate_;
            TestData* data_;

        };

        TestData() :
            type_()
            , outPerform_tilte_("Interpolated zero rate (by " + type_.getName() + ") \\ndifferentiation performance with respect to yield rate")
            , outAdjoint_tilte_("Interpolated zero rate (by " + type_.getName() + ") \\nadjoint differentiation performance with respect to yield rate")
            , out_tilte_("Zero Rate dependence on yield rate by" + type_.getName())
            , out_filename_("ZeroRateOnYieldRateBy" + type_.getName())
            , outPerform_(OUTPUT_FOLDER_NAME "//" + type_.getName()
            , { { "filename", "AdjointPerformance" }
        , { "not_clear", "Not" }
        , { "title", outPerform_tilte_ }
        , { "ylabel", "Time (s)" }
        , { "xlabel", "Number of yield rates" }
        , { "smooth", "default" }
        , { "line_box_width", "-5" }
        , { "cleanlog", "true" } })
            , outAdjoint_(OUTPUT_FOLDER_NAME "//" + type_.getName()
            , { { "filename", "Adjoint" }
        , { "not_clear", "Not" }
        , { "title", outAdjoint_tilte_ }
        , { "xlabel", "Number of yield rates" }
        , { "smooth", "default" }
        , { "ylabel", "Time (s)" }
        , { "cleanlog", "false" } })
            , outSize_(OUTPUT_FOLDER_NAME "//" + type_.getName()
            , { { "filename", "TapeSize" }
        , { "not_clear", "Not" }
        , { "title", "Tape size dependence on number of yield rates" }
        , { "xlabel", "Number of yield rates" }
        , { "ylabel", "Memory(MB)" }
        , { "cleanlog", "false" } })
            , out_(OUTPUT_FOLDER_NAME "//" + type_.getName() + "//output"
            , { { "filename", out_filename_ }
        , { "not_clear", "Not" }
        , { "title", out_tilte_ }
        , { "xlabel", "Yield rates" }
        , { "ylabel", "Zero Rate" }
        , { "cleanlog", "false" } })
        {
        }

        bool makeOutput()
        {
            bool ok = true;
            if (pointNo > 0)
            {
                ok &= recordDependencePlot();
            }
            ok &= cl::recordPerformance(*this, iterNo, step);
            return ok;
        }

        std::shared_ptr<Test> getTest(size_t size)
        {
            return std::make_shared<Test>(10 + size, this);
        }

        // Makes plots for sensitivity dependence.
        bool recordDependencePlot()
        {
            std::vector<RateDependence> outData(pointNo);
            auto test = getTest(10);
            std::vector<Real> rates = test->rates_;
            std::vector<Real> result(1);
            for (Size i = 0; i < pointNo; i++)
            {
                rates[5] = (i + 1)*0.01;
                test->calculateResRates(rates, result);
                outData[i] = { rates[5], result[0] };
            }
            out_ << outData;
            return true;
        }

        InterpolationType type_;
        std::string outPerform_tilte_;
        std::string outAdjoint_tilte_;
        std::string out_tilte_;
        std::string out_filename_;
        cl::tape_empty_test_output outPerform_;
        cl::tape_empty_test_output outAdjoint_;
        cl::tape_empty_test_output outSize_;
        cl::tape_empty_test_output out_;

    };
}
#endif


#include "irrigation.h"

#include <boost/log/trivial.hpp>

namespace WorldEngine
{

static void IrrigationExecute(World& world);

void IrrigationSimulation(World& world)
{
   BOOST_LOG_TRIVIAL(info) << "Irrigation simulation start";

   IrrigationExecute(world);

   BOOST_LOG_TRIVIAL(info) << "Irrigation simulation finish";
}

static void IrrigationExecute(World& world)
{
   const int32_t width  = world.width();
   const int32_t height = world.height();
   const int32_t radius = 10;

   const WaterMapArrayType& watermap   = world.GetWaterMapData();
   IrrigationArrayType&     irrigation = world.GetIrrigationData();
   irrigation.resize(boost::extents[height][width]);

   std::fill(
      irrigation.data(), irrigation.data() + irrigation.num_elements(), 0.0f);

   // Create array of pre-calculated values
   boost::multi_array<float, 2> logs(
      boost::extents[radius * 2 + 1][radius * 2 + 1]);
   for (int32_t y = 0; y <= radius * 2; y++)
   {
      // Y distance to center: [-10, 10]
      float dy = static_cast<float>(y - radius);

      for (int32_t x = 0; x <= radius * 2; x++)
      {
         // X distance to center: [-10, 10]
         float dx = static_cast<float>(x - radius);

         // Calculate final matrix: ln(sqrt(x^2 + y^2) + 1) + 1
         logs[y][x] = log1pf(sqrtf(dx * dx + dy * dy)) + 1;
      }
   }

   for (int32_t y = 0; y < height; y++)
   {
      for (int32_t x = 0; x < width; x++)
      {
         if (world.IsOcean(x, y))
         {
            // Coordinates (top-left / bottom-right) used for the values slice
            uint32_t tlXV = std::max(x - radius, 0);
            uint32_t tlYV = std::max(y - radius, 0);
            uint32_t brXV = std::min(x + radius, width - 1);
            uint32_t brYV = std::min(y + radius, height - 1);

            // Coordinates (top-left / bottom-right) used for the logs slice
            uint32_t tlXL = std::max(radius - x, 0);
            uint32_t tlYL = std::max(radius - y, 0);
            uint32_t brXL = std::min(radius - x + width - 1, 2 * radius);
            uint32_t brYL = std::min(radius - y + height - 1, 2 * radius);

            // Values slice and logs slice should be the same size and
            // dimensions

            for (uint32_t vy = tlYV, ly = tlYL; //
                 vy <= brYV && ly <= brYL;
                 vy++, ly++)
            {
               for (uint32_t vx = tlXV, lx = tlXL; //
                    vx <= brXV && lx <= brXL;
                    vx++, lx++)
               {
                  irrigation[vy][vx] += watermap[y][x] / logs[ly][lx];
               }
            }
         }
      }
   }
}

} // namespace WorldEngine


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
#include <iostream>
#include <cstdio>
#include <cstring>

int main()
{
    const int COLS = 2208, ROWS = 1242;

    cv::Mat depth = cv::imread("../data/1_dpt.tiff", cv::IMREAD_ANYDEPTH);
    cv::Mat img = cv::imread("../data/1.jpg");
    cv::FileStorage reader("../data/data.yml", cv::FileStorage::READ);
    cv::Mat c_mat, p_mat;
    Eigen::Matrix<double, 3, 3> C;
    Eigen::Matrix<double, 4, 4> P;
    reader["C"] >> c_mat;
    reader["D"] >> p_mat;

    // std::cout << c_mat << std::endl << p_mat << std::endl << depth << std::endl;
    cv::cv2eigen(c_mat, C);
    cv::cv2eigen(p_mat, P);

    std::vector<cv::Point2f> pt_u;
    std::vector<cv::Point2f> pt_c;

    for (int i = 0; i < img.rows; i++)
        for (int j = 0; j < img.cols; j++)
            pt_u.push_back(cv::Point2f{j, i});
    cv::undistortPoints(pt_u, pt_c, c_mat, cv::noArray());

    pt_u.clear();

    std::vector<cv::Point2f> pt_c2;
    // std::cout << pt_c.size() << " : " << depth.rows * depth.cols << std::endl;
    for (int i = 0; i < pt_c.size(); i++)
    {
        Eigen::Matrix<double, 4, 1> pt_w, tmp;
        pt_w << pt_c[i].x, pt_c[i].y, 1, 1;
        pt_w *= depth.at<float>(i / depth.cols, i % depth.cols);
        pt_w(3, 0) = 1;
        Eigen::Matrix<double, 3, 1> pt, result;
        tmp = P * pt_w;
        pt << tmp(0, 0) / tmp(2, 0), tmp(1, 0) / tmp(2, 0), 1;
        result = C * pt;
        // std::cout << i << ":\n" << result << std::endl;
        pt_c2.push_back({result(0, 0) / result(2, 0), result(1, 0) / result(2, 0)});
    }
    cv::Mat result = cv::Mat::zeros(cv::Size(img.cols, img.rows), CV_8UC3);
    for (int i = 0; i < depth.rows; i++)
        for (int j = 0; j < depth.cols; j++)
        {
            cv::Point2f pt = pt_c2[i * img.cols + j];
            int x = (int)pt.x, y = (int)pt.y;
            if (x < 0 || x > result.cols - 1 || y < 0 || y > result.rows - 1)
                continue;
            result.at<cv::Vec3b>(y, x) = img.at<cv::Vec3b>(i, j);
        }
    cv::imwrite("../out.jpg", result);
    cv::namedWindow("result", 0);
    cv::imshow("result", result);
    cv::waitKey(0);
    return 0;
}


#ifndef TCM_DIELECTRIC_FUNCTION_HPP
#define TCM_DIELECTRIC_FUNCTION_HPP

#include <cmath>
#include <cassert>

#include <iostream>
#include <vector>
#include <array>
#include <fstream>
#include <regex>
#include <algorithm>

#include <boost/core/demangle.hpp>

#include <benchmark.hpp>
#include <logging.hpp>

#include <constants.hpp>
#include <matrix.hpp>
#include <blas.hpp>

namespace tcm {

template <class T> struct huge_val;

template <>
struct huge_val<float> { static constexpr float value = HUGE_VALF; };

template <>
struct huge_val<double> { static constexpr double value = HUGE_VAL; };

template <>
struct huge_val<long double> { static constexpr long double value = HUGE_VALL; };

constexpr float huge_val<float>::value;

///////////////////////////////////////////////////////////////////////////////
/// \brief Computes \f$ f(E) \f$

/// Calculates the Fermi-Dirac distribution:
/// \f[ f(E) := \frac{1}{\exp(\frac{E - \mu}{k_{\text{B}}T}) + 1}. \f]
///
/// In the calculation we use that p
/// \f[ \begin{aligned}
///         \lim_{E\to -\infty} f(E) &= 1 //
///         \lim_{E\to +\infty} f(E) &= 0
///     \end{algned}
/// \f]
/// If `std::exp` returns HUGE_VAL, HUGE_VALF or HUGE_VALL, 0 is returned.
/// \param     E       Energy, i.e. a real number. Thus `_F` must be floating
///                    point: `std::is_floating_point<_F>::value == true`.
/// \param     mu      Chemical potential \f$ \mu \f$. It has the dimensions
///                    of energy \f$\implies\f$ `_R` is also floating point.
/// \param     t       Temperature \f$ T \f$.
/// \param     kb      Boltzmann constant \f$ k_\text{B} \f$.
///
/// \return \f$ f(E) \f$.
///////////////////////////////////////////////////////////////////////////////
template<class _F, class _R>
auto fermi_dirac(_F const E, _R const t, _R const mu, _R const kb ) noexcept
{
	static_assert(std::is_floating_point<_F>::value, "Energy must be real.");
	static_assert(std::is_floating_point<_R>::value, "Chemical potential, "
		"temperature and Boltzmann's constant must be real.");

	auto const x = std::exp((E - mu) / (kb * t));

	if (std::isinf(x)) return 0.0;
	if (x < std::numeric_limits<decltype(x)>::epsilon()) return 1.0;
	return 1.0 / (x + 1.0);
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Defines tools to calculate the \f$ G(\omega) \f$ matrix.
///////////////////////////////////////////////////////////////////////////////
namespace g_function {

///////////////////////////////////////////////////////////////////////////////
/// \brief Computes \f$G_{i, j}(\omega)=\frac{f_i-f_j}{E_i-E_j-\omega}\f$.

/// \tparam    _F      Represents a real/complex field.
/// \tparam    _R      Represents a real field.
/// \tparam    _Number Just some abstract field.
/// \param     i       Row of the matrix \f$G(\omega)\f$.
/// \param     j       Column of the matrix \f$G(\omega)\f$.
/// \param     E       Pointer into the array of energies. `_F` must be real,
///                    and size of \p E must be at least `max(i,j)`.
/// \param     f       Pointer into the array of occupational numbers. `_R`
///                    must be real, and size of \p f must be at least
///                    `max(i,j)`.
///
/// \return \f$G_{i,j}(\omega)\f$.
///////////////////////////////////////////////////////////////////////////////
template<class _F, class _R, class _Number>
auto at( std::size_t const i, std::size_t const j
       , _Number const omega
       , _F const* E
       , _R const* f ) noexcept
{
	static_assert(std::is_floating_point<_F>::value, "Energy must be real.");
	static_assert(std::is_floating_point<_R>::value, "Occupational numbers "
		"must be real.");
	return (f[i] - f[j]) / (E[i] - E[j] - omega);
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Computes \f$ G(\omega) \f$.

/// \f[ G_{i,j}(\omega) = \frac{f_i - f_j}{E_i - E_j - \omega}. \f]
///
/// \param omega    Frequency \f$\omega\f$ at which to calculate \f$ G \f$.
///                 It may be either real or complex.
/// \param E        Energies of the system: \f$1 \times N\f$ matrix (i.e. a
///                 column vector). `_F` must be floating point.
/// \param cs       Constants map. This function requires the availability of
///                 \f$ T, \mu, k_\text{B}, \hbar \f$ to run. Checks are
///                 performed at runtime, i.e. this function <b>may throw</b>!
///                 `_R`, the type of constants in \p cs must also be floating
///                 point.
/// \param lg       The logger.
/// \return         \f$G(\omega)\f$.
/// \exception      May throw.
///////////////////////////////////////////////////////////////////////////////
template<class _Number, class _F, class _R, class _Logger>
auto make( _Number const omega
         , Matrix<_F> const& E
         , std::map<std::string, _R> const& cs
         , _Logger & lg )
{
	static_assert(std::is_floating_point<_F>::value, "Energy must be real.");
	static_assert(std::is_floating_point<_R>::value, "Physical constants "
		"such as chemical potential and temperature must be real.");
	using Real = decltype( fermi_dirac( std::declval<_F>()
	                                  , std::declval<_R>()
	                                  , std::declval<_R>()
	                                  , std::declval<_R>() ));
	using Complex = decltype( at( std::declval<std::size_t>()
	                            , std::declval<std::size_t>()
	                            , std::declval<_Number>()
	                            , std::declval<_F const*>()
	                            , std::declval<_R const*>() ));

	TCM_MEASURE( "g_function::make<" + boost::core::demangle(
		typeid(Complex).name()) + ">()" );
	LOG(lg, debug) << "Calculating G for omega = " << omega << "...";
	require(__PRETTY_FUNCTION__, cs, "temperature");
	require(__PRETTY_FUNCTION__, cs, "chemical-potential");
	require(__PRETTY_FUNCTION__, cs, "boltzmann-constant");
	assert( is_column(E) == 1 );
	const auto t  = cs.at("temperature");
	const auto mu = cs.at("chemical-potential");
	const auto kb = cs.at("boltzmann-constant");
	const auto N  = E.height();

	Matrix<Real> f{N, 1};
	std::transform( E.data(), E.data() + N, f.data()
	              , [t, mu, kb](auto Ei) noexcept
	                { return fermi_dirac(Ei, t, mu, kb); } );
	Matrix<Complex> G{N, N};
	for (std::size_t j = 0; j < N; ++j) {
		for (std::size_t i = 0; i < N; ++i) {
			G(i,j) = at(i, j, omega, E.data(), f.data());
		}
	}

	LOG(lg, debug) << "Successfully calculated G.";
	return G;
}

} // namespace g_function

///////////////////////////////////////////////////////////////////////////////
/// Defines tools to compute \f$ \chi(\omega) \f$ matrix.
///////////////////////////////////////////////////////////////////////////////
namespace chi_function {

///////////////////////////////////////////////////////////////////////////////
/// \brief Calculates \f$ \chi_{a,b}(\omega) \f$.

/// We compute \f$ \chi_{a,b}(\omega) \f$ as
/// \f[ \begin{aligned}
///         A &:= \psi_a \circ \psi_b^*,
///         \text{ i.e. } A_i = \psi_{i,a}\cdot\psi{i,b}^* \\ \text{}
///         \chi_{a,b}(\omega) &= A^\dagger \times G(\omega) \times A.
///     \end{aligned}
/// \f]
///
/// Hadamard product \f$ \circ \f$ is computed using `std::transform`, which
/// can easily be parallelized using GNU parallel mode of the `stdlibc++`.
/// Matrix-vector products are calculated by first calling `?GEMV` and then
/// `?DOTC`. Intel MKL has a highly parallel implementation of both of this
/// functions.
///
/// \param a    Row of the matrix.
/// \param b    Column of the matrix.
/// \param Psi  Eigenstates of the system.
/// \param G    G function calculated by calling g_function::make().
///
/// \returns    \f$ \chi_{a,b}(\omega) \f$.
/// \exception  May throw if memory allocations or LAPACK operations fail.
///////////////////////////////////////////////////////////////////////////////
template <class _F, class _C>
auto at( std::size_t const a, std::size_t const b
       , Matrix<_F> const& Psi, Matrix<_C> const& G )
{
	TCM_MEASURE( "chi_function::at<" + boost::core::demangle(
		typeid(_F).name()) + ", " + boost::core::demangle(
		typeid(_C).name()) + ">()" );
	using Complex = std::common_type_t<_F, _C>;

	const auto N = Psi.height();
	Matrix<Complex>    A{N, 1};
	Matrix<Complex> temp{N, 1};

	std::transform( Psi.cbegin_row(a), Psi.cend_row(a)
	              , Psi.cbegin_row(b)
	              , A.data()
	              , [](auto x, auto y) { return x * std::conj(y); } );
	blas::gemv( blas::Operator::T
	          , Complex{1}, G, A
	          , Complex{0}, temp );
	return Complex{2} * blas::dot(A, temp);
}

namespace {
// For the case that eigenstates are actually real.
template<class _Number, class _F, class _R, class _Logger>
auto make_impl( _Number const omega
              , Matrix<_F> const& E
              , Matrix<_F> const& Psi
              , std::map<std::string, _R> const& cs
              , _Logger & lg )
{
	static_assert(std::is_floating_point<_F>::value, "Energy must be real.");
	static_assert(std::is_floating_point<_R>::value, "Physical constants "
		"such as chemical potential and temperature must be real.");
	TCM_MEASURE( "chi_function::make_impl<" + boost::core::demangle(
		typeid(_F).name()) + ">()" );
	auto const N = E.height();
	auto const G = g_function::make(omega, E, cs, lg);

	using T = decltype( at( std::declval<std::size_t>()
	                      , std::declval<std::size_t>()
	                      , std::declval<Matrix<_F>>()
	                      , std::declval<decltype(G)>() ));
	Matrix<T> Chi{N, N};

	auto const _total_points_ = static_cast<double>(N * (N - 1) / 2);
	auto _start_ = std::chrono::system_clock::now();
	// fill the diagonal
	for (std::size_t i = 0; i < N; ++i) {
			if ((_start_ - std::chrono::system_clock::now()) >
				std::chrono::minutes{5}) {

				LOG(lg, info) << "at " << std::round((i + 1) / _total_points_)
				              << "% ..." << std::flush;
				_start_ = std::chrono::system_clock::now();
			}
			Chi(i, i) = at(i, i, Psi, G);
	}
	// calculate upper triangle
	for (std::size_t j = 0; j < N; ++j) {
		for (std::size_t i = 0; i < j; ++i) {
			if ((_start_ - std::chrono::system_clock::now()) >
				std::chrono::minutes{5}) {

				LOG(lg, info) << "at " << std::round((N + (i + 1)* (j + 1))
					/ _total_points_)
				              << "% ..." << std::flush;
				_start_ = std::chrono::system_clock::now();
			}
			Chi(i, j) = at(i, j, Psi, G);
			Chi(j, i) = Chi(i, j);
		}
	}
	return Chi;
}

// For the case that eigenstates are complex.
template<class _Number, class _F, class _R, class _Logger>
auto make_impl( _Number const omega
              , Matrix<_F> const& E
              , Matrix<std::complex<_F>> const& Psi
              , std::map<std::string, _R> const& cs
              , _Logger & lg )
{
	static_assert(std::is_floating_point<_F>::value, "Energy must be real.");
	static_assert(std::is_floating_point<_R>::value, "Physical constants "
		"such as chemical potential and temperature must be real.");
	TCM_MEASURE( "chi_function::make_impl<" + boost::core::demangle(
		typeid(std::complex<_F>).name()) + ">()" );
	auto const N = E.height();
	auto const G = g_function::make(omega, E, cs, lg);

	using T = decltype( at( std::declval<std::size_t>()
	                      , std::declval<std::size_t>()
	                      , std::declval<Matrix<std::complex<_F>>>()
	                      , std::declval<decltype(G)>() ));
	Matrix<T> Chi{N, N};

	auto const _total_points_ = static_cast<double>(N * N);
	auto _start_ = std::chrono::system_clock::now();
	for (std::size_t j = 0; j < N; ++j) {
		for (std::size_t i = 0; i < N; ++i) {
			if ((_start_ - std::chrono::system_clock::now()) >
				std::chrono::minutes{5}) {

				LOG(lg, info) << "at " << std::round(((i + 1) * (j + 1)) / _total_points_)
				              << "% ..." << std::flush;
				_start_ = std::chrono::system_clock::now();
			}
			Chi(i, j) = at(i, j, Psi, G);
		}
	}
	return Chi;
}
} // end unnamed namespace

///////////////////////////////////////////////////////////////////////////////
/// \brief Calculates \f$ \chi(\omega) \f$.

/// First, calculates \f$ G(\omega) \f$ by calling tcm::g_function::make and
/// then computes each matrix element by calling at().
/// \tparam _Number   Some abstract field.
/// \tparam _F        Complex or real field.
/// \tparam _C        Complex field.
/// \tparam _F        Real field.
/// \tparam _Logger   Type of the logger.
/// \param omega      Frequency \f$ \omega \f$ at which to calculate
///                   \f$\chi\f$.
/// \param E          Eigenenergies of the system.
/// \param Psi        Eigenstates of the system.
/// \param cs         Constants.
/// \param lg         Logger object.
///
/// \returns \f$ \chi(\omega) \f$ as a Matrix<_C>.
/// \exception May throw.
///////////////////////////////////////////////////////////////////////////////
template<class _Number, class _F, class _C, class _R, class _Logger>
auto make( _Number const omega
         , Matrix<_F> const& E
         , Matrix<_C> const& Psi
         , std::map<std::string, _R> const& cs
         , _Logger & lg )
{
	TCM_MEASURE( "chi_function::make<" + boost::core::demangle(
		typeid(_C).name()) + ">()" );
	LOG(lg, debug) << "Calculating chi for omega = " << omega << "...";

	const auto N = E.height();
	assert( is_column(E) );
	assert( is_square(Psi) );
	assert( N == Psi.height() );

	auto const Chi = make_impl(omega, E, Psi, cs, lg);
	LOG(lg, debug) << "Successfully calculating chi.";
	return Chi;
}

} // namespace chi_function

///////////////////////////////////////////////////////////////////////////////
/// \brief Defines tools to calculate the Coulomb interaction potential.
///////////////////////////////////////////////////////////////////////////////
namespace coulomb {

namespace {
///////////////////////////////////////////////////////////////////////////////
/// \brief Computes the distance between two points in \f$ F^3 \f$.
///////////////////////////////////////////////////////////////////////////////
template<class _F>
auto distance(std::array<_F, 3> const& v, std::array<_F, 3> const& w)
{
	return std::sqrt( std::pow(std::abs(v[0] - w[0]), 2)
	                + std::pow(std::abs(v[1] - w[1]), 2)
	                + std::pow(std::abs(v[2] - w[2]), 2)
	                );
}
} // unnamed namespace

///////////////////////////////////////////////////////////////////////////////
/// \brief Calculates \f$ V_{i,j} \f$.

/// Potential is calculated as following
/// \f[ V_{i,j} = \left\{
///     \begin{aligned}
///         &\frac{e}{4\pi\varepsilon_0|\mathbf{r_i} - \mathbf{r_j}|}
///              , &\text{if } i \neq j, \\ \text{}
///         &V_0, &\text{if } i = j.
///     \end{aligned}
///     \right.
/// \f]
///
/// \tparam _F        Real field.
/// \tparam _R        Another real field.
/// \param i          Index of the first atom, i.e. row of the matrix.
/// \param j          Index of the second atom,.i.e. column of the matrix.
/// \param positions  Positions of the atoms, in __meters__.
/// \param e          Elementary charge, in Coulombs.
/// \param pi         \f$\pi\f$.
/// \param eps0       \f$\varepsilon_0\f$.
/// \param v0         Self-interaction potential \f$V_0\f$, in eV.
///
/// \returns Potential in eV.
/// \exceptions Should not throw.
///////////////////////////////////////////////////////////////////////////////
template<class _F, class _R>
auto at( std::size_t const i, std::size_t const j
       , std::vector<std::array<_F, 3>> const& positions
       , _R const e
       , _R const pi
       , _R const eps0
       , _R const v0 ) noexcept
{
	return (i == j)
		? v0
		: e / (_R{4.0} * pi * eps0 * distance(positions[i], positions[j]));
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Construct an Elemental-like matrix \f$ V \f$, representing the
/// Coulomb potential.

/// \tparam _T       Element type of the output Matrix.
/// \tparam _F       Real field.
/// \tparam _R       Another real field.
/// \tparam _Logger  The logger type.
/// \param positions Array with positions of atoms.
/// \param cs        Constants. `elementary-charge`, `vacuum-permittivity`,
///                  `pi` and `self-interaction-potential` are needed.
/// \param lg        The logger.
///
/// \return Matrix describing the Coulomb interaction.
/// \exception May throw.
///////////////////////////////////////////////////////////////////////////////
template<class _T, class _F, class _R, class _Logger>
auto make( std::vector<std::array<_F, 3>> const& positions
         , std::map<std::string, _R> const& cs
         , _Logger & lg ) -> Matrix<_T>
{
	TCM_MEASURE( "coulomb::make<" + boost::core::demangle(
		typeid(_T).name()) + ">()" );
	LOG(lg, debug) << "Calculating V...";

	require(__PRETTY_FUNCTION__, cs, "elementary-charge");
	require(__PRETTY_FUNCTION__, cs, "pi");
	require(__PRETTY_FUNCTION__, cs, "vacuum-permittivity");
	require(__PRETTY_FUNCTION__, cs, "self-interaction-potential");

	auto const N         = positions.size();
	auto const e         = cs.at("elementary-charge");
	auto const pi        = cs.at("pi");
	auto const eps0      = cs.at("vacuum-permittivity");
	auto const v0        = cs.at("self-interaction-potential");

	auto const V = build_matrix
		( N, N
		, [&positions, e, pi, eps0, v0] (auto i, auto j)
		  { return boost::numeric_cast<_T>(
		        at(i, j, positions, e, pi, eps0, v0)
			);
		  }
		);

	LOG(lg, debug) << "Successfully calculated V.";
	return V;
}

} // namespace coulomb

///////////////////////////////////////////////////////////////////////////////
/// \brief Defines tools to compute the dielectric function.
///////////////////////////////////////////////////////////////////////////////
namespace dielectric_function {

///////////////////////////////////////////////////////////////////////////////
/// \brief Calculates the dielectric function matrix \f$\epsilon(\omega)\f$.
///////////////////////////////////////////////////////////////////////////////
template< class _Number, class _F, class _C, class _R, class _T, class _Logger>
auto make( _Number const omega
         , Matrix<_F> const& E
         , Matrix<_C> const& Psi
         , Matrix<_T> const& V
         , std::map<std::string, _R> const& cs
         , _Logger & lg )
{
	TCM_MEASURE( "dielectric_function::make<" + boost::core::demangle(
		typeid(_C).name()) + ">()" );
	LOG(lg, debug) << "Calculating epsilon for omega = " << omega << "...";

	const auto N = E.height();
	assert( is_column(E) );
	assert( is_square(Psi) );
	assert( is_square(V) );
	assert( Psi.height() == N );
	assert( V.height() == N );

	auto const Chi = chi_function::make(omega, E, Psi, cs, lg);

	static_assert(std::is_same<_T, typename decltype(Chi)::value_type>::value, "");
	Matrix<_T> epsilon{N, N};
	for (std::size_t j = 0; j < N; ++j) {
		for (std::size_t i = 0; i < N; ++i) {
			epsilon(i, j) = (i == j) ? 1.0 : 0.0;
		}
	}

	blas::gemm( blas::Operator::None, blas::Operator::None
	          , _T{-1.0}, V, Chi
	          , _T{ 1.0}, epsilon );

	LOG(lg, debug) << "Successfully calculating epsilon.";
	return epsilon;
}

} // namespace dielectric function

} // namespace tcm

#endif // TCM_DIELECTRIC_FUNCTION_HPP


//=======================================================================
// Copyright (c)
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
/**
 * @file gamma_oracle_example.cpp
 * @brief
 * @author Robert Rosolek
 * @version 1.0
 * @date 2014-6-6
 */

#include "paal/auctions/auction_components.hpp"
#include "paal/data_structures/fraction.hpp"

#include <boost/optional/optional.hpp>
#include <boost/range/algorithm/copy.hpp>

#include <cassert>
#include <iostream>
#include <utility>
#include <vector>

//! [Gamma Oracle Auction Components Example]

namespace pa = paal::auctions;
namespace pds = paal::data_structures;

using Bidder = std::string;
using Item = std::string;
using Items = std::vector<Item>;
using Value = int;
using Frac = pds::fraction<Value, Value>;

const std::vector<Bidder> bidders {"Pooh Bear", "Rabbit"};

const Items items {"honey", "baby carrot", "carrot", "jam"};

const int gamma_val = 2;

struct gamma_oracle_func {
      template <class GetPrice, class Threshold>
      boost::optional<std::pair<Items, Frac>>
      operator()(Bidder bidder, GetPrice get_price, Threshold z) const {

          if (bidder == "Pooh Bear") {
              const Value val = 10;
              if (val <= z) return boost::none;
              return std::make_pair(Items{"honey"}, Frac(get_price("honey"), val - z));
          }

          assert(bidder == "Rabbit");

          const Value baby_val = 2, val = 3;
          auto const baby_price = get_price("baby carrot");
          auto const price = get_price("carrot");
          auto const baby_frac = Frac(baby_price, baby_val - z),
          frac = Frac(price, val - z),
          both_frac = Frac(baby_price + price, baby_val + val - z);

          auto check = [=](Frac candidate, Frac other1, Frac other2) {
            if (candidate.den <= 0) return false;
            auto check_single = [=](Frac candidate, Frac other) {
                 return other.den <= 0 || candidate <= gamma_val * other;
            };
            return check_single(candidate, other1) && check_single(candidate, other2);
          };

          if (check(baby_frac, frac, both_frac))
              return std::make_pair(Items{"baby carrot"}, baby_frac);
          if (check(frac, baby_frac, both_frac))
              return std::make_pair(Items{"carrot"}, frac);
          if (check(both_frac, baby_frac, frac))
              return std::make_pair(Items{"baby carrot", "carrot"}, both_frac);
          return boost::none;
      }
};

//! [Gamma Oracle Auction Components Example]

int main()
{
   //! [Gamma Oracle Auction Create Example]
   auto const auction = pa::make_gamma_oracle_auction_components(
      bidders, items, gamma_oracle_func(), gamma_val
   );
   //! [Gamma Oracle Auction Create Example]

   //! [Gamma Oracle Auction Use Example]
   auto get_price_func = [](Item item) { return item == "honey" ? 5 : 2; };

   std::cout << "pooh bear buys: ";
   auto got_pooh_bear =
      auction.call<pa::gamma_oracle>("Pooh Bear", get_price_func, 10);
   if (!got_pooh_bear)
      std::cout << "nothing";
   else
      boost::copy(got_pooh_bear->first, std::ostream_iterator<Item>(std::cout, ", "));
   std::cout << std::endl;

   std::cout << "rabbit oracle buys: ";
   auto got_rabbit = auction.call<pa::gamma_oracle>("Rabbit", get_price_func, 1);
   if (!got_rabbit)
      std::cout << "nothing";
   else
      boost::copy(got_rabbit->first, std::ostream_iterator<Item>(std::cout, ", "));
   std::cout << std::endl;

   //! [Gamma Oracle Auction Use Example]
   return 0;
}


/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/integral.hpp>
using namespace boost::hana;

int main() {
    //! [main]
    BOOST_HANA_CONSTANT_ASSERT(less(int_<-3>, int_<3>));
    BOOST_HANA_CONSTANT_ASSERT(max(int_<-3>, long_<2>) == long_<2>);
    BOOST_HANA_CONSTANT_ASSERT(min(int_<-3>, long_<2>) == int_<-3>);
    //! [main]
}


/* boost random/geometric_distribution.hpp header file
 *
 * Copyright Jens Maurer 2000-2001
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id: geometric_distribution.hpp 49314 2008-10-13 09:00:03Z johnmaddock $
 *
 * Revision history
 *  2001-02-18  moved to individual header files
 */

#ifndef BOOST_RANDOM_GEOMETRIC_DISTRIBUTION_HPP
#define BOOST_RANDOM_GEOMETRIC_DISTRIBUTION_HPP

#include <boost/config/no_tr1/cmath.hpp>          // std::log
#include <cassert>
#include <iostream>
#include <boost/random/uniform_01.hpp>

namespace boost {

#if defined(__GNUC__) && (__GNUC__ < 3)
// Special gcc workaround: gcc 2.95.x ignores using-declarations
// in template classes (confirmed by gcc author Martin v. Loewis)
  using std::log;
#endif

// geometric distribution: p(i) = (1-p) * pow(p, i-1)   (integer)
template<class IntType = int, class RealType = double>
class geometric_distribution
{
public:
  typedef RealType input_type;
  typedef IntType result_type;

  explicit geometric_distribution(const RealType& p_arg = RealType(0.5))
    : _p(p_arg)
  {
    assert(RealType(0) < _p && _p < RealType(1));
    init();
  }

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

  RealType p() const { return _p; }
  void reset() { }

  template<class Engine>
  result_type operator()(Engine& eng)
  {
#ifndef BOOST_NO_STDC_NAMESPACE
    using std::log;
    using std::floor;
#endif
    return IntType(floor(log(RealType(1)-eng()) / _log_p)) + IntType(1);
  }

#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  template<class CharT, class Traits>
  friend std::basic_ostream<CharT,Traits>&
  operator<<(std::basic_ostream<CharT,Traits>& os, const geometric_distribution& gd)
  {
    os << gd._p;
    return os;
  }

  template<class CharT, class Traits>
  friend std::basic_istream<CharT,Traits>&
  operator>>(std::basic_istream<CharT,Traits>& is, geometric_distribution& gd)
  {
    is >> std::ws >> gd._p;
    gd.init();
    return is;
  }
#endif

private:
  void init()
  {
#ifndef BOOST_NO_STDC_NAMESPACE
    using std::log;
#endif
    _log_p = log(_p);
  }

  RealType _p;
  RealType _log_p;
};

} // namespace boost

#endif // BOOST_RANDOM_GEOMETRIC_DISTRIBUTION_HPP