//
// Copyright (c) 2002--2010
// Toon Knapen, Karl Meerbergen, Kresimir Fresl,
// Thomas Klimpel and Rutger ter Borg
//
// 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)
//
// THIS FILE IS AUTOMATICALLY GENERATED
// PLEASE DO NOT EDIT!
//

#ifndef BOOST_NUMERIC_BINDINGS_LAPACK_COMPUTATIONAL_TGEVC_HPP
#define BOOST_NUMERIC_BINDINGS_LAPACK_COMPUTATIONAL_TGEVC_HPP

#include <boost/assert.hpp>
#include <boost/numeric/bindings/begin.hpp>
#include <boost/numeric/bindings/detail/array.hpp>
#include <boost/numeric/bindings/is_column_major.hpp>
#include <boost/numeric/bindings/is_complex.hpp>
#include <boost/numeric/bindings/is_mutable.hpp>
#include <boost/numeric/bindings/is_real.hpp>
#include <boost/numeric/bindings/lapack/workspace.hpp>
#include <boost/numeric/bindings/remove_imaginary.hpp>
#include <boost/numeric/bindings/size.hpp>
#include <boost/numeric/bindings/stride.hpp>
#include <boost/numeric/bindings/value_type.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/utility/enable_if.hpp>

//
// The LAPACK-backend for tgevc is the netlib-compatible backend.
//
#include <boost/numeric/bindings/lapack/detail/lapack.h>
#include <boost/numeric/bindings/lapack/detail/lapack_option.hpp>

namespace boost {
namespace numeric {
namespace bindings {
namespace lapack {

//
// The detail namespace contains value-type-overloaded functions that
// dispatch to the appropriate back-end LAPACK-routine.
//
namespace detail {

//
// Overloaded function for dispatching to
// * netlib-compatible LAPACK backend (the default), and
// * float value-type.
//
template< typename Side >
inline std::ptrdiff_t tgevc( const Side, const char howmny,
        const fortran_bool_t* select, const fortran_int_t n, const float* s,
        const fortran_int_t lds, const float* p, const fortran_int_t ldp,
        float* vl, const fortran_int_t ldvl, float* vr,
        const fortran_int_t ldvr, const fortran_int_t mm, fortran_int_t& m,
        float* work ) {
    fortran_int_t info(0);
    LAPACK_STGEVC( &lapack_option< Side >::value, &howmny, select, &n, s,
            &lds, p, &ldp, vl, &ldvl, vr, &ldvr, &mm, &m, work, &info );
    return info;
}

//
// Overloaded function for dispatching to
// * netlib-compatible LAPACK backend (the default), and
// * double value-type.
//
template< typename Side >
inline std::ptrdiff_t tgevc( const Side, const char howmny,
        const fortran_bool_t* select, const fortran_int_t n, const double* s,
        const fortran_int_t lds, const double* p, const fortran_int_t ldp,
        double* vl, const fortran_int_t ldvl, double* vr,
        const fortran_int_t ldvr, const fortran_int_t mm, fortran_int_t& m,
        double* work ) {
    fortran_int_t info(0);
    LAPACK_DTGEVC( &lapack_option< Side >::value, &howmny, select, &n, s,
            &lds, p, &ldp, vl, &ldvl, vr, &ldvr, &mm, &m, work, &info );
    return info;
}

//
// Overloaded function for dispatching to
// * netlib-compatible LAPACK backend (the default), and
// * complex<float> value-type.
//
template< typename Side >
inline std::ptrdiff_t tgevc( const Side, const char howmny,
        const fortran_bool_t* select, const fortran_int_t n,
        const std::complex<float>* s, const fortran_int_t lds,
        const std::complex<float>* p, const fortran_int_t ldp,
        std::complex<float>* vl, const fortran_int_t ldvl,
        std::complex<float>* vr, const fortran_int_t ldvr,
        const fortran_int_t mm, fortran_int_t& m, std::complex<float>* work,
        float* rwork ) {
    fortran_int_t info(0);
    LAPACK_CTGEVC( &lapack_option< Side >::value, &howmny, select, &n, s,
            &lds, p, &ldp, vl, &ldvl, vr, &ldvr, &mm, &m, work, rwork, &info );
    return info;
}

//
// Overloaded function for dispatching to
// * netlib-compatible LAPACK backend (the default), and
// * complex<double> value-type.
//
template< typename Side >
inline std::ptrdiff_t tgevc( const Side, const char howmny,
        const fortran_bool_t* select, const fortran_int_t n,
        const std::complex<double>* s, const fortran_int_t lds,
        const std::complex<double>* p, const fortran_int_t ldp,
        std::complex<double>* vl, const fortran_int_t ldvl,
        std::complex<double>* vr, const fortran_int_t ldvr,
        const fortran_int_t mm, fortran_int_t& m, std::complex<double>* work,
        double* rwork ) {
    fortran_int_t info(0);
    LAPACK_ZTGEVC( &lapack_option< Side >::value, &howmny, select, &n, s,
            &lds, p, &ldp, vl, &ldvl, vr, &ldvr, &mm, &m, work, rwork, &info );
    return info;
}

} // namespace detail

//
// Value-type based template class. Use this class if you need a type
// for dispatching to tgevc.
//
template< typename Value, typename Enable = void >
struct tgevc_impl {};

//
// This implementation is enabled if Value is a real type.
//
template< typename Value >
struct tgevc_impl< Value, typename boost::enable_if< is_real< Value > >::type > {

    typedef Value value_type;
    typedef typename remove_imaginary< Value >::type real_type;

    //
    // Static member function for user-defined workspaces, that
    // * Deduces the required arguments for dispatching to LAPACK, and
    // * Asserts that most arguments make sense.
    //
    template< typename Side, typename VectorSELECT, typename MatrixS,
            typename MatrixP, typename MatrixVL, typename MatrixVR,
            typename WORK >
    static std::ptrdiff_t invoke( const Side side, const char howmny,
            const VectorSELECT& select, const MatrixS& s, const MatrixP& p,
            MatrixVL& vl, MatrixVR& vr, const fortran_int_t mm,
            fortran_int_t& m, detail::workspace1< WORK > work ) {
        namespace bindings = ::boost::numeric::bindings;
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixS >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixP >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixVL >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixVR >::value) );
        BOOST_STATIC_ASSERT( (boost::is_same< typename remove_const<
                typename bindings::value_type< MatrixS >::type >::type,
                typename remove_const< typename bindings::value_type<
                MatrixP >::type >::type >::value) );
        BOOST_STATIC_ASSERT( (boost::is_same< typename remove_const<
                typename bindings::value_type< MatrixS >::type >::type,
                typename remove_const< typename bindings::value_type<
                MatrixVL >::type >::type >::value) );
        BOOST_STATIC_ASSERT( (boost::is_same< typename remove_const<
                typename bindings::value_type< MatrixS >::type >::type,
                typename remove_const< typename bindings::value_type<
                MatrixVR >::type >::type >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_mutable< MatrixVL >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_mutable< MatrixVR >::value) );
        BOOST_ASSERT( bindings::size(work.select(real_type())) >=
                min_size_work( bindings::size_column(s) ));
        BOOST_ASSERT( bindings::size_column(s) >= 0 );
        BOOST_ASSERT( bindings::size_minor(p) == 1 ||
                bindings::stride_minor(p) == 1 );
        BOOST_ASSERT( bindings::size_minor(s) == 1 ||
                bindings::stride_minor(s) == 1 );
        BOOST_ASSERT( bindings::size_minor(vl) == 1 ||
                bindings::stride_minor(vl) == 1 );
        BOOST_ASSERT( bindings::size_minor(vr) == 1 ||
                bindings::stride_minor(vr) == 1 );
        BOOST_ASSERT( bindings::stride_major(p) >= std::max< std::ptrdiff_t >(1,
                bindings::size_column(s)) );
        BOOST_ASSERT( bindings::stride_major(s) >= std::max< std::ptrdiff_t >(1,
                bindings::size_column(s)) );
        BOOST_ASSERT( howmny == 'A' || howmny == 'B' || howmny == 'S' );
        return detail::tgevc( side, howmny, bindings::begin_value(select),
                bindings::size_column(s), bindings::begin_value(s),
                bindings::stride_major(s), bindings::begin_value(p),
                bindings::stride_major(p), bindings::begin_value(vl),
                bindings::stride_major(vl), bindings::begin_value(vr),
                bindings::stride_major(vr), mm, m,
                bindings::begin_value(work.select(real_type())) );
    }

    //
    // Static member function that
    // * Figures out the minimal workspace requirements, and passes
    //   the results to the user-defined workspace overload of the
    //   invoke static member function
    // * Enables the unblocked algorithm (BLAS level 2)
    //
    template< typename Side, typename VectorSELECT, typename MatrixS,
            typename MatrixP, typename MatrixVL, typename MatrixVR >
    static std::ptrdiff_t invoke( const Side side, const char howmny,
            const VectorSELECT& select, const MatrixS& s, const MatrixP& p,
            MatrixVL& vl, MatrixVR& vr, const fortran_int_t mm,
            fortran_int_t& m, minimal_workspace ) {
        namespace bindings = ::boost::numeric::bindings;
        bindings::detail::array< real_type > tmp_work( min_size_work(
                bindings::size_column(s) ) );
        return invoke( side, howmny, select, s, p, vl, vr, mm, m,
                workspace( tmp_work ) );
    }

    //
    // Static member function that
    // * Figures out the optimal workspace requirements, and passes
    //   the results to the user-defined workspace overload of the
    //   invoke static member
    // * Enables the blocked algorithm (BLAS level 3)
    //
    template< typename Side, typename VectorSELECT, typename MatrixS,
            typename MatrixP, typename MatrixVL, typename MatrixVR >
    static std::ptrdiff_t invoke( const Side side, const char howmny,
            const VectorSELECT& select, const MatrixS& s, const MatrixP& p,
            MatrixVL& vl, MatrixVR& vr, const fortran_int_t mm,
            fortran_int_t& m, optimal_workspace ) {
        namespace bindings = ::boost::numeric::bindings;
        return invoke( side, howmny, select, s, p, vl, vr, mm, m,
                minimal_workspace() );
    }

    //
    // Static member function that returns the minimum size of
    // workspace-array work.
    //
    static std::ptrdiff_t min_size_work( const std::ptrdiff_t n ) {
        return 6*n;
    }
};

//
// This implementation is enabled if Value is a complex type.
//
template< typename Value >
struct tgevc_impl< Value, typename boost::enable_if< is_complex< Value > >::type > {

    typedef Value value_type;
    typedef typename remove_imaginary< Value >::type real_type;

    //
    // Static member function for user-defined workspaces, that
    // * Deduces the required arguments for dispatching to LAPACK, and
    // * Asserts that most arguments make sense.
    //
    template< typename Side, typename VectorSELECT, typename MatrixS,
            typename MatrixP, typename MatrixVL, typename MatrixVR,
            typename WORK, typename RWORK >
    static std::ptrdiff_t invoke( const Side side, const char howmny,
            const VectorSELECT& select, const MatrixS& s, const MatrixP& p,
            MatrixVL& vl, MatrixVR& vr, const fortran_int_t mm,
            fortran_int_t& m, detail::workspace2< WORK, RWORK > work ) {
        namespace bindings = ::boost::numeric::bindings;
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixS >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixP >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixVL >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_column_major< MatrixVR >::value) );
        BOOST_STATIC_ASSERT( (boost::is_same< typename remove_const<
                typename bindings::value_type< MatrixS >::type >::type,
                typename remove_const< typename bindings::value_type<
                MatrixP >::type >::type >::value) );
        BOOST_STATIC_ASSERT( (boost::is_same< typename remove_const<
                typename bindings::value_type< MatrixS >::type >::type,
                typename remove_const< typename bindings::value_type<
                MatrixVL >::type >::type >::value) );
        BOOST_STATIC_ASSERT( (boost::is_same< typename remove_const<
                typename bindings::value_type< MatrixS >::type >::type,
                typename remove_const< typename bindings::value_type<
                MatrixVR >::type >::type >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_mutable< MatrixVL >::value) );
        BOOST_STATIC_ASSERT( (bindings::is_mutable< MatrixVR >::value) );
        BOOST_ASSERT( bindings::size(work.select(real_type())) >=
                min_size_rwork( bindings::size_column(s) ));
        BOOST_ASSERT( bindings::size(work.select(value_type())) >=
                min_size_work( bindings::size_column(s) ));
        BOOST_ASSERT( bindings::size_column(s) >= 0 );
        BOOST_ASSERT( bindings::size_minor(p) == 1 ||
                bindings::stride_minor(p) == 1 );
        BOOST_ASSERT( bindings::size_minor(s) == 1 ||
                bindings::stride_minor(s) == 1 );
        BOOST_ASSERT( bindings::size_minor(vl) == 1 ||
                bindings::stride_minor(vl) == 1 );
        BOOST_ASSERT( bindings::size_minor(vr) == 1 ||
                bindings::stride_minor(vr) == 1 );
        BOOST_ASSERT( bindings::stride_major(p) >= std::max< std::ptrdiff_t >(1,
                bindings::size_column(s)) );
        BOOST_ASSERT( bindings::stride_major(s) >= std::max< std::ptrdiff_t >(1,
                bindings::size_column(s)) );
        BOOST_ASSERT( howmny == 'A' || howmny == 'B' || howmny == 'S' );
        return detail::tgevc( side, howmny, bindings::begin_value(select),
                bindings::size_column(s), bindings::begin_value(s),
                bindings::stride_major(s), bindings::begin_value(p),
                bindings::stride_major(p), bindings::begin_value(vl),
                bindings::stride_major(vl), bindings::begin_value(vr),
                bindings::stride_major(vr), mm, m,
                bindings::begin_value(work.select(value_type())),
                bindings::begin_value(work.select(real_type())) );
    }

    //
    // Static member function that
    // * Figures out the minimal workspace requirements, and passes
    //   the results to the user-defined workspace overload of the
    //   invoke static member function
    // * Enables the unblocked algorithm (BLAS level 2)
    //
    template< typename Side, typename VectorSELECT, typename MatrixS,
            typename MatrixP, typename MatrixVL, typename MatrixVR >
    static std::ptrdiff_t invoke( const Side side, const char howmny,
            const VectorSELECT& select, const MatrixS& s, const MatrixP& p,
            MatrixVL& vl, MatrixVR& vr, const fortran_int_t mm,
            fortran_int_t& m, minimal_workspace ) {
        namespace bindings = ::boost::numeric::bindings;
        bindings::detail::array< value_type > tmp_work( min_size_work(
                bindings::size_column(s) ) );
        bindings::detail::array< real_type > tmp_rwork( min_size_rwork(
                bindings::size_column(s) ) );
        return invoke( side, howmny, select, s, p, vl, vr, mm, m,
                workspace( tmp_work, tmp_rwork ) );
    }

    //
    // Static member function that
    // * Figures out the optimal workspace requirements, and passes
    //   the results to the user-defined workspace overload of the
    //   invoke static member
    // * Enables the blocked algorithm (BLAS level 3)
    //
    template< typename Side, typename VectorSELECT, typename MatrixS,
            typename MatrixP, typename MatrixVL, typename MatrixVR >
    static std::ptrdiff_t invoke( const Side side, const char howmny,
            const VectorSELECT& select, const MatrixS& s, const MatrixP& p,
            MatrixVL& vl, MatrixVR& vr, const fortran_int_t mm,
            fortran_int_t& m, optimal_workspace ) {
        namespace bindings = ::boost::numeric::bindings;
        return invoke( side, howmny, select, s, p, vl, vr, mm, m,
                minimal_workspace() );
    }

    //
    // Static member function that returns the minimum size of
    // workspace-array work.
    //
    static std::ptrdiff_t min_size_work( const std::ptrdiff_t n ) {
        return 2*n;
    }

    //
    // Static member function that returns the minimum size of
    // workspace-array rwork.
    //
    static std::ptrdiff_t min_size_rwork( const std::ptrdiff_t n ) {
        return 2*n;
    }
};

//
// Functions for direct use. These functions are overloaded for temporaries,
// so that wrapped types can still be passed and used for write-access. In
// addition, if applicable, they are overloaded for user-defined workspaces.
// Calls to these functions are passed to the tgevc_impl classes. In the
// documentation, most overloads are collapsed to avoid a large number of
// prototypes which are very similar.
//

//
// Overloaded function for tgevc. Its overload differs for
// * User-defined workspace
//
template< typename Side, typename VectorSELECT, typename MatrixS,
        typename MatrixP, typename MatrixVL, typename MatrixVR,
        typename Workspace >
inline typename boost::enable_if< detail::is_workspace< Workspace >,
        std::ptrdiff_t >::type
tgevc( const Side side, const char howmny, const VectorSELECT& select,
        const MatrixS& s, const MatrixP& p, MatrixVL& vl, MatrixVR& vr,
        const fortran_int_t mm, fortran_int_t& m, Workspace work ) {
    return tgevc_impl< typename bindings::value_type<
            MatrixS >::type >::invoke( side, howmny, select, s, p, vl, vr, mm,
            m, work );
}

//
// Overloaded function for tgevc. Its overload differs for
// * Default workspace-type (optimal)
//
template< typename Side, typename VectorSELECT, typename MatrixS,
        typename MatrixP, typename MatrixVL, typename MatrixVR >
inline typename boost::disable_if< detail::is_workspace< MatrixVR >,
        std::ptrdiff_t >::type
tgevc( const Side side, const char howmny, const VectorSELECT& select,
        const MatrixS& s, const MatrixP& p, MatrixVL& vl, MatrixVR& vr,
        const fortran_int_t mm, fortran_int_t& m ) {
    return tgevc_impl< typename bindings::value_type<
            MatrixS >::type >::invoke( side, howmny, select, s, p, vl, vr, mm,
            m, optimal_workspace() );
}

} // namespace lapack
} // namespace bindings
} // namespace numeric
} // namespace boost

#endif


//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// 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)
//=======================================================================

/*
  Sample data (edge_iterator_constructor.dat):
  5
  10
  0 1
  1 2
  1 3
  2 4
  3 4
  1 0
  2 1
  3 1
  4 2
  4 3

  Sample output:

  0 --> 1
  1 --> 2 3 0
  2 --> 4 1
  3 --> 4 1
  4 --> 2 3

 */

#include <boost/config.hpp>
#include <utility>
#include <iostream>
#include <fstream>

#include <iterator>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/adjacency_list.hpp>

class edge_stream_iterator {
public:
  typedef std::input_iterator_tag  iterator_category;
  typedef std::pair<int,int>  value_type;
  typedef std::ptrdiff_t      difference_type;
  typedef const value_type*   pointer;
  typedef const value_type&   reference;

  edge_stream_iterator() : m_stream(0), m_end_marker(false) {}
  edge_stream_iterator(std::istream& s) : m_stream(&s) { m_read(); }
  reference operator*() const { return m_edge; }
  edge_stream_iterator& operator++() {
    m_read();
    return *this;
  }
  edge_stream_iterator operator++(int)  {
    edge_stream_iterator tmp = *this;
    m_read();
    return tmp;
  }
protected:
  std::istream* m_stream;
  value_type m_edge;
  bool m_end_marker;
  void m_read() {
    m_end_marker = (*m_stream) ? true : false;
    if (m_end_marker) {
      *m_stream >> m_edge.first >> m_edge.second;
    }
    m_end_marker = (*m_stream) ? true : false;
  }
  friend bool operator==(const edge_stream_iterator& x,
                         const edge_stream_iterator& y);

};
bool operator==(const edge_stream_iterator& x,
                const edge_stream_iterator& y)
{
  return (x.m_stream == y.m_stream && x.m_end_marker == y.m_end_marker)
    || x.m_end_marker == false && y.m_end_marker == false;
}
bool operator!=(const edge_stream_iterator& x,
                const edge_stream_iterator& y)
{
  return !(x == y);
}

int
main()
{
  typedef boost::adjacency_list<> IteratorConstructibleGraph;
  typedef boost::graph_traits<IteratorConstructibleGraph> Traits;
  Traits::vertices_size_type size_V;
  Traits::edges_size_type size_E;

  std::ifstream f("edge_iterator_constructor.dat");
  f >> size_V >> size_E;

  edge_stream_iterator edge_iter(f), end;
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
  // VC++ can't handle the iterator constructor
  IteratorConstructibleGraph G(size_V);
  while (edge_iter != end) {
    int i, j;
    boost::tie(i, j) = *edge_iter++;
    boost::add_edge(i, j, G);
  }
#else
  IteratorConstructibleGraph G(edge_iter, end, size_V);
#endif
  boost::print_graph(G);

  return 0;
}


#ifndef STAN_MATH_PRIM_PROB_POISSON_LOG_RNG_HPP
#define STAN_MATH_PRIM_PROB_POISSON_LOG_RNG_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <boost/random/poisson_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <cmath>

namespace stan {
namespace math {

/** \ingroup prob_dists
 * Return a Poisson random variate with specified log rate parameter
 * using the given random number generator.
 *
 * lambda can be a scalar or a one-dimensional container.
 *
 * @tparam T_rate type of log rate parameter
 * @tparam RNG type of random number generator
 * @param alpha (Sequence of) log rate parameter(s)
 * @param rng random number generator
 * @return (Sequence of) Poisson random variate(s)
 * @throw std::domain_error if alpha is nonfinite
 */
template <typename T_rate, class RNG>
inline typename VectorBuilder<true, int, T_rate>::type poisson_log_rng(
    const T_rate& alpha, RNG& rng) {
  using boost::variate_generator;
  using boost::random::poisson_distribution;
  static const char* function = "poisson_log_rng";
  static const double POISSON_MAX_LOG_RATE = 30 * LOG_TWO;
  const auto& alpha_ref = to_ref(alpha);
  check_finite(function, "Log rate parameter", alpha_ref);
  check_less(function, "Log rate parameter", alpha_ref, POISSON_MAX_LOG_RATE);

  scalar_seq_view<T_rate> alpha_vec(alpha_ref);
  size_t N = stan::math::size(alpha);
  VectorBuilder<true, int, T_rate> output(N);

  for (size_t n = 0; n < N; ++n) {
    variate_generator<RNG&, poisson_distribution<> > poisson_rng(
        rng, poisson_distribution<>(std::exp(alpha_vec[n])));
    output[n] = poisson_rng();
  }

  return output.data();
}

}  // namespace math
}  // namespace stan
#endif


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE LibmeshEntityLocalMapTester
#include <boost/test/included/unit_test.hpp>
#include <cmath>
#include <iostream>
#include <sstream>
#include <vector>

#include "LibmeshAdjacencies.hpp"
#include "LibmeshEntity.hpp"
#include "LibmeshEntityIntegrationRule.hpp"

#include "Teuchos_Array.hpp"
#include "Teuchos_ArrayRCP.hpp"
#include "Teuchos_DefaultComm.hpp"
#include "Teuchos_Ptr.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_UnitTestHarness.hpp"
#include <Teuchos_DefaultMpiComm.hpp>

#include <libmesh/cell_hex8.h>
#include <libmesh/equation_systems.h>
#include <libmesh/libmesh.h>
#include <libmesh/linear_implicit_system.h>
#include <libmesh/mesh.h>
#include <libmesh/node.h>
#include <libmesh/parallel.h>
#include <libmesh/point.h>
#include <libmesh/system.h>

//---------------------------------------------------------------------------//
// Hex-8 test.
BOOST_AUTO_TEST_CASE( checkLibmeshEntityIntegrationRule )
{
	const std::string argv_string = "unit_test --keep-cout";
	const char *argv_char = argv_string.c_str();
	Teuchos::GlobalMPISession mpiSession(
			&boost::unit_test::framework::master_test_suite().argc,
			&boost::unit_test::framework::master_test_suite().argv);
	auto comm = Teuchos::DefaultComm<int>::getComm();
	auto mpi_comm = Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(
			comm);
	auto opaque_comm = mpi_comm->getRawMpiComm();
	auto raw_comm = (*opaque_comm)();

    // Create the mesh.
    int space_dim = 3;
    libMesh::LibMeshInit libmesh_init( 1, &argv_char, raw_comm );
    BOOST_VERIFY( libMesh::initialized() );
    BOOST_VERIFY( (int)libmesh_init.comm().rank() == comm->getRank() );
    Teuchos::RCP<libMesh::Mesh> mesh =
        Teuchos::rcp( new libMesh::Mesh( libmesh_init.comm(), space_dim ) );

    // Create the nodes.
    int rank = comm->getRank();
    Teuchos::Array<libMesh::Node *> nodes( 8 );
    double node_coords[3];
    node_coords[0] = 0.0;
    node_coords[1] = 0.0;
    node_coords[2] = 0.0;
    nodes[0] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 0,
        rank );

    node_coords[0] = 1.0;
    node_coords[1] = 0.0;
    node_coords[2] = 0.0;
    nodes[1] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 1,
        rank );

    node_coords[0] = 1.0;
    node_coords[1] = 1.0;
    node_coords[2] = 0.0;
    nodes[2] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 2,
        rank );

    node_coords[0] = 0.0;
    node_coords[1] = 1.0;
    node_coords[2] = 0.0;
    nodes[3] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 3,
        rank );

    node_coords[0] = 0.0;
    node_coords[1] = 0.0;
    node_coords[2] = 1.0;
    nodes[4] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 4,
        rank );

    node_coords[0] = 1.0;
    node_coords[1] = 0.0;
    node_coords[2] = 1.0;
    nodes[5] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 5,
        rank );

    node_coords[0] = 1.0;
    node_coords[1] = 1.0;
    node_coords[2] = 1.0;
    nodes[6] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 6,
        rank );

    node_coords[0] = 0.0;
    node_coords[1] = 1.0;
    node_coords[2] = 1.0;
    nodes[7] = mesh->add_point(
        libMesh::Point( node_coords[0], node_coords[1], node_coords[2] ), 7,
        rank );

    // Make a hex-8.
    int num_nodes = 8;
    libMesh::Elem *hex_elem = mesh->add_elem( new libMesh::Hex8 );
    hex_elem->processor_id() = rank;
    hex_elem->set_id() = 2 * rank;
    for ( int i = 0; i < num_nodes; ++i )
        hex_elem->set_node( i ) = nodes[i];

    // Check libmesh validity.
    mesh->libmesh_assert_valid_parallel_ids();

    // Make an adjacency data structure.
    LibmeshAdapter::LibmeshAdjacencies adjacencies( mesh );

    // Create a  entity for the hex.
    auto dtk_entity =
        LibmeshAdapter::LibmeshEntity<libMesh::Elem>(
            Teuchos::ptr( hex_elem ), mesh.ptr(),
            Teuchos::ptrFromRef( adjacencies ) );

    // Create an integration rule.
   auto integration_rule =
        Teuchos::rcp( new LibmeshAdapter::LibmeshEntityIntegrationRule() );

    // Test the integration rule.
    Teuchos::Array<Teuchos::Array<double>> p_1;
    Teuchos::Array<double> w_1;
    integration_rule->getIntegrationRule( dtk_entity, 1, p_1, w_1 );
    BOOST_VERIFY( 1 == w_1.size() );
    BOOST_VERIFY( 1 == p_1.size() );
    BOOST_VERIFY( 3 == p_1[0].size() );
    BOOST_VERIFY( 8.0 == w_1[0] );
    BOOST_VERIFY( 0.0 == p_1[0][0] );
    BOOST_VERIFY( 0.0 == p_1[0][1] );
    BOOST_VERIFY( 0.0 == p_1[0][2] );

    Teuchos::Array<Teuchos::Array<double>> p_2;
    Teuchos::Array<double> w_2;
    integration_rule->getIntegrationRule( dtk_entity, 2, p_2, w_2 );
    BOOST_VERIFY( 8 == w_2.size() );
    BOOST_VERIFY( 8 == p_2.size() );
    for ( int i = 0; i < 8; ++i )
    {
    	BOOST_VERIFY( w_2[i] == 1.0 );
    	BOOST_VERIFY( p_2[i].size() == 3 );

        for ( int d = 0; d < 3; ++d )
        {
			BOOST_TEST(std::abs( p_2[i][d] ) == ( 1.0 / std::sqrt( 3.0 )),
					boost::test_tools::tolerance(1.0e-15));
		}
    }
}

//---------------------------------------------------------------------------//
// end of tstLibmeshEntityIntegrationRule.cpp
//---------------------------------------------------------------------------//


/*!
  \file gpp_hyper_and_EI_demo.cpp
  \rst
  ``moe/optimal_learning/cpp/gpp_hyper_and_EI_demo.cpp``

  This demo combines gpp_hyperparameter_optimization_demo.cpp and gpp_expected_improvement_demo.cpp.  If you have read
  and understood those, then this demo should be very straightforward insofar as it is currently almost a direct copy-paste.

  The purpose here is to give an "end to end" demo of how someone might use MOE/OL to generate new experimental cohorts,
  beginning with a set of known experimental cohorts/objective function values, measurement noise, and knowledge of any
  ongoing experiments.

  The basic layout is:

  1. Set up input data sizes
  2. Generate random hyperparameters
  3. Generate (random) set of sampled point locations, noise variances
  4. Use a randomly constructed (from inputs in steps 1-3) Gaussian Process (generator) to generate imaginary objective function values
  5. Optimize hyperparameters on the constructed function values
  6. Select desired concurrent experiment locations (points_being_sampled)
  7. Construct Gaussian Process (model) to model the training data "world," using the optimized hyperparameters
  8. Optimize Expected Improvement to decide what point we would sample next

     a. Do this once using the optimized hyperparameters
     b. And again using wrong hyperparameters to emulate a human not knowing how to pick (but drawing from a GP with the same state).
        To do this, we build another GP (wrong_hyper) using the wrong hyperparameters but the same training data as the model gp
     c. Compare resulting function values

  Steps 1-4 happen in both other demos.  Step 5 is the heart of gpp_hyperparameter_optimization_demo.cpp and steps 6-7 are
  the heart of gpp_expected_improvement_demo.cpp.

  Please read and understand the file comments for gpp_expected_improvement_demo.cpp (first) and
  gpp_hyperparameter_optimization_demo.cpp (second) before going through this demo.  The comments are a lot sparser here
  than in the aforementioned two files to avoid redundancy.
\endrst*/

#include <cstdio>

#include <algorithm>
#include <vector>

#include <boost/random/uniform_real.hpp>  // NOLINT(build/include_order)

#include "gpp_common.hpp"
#include "gpp_covariance.hpp"
#include "gpp_domain.hpp"
#include "gpp_logging.hpp"
#include "gpp_math.hpp"
#include "gpp_model_selection.hpp"
#include "gpp_optimization.hpp"
#include "gpp_optimizer_parameters.hpp"
#include "gpp_random.hpp"
#include "gpp_test_utils.hpp"

using namespace optimal_learning;  // NOLINT, i'm lazy in this file which has no external linkage anyway
int main() {
  using DomainType = TensorProductDomain;
  using HyperparameterDomainType = TensorProductDomain;
  // here we set some configurable parameters
  // feel free to change them (and recompile) as you explore
  // comments next to each parameter will indicate its purpose and domain

  // the "spatial" dimension, aka the number of independent (experiment) parameters
  static const int dim = 3;  // > 0

  // number of points to optimize simultaneously (for simult experiments); "q" in q,p-EI
  static const int num_to_sample = 1;  // >= 1

  // number of concurrent samples running alongside the optimization; "p" in q,p-EI
  static const int num_being_sampled = 2;  // >= 0

  // number of points that we have already sampled; i.e., size of the training set
  static const int num_sampled = 10;  // >= 0

  UniformRandomGenerator uniform_generator(314);  // repeatable results
  // construct with (base_seed, thread_id) to generate a 'random' seed

  // specifies the domain of each independent variable in (min, max) pairs
  std::vector<ClosedInterval> domain_bounds = {
    {-1.5, 2.3},
    {0.1,  3.1},
    {1.7,  2.9}};
  DomainType domain(domain_bounds.data(), dim);

  // now we allocate point sets; ALL POINTS MUST LIE INSIDE THE DOMAIN!
  std::vector<double> points_sampled(num_sampled*dim);

  std::vector<double> points_sampled_value(num_sampled);

  // default to 0 noise
  std::vector<double> noise_variance(num_sampled, 0.0);  // each entry must be >= 0.0

  // covariance selection
  using CovarianceClass = SquareExponential;  // see gpp_covariance.hpp for other options

  // arbitrary hyperparameters used to generate data
  std::vector<double> hyperparameters_original(1 + dim);
  // generate randomly
  boost::uniform_real<double> uniform_double_for_hyperparameter(0.5, 1.5);
  CovarianceClass covariance_original(dim, 1.0, 1.0);
  FillRandomCovarianceHyperparameters(uniform_double_for_hyperparameter, &uniform_generator,
                                      &hyperparameters_original, &covariance_original);

  // Generate data that will be used to build the GP
  // set noise
  std::fill(noise_variance.begin(), noise_variance.end(), 1.0e-1);  // arbitrary choice

  // use latin hypercube sampling to get a reasonable distribution of training point locations
  domain.GenerateUniformPointsInDomain(num_sampled, &uniform_generator, points_sampled.data());

  // build an empty GP: since num_sampled (last arg) is 0, none of the data arrays will be used here
  GaussianProcess gp_generator(covariance_original, points_sampled.data(), points_sampled_value.data(),
                               noise_variance.data(), dim, 0);
  // fill the GP with randomly generated data
  FillRandomGaussianProcess(points_sampled.data(), noise_variance.data(), dim, num_sampled,
                            points_sampled_value.data(), &gp_generator);

  // simulate not knowing the hyperparameters by choosing a new set randomly (start hyperparameter opt from here)
  std::vector<double> hyperparameters_perturbed(covariance_original.GetNumberOfHyperparameters());
  // choose from a small-ish range; for the demo we want hyperparameter opt to converge fairly quickly/robustly
  boost::uniform_real<double> uniform_double_for_perturbed_hyperparameter(4.0, 8.0);
  CovarianceClass covariance_perturbed(dim, 1.0, 1.0);
  FillRandomCovarianceHyperparameters(uniform_double_for_perturbed_hyperparameter, &uniform_generator,
                                      &hyperparameters_perturbed, &covariance_perturbed);

  std::vector<ClosedInterval> hyperparameter_domain_bounds(covariance_original.GetNumberOfHyperparameters(), {1.0e-10, 1.0e10});
  HyperparameterDomainType hyperparameter_domain(hyperparameter_domain_bounds.data(),
                                                 covariance_original.GetNumberOfHyperparameters());

  // Log Likelihood eval
  using LogLikelihoodEvaluator = LogMarginalLikelihoodEvaluator;
  // log likelihood evaluator object
  LogLikelihoodEvaluator log_marginal_eval(points_sampled.data(), points_sampled_value.data(),
                                           noise_variance.data(), dim, num_sampled);

  // Newton setup
  int total_newton_errors = 0;  // number of newton runs that failed due to singular hessians
  int newton_max_num_steps = 500;  // max number of newton steps
  double gamma_newton = 1.05;  // newton diagonal dominance scale-down factor (see newton docs for details)
  double pre_mult_newton = 1.0e-1;  // newton diagonal dominance scaling factor (see newton docs for details)
  double max_relative_change_newton = 1.0;
  double tolerance_newton = 1.0e-11;
  NewtonParameters newton_parameters(1, newton_max_num_steps, gamma_newton, pre_mult_newton,
                                     max_relative_change_newton, tolerance_newton);

  std::vector<double> new_newton_hyperparameters(covariance_original.GetNumberOfHyperparameters());

  printf(OL_ANSI_COLOR_CYAN "ORIGINAL HYPERPARMETERS:\n" OL_ANSI_COLOR_RESET);
  printf("Original Hyperparameters:\n");
  PrintMatrix(hyperparameters_original.data(), 1, covariance_original.GetNumberOfHyperparameters());

  printf(OL_ANSI_COLOR_CYAN "NEWTON OPTIMIZED HYPERPARAMETERS:\n" OL_ANSI_COLOR_RESET);
  // run newton optimization
  total_newton_errors += NewtonHyperparameterOptimization(log_marginal_eval, covariance_perturbed,
                                                          newton_parameters, hyperparameter_domain,
                                                          new_newton_hyperparameters.data());

  printf("Result of newton:\n");
  PrintMatrix(new_newton_hyperparameters.data(), 1, covariance_original.GetNumberOfHyperparameters());

  if (total_newton_errors > 0) {
    printf("WARNING: %d newton runs exited due to singular Hessian matrices.\n", total_newton_errors);
  }

  // Now optimize EI using the 'best' hyperparameters
  // set gaussian process's hyperparameters to the result of newton optimization
  CovarianceClass covariance_opt(dim, new_newton_hyperparameters[0], new_newton_hyperparameters.data() + 1);
  GaussianProcess gp_model(covariance_opt, points_sampled.data(), points_sampled_value.data(),
                           noise_variance.data(), dim, num_sampled);

  // remaining inputs to EI optimization
  // just an arbitrary point set for when num_being_sampled = 2, as in the default setting for this demo
  std::vector<double> points_being_sampled(num_being_sampled*dim);
  if (num_being_sampled == 2) {
    points_being_sampled[0] = 0.3; points_being_sampled[1] = 2.7; points_being_sampled[2] = 2.2;
    points_being_sampled[3] = -0.2; points_being_sampled[4] = 0.6; points_being_sampled[5] = 1.9;
  }

  // multithreading
  int max_num_threads = 2;  // feel free to experiment with different numbers
  ThreadSchedule thread_schedule(max_num_threads, omp_sched_dynamic);

  // set up RNG containers
  int64_t pi_array[] = {314, 3141, 31415, 314159, 3141592, 31415926, 314159265, 3141592653, 31415926535, 314159265359};  // arbitrarily used digits of pi as seeds
  std::vector<NormalRNG> normal_rng_vec(max_num_threads);
  for (int i = 0; i < max_num_threads; ++i) {
    normal_rng_vec[i].SetExplicitSeed(pi_array[i]);  // to get repeatable results
    // call SetRandomizedSeed(base_seed, thread_id) to automatically choose 'random' seeds
  }

  double best_so_far = *std::min_element(points_sampled_value.begin(), points_sampled_value.end());  // this is simply the best function value seen to date

  // gradient descent parameters
  double gamma = 0.1;  // we decrease step size by a factor of 1/(iteration)^gamma
  double pre_mult = 1.0;  // scaling factor
  double max_relative_change_ei = 1.0;
  double tolerance_ei = 1.0e-7;
  int num_multistarts = 10;  // max number of multistarted locations
  int max_num_steps = 500;  // maximum number of GD iterations per restart
  int max_num_restarts = 20;  // number of restarts to run with GD
  int num_steps_averaged = 0;  // number of steps to use in polyak-ruppert averaging
  GradientDescentParameters gd_params(num_multistarts, max_num_steps, max_num_restarts,
                                      num_steps_averaged, gamma,
                                      pre_mult, max_relative_change_ei, tolerance_ei);

  // EI evaluation parameters
  int max_int_steps = 1000;  // number of monte carlo iterations
  std::vector<double> next_point_winner(dim);

  {  // optimize EI using a model with the optimized hyperparameters
    printf(OL_ANSI_COLOR_CYAN "OPTIMIZING EXPECTED IMPROVEMENT... (optimized hyperparameters)\n" OL_ANSI_COLOR_RESET);
    bool found_flag = false;
    ComputeOptimalPointsToSampleWithRandomStarts(gp_model, gd_params, domain, thread_schedule,
                                                 points_being_sampled.data(), num_to_sample,
                                                 num_being_sampled, best_so_far, max_int_steps,
                                                 &found_flag, &uniform_generator, normal_rng_vec.data(),
                                                 next_point_winner.data());
    printf(OL_ANSI_COLOR_CYAN "EI OPTIMIZATION FINISHED (optimized hyperparameters). Success status: %s\n" OL_ANSI_COLOR_RESET, found_flag ? "True" : "False");
    printf("Next best sample point according to EI (opt hyper):\n");
    PrintMatrix(next_point_winner.data(), 1, dim);

    // check what the actual improvement would've been by sampling from our GP and comparing to best_so_far
    // put randomness in a known state
    gp_generator.SetExplicitSeed(31415);
    double function_value = gp_generator.SamplePointFromGP(next_point_winner.data(), 0.0);  // sample w/o noise

    printf(OL_ANSI_COLOR_CYAN "RESULT OF SAMPLING AT THE NEXT BEST POINT (positive improvement is better) WITH OPT HYPERPARMS:\n" OL_ANSI_COLOR_RESET);
    printf("new function value: %.18E, previous best: %.18E, difference (improvement): %.18E\n", function_value, best_so_far, best_so_far - function_value);
  }

  {  // optimize EI using a model with randomly chosen (incorrect) hyperparameters
    // see how we would've done with the wrong hyperparameters
    printf(OL_ANSI_COLOR_CYAN "OPTIMIZING EXPECTED IMPROVEMENT... (wrong hyperparameters) \n" OL_ANSI_COLOR_RESET);

    // choose some wrong hyperparameters
    std::vector<double> hyperparameters_wrong(covariance_original.GetNumberOfHyperparameters());
    boost::uniform_real<double> uniform_double_for_wrong_hyperparameter(0.1, 0.5);
    CovarianceClass covariance_wrong(dim, 1.0, 1.0);
    FillRandomCovarianceHyperparameters(uniform_double_for_wrong_hyperparameter, &uniform_generator,
                                        &hyperparameters_wrong, &covariance_wrong);
    GaussianProcess gp_wrong_hyper(covariance_wrong, points_sampled.data(), points_sampled_value.data(),
                                   noise_variance.data(), dim, num_sampled);

    bool found_flag = false;
    ComputeOptimalPointsToSampleWithRandomStarts(gp_wrong_hyper, gd_params, domain, thread_schedule,
                                                 points_being_sampled.data(), num_to_sample,
                                                 num_being_sampled, best_so_far, max_int_steps,
                                                 &found_flag, &uniform_generator, normal_rng_vec.data(),
                                                 next_point_winner.data());
    printf(OL_ANSI_COLOR_CYAN "EI OPTIMIZATION FINISHED (wrong hyperparameters). Success status: %s\n" OL_ANSI_COLOR_RESET, found_flag ? "True" : "False");
    printf("Next best sample point according to EI (wrong hyper):\n");
    PrintMatrix(next_point_winner.data(), 1, dim);

    // check what the actual improvement would've been by sampling from our GP with wrong hyperparameters and comparing to best_so_far
    // Not sure if this comparison is valid; maybe gp_generator needs to have the same random state for both calls to
    // SamplePointFromGP?  Or maybe it only makes sense to look after repeated calls?  I think putting the PRNG in the same
    // state for both draws is a reasonable comparison, since then we have two identical GPs

    // put gp_generator in same prng state as when we did the draw for the optimized hyperparameter result
    gp_generator.ResetToMostRecentSeed();
    double function_value = gp_generator.SamplePointFromGP(next_point_winner.data(), 0.0);  // sample w/o noise
    printf(OL_ANSI_COLOR_CYAN "RESULT OF SAMPLING AT THE NEXT BEST POINT (positive improvement is better) WITH WRONG HYPERPARAMS:\n" OL_ANSI_COLOR_RESET);
    printf("new function value: %.18E, previous best: %.18E, difference (improvement): %.18E\n", function_value, best_so_far, best_so_far - function_value);
  }

  return 0;
}  // end main


#include "meetup.h"
#define BOOST_TEST_MAIN
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/test/unit_test.hpp>

// See <http://www.boost.org/doc/libs/1_59_0/doc/html/date_time.html>
// for documentation on boost::gregorian::date

BOOST_AUTO_TEST_CASE(monteenth_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.monteenth());
}

#if defined(EXERCISM_RUN_ALL_TESTS)
BOOST_AUTO_TEST_CASE(monteenth_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.monteenth());
}

BOOST_AUTO_TEST_CASE(monteenth_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.monteenth());
}

BOOST_AUTO_TEST_CASE(tuesteenth_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.tuesteenth());
}

BOOST_AUTO_TEST_CASE(tuesteenth_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.tuesteenth());
}

BOOST_AUTO_TEST_CASE(tuesteenth_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.tuesteenth());
}

BOOST_AUTO_TEST_CASE(wednesteenth_of_January_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jan, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jan, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.wednesteenth());
}

BOOST_AUTO_TEST_CASE(wednesteenth_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.wednesteenth());
}

BOOST_AUTO_TEST_CASE(wednesteenth_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.wednesteenth());
}

BOOST_AUTO_TEST_CASE(thursteenth_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.thursteenth());
}

BOOST_AUTO_TEST_CASE(thursteenth_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.thursteenth());
}

BOOST_AUTO_TEST_CASE(thursteenth_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.thursteenth());
}

BOOST_AUTO_TEST_CASE(friteenth_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.friteenth());
}

BOOST_AUTO_TEST_CASE(friteenth_of_Aug_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.friteenth());
}

BOOST_AUTO_TEST_CASE(friteenth_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.friteenth());
}

BOOST_AUTO_TEST_CASE(saturteenth_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.saturteenth());
}

BOOST_AUTO_TEST_CASE(saturteenth_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.saturteenth());
}

BOOST_AUTO_TEST_CASE(sunteenth_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.sunteenth());
}

BOOST_AUTO_TEST_CASE(sunteenth_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.sunteenth());
}

BOOST_AUTO_TEST_CASE(sunteenth_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.sunteenth());
}

BOOST_AUTO_TEST_CASE(first_Monday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 4};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_monday());
}

BOOST_AUTO_TEST_CASE(first_Monday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 1};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_monday());
}

BOOST_AUTO_TEST_CASE(first_Tuesday_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 7};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_tuesday());
}

BOOST_AUTO_TEST_CASE(first_Tuesday_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 4};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_tuesday());
}

BOOST_AUTO_TEST_CASE(first_Wednesday_of_July_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jul, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jul, 3};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_wednesday());
}

BOOST_AUTO_TEST_CASE(first_Wednesday_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 7};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_wednesday());
}

BOOST_AUTO_TEST_CASE(first_Thursday_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 5};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_thursday());
}

BOOST_AUTO_TEST_CASE(first_Thursday_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 3};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_thursday());
}

BOOST_AUTO_TEST_CASE(first_Friday_of_November_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Nov, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Nov, 1};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_friday());
}

BOOST_AUTO_TEST_CASE(first_Friday_of_December_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Dec, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Dec, 6};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_friday());
}

BOOST_AUTO_TEST_CASE(first_Saturday_of_January_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jan, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jan, 5};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_saturday());
}

BOOST_AUTO_TEST_CASE(first_Saturday_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 2};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_saturday());
}

BOOST_AUTO_TEST_CASE(first_Sunday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 3};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_sunday());
}

BOOST_AUTO_TEST_CASE(first_Sunday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 7};
    BOOST_REQUIRE_EQUAL(expected, meetup.first_sunday());
}

BOOST_AUTO_TEST_CASE(second_Monday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 11};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_monday());
}

BOOST_AUTO_TEST_CASE(second_Monday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 8};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_monday());
}

BOOST_AUTO_TEST_CASE(second_Tuesday_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 14};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_tuesday());
}

BOOST_AUTO_TEST_CASE(second_Tuesday_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 11};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_tuesday());
}

BOOST_AUTO_TEST_CASE(second_Wednesday_of_July_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jul, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jul, 10};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_wednesday());
}

BOOST_AUTO_TEST_CASE(second_Wednesday_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 14};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_wednesday());
}

BOOST_AUTO_TEST_CASE(second_Thursday_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 12};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_thursday());
}

BOOST_AUTO_TEST_CASE(second_Thursday_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 10};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_thursday());
}

BOOST_AUTO_TEST_CASE(second_Friday_of_November_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Nov, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Nov, 8};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_friday());
}

BOOST_AUTO_TEST_CASE(second_Friday_of_December_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Dec, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Dec, 13};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_friday());
}

BOOST_AUTO_TEST_CASE(second_Saturday_of_January_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jan, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jan, 12};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_saturday());
}

BOOST_AUTO_TEST_CASE(second_Saturday_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 9};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_saturday());
}

BOOST_AUTO_TEST_CASE(second_Sunday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 10};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_sunday());
}

BOOST_AUTO_TEST_CASE(second_Sunday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 14};
    BOOST_REQUIRE_EQUAL(expected, meetup.second_sunday());
}

BOOST_AUTO_TEST_CASE(third_Monday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 18};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_monday());
}

BOOST_AUTO_TEST_CASE(third_Monday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 15};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_monday());
}

BOOST_AUTO_TEST_CASE(third_Tuesday_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 21};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_tuesday());
}

BOOST_AUTO_TEST_CASE(third_Tuesday_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 18};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_tuesday());
}

BOOST_AUTO_TEST_CASE(third_Wednesday_of_July_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jul, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jul, 17};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_wednesday());
}

BOOST_AUTO_TEST_CASE(third_Wednesday_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 21};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_wednesday());
}

BOOST_AUTO_TEST_CASE(third_Thursday_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_thursday());
}

BOOST_AUTO_TEST_CASE(third_Thursday_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 17};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_thursday());
}

BOOST_AUTO_TEST_CASE(third_Friday_of_November_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Nov, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Nov, 15};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_friday());
}

BOOST_AUTO_TEST_CASE(third_Friday_of_December_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Dec, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Dec, 20};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_friday());
}

BOOST_AUTO_TEST_CASE(third_Saturday_of_January_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jan, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jan, 19};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_saturday());
}

BOOST_AUTO_TEST_CASE(third_Saturday_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 16};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_saturday());
}

BOOST_AUTO_TEST_CASE(third_Sunday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 17};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_sunday());
}

BOOST_AUTO_TEST_CASE(third_Sunday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 21};
    BOOST_REQUIRE_EQUAL(expected, meetup.third_sunday());
}

BOOST_AUTO_TEST_CASE(fourth_Monday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 25};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_monday());
}

BOOST_AUTO_TEST_CASE(fourth_Monday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 22};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_monday());
}

BOOST_AUTO_TEST_CASE(fourth_Tuesday_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 28};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_tuesday());
}

BOOST_AUTO_TEST_CASE(fourth_Tuesday_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 25};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_tuesday());
}

BOOST_AUTO_TEST_CASE(fourth_Wednesday_of_July_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jul, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jul, 24};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_wednesday());
}

BOOST_AUTO_TEST_CASE(fourth_Wednesday_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 28};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_wednesday());
}

BOOST_AUTO_TEST_CASE(fourth_Thursday_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 26};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_thursday());
}

BOOST_AUTO_TEST_CASE(fourth_Thursday_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 24};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_thursday());
}

BOOST_AUTO_TEST_CASE(fourth_Friday_of_November_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Nov, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Nov, 22};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_friday());
}

BOOST_AUTO_TEST_CASE(fourth_Friday_of_December_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Dec, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Dec, 27};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_friday());
}

BOOST_AUTO_TEST_CASE(fourth_Saturday_of_January_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jan, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jan, 26};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_saturday());
}

BOOST_AUTO_TEST_CASE(fourth_Saturday_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 23};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_saturday());
}

BOOST_AUTO_TEST_CASE(fourth_Sunday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 24};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_sunday());
}

BOOST_AUTO_TEST_CASE(fourth_Sunday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 28};
    BOOST_REQUIRE_EQUAL(expected, meetup.fourth_sunday());
}

BOOST_AUTO_TEST_CASE(last_Monday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 25};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_monday());
}

BOOST_AUTO_TEST_CASE(last_Monday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 29};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_monday());
}

BOOST_AUTO_TEST_CASE(last_Tuesday_of_May_2013)
{
    const meetup::scheduler meetup{boost::gregorian::May, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::May, 28};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_tuesday());
}

BOOST_AUTO_TEST_CASE(last_Tuesday_of_June_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jun, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jun, 25};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_tuesday());
}

BOOST_AUTO_TEST_CASE(last_Wednesday_of_July_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jul, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jul, 31};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_wednesday());
}

BOOST_AUTO_TEST_CASE(last_Wednesday_of_August_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Aug, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Aug, 28};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_wednesday());
}

BOOST_AUTO_TEST_CASE(last_Thursday_of_September_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Sep, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Sep, 26};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_thursday());
}

BOOST_AUTO_TEST_CASE(last_Thursday_of_October_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Oct, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Oct, 31};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_thursday());
}

BOOST_AUTO_TEST_CASE(last_Friday_of_November_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Nov, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Nov, 29};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_friday());
}

BOOST_AUTO_TEST_CASE(last_Friday_of_December_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Dec, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Dec, 27};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_friday());
}

BOOST_AUTO_TEST_CASE(last_Saturday_of_January_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Jan, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Jan, 26};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_saturday());
}

BOOST_AUTO_TEST_CASE(last_Saturday_of_February_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Feb, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Feb, 23};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_saturday());
}

BOOST_AUTO_TEST_CASE(last_Sunday_of_March_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Mar, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Mar, 31};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_sunday());
}

BOOST_AUTO_TEST_CASE(last_Sunday_of_April_2013)
{
    const meetup::scheduler meetup{boost::gregorian::Apr, 2013};

    const boost::gregorian::date expected{2013, boost::gregorian::Apr, 28};
    BOOST_REQUIRE_EQUAL(expected, meetup.last_sunday());
}
#endif


//    Copyright 2017 Rainer Gemulla
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
/*
 * mfcreateSeedFile.cc
 *
 *  Created on: May 9, 2012
 *      Author: chteflio
 *
 * This program creates a file descriptor for generating synthetic matrices on the fly
 * in a parallel or distributed manner
 *
 * For a given experiment you will need 2 such files:
 * (i) a file containing the original factors + the data matrix + the test matrix (optionally)
 * (ii) a file containing the starting points (initial factors)
 *
 * Before creating a file take into consideration the following:
 *
 * (1) parallelization happens in row-chunk manner. Please make sure that the blocks1 dimension
 * is enough fine-grained, so that the threads of each node will have enough row-blocks
 * to work on
 *
 * (2) make sure that the blocks1, blocks2 values are at least as much as the most
 * fine-blocked matrix that you want your file to be able to create
 *
 * (3) blocks_in_file mod blocks_of_the_matrix = 0        !!!
 *
 * (4) rows/columns_of_the_matrix mod blocks_in_file = 0  !!!
 *
 *
 */

#include <string>

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

#include <util/io.h>
#include <mpi2/mpi2.h>
#include <mf/mf.h>

#include "parse.h"

using namespace std;
using namespace mf;
using namespace mpi2;
using namespace boost;
using namespace boost::program_options;
using namespace rg;

// program arguments
// if nnz and nnzTest=0 then I am only interested in creating initial W and H
struct Args {
	mf_size_type size1, size2, nnz,nnzTest,rank;
	int blocks1,blocks2;
	string values,noise;
	string outFilename;
};

// main program
int main(int argc, char *argv[]) {
	Args args;

	// parse command line
	options_description desc("Options");
	desc.add_options()
		("help", "produce help message")
		("size1", value<mf_size_type>(&args.size1), "number of rows to generate")
		("size2", value<mf_size_type>(&args.size2), "number of columns to generate")
		("nnz", value<mf_size_type>(&args.nnz)->default_value(0), "number of non-zero entries to generate")
		("nnzTest", value<mf_size_type>(&args.nnzTest)->default_value(0), "number of test entries to generate ")
		("rank", value<mf_size_type>(&args.rank), "rank for the Worig and Horig ")
		("values", value<string>(&args.values), "distribution of values (e.g., \"Normal(0,1)\", \"Uniform(-1,1)\")")
		("noise", value<string>(&args.noise), "distribution of noise (e.g., \"Normal(0,1)\", \"Uniform(-1,1)\")")
		("blocks1", value<int>(&args.blocks1), "number of row-blocks to generate")
		("blocks2", value<int>(&args.blocks2), "number of column-blocks to generate")
		("output-file", value<string>(&args.outFilename), "output file (extension .rm)")
	;
	positional_options_description pdesc;
	pdesc.add("output-file", 1);

	variables_map vm;
	store(command_line_parser(argc, argv).options(desc).positional(pdesc).run(), vm);
	notify(vm);

	// check required arguments
	if (vm.count("help") || vm.count("values")==0 || vm.count("size1")==0 || vm.count("size2")==0 ||
			vm.count("blocks1")==0||vm.count("blocks2")==0) {
		cerr << "Error: Options size1,size2,blocks1,blocks2,values,output-file are required" << endl;
		cerr << "mfcreateSeedFile [options]" << endl;
	    cerr << desc << endl;
	    exit(1);
	}

	if (!mf::detail::endsWith(args.outFilename,".rm")){
		cerr << "the output-file should have extension .rm" << endl;
		exit(1);
	}

	std::cout<<"create the seedDescriptor"<<std::endl;
	RandomMatrixDescriptor rmd;
	rmd=RandomMatrixDescriptor::create(args.size1,args.size2,args.blocks1,args.blocks2,args.nnz, args.nnzTest, args.rank, args.values, args.noise);
	std::cout<<"save the seedDescriptor file: "<<args.outFilename<<std::endl;
	rmd.save(args.outFilename);

	// everything OK
	return 0;
}


#pragma once

#include <mapnik/datasource.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_adapters.hpp>

#include <boost/geometry/index/rtree.hpp>

#include "feature.hh"
#include "virtual_datasource.hh"

namespace flywave {
namespace nik {

class geometry_datasource : public virtual_datasource {
public:
  using box_type = mapnik::box2d<double>;
  using item_type = std::pair<box_type, std::size_t>;
  using linear_type = boost::geometry::index::linear<16, 4>;
  using spatial_index_type =
      boost::geometry::index::rtree<item_type, linear_type>;

  geometry_datasource(feature_collection<double> ds);

  datasource_t type() const override;
  boost::optional<mapnik::datasource_geometry_t>
  get_geometry_type() const override;

  mapnik::featureset_ptr features(mapnik::query const &q) const override;
  mapnik::featureset_ptr features_at_point(mapnik::coord2d const &pt,
                                           double tol = 0) const override;

  mapnik::box2d<double> envelope() const override;
  mapnik::layer_descriptor get_descriptor() const override;

private:
  void init();

  mutable mapnik::box2d<double> extent_;
  mutable mapnik::box2d<double> cached_extent_;
  mutable mapnik::featureset_ptr cached_features_{nullptr};
  mapnik::layer_descriptor desc_;
  feature_collection<double> features_;
  std::unique_ptr<spatial_index_type> tree_;
  mapnik::datasource_geometry_t geometry_type_;
};

} // namespace nik
} // namespace flywave