//=======================================================================
// Copyright 2008
// Author: Matyas W Egyhazy
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef BOOST_GRAPH_METRIC_TSP_APPROX_HPP
#define BOOST_GRAPH_METRIC_TSP_APPROX_HPP

// metric_tsp_approx
// Generates an approximate tour solution for the traveling salesperson
// problem in polynomial time. The current algorithm guarantees a tour with a
// length at most as long as 2x optimal solution. The graph should have
// 'natural' (metric) weights such that the triangle inequality is maintained.
// Graphs must be fully interconnected.

// TODO:
// There are a couple of improvements that could be made.
// 1) Change implementation to lower uppper bound Christofides heuristic
// 2) Implement a less restrictive TSP heuristic (one that does not rely on
//    triangle inequality).
// 3) Determine if the algorithm can be implemented without creating a new
//    graph.

#include <vector>

#include <boost/shared_ptr.hpp>
#include <boost/concept_check.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_as_tree.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp>
#include <boost/graph/lookup_edge.hpp>
#include <boost/throw_exception.hpp>

namespace boost
{
    // Define a concept for the concept-checking library.
    template <typename Visitor, typename Graph>
    struct TSPVertexVisitorConcept
    {
    private:
        Visitor vis_;
    public:
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

        BOOST_CONCEPT_USAGE(TSPVertexVisitorConcept)
        {
            Visitor vis(vis_);  // require copy construction
            Graph g(1);
            Vertex v(*vertices(g).first);
            vis_.visit_vertex(v, g); // require visit_vertex
        }
    };

    // Tree visitor that keeps track of a preorder traversal of a tree
    // TODO: Consider migrating this to the graph_as_tree header.
    // TODO: Parameterize the underlying stores o it doesn't have to be a vector.
    template<typename Node, typename Tree> class PreorderTraverser
    {
    private:
        std::vector<Node>& path_;
    public:
        typedef typename std::vector<Node>::const_iterator const_iterator;

        PreorderTraverser(std::vector<Node>& p) : path_(p) {}

        void preorder(Node n, const Tree&)
        { path_.push_back(n); }

        void inorder(Node, const Tree&) const {}
        void postorder(Node, const Tree&) const {}

        const_iterator begin() const { return path_.begin(); }
        const_iterator end() const { return path_.end(); }
    };

    // Forward declarations
    template <typename> class tsp_tour_visitor;
    template <typename, typename, typename, typename> class tsp_tour_len_visitor;

    template<typename VertexListGraph, typename OutputIterator>
    void metric_tsp_approx_tour(VertexListGraph& g, OutputIterator o)
    {
        metric_tsp_approx_from_vertex(g, *vertices(g).first,
            get(edge_weight, g), get(vertex_index, g),
            tsp_tour_visitor<OutputIterator>(o));
    }

    template<typename VertexListGraph, typename WeightMap, typename OutputIterator>
    void metric_tsp_approx_tour(VertexListGraph& g, WeightMap w, OutputIterator o)
    {
        metric_tsp_approx_from_vertex(g, *vertices(g).first,
            w, tsp_tour_visitor<OutputIterator>(o));
    }

    template<typename VertexListGraph, typename OutputIterator>
    void metric_tsp_approx_tour_from_vertex(VertexListGraph& g,
        typename graph_traits<VertexListGraph>::vertex_descriptor start,
        OutputIterator o)
    {
        metric_tsp_approx_from_vertex(g, start, get(edge_weight, g),
            get(vertex_index, g), tsp_tour_visitor<OutputIterator>(o));
    }

    template<typename VertexListGraph, typename WeightMap,
        typename OutputIterator>
    void metric_tsp_approx_tour_from_vertex(VertexListGraph& g,
    typename graph_traits<VertexListGraph>::vertex_descriptor start,
        WeightMap w, OutputIterator o)
    {
        metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g),
            tsp_tour_visitor<OutputIterator>(o));
    }

    template<typename VertexListGraph, typename TSPVertexVisitor>
    void metric_tsp_approx(VertexListGraph& g, TSPVertexVisitor vis)
    {
        metric_tsp_approx_from_vertex(g, *vertices(g).first,
            get(edge_weight, g), get(vertex_index, g), vis);
    }

    template<typename VertexListGraph, typename Weightmap,
        typename VertexIndexMap, typename TSPVertexVisitor>
    void metric_tsp_approx(VertexListGraph& g, Weightmap w,
        TSPVertexVisitor vis)
    {
        metric_tsp_approx_from_vertex(g, *vertices(g).first, w,
            get(vertex_index, g), vis);
    }

    template<typename VertexListGraph, typename WeightMap,
        typename VertexIndexMap, typename TSPVertexVisitor>
    void metric_tsp_approx(VertexListGraph& g, WeightMap w, VertexIndexMap id,
        TSPVertexVisitor vis)
    {
        metric_tsp_approx_from_vertex(g, *vertices(g).first, w, id, vis);
    }

    template<typename VertexListGraph, typename WeightMap,
        typename TSPVertexVisitor>
    void metric_tsp_approx_from_vertex(VertexListGraph& g,
    typename graph_traits<VertexListGraph>::vertex_descriptor start,
        WeightMap w, TSPVertexVisitor vis)
    {
        metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g), vis);
    }

    template <
        typename VertexListGraph,
        typename WeightMap,
        typename VertexIndexMap,
        typename TSPVertexVisitor>
    void metric_tsp_approx_from_vertex(const VertexListGraph& g,
                                       typename graph_traits<VertexListGraph>::vertex_descriptor start,
                                       WeightMap weightmap,
                                       VertexIndexMap indexmap,
                                       TSPVertexVisitor vis)
    {
        using namespace boost;
        using namespace std;

        BOOST_CONCEPT_ASSERT((VertexListGraphConcept<VertexListGraph>));
        BOOST_CONCEPT_ASSERT((TSPVertexVisitorConcept<TSPVertexVisitor, VertexListGraph>));

        // Types related to the input graph (GVertex is a template parameter).
        typedef typename graph_traits<VertexListGraph>::vertex_descriptor GVertex;
        typedef typename graph_traits<VertexListGraph>::vertex_iterator GVItr;

        // We build a custom graph in this algorithm.
        typedef adjacency_list <vecS, vecS, directedS, no_property, no_property > MSTImpl;
        typedef graph_traits<MSTImpl>::vertex_descriptor Vertex;
        typedef graph_traits<MSTImpl>::vertex_iterator VItr;

        // And then re-cast it as a tree.
        typedef iterator_property_map<vector<Vertex>::iterator, property_map<MSTImpl, vertex_index_t>::type> ParentMap;
        typedef graph_as_tree<MSTImpl, ParentMap> Tree;
        typedef tree_traits<Tree>::node_descriptor Node;

        // A predecessor map.
        typedef vector<GVertex> PredMap;
        typedef iterator_property_map<typename PredMap::iterator, VertexIndexMap> PredPMap;

        PredMap preds(num_vertices(g));
        PredPMap pred_pmap(preds.begin(), indexmap);

        // Compute a spanning tree over the in put g.
        prim_minimum_spanning_tree(g, pred_pmap,
             root_vertex(start)
            .vertex_index_map(indexmap)
            .weight_map(weightmap));

        // Build a MST using the predecessor map from prim mst
        MSTImpl mst(num_vertices(g));
        std::size_t cnt = 0;
        pair<VItr, VItr> mst_verts(vertices(mst));
        for(typename PredMap::iterator vi(preds.begin()); vi != preds.end(); ++vi, ++cnt)
        {
            if(indexmap[*vi] != cnt) {
                add_edge(*next(mst_verts.first, indexmap[*vi]),
                         *next(mst_verts.first, cnt), mst);
            }
        }

        // Build a tree abstraction over the MST.
        vector<Vertex> parent(num_vertices(mst));
        Tree t(mst, *vertices(mst).first,
            make_iterator_property_map(parent.begin(),
            get(vertex_index, mst)));

        // Create tour using a preorder traversal of the mst
        vector<Node> tour;
        PreorderTraverser<Node, Tree> tvis(tour);
        traverse_tree(indexmap[start], t, tvis);

        pair<GVItr, GVItr> g_verts(vertices(g));
        for(PreorderTraverser<Node, Tree>::const_iterator curr(tvis.begin());
            curr != tvis.end(); ++curr)
        {
            // TODO: This is will be O(n^2) if vertex storage of g != vecS.
            GVertex v = *next(g_verts.first, get(vertex_index, mst)[*curr]);
            vis.visit_vertex(v, g);
        }

        // Connect back to the start of the tour
        vis.visit_vertex(start, g);
    }

    // Default tsp tour visitor that puts the tour in an OutputIterator
    template <typename OutItr>
    class tsp_tour_visitor
    {
        OutItr itr_;
    public:
        tsp_tour_visitor(OutItr itr)
            : itr_(itr)
        { }

        template <typename Vertex, typename Graph>
        void visit_vertex(Vertex v, const Graph&)
        {
            BOOST_CONCEPT_ASSERT((OutputIterator<OutItr, Vertex>));
            *itr_++ = v;
        }

    };

    // Tsp tour visitor that adds the total tour length.
    template<typename Graph, typename WeightMap, typename OutIter, typename Length>
    class tsp_tour_len_visitor
    {
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
        BOOST_CONCEPT_ASSERT((OutputIterator<OutIter, Vertex>));

        OutIter iter_;
        Length& tourlen_;
        WeightMap& wmap_;
        Vertex previous_;

        // Helper function for getting the null vertex.
        Vertex null()
        { return graph_traits<Graph>::null_vertex(); }

    public:
        tsp_tour_len_visitor(Graph const&, OutIter iter, Length& l, WeightMap map)
            : iter_(iter), tourlen_(l), wmap_(map), previous_(null())
        { }

        void visit_vertex(Vertex v, const Graph& g)
        {
            typedef typename graph_traits<Graph>::edge_descriptor Edge;

            // If it is not the start, then there is a
            // previous vertex
            if(previous_ != null())
            {
                // NOTE: For non-adjacency matrix graphs g, this bit of code
                // will be linear in the degree of previous_ or v. A better
                // solution would be to visit edges of the graph, but that
                // would require revisiting the core algorithm.
                Edge e;
                bool found;
                boost::tie(e, found) = lookup_edge(previous_, v, g);
                if(!found) {
                    BOOST_THROW_EXCEPTION(not_complete());
                }

                tourlen_ += wmap_[e];
            }

            previous_ = v;
            *iter_++ = v;
        }
    };

    // Object generator(s)
    template <typename OutIter>
    inline tsp_tour_visitor<OutIter>
    make_tsp_tour_visitor(OutIter iter)
    { return tsp_tour_visitor<OutIter>(iter); }

    template <typename Graph, typename WeightMap, typename OutIter, typename Length>
    inline tsp_tour_len_visitor<Graph, WeightMap, OutIter, Length>
    make_tsp_tour_len_visitor(Graph const& g, OutIter iter, Length& l, WeightMap map)
    { return tsp_tour_len_visitor<Graph, WeightMap, OutIter, Length>(g, iter, l, map); }

} //boost

#endif // BOOST_GRAPH_METRIC_TSP_APPROX_HPP


//
//  utility.hpp
//  NeuralNetwork
//
//  Created by Nikhil Joshi on 10/15/14.
//  Copyright (c) 2014 Nikhil Joshi. All rights reserved.
//

#ifndef NeuralNetwork_utility_hpp
#define NeuralNetwork_utility_hpp

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

// NNetwork exception
namespace NNetwork {

    class Exception: public std::exception {
    public:
        Exception(const std::string& message)
        : _message(message){
            _message = "NNException:: " + _message;

        }
        Exception(std::initializer_list<std::string> messages) {

            std::stringstream msgStream;
            for (auto& message: messages)
                msgStream << "NNException:: " << message << "\n";

            _message = msgStream.str();

        }

        const char* what(void){
            std::cerr << "NNException occurred!" << std::endl;
            return _message.c_str();
        }

    private:
        std::string _caller, _message;
    };

}

// New typedefs, utilities for Eigen
namespace Eigen {
    typedef Matrix<unsigned int, Dynamic, 1> VectorXu;

    // Convert std::vector to Eigen Matrix
    template <typename T>
    inline Eigen::Matrix<T, Dynamic, 1> toEigen(const std::vector<T>& stdVec ) {
        return Eigen::Matrix<T, Dynamic, 1>::Map(stdVec.data(), stdVec.size());
    }

    template <typename T>
    Eigen::Matrix<T, Dynamic, Dynamic> toEigen(const std::vector<std::vector<T>>& stdVec) {

        if (stdVec.empty())
            throw NNetwork::Exception("Cannot convert empty std::vector<std::vector> to Eigen::Matrix.");

        size_t numRows(stdVec.size()), numCols(stdVec[0].size());

        // Possible return matrix
        Eigen::Matrix<T, Dynamic, Dynamic> eigenMat(numRows, numCols);

        // for each row
        for (int i = 0; i < numRows; i++) {
            if (stdVec[i].size() != numCols)
                throw NNetwork::Exception("Provided matrix contains variable length columns.");
            else
                eigenMat.row(i) = Eigen::toEigen(stdVec[i]);
        }

        return eigenMat;
    }

    template <typename T>
    std::vector<T> toStdVector(const Eigen::Matrix<T, Dynamic, 1>& eigenVec){
        return std::vector<T>(eigenVec.data(), eigenVec.data() + eigenVec.size());
    }

    // Append a 1 at each column head
    inline MatrixXd appendOnesAtHead(const Eigen::MatrixXd& mat) {
        MatrixXd augmentedMat(mat.rows() + 1, mat.cols());

        augmentedMat << Eigen::MatrixXd::Ones(1, mat.cols()), mat;

        return augmentedMat;
    }

    // Romove a particular row
    inline Eigen::MatrixXd removeRow(const Eigen::Ref<const Eigen::MatrixXd>& matrix,
                                     const unsigned int rowToRemove) {
        Eigen::MatrixXd reducedMatrix = matrix;

        size_t numRows = matrix.rows();
        size_t numCols = matrix.cols();

        if( rowToRemove < numRows - 1)
            reducedMatrix.block(rowToRemove, 0 ,
                                numRows - 1 - rowToRemove,
                                numCols) = reducedMatrix.block(rowToRemove + 1, 0,
                                                               numRows- 1 -rowToRemove,
                                                               numCols);

        reducedMatrix.conservativeResize(numRows - 1,numCols);
        return reducedMatrix;
    }

    // Remove a particular column
    inline Eigen::MatrixXd removeColumn(const Eigen::Ref<const Eigen::MatrixXd>& matrix,
                                        const unsigned int colToRemove) {
        Eigen::MatrixXd reducedMatrix = matrix;

        size_t numRows(reducedMatrix.rows()), numCols(reducedMatrix.cols());

        if( colToRemove < numCols - 1)
            reducedMatrix.block(0, colToRemove,
                                numRows, numCols - 1 - colToRemove) = matrix.block(0,
                                                                                colToRemove + 1,
                                                                                numRows, numCols - 1 - colToRemove);

        reducedMatrix.conservativeResize(numRows,numCols - 1);
        return reducedMatrix;
    }

    inline Eigen::MatrixXd resetColumnToValue(const Eigen::Ref<const Eigen::MatrixXd>& matrix,
                                              const unsigned int colToReset) {
        Eigen::MatrixXd resetedMatrix = matrix;
        resetedMatrix.col(colToReset) = Eigen::VectorXd::Zero(resetedMatrix.rows());
        return resetedMatrix;
    }

    inline Eigen::MatrixXd resetRowToZero(const Eigen::Ref<const Eigen::MatrixXd>& matrix,
                                          const unsigned int rowToReset) {
        Eigen::MatrixXd resetedMatrix = matrix;
        resetedMatrix.row(rowToReset) = Eigen::VectorXd::Zero(resetedMatrix.cols()).transpose();
        return resetedMatrix;
    }

    // Append given vector as a row to the existing matrix (at the bottom)
    inline void appendRowAtBottom(Eigen::MatrixXd& matrix,
                                  const Eigen::Ref<const Eigen::VectorXd>& vec) {

        // check consistancy with the number of cols
        if (matrix.cols() != vec.rows())
            throw NNetwork::Exception("Tried appending a vector with mis-matching dimensions (number of columns).");

        matrix =  ( Eigen::MatrixXd(matrix.rows() + 1, matrix.cols())
                   << matrix, vec.transpose() ).finished();

    }
    // Append given vector as a column to an existing matrix (on the right)
    inline void appendColumnAtRight(Eigen::MatrixXd& matrix,
                                    const Eigen::Ref<const Eigen::VectorXd>& vec) {

        // check consistancy with the number of cols
        if (matrix.rows() != vec.rows())
            throw NNetwork::Exception("Tried appending a vector with mis-matching dimensions (number of rows).");

        matrix = ( Eigen::MatrixXd(matrix.rows(), matrix.cols() + 1)
                  << matrix, vec ).finished();

    }

    template <typename MatrixType>
    inline MatrixType random(const size_t numRows, const size_t numCols,
                             const typename MatrixType::Scalar lower, const typename MatrixType::Scalar upper){

        return (lower * MatrixType::Ones(numRows, numCols)
                + (upper - lower) * MatrixType::Random(numRows, numCols).cwiseAbs());

    }

    // Produce a transformed vector by operating the given funcion
    inline Eigen::VectorXd operateFunction(const std::function<double(double)>& function,
                                           const Eigen::VectorXd &inputs) {

        size_t size = inputs.size();

        Eigen::VectorXd output(size);

        for (int i = 0; i < size; i++) {
            output[i] = function(inputs[i]);
        }

        return output;
    }

    inline Eigen::VectorXd operateFunction(const std::function<double(double, double)>& function,
                                           const Eigen::Ref<const Eigen::VectorXd>& in1,
                                           const Eigen::Ref<const Eigen::VectorXd>& in2) {

        size_t size = in1.size();

        if (size != in2.size()) {
            throw NNetwork::Exception("Input vectors size mis-match error.");
        }

        Eigen::VectorXd output(size);

        for (int i = 0; i < size; i++) {
            output[i] = function(in1[i], in2[i]);
        }

        return output;
    }

    template <typename MatrixType>
    void saveToFile(const char *filename, const Eigen::Ref<const MatrixType>& mat,
                    const std::ios::ios_base::openmode& ioType = std::ios::binary) {
        std::ofstream outFile(filename, ioType);
        typename MatrixType::Index rows(mat.rows()), cols(mat.cols());
        outFile.write((char *)&rows, sizeof(typename MatrixType::Index));
        outFile.write((char *)&cols, sizeof(typename MatrixType::Index));
        outFile.write((char *)mat.data(), sizeof(typename MatrixType::Scalar)*rows*cols);
        outFile.close();
    }

    template <typename MatrixScalar>
    Eigen::Matrix<MatrixScalar, Eigen::Dynamic, Eigen::Dynamic> loadFromBinaryFile(const char* filename,
                                                                                const std::ios::ios_base::openmode& openMode = std::ios::binary) {
        typedef Eigen::Matrix<MatrixScalar, Dynamic, Dynamic> MatrixType;
        // Open file
        std::ifstream inFile(filename, openMode);
        // A matrix
        MatrixType matrix;

        typename MatrixType::Index rows=0, cols=0;
        inFile.read((char*) (&rows),sizeof(typename MatrixType::Index));
        inFile.read((char*) (&cols),sizeof(typename MatrixType::Index));
        matrix.resize(rows, cols);
        inFile.read( (char *) matrix.data() , rows*cols*sizeof(typename MatrixType::Scalar) );
        inFile.close();

        return matrix;
    }

    inline void fetchNextExample(Eigen::VectorXd& input,
                                 Eigen::VectorXd& output,
                                 int inputLength, int outputLength,
                                 std::ifstream& sourceFile,
                                 const std::ios::ios_base::openmode& openMode = std::ios::binary){

        // if the supplied file is not open, open it
        if (!sourceFile.is_open() ||
            !sourceFile.good())
            throw NNetwork::Exception("Source file is either not open or not in healthy(good) state.");

        input.resize(inputLength);
        output.resize(outputLength);

        sourceFile.read((char *)input.data(), inputLength * sizeof(double));
        sourceFile.read((char *)output.data(), outputLength * sizeof(double));
    }

}

#endif


/* ----------------------------------------------------------------------- *//**
 *
 * @file Math.hpp
 *
 *//* ----------------------------------------------------------------------- */

#ifndef MADLIB_MATH_HPP
#define MADLIB_MATH_HPP

#include <boost/utility/enable_if.hpp>
#include <boost/math/special_functions/fpclassify.hpp>

namespace madlib {

namespace utils {

/**
 * @brief Return the smallest power of 2 that is greater or equal to a number
 *
 * This implementation is for integers only.
 */
template <class T>
typename boost::enable_if_c<std::numeric_limits<T>::is_integer, T>::type
nextPowerOfTwo(T inValue) {
    if (std::numeric_limits<T>::is_signed && inValue == 0)
        return 1;

    inValue--;
    for (int i = 1; i < std::numeric_limits<T>::digits; i <<= 1)
        // Note: No overflow can occur in the following line
        inValue = static_cast<T>(inValue | (inValue >> i));

    return static_cast<T>(inValue + 1);
}

/**
 * @brief Return if two floating point numbers are almost equal.
 *
 * If either of \c inX or \c inY is infinity, the other value has to be infinity
 * as well in order to be considered equal (irrespective of the units in the
 * last place).
 */
template<class T>
typename boost::enable_if_c<!std::numeric_limits<T>::is_integer, bool>::type
almostEqual(T inX, T inY, int inULP) {
    // The machine epsilon has to be scaled to the magnitude of the larger value
    // and multiplied by the desired precision in ULPs (units in the last place)
    return (
           std::fabs(inX - inY)
        <= std::numeric_limits<T>::epsilon()
            * std::max(std::fabs(inX), std::fabs(inY))
            * inULP
        ) || (
            boost::math::isinf(inX) && boost::math::isinf(inY)
            && ((inX < 0) == (inY < 0))
        );
}

/**
 * @brief Test if value is negative
 *
 * This is the implementation for unsigned T. We use SFINAE because
 * otherwise the compiler would warn that a comparison < 0 is always false
 * for unsigned types.
 */
template <class T>
inline
typename boost::enable_if_c<
    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
    bool
>::type
isNegative(const T&) {
    return false;
}

template <class T>
inline
typename boost::enable_if_c<
    !std::numeric_limits<T>::is_integer || std::numeric_limits<T>::is_signed,
    bool
>::type
isNegative(const T& inValue) {
    return inValue < static_cast<T>(0);
}

} // namespace utils

} // namespace regress

#endif


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

  @copyright 2012-2015 NumScale SAS

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

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{
  /*!
    @ingroup group-constant
    Generates a value of the chosen type equals to the difference between 1 and the next
    representable value of the chosen type.

    @par Semantic:

    @code
    T r = Eps<T>();
    @endcode

    is equivalent to:

    - if @c T is an integral type:
      @code
      T r = 1;
      @endcode

    - otherwise:
      @code
      T r = std::numeric_limits<boost::dispatch::scalar_of_t<T>>::epsilon();
      @endcode

    @return A value of type @c T equals to the difference between 1 and the next
            representable value of the chosen type.

     @see functional::eps
  **/
  template<typename T> T Eps();

  namespace functional
  {
    /*!
      @ingroup group-callable-constant
      Generates a value of the chosen type equals to the difference between 1 and the next
      representable value of the chosen type.

      @par Semantic:

      For any value @c x of type @c T:
      @code
      T r = simd::functional::eps( boost::simd::as(x) );
      @endcode

      is equivalent to:

      @code
      T r = simd::Eps<T>();
      @endcode

      @return A value of type @c T equals to the difference between 1 and the next
              representable value of the chosen type.

      @see Eps
    **/
    const boost::dispatch::functor<tag::eps_> eps = {};
  }
} }
#endif

#include <boost/simd/constant/definition/eps.hpp>
#include <boost/simd/arch/common/scalar/constant/constant_value.hpp>
#include <boost/simd/arch/common/simd/constant/constant_value.hpp>

#endif


/*    This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
 *    See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
 *    Author(s):       Vincent Rouvreau
 *
 *    Copyright (C) 2015 Inria
 *
 *    Modification(s):
 *      - YYYY/MM Author: Description of the modification
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "alpha_complex"
#include <boost/test/unit_test.hpp>
#include <boost/mpl/list.hpp>

#include <CGAL/Delaunay_triangulation.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Epeck_d.h>

#include <cmath>  // float comparison
#include <limits>
#include <string>
#include <vector>

#include <gudhi/Alpha_complex.h>
// to construct a simplex_tree from Delaunay_triangulation
#include <gudhi/graph_simplicial_complex.h>
#include <gudhi/Simplex_tree.h>
#include <gudhi/Unitary_tests_utils.h>

// Use dynamic_dimension_tag for the user to be able to set dimension
typedef CGAL::Epeck_d< CGAL::Dynamic_dimension_tag > Exact_kernel_d;
// Use static dimension_tag for the user not to be able to set dimension
typedef CGAL::Epeck_d< CGAL::Dimension_tag<3> > Exact_kernel_s;
// Use dynamic_dimension_tag for the user to be able to set dimension
typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > Inexact_kernel_d;
// Use static dimension_tag for the user not to be able to set dimension
typedef CGAL::Epick_d< CGAL::Dimension_tag<3> > Inexact_kernel_s;
// The triangulation uses the default instantiation of the TriangulationDataStructure template parameter

typedef boost::mpl::list<Exact_kernel_d, Exact_kernel_s, Inexact_kernel_d, Inexact_kernel_s> list_of_kernel_variants;

BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_from_OFF_file, TestedKernel, list_of_kernel_variants) {
  // ----------------------------------------------------------------------------
  //
  // Init of an alpha-complex from a OFF file
  //
  // ----------------------------------------------------------------------------
  std::string off_file_name("alphacomplexdoc.off");
  double max_alpha_square_value = 60.0;
  std::clog << "========== OFF FILE NAME = " << off_file_name << " - alpha²=" <<
      max_alpha_square_value << "==========" << std::endl;

  Gudhi::alpha_complex::Alpha_complex<TestedKernel> alpha_complex_from_file(off_file_name);

  Gudhi::Simplex_tree<> simplex_tree_60;
  BOOST_CHECK(alpha_complex_from_file.create_complex(simplex_tree_60, max_alpha_square_value));

  std::clog << "simplex_tree_60.dimension()=" << simplex_tree_60.dimension() << std::endl;
  BOOST_CHECK(simplex_tree_60.dimension() == 2);

  std::clog << "simplex_tree_60.num_vertices()=" << simplex_tree_60.num_vertices() << std::endl;
  BOOST_CHECK(simplex_tree_60.num_vertices() == 7);

  std::clog << "simplex_tree_60.num_simplices()=" << simplex_tree_60.num_simplices() << std::endl;
  BOOST_CHECK(simplex_tree_60.num_simplices() == 25);

  max_alpha_square_value = 59.0;
  std::clog << "========== OFF FILE NAME = " << off_file_name << " - alpha²=" <<
      max_alpha_square_value << "==========" << std::endl;

  Gudhi::Simplex_tree<> simplex_tree_59;
  BOOST_CHECK(alpha_complex_from_file.create_complex(simplex_tree_59, max_alpha_square_value));

  std::clog << "simplex_tree_59.dimension()=" << simplex_tree_59.dimension() << std::endl;
  BOOST_CHECK(simplex_tree_59.dimension() == 2);

  std::clog << "simplex_tree_59.num_vertices()=" << simplex_tree_59.num_vertices() << std::endl;
  BOOST_CHECK(simplex_tree_59.num_vertices() == 7);

  std::clog << "simplex_tree_59.num_simplices()=" << simplex_tree_59.num_simplices() << std::endl;
  BOOST_CHECK(simplex_tree_59.num_simplices() == 23);
}

// Use static dimension_tag for the user not to be able to set dimension
typedef CGAL::Epeck_d< CGAL::Dimension_tag<4> > Kernel_4;
typedef Kernel_4::Point_d Point_4;
typedef std::vector<Point_4> Vector_4_Points;

bool is_point_in_list(Vector_4_Points points_list, Point_4 point) {
  for (auto& point_in_list : points_list) {
    if (point_in_list == point) {
      return true;  // point found
    }
  }
  return false;  // point not found
}

BOOST_AUTO_TEST_CASE(Alpha_complex_from_points) {
  // ----------------------------------------------------------------------------
  // Init of a list of points
  // ----------------------------------------------------------------------------
  Vector_4_Points points;
  std::vector<double> coords = { 0.0, 0.0, 0.0, 1.0 };
  points.push_back(Point_4(coords.begin(), coords.end()));
  coords = { 0.0, 0.0, 1.0, 0.0 };
  points.push_back(Point_4(coords.begin(), coords.end()));
  coords = { 0.0, 1.0, 0.0, 0.0 };
  points.push_back(Point_4(coords.begin(), coords.end()));
  coords = { 1.0, 0.0, 0.0, 0.0 };
  points.push_back(Point_4(coords.begin(), coords.end()));

  // ----------------------------------------------------------------------------
  // Init of an alpha complex from the list of points
  // ----------------------------------------------------------------------------
  Gudhi::alpha_complex::Alpha_complex<Kernel_4> alpha_complex_from_points(points);

  std::clog << "========== Alpha_complex_from_points ==========" << std::endl;

  Gudhi::Simplex_tree<> simplex_tree;
  BOOST_CHECK(alpha_complex_from_points.create_complex(simplex_tree));

  // Another way to check num_simplices
  std::clog << "Iterator on alpha complex simplices in the filtration order, with [filtration value]:" << std::endl;
  int num_simplices = 0;
  for (auto f_simplex : simplex_tree.filtration_simplex_range()) {
    num_simplices++;
    std::clog << "   ( ";
    for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex)) {
      std::clog << vertex << " ";
    }
    std::clog << ") -> " << "[" << simplex_tree.filtration(f_simplex) << "] ";
    std::clog << std::endl;
  }
  BOOST_CHECK(num_simplices == 15);
  std::clog << "simplex_tree.num_simplices()=" << simplex_tree.num_simplices() << std::endl;
  BOOST_CHECK(simplex_tree.num_simplices() == 15);

  std::clog << "simplex_tree.dimension()=" << simplex_tree.dimension() << std::endl;
  BOOST_CHECK(simplex_tree.dimension() == 3);
  std::clog << "simplex_tree.num_vertices()=" << simplex_tree.num_vertices() << std::endl;
  BOOST_CHECK(simplex_tree.num_vertices() == points.size());

  for (auto f_simplex : simplex_tree.filtration_simplex_range()) {
    switch (simplex_tree.dimension(f_simplex)) {
      case 0:
        GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(f_simplex), 0.0);
        break;
      case 1:
        GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(f_simplex), 1.0/2.0);
        break;
      case 2:
        GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(f_simplex), 2.0/3.0);
        break;
      case 3:
        GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(f_simplex), 3.0/4.0);
        break;
      default:
        BOOST_CHECK(false);  // Shall not happen
        break;
    }
  }

  Point_4 p0 = alpha_complex_from_points.get_point(0);
  std::clog << "alpha_complex_from_points.get_point(0)=" << p0 << std::endl;
  BOOST_CHECK(4 == p0.dimension());
  BOOST_CHECK(is_point_in_list(points, p0));

  Point_4 p1 = alpha_complex_from_points.get_point(1);
  std::clog << "alpha_complex_from_points.get_point(1)=" << p1 << std::endl;
  BOOST_CHECK(4 == p1.dimension());
  BOOST_CHECK(is_point_in_list(points, p1));

  Point_4 p2 = alpha_complex_from_points.get_point(2);
  std::clog << "alpha_complex_from_points.get_point(2)=" << p2 << std::endl;
  BOOST_CHECK(4 == p2.dimension());
  BOOST_CHECK(is_point_in_list(points, p2));

  Point_4 p3 = alpha_complex_from_points.get_point(3);
  std::clog << "alpha_complex_from_points.get_point(3)=" << p3 << std::endl;
  BOOST_CHECK(4 == p3.dimension());
  BOOST_CHECK(is_point_in_list(points, p3));

  // Test to the limit
  BOOST_CHECK_THROW (alpha_complex_from_points.get_point(4), std::out_of_range);
  BOOST_CHECK_THROW (alpha_complex_from_points.get_point(-1), std::out_of_range);
  BOOST_CHECK_THROW (alpha_complex_from_points.get_point(1234), std::out_of_range);

  // Test after prune_above_filtration
  bool modified = simplex_tree.prune_above_filtration(0.6);
  BOOST_CHECK(modified);

  // Another way to check num_simplices
  std::clog << "Iterator on alpha complex simplices in the filtration order, with [filtration value]:" << std::endl;
  num_simplices = 0;
  for (auto f_simplex : simplex_tree.filtration_simplex_range()) {
    num_simplices++;
    std::clog << "   ( ";
    for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex)) {
      std::clog << vertex << " ";
    }
    std::clog << ") -> " << "[" << simplex_tree.filtration(f_simplex) << "] ";
    std::clog << std::endl;
  }
  BOOST_CHECK(num_simplices == 10);
  std::clog << "simplex_tree.num_simplices()=" << simplex_tree.num_simplices() << std::endl;
  BOOST_CHECK(simplex_tree.num_simplices() == 10);

  std::clog << "simplex_tree.dimension()=" << simplex_tree.dimension() << std::endl;
  BOOST_CHECK(simplex_tree.dimension() == 1);
  std::clog << "simplex_tree.num_vertices()=" << simplex_tree.num_vertices() << std::endl;
  BOOST_CHECK(simplex_tree.num_vertices() == 4);

  for (auto f_simplex : simplex_tree.filtration_simplex_range()) {
    switch (simplex_tree.dimension(f_simplex)) {
      case 0:
        GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(f_simplex), 0.0);
        break;
      case 1:
        GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(f_simplex), 1.0/2.0);
        break;
      default:
        BOOST_CHECK(false);  // Shall not happen
        break;
    }
  }

}

BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_from_empty_points, TestedKernel, list_of_kernel_variants) {
  std::clog << "========== Alpha_complex_from_empty_points ==========" << std::endl;

  // ----------------------------------------------------------------------------
  // Init of an empty list of points
  // ----------------------------------------------------------------------------
  std::vector<typename TestedKernel::Point_d> points;

  // ----------------------------------------------------------------------------
  // Init of an alpha complex from the list of points
  // ----------------------------------------------------------------------------
  Gudhi::alpha_complex::Alpha_complex<TestedKernel> alpha_complex_from_points(points);

  // Test to the limit
  BOOST_CHECK_THROW (alpha_complex_from_points.get_point(0), std::out_of_range);

  Gudhi::Simplex_tree<> simplex_tree;
  BOOST_CHECK(!alpha_complex_from_points.create_complex(simplex_tree));

  std::clog << "simplex_tree.num_simplices()=" << simplex_tree.num_simplices() << std::endl;
  BOOST_CHECK(simplex_tree.num_simplices() == 0);

  std::clog << "simplex_tree.dimension()=" << simplex_tree.dimension() << std::endl;
  BOOST_CHECK(simplex_tree.dimension() == -1);

  std::clog << "simplex_tree.num_vertices()=" << simplex_tree.num_vertices() << std::endl;
  BOOST_CHECK(simplex_tree.num_vertices() == points.size());
}

using Inexact_kernel_2 = CGAL::Epick_d< CGAL::Dimension_tag<2> >;
using Exact_kernel_2 = CGAL::Epeck_d< CGAL::Dimension_tag<2> >;
using list_of_kernel_2_variants = boost::mpl::list<Inexact_kernel_2, Exact_kernel_2>;

BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_with_duplicated_points, TestedKernel, list_of_kernel_2_variants) {
  std::clog << "========== Alpha_complex_with_duplicated_points ==========" << std::endl;

  using Point = typename TestedKernel::Point_d;
  using Vector_of_points = std::vector<Point>;

  // ----------------------------------------------------------------------------
  // Init of a list of points
  // ----------------------------------------------------------------------------
  Vector_of_points points;
  points.push_back(Point(1.0, 1.0));
  points.push_back(Point(7.0, 0.0));
  points.push_back(Point(4.0, 6.0));
  points.push_back(Point(9.0, 6.0));
  points.push_back(Point(0.0, 14.0));
  points.push_back(Point(2.0, 19.0));
  points.push_back(Point(9.0, 17.0));
  // duplicated points
  points.push_back(Point(1.0, 1.0));
  points.push_back(Point(7.0, 0.0));

  // ----------------------------------------------------------------------------
  // Init of an alpha complex from the list of points
  // ----------------------------------------------------------------------------
  std::clog << "Init" << std::endl;
  Gudhi::alpha_complex::Alpha_complex<TestedKernel> alpha_complex_from_points(points);

  Gudhi::Simplex_tree<> simplex_tree;
  std::clog << "create_complex" << std::endl;
  BOOST_CHECK(alpha_complex_from_points.create_complex(simplex_tree));

  std::clog << "simplex_tree.num_vertices()=" << simplex_tree.num_vertices()
      << std::endl;
  BOOST_CHECK(simplex_tree.num_vertices() < points.size());
}


/**
 * Copyright (c) 2015
 * Jakob van Santen <jvansanten@icecube.wisc.edu>
 * and the IceCube Collaboration <http://www.icecube.wisc.edu>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *
 * $Id$
 *
 * @file Axis.cxx
 * @version $LastChangedRevision$
 * @date $Date$
 * @author Jakob van Santen
 */

#include "clsim/tabulator/Axis.h"
#include "clsim/I3CLSimHelperToFloatString.h"

#include <boost/foreach.hpp>

#include <cmath>

namespace clsim {

namespace tabulator {

Axis::Axis(double min, double max, unsigned n_bins)
    : min_(min), max_(max), n_bins_(n_bins)
{}

Axis::~Axis()
{}

std::string
Axis::GetIndexCode(const std::string &var) const {

	std::ostringstream ss;
	double scale = n_bins_/(InverseTransform(max_)-InverseTransform(min_));
	double offset = scale*InverseTransform(min_);

	using I3CLSimHelper::ToFloatString;
	ss << "(clamp(convert_int_sat_rtn("
	    <<ToFloatString(scale)<<"*"<<GetInverseTransformCode(var)
	    <<" - "<<ToFloatString(offset)
	    <<"), -1, "<<(n_bins_)<<")+1)";

	return ss.str();
}

std::vector<double>
Axis::GetBinEdges() const
{
	std::vector<double> edges(GetNBins()+1);

	double imin = InverseTransform(GetMin());
	double imax = InverseTransform(GetMax());
	double istep = (imax-imin)/GetNBins();
	for (unsigned i = 0; i <= GetNBins(); i++)
		edges[i] = Transform(imin + i*istep);

	return edges;
}

double
Axis::GetBinEdge(unsigned i) const
{
	double imin = InverseTransform(GetMin());
	double imax = InverseTransform(GetMax());
	double istep = (imax-imin)/GetNBins();
	return Transform(imin + i*istep);
}

LinearAxis::LinearAxis(double min, double max, unsigned n_bins)
    : Axis(min, max, n_bins)
{}

LinearAxis::~LinearAxis()
{}

double
LinearAxis::Transform(double value) const
{
	return value;
}

double
LinearAxis::InverseTransform(double value) const
{
	return value;
}

std::string
LinearAxis::GetTransformCode(const std::string &var) const
{
	return var;
}

std::string
LinearAxis::GetInverseTransformCode(const std::string &var) const
{
	return var;
}

PowerAxis::PowerAxis(double min, double max, unsigned n_bins, unsigned power)
    : Axis(min, max, n_bins), power_(power)
{}

PowerAxis::~PowerAxis()
{}

double
PowerAxis::Transform(double value) const
{
	return std::pow(value, power_);
}

double
PowerAxis::InverseTransform(double value) const
{
	return std::pow(value, 1./power_);
}

std::string
PowerAxis::GetTransformCode(const std::string &var) const
{
	std::ostringstream ss;
	if (power_ == 0) {
		ss << 1;
	} else if (power_ < 5) {
		ss << var;
		for (unsigned i = 0; i+1 < power_; i++)
			ss << "*" << var;
	} else {
		ss << "pow("<<var<<", "<<power_<< ")";
	}
	return ss.str();
}

std::string
PowerAxis::GetInverseTransformCode(const std::string &var) const
{
	std::ostringstream ss;
	switch (power_) {
		case 0:
			ss << 1;
			break;
		case 1:
			ss << var;
			break;
		case 2:
			ss << "sqrt(" << var << ")";
			break;
		case 3:
			ss << "cbrt(" << var << ")";
			break;
		default:
			ss << "pow(" << var << "," << I3CLSimHelper::ToFloatString(1./power_) << ")";
	}
	return ss.str();
}

}

}


/* pyublas/numpy.hpp:
 * Defines pyublas::numpy_vector<type> */
#include <pyublas/numpy.hpp>
/* stdlib.h:
 * Numeric conversions, rand/srand (pseudo random number generators),
 * {m,re,c}alloc/free and process control (exit/abort/getenv/system). */
#include <stdlib.h>
/* iostream:
 * For std::cout <<, std::cin << functionality */
#include <iostream>
/* time.h:
 * For timing (time()) */
//#include <time.h>
/* list:
 * For list types like std::list<long> */
//#include <list>
/* vector:
 * Vector types, obviously; e.g. a vector of long lists:
 *     std::vector<std::list<long>>
 * Vectors are like arrays (performance-wise), but clean up after themselves. */
#include <vector>
/* math.h:
 * Mathematical functions like pow, exp, log, sin, etc.
 * N.B.: need to include this in the CMakeLists target_link_libraries (as m) */
//#include <math.h>
/* functional:
 * Needed for std::bind. */
#include <functional>

// For testing types of variables (typeid(var).name())
#include <typeinfo>

// BOOST (http://www.boost.org/libs/random/random-generators.html)
#include <boost/random/mersenne_twister.hpp>

#include "crunch.hpp"

using namespace crunch;

typedef boost::mt19937 rng_type;

double_vector crunch::resolution_independent_random_grid(int gridsize, unsigned int seed) {
    rng_type engine; // only initialize an RNG once! http://tinyurl.com/cwbqqvg
    int i, j, k;

    // Create the output array:
    double_vector out(gridsize * gridsize * (gridsize/2+1));
    double* outpoint = out.data().begin();
    int i_stride = gridsize*(gridsize/2+1);
    int j_stride = (gridsize/2+1);

    // Seed random number generator:
    engine.seed(seed); // don't seed too much! http://tinyurl.com/cwbqqvg

    // Fill out:
    for (i = 0; i < gridsize / 2; i++) {
        for (k = 0; k < i+1; k++) {
            for (j = 0; j < i; j++)
                outpoint[i * i_stride + j * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i + 1; j++)
                outpoint[j * i_stride + i * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i; j++)
                outpoint[(gridsize - 1 - i) * i_stride + j * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i + 1; j++)
                outpoint[(gridsize - 1 - j) * i_stride + i * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i; j++)
                outpoint[i * i_stride + (gridsize - 1 - j) * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i + 1; j++)
                outpoint[j * i_stride + (gridsize - 1 - i) * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i; j++)
                outpoint[(gridsize - 1 - i) * i_stride + (gridsize - 1 - j) * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
            for (j = 0; j < i + 1; j++)
                outpoint[(gridsize - 1 - j) * i_stride + (gridsize - 1 - i) * j_stride + k] = (double) ((unsigned long) engine()) / 0x100000000;
        }
        for (j = 0; j < i; j++) {
            for (k = 0; k < i; k++) {
                outpoint[j * i_stride + k * j_stride + i] = (double) ((unsigned long) engine()) / 0x100000000;
                outpoint[(gridsize - 1 - j) * i_stride + k * j_stride + i] = (double) ((unsigned long) engine()) / 0x100000000;
                outpoint[j * i_stride + (gridsize - 1 - k) * j_stride + i] = (double) ((unsigned long) engine()) / 0x100000000;
                outpoint[(gridsize - 1 - j) * i_stride + (gridsize - 1 - k) * j_stride + i] = (double) ((unsigned long) engine()) / 0x100000000;
            }
        }
    }

    // Fill out's nyquist plane:
    for (i = 0; i < gridsize; i++) {
        for (j = 0; j < gridsize; j++) {
            outpoint[i_stride*i + j_stride*j + gridsize/2] = (double) ((unsigned long) engine()) / 0x100000000;
        }
    }

    const npy_intp dims[3] = {(npy_intp) gridsize, (npy_intp) gridsize, (npy_intp) gridsize/2+1};
    out.reshape(3, dims);
    return out;
}

// EXTRA TEST FUNCTIE VOOR VERGELIJKING MET numpy.random.random
double_vector crunch::naive_random_grid(int gridsize, unsigned int seed) {
    rng_type engine; // only initialize an RNG once! http://tinyurl.com/cwbqqvg
    int i, j, k;

    // Create the output array:
    double_vector out(gridsize * gridsize * (gridsize/2+1));
    double* outpoint = out.data().begin();

    // Seed random number generator:
    engine.seed(seed); // don't seed too much! http://tinyurl.com/cwbqqvg

    int gridcells = gridsize*gridsize*(gridsize/2+1);
    // Fill out:
    for (i = 0; i < gridcells; i++) {
        outpoint[i] = (double) ((unsigned long) engine()) / 0x100000000;
    }

    const npy_intp dims[3] = {(npy_intp) gridsize, (npy_intp) gridsize, (npy_intp) gridsize/2+1};
    out.reshape(3, dims);
    return out;
}

// OLD VERSION (using seedtable as in N-GenIC -> slow!)
/* Based on:
 * http://en.wikipedia.org/wiki/C%2B%2B11#Extensible_random_number_facility
 * http://www.boost.org/doc/libs/1_40_0/libs/random/random_demo.cpp
 * and N-GenIC.
 * N.B.: gridsize must be an even number.*/
double_vector crunch::resolution_independent_random_grid_seedtable(int gridsize, unsigned int seed) {
    rng_type engine; // only initialize an RNG once! http://tinyurl.com/cwbqqvg
    std::vector<unsigned int> seedtable(gridsize * gridsize);
    int i, j, k;

    // Seed for the random integers:
    engine.seed(seed); // don't seed too much! http://tinyurl.com/cwbqqvg

    // Filling seedtable (cell 0 == "lower left" and count left-right, down-up):
    for (i = 0; i < gridsize / 2; i++) {
        for (j = 0; j < i; j++) /* i==0 -> nothing
                                * i!=0 -> the edge above cell 0 */
            seedtable[i * gridsize + j] = engine();
        for (j = 0; j < i + 1; j++) /* i==0 -> cell 0
                                    * i!=0 -> the edge to the right of cell 0 */
            seedtable[j * gridsize + i] = engine();
        for (j = 0; j < i; j++) /* i==0 -> nothing
                                * i!=0 -> the edge below cell y */
            seedtable[(gridsize - 1 - i) * gridsize + j] = engine();
        for (j = 0; j < i + 1; j++) /* i==0 -> cell y ("top left")
                                    * i!=0 -> the edge to the right of cell y */
            seedtable[(gridsize - 1 - j) * gridsize + i] = engine();
        for (j = 0; j < i; j++) /* i==0 -> nothing
                                * i!=0 -> the edge above cell x*/
            seedtable[i * gridsize + (gridsize - 1 - j)] = engine();
        for (j = 0; j < i + 1; j++) /* i==0 -> cell x ("bottom right")
                                    * i!=0 -> the edge to the left of cell x */
            seedtable[j * gridsize + (gridsize - 1 - i)] = engine();
        for (j = 0; j < i; j++) /* i==0 -> nothing
                                * i!=0 -> the edge below cell xy */
            seedtable[(gridsize - 1 - i) * gridsize + (gridsize - 1 - j)] = engine();
        for (j = 0; j < i + 1; j++) /* i==0 -> cell xy ("top right")
                                    * i!=0 -> the edge to the left of cell xy */
            seedtable[(gridsize - 1 - j) * gridsize + (gridsize - 1 - i)] = engine();
    }

    // Create the output array:
    double_vector out(gridsize * gridsize * (gridsize/2+1));
    double* outpoint = out.data().begin();
    int i_stride = gridsize*(gridsize/2+1);
    int j_stride = (gridsize/2+1);

    for (i = 0; i < gridsize; i++) {
        for (j = 0; j < gridsize; j++) {
            // Reseed using seedtable:
            engine.seed(seedtable[i*gridsize + j]); // too much seeding really..
            for (k = 0; k < gridsize/2+1; k++) {
                outpoint[i_stride*i + j_stride*j + k] = (double) ((unsigned long) engine()) / 0x100000000;
            }
        }
    }

    const npy_intp dims[3] = {(npy_intp) gridsize, (npy_intp) gridsize, (npy_intp) gridsize/2+1};
    out.reshape(3, dims);
    return out;
}

// t3 = Timer("array=c.naive_random_grid(32,0)", "import pyublas; import egp.crunch as c")


/** nonfinite_num_facet_trap.cpp
*
* Copyright (c) 2012 Paul A. Bristow
*
* 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 very simple program illustrates how to use the
* `boost/math/nonfinite_num_facets.hpp` trapping output of infinity and/or NaNs.
*
\file

\brief A very simple example of using non_finite_num facet for
trapping output of infinity and/or NaNs.

\note To actually get an exception throw by the iostream library
one must enable exceptions.
  `oss.exceptions(std::ios_base::failbit | std::ios_base::badbit);`
\note Which bit is set is implementation dependent, so enable exceptions for both.

This is a fairly brutal method of catching nonfinites on output,
but may suit some applications.

*/

#ifdef _MSC_VER
#   pragma warning(disable : 4127) // conditional expression is constant.
// assumes C++ exceptions enabled /EHsc
#endif

#include <boost/cstdint.hpp>
#include <boost/math/special_functions/nonfinite_num_facets.hpp>

#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::hex;
#include <exception>
#include <limits> // numeric_limits
using std::numeric_limits;

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

  std::cout << "nonfinite_num_facet_trap.cpp" << std::endl;

  const double inf = +std::numeric_limits<double>::infinity ();
  const double nan = +std::numeric_limits<double>::quiet_NaN ();

  { // Output infinity and NaN with default flags (no trapping).
    std::ostringstream oss;
    std::locale default_locale (std::locale::classic ());
    std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>);
    oss.imbue (C99_out_locale);
    oss.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    oss << inf <<  ' ' << nan;
    cout << "oss.rdstate()  = " << hex << oss.rdstate() << endl; // 0
    cout << "os.str() = " << oss.str() << endl; // os.str() = inf nan
  }

  try
  { // // Output infinity with flags set to trap and catch any infinity.
    std::ostringstream oss;
    std::locale default_locale (std::locale::classic ());
    std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>(trap_infinity));
    oss.imbue (C99_out_locale);
    oss.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    // Note that which bit is set is implementation dependent, so enable exceptions for both.
    oss << inf;
    cout << "oss.rdstate()  = " << hex << oss.rdstate() << endl;
    cout << "oss.str() = " << oss.str() << endl;
  }
  catch(const std::ios_base::failure& e)
  { // Expect "Infinity".
    std::cout << "\n""Message from thrown exception was: " << e.what() << std::endl;
  }

  try
  { // // Output NaN with flags set to catch any NaNs.
    std::ostringstream oss;
    std::locale default_locale (std::locale::classic ());
    std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>(trap_nan));
    oss.imbue (C99_out_locale);
    oss.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    // Note that which bit is set is implementation dependent, so enable exceptions for both.
    oss << nan;
    cout << "oss.str() = " << oss.str() << endl;
  }
  catch(const std::ios_base::failure& e)
  { // Expect "Infinity".
    std::cout << "\n""Message from thrown exception was: " << e.what() << std::endl;
 }

  return 0; // end of nonfinite_num_facet_trap.cpp
} // int main()

/*

Output:

  nonfinite_num_facet_trap.cpp
  oss.rdstate()  = 0
  os.str() = inf nan

  Message from thrown exception was: Infinity

  Message from thrown exception was: NaN

*/


#include "glview.h"
#include "gldrow.h"
#include "workspace.h"
#include <QtMath>

#include <Eigen/Geometry>
#include <Eigen/Core>
#include <Eigen/Dense>

using namespace Eigen;

GLView::GLView(QWidget *parent)
{

}

GLView::~GLView()
{

}

void GLView::initializeGL()
{
    initializeOpenGLFunctions();

    glEnable(GL_TEXTURE_2D);
    glShadeModel( GL_SMOOTH );
    glClearColor( 0.0, 0.0, 0.0, 0.0 );
    glClearDepth( 1.0 );
    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LEQUAL );
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

    cameraInit(10,30,4.0f);
}

void GLView::updateGL()
{

}

void GLView::paintGL()
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt (eye[0],      eye[1],     eye[2],
               center[0],   center[1],  center[2],
               up[0],       up[1],      up[2]);

    glPushMatrix();

    //欧拉角角度不一致，需要转换一下

    glRotatef(-rol, 1, 0, 0);
    glRotatef(pit, 0, 1, 0);
    glRotatef(yaw, 0, 0, 1);

    GLDrow::DrowCube();

    glPopMatrix();

    glPushMatrix();
    glTranslatef(0.0,0.0,-0.8);//下移
    GLDrow::DrowGrid();
    glPopMatrix();

    QMetaObject::invokeMethod(this,"update",Qt::QueuedConnection);

}

void GLView::resizeGL(int w, int h)
{
    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLfloat) w/(GLfloat) h, 0.1, 100.0);

    cameraTurn(yawCam,pitchCam,farCam);

    //DBG("resizeGL");

}

void GLView::setAngle(float rol, float pit, float yaw)
{
    this->rol = rol;
    this->pit = pit;
    this->yaw = yaw;
}

void GLView::cameraInit(double yaw, double pitch, double R_long)
{

    yawCam      = yaw;
    pitchCam    = pitch;
    farCam      = R_long;
}

void GLView::cameraTurn(double yaw, double pitch, double R_long)
{

    if (pitch > 90)
        pitch = 90;
    else if (pitch < -90)
        pitch = -90;

    double angle_yaw    = yaw * M_PI / 180;
    double angle_pitch  = pitch * M_PI / 180;

    Vector3d v(0,1,0);           //{ { 0 }, { 1 }, { 0 } };
    Vector3d v_top(0,0,1);       // { { 0 }, { 0 }, { 1 } };
    Vector3d yaw_k(0,0,1);       // { { 0 }, { 0 }, { 1 } };
    Vector3d pitch_k(1,0,0);     // { { 1 }, { 0 }, { 0 } };

    Matrix3d E;
    E << 1,0,0,
         0,1,0,
         0,0,1;

    Matrix3d G_yaw;
    G_yaw <<    0,          -yaw_k[2],  yaw_k[1],
                yaw_k[2],   0,          -yaw_k[0],
                -yaw_k[1],  yaw_k[0],   0;

    v = E * qCos(angle_yaw) * v + (1 - qCos(angle_yaw)) * yaw_k * yaw_k.transpose() * v + qSin(angle_yaw) * G_yaw * v;
    pitch_k = E * qCos(angle_yaw) * pitch_k + (1 - qCos(angle_yaw)) * yaw_k * yaw_k.transpose() * pitch_k + qSin(angle_yaw) * G_yaw * pitch_k;

    Matrix3d G_pitch;
    G_pitch <<  0,          -pitch_k[2],    pitch_k[1],
                pitch_k[2], 0,              -pitch_k[0],
                -pitch_k[1],pitch_k[0],     0;

    v = E * qCos(angle_pitch) * v + (1 - qCos(angle_pitch)) * pitch_k * pitch_k.transpose() * v + qSin(angle_pitch) * G_pitch * v;
    v = v * R_long;

    pitch_k <<  1,0,0;

    v_top = E * qCos(angle_yaw) * v_top + (1 - qCos(angle_yaw)) * yaw_k * yaw_k.transpose() * v_top + qSin(angle_yaw) * G_yaw * v_top;
    pitch_k = E * qCos(angle_yaw) * pitch_k + (1 - qCos(angle_yaw)) * yaw_k * yaw_k.transpose() * pitch_k + qSin(angle_yaw) * G_yaw * pitch_k;

    G_pitch <<  0,          -pitch_k[2],    pitch_k[1],
                pitch_k[2], 0,              -pitch_k[0],
                -pitch_k[1],pitch_k[0],     0;

    v_top = E * qCos(angle_pitch) * v_top + (1 - qCos(angle_pitch)) * pitch_k * pitch_k.transpose() * v_top + qSin(angle_pitch) * G_pitch * v_top;

    eye[0] = v[0];
    eye[1] = v[1];
    eye[2] = v[2];
    center[0] = 0;
    center[1] = 0;
    center[2] = 0;
    up[0] = v_top[0];
    up[1] = v_top[1];
    up[2] = v_top[2];

    //DBG("yawCam:%0.2f\tpitchCam:%0.2f\tfarCam:%0.2f\t",yaw,pitch,R_long);
}

void GLView::mousePressEvent(QMouseEvent*event){
    if(event->buttons()==Qt::LeftButton){               //如果鼠标按下的是左键
        clickX = event->globalX();
        clickY = event->globalY();
        //DBG("LeftButton %d %d",event->globalX(),event->globalY());
    }else if(event->buttons()==Qt::RightButton){         //如果鼠标按下的是右键
        //DBG("RightButton %d %d",event->globalX(),event->globalY());
    }
}

void GLView::mouseMoveEvent(QMouseEvent*event){
    if(event->buttons()==Qt::LeftButton){//如果鼠标按下的是左键
        //DBG("mouseMoveEvent %d %d",event->globalX(),event->globalY());

        if(clickX != event->globalX())
        {
            yawCam += (clickX-event->globalX()) * 1.0;
            clickX = event->globalX();
        }

        if(clickY != event->globalY())
        {
            pitchCam -= (clickY-event->globalY()) * 1.0;
            clickY = event->globalY();
        }

        cameraTurn(yawCam,pitchCam,farCam);

    }
}

void GLView::mouseReleaseEvent(QMouseEvent*event){

}

void GLView::mouseDoubleClickEvent(QMouseEvent*event){
}

void GLView::wheelEvent(QWheelEvent*event){

    DBG("wheelEvent %d",event->delta());

    if(event->delta() > 0)
    {
        farCam -= 0.1;
    }
    else{
        farCam += 0.1;
    }

    cameraTurn(yawCam,pitchCam,farCam);

}


#include <scitbx/array_family/boost_python/flex_fwd.h>

#include <boost/python/class.hpp>
#include <scitbx/math/golay.h>
#include <scitbx/boost_python/iterator_wrappers.h>

namespace scitbx { namespace math {

namespace {

  struct golay_24_12_generator_wrappers
  {
    typedef golay_24_12_generator<> w_t;

    static af::tiny<int, 24>
    next(w_t& o)
    {
      if (o.at_end()) {
        PyErr_SetString(PyExc_StopIteration,
          "golay_24_12_generator is exhausted.");
        boost::python::throw_error_already_set();
      }
      return o.next();
    }

    static void
    wrap()
    {
      using namespace boost::python;
      class_<w_t>("golay_24_12_generator")
        .def("at_end", &w_t::at_end)
        .def("next", next)
        .def("__next__", next)
        .def("__iter__", boost_python::pass_through)
      ;
    }
  };

} // namespace <anonymous>

namespace boost_python {

  void wrap_golay()
  {
    golay_24_12_generator_wrappers::wrap();
  }

}}} // namespace scitbx::math::boost_python


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#include <iostream>
#include <boost/numeric/mtl/mtl.hpp>
#include <boost/numeric/itl/itl.hpp>

int main()
{
    // For a more realistic example set sz to 1000 or larger
    const int size = 3, N = size * size;

    typedef mtl::compressed2D<double>  matrix_type;
    mtl::compressed2D<double>          A(N, N);
    laplacian_setup(A, size, size);

    itl::pc::ic_0<matrix_type, float>  P(A);
    mtl::dense_vector<double>          x(N), y, yc(N);
    iota(x);
    yc= 1.03194,1.60198,1.45357,2.5258,3.55386,3.16,2.91787,4.09338,3.81335;

    std::cout << x << '\n';
    y= solve(P, x);
    std::cout << y << '\n';

    MTL_THROW_IF(two_norm(mtl::dense_vector<double>(y - yc)) > 0.001,
		 mtl::logic_error("IC(0) doesn't yield expected result"));
    return 0;
}


//
//  torus.cpp
//
//
//  Created by Protoss Probe on 2017/04/09.
//  Copyright © 2016-2017年 probe. All rights reserved.
//

#include "poly_run.hpp"
#include "poly_grav.hpp"
#include <boost/array.hpp>
#include <cmath>
#include <iostream>
#include <string>

using namespace std;

class Particle {
  public:
    Particle() = default;
    ~Particle() = default;
    Particle(pos position) : r(position[0]), z(position[1]) {}
    Particle(state_type5 state)
        : r(state[0]), z(state[1]), r_dot(state[2]), z_dot(state[3]),
          lam_dot(state[4]) {}
    Particle(state_type5 state, double time)
        : r(state[0]), z(state[1]), r_dot(state[2]), z_dot(state[3]),
          lam_dot(state[4]), t(time) {}

    double r = 0.0, z = 0.0, r_dot = 0.0, z_dot = 0.0, lam_dot = 0.0, t = 0.0;

    state_type5 convert2state() const { return {r, z, r_dot, z_dot, lam_dot}; }
    pos convert2pos() const { return {r, z}; }
    vel convert2vel() const { return {r_dot, z_dot, lam_dot}; }
};

int main(int argc, char *argv[]) {
    string filename(argv[1]);

    PolyGrav poly(filename);

    poly.init();
    cout << poly.vert_n << '\t' << poly.face_n << '\t' << poly.edge_n << endl;
    poly.principle_axes();
    poly.export_3d_txt("assets/" + filename + "_prin.txt", 'd');

    vec3 pos;
    double x = 1.1;
    // double real = -1 / x;
    // poly.co = -1 / (4. / 3. * M_PI) * 0.5;

    const clock_t start = clock();
    pos = {{x, 0, 0}};
    // for (double i = 1.1; i < 3.0; i = i + 0.1) {
    //     pos[0] = i;
    //     cout << endl;
    //     cout << setprecision(12) << -1 / i << endl;
    //     cout << poly.potential(pos) << endl;
    //     cout << (-1 / i - poly.potential(pos)) / (-1 / i) << endl;
    // }
    double value = poly.potential(pos);
    cout << endl
         << "Cpu Time: "
         << static_cast<double>(clock() - start) / CLOCKS_PER_SEC << endl;
    cout << endl << "------------" << endl;
    // cout << "Real : " << real << endl;
    cout << "Poly Value : " << value << endl;
    // cout << "Ratio : " << real / value << endl;
    cout << "------------" << endl;
}


/* boost random/extreme_value_distribution.hpp header file
 *
 * Copyright Steven Watanabe 2010
 * 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: extreme_value_distribution.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $
 */

#ifndef BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP
#define BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP

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

namespace boost {
namespace random {

/**
 * The extreme value distribution is a real valued distribution with two
 * parameters a and b.
 *
 * It has \f$\displaystyle p(x) = \frac{1}{b}e^{\frac{a-x}{b} - e^\frac{a-x}{b}}\f$.
 */
template<class RealType = double>
class extreme_value_distribution {
public:
    typedef RealType result_type;
    typedef RealType input_type;

    class param_type {
    public:
        typedef extreme_value_distribution distribution_type;

        /**
         * Constructs a @c param_type from the "a" and "b" parameters
         * of the distribution.
         *
         * Requires: b > 0
         */
        explicit param_type(RealType a_arg = 1.0, RealType b_arg = 1.0)
          : _a(a_arg), _b(b_arg)
        {}

        /** Returns the "a" parameter of the distribtuion. */
        RealType a() const { return _a; }
        /** Returns the "b" parameter of the distribution. */
        RealType b() const { return _b; }

        /** Writes a @c param_type to a @c std::ostream. */
        BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
        { os << parm._a << ' ' << parm._b; return os; }

        /** Reads a @c param_type from a @c std::istream. */
        BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
        { is >> parm._a >> std::ws >> parm._b; return is; }

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

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

    private:
        RealType _a;
        RealType _b;
    };

    /**
     * Constructs an @c extreme_value_distribution from its "a" and "b" parameters.
     *
     * Requires: b > 0
     */
    explicit extreme_value_distribution(RealType a_arg = 1.0, RealType b_arg = 1.0)
      : _a(a_arg), _b(b_arg)
    {}
    /** Constructs an @c extreme_value_distribution from its parameters. */
    explicit extreme_value_distribution(const param_type& parm)
      : _a(parm.a()), _b(parm.b())
    {}

    /**
     * Returns a random variate distributed according to the
     * @c extreme_value_distribution.
     */
    template<class URNG>
    RealType operator()(URNG& urng) const
    {
        using std::log;
        return _a - log(-log(uniform_01<RealType>()(urng))) * _b;
    }

    /**
     * Returns a random variate distributed accordint to the extreme
     * value distribution with parameters specified by @c param.
     */
    template<class URNG>
    RealType operator()(URNG& urng, const param_type& parm) const
    {
        return extreme_value_distribution(parm)(urng);
    }

    /** Returns the "a" parameter of the distribution. */
    RealType a() const { return _a; }
    /** Returns the "b" parameter of the distribution. */
    RealType b() const { return _b; }

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

    /** Returns the parameters of the distribution. */
    param_type param() const { return param_type(_a, _b); }
    /** Sets the parameters of the distribution. */
    void param(const param_type& parm)
    {
        _a = parm.a();
        _b = parm.b();
    }

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

    /** Writes an @c extreme_value_distribution to a @c std::ostream. */
    BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, extreme_value_distribution, wd)
    {
        os << wd.param();
        return os;
    }

    /** Reads an @c extreme_value_distribution from a @c std::istream. */
    BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, extreme_value_distribution, wd)
    {
        param_type parm;
        if(is >> parm) {
            wd.param(parm);
        }
        return is;
    }

    /**
     * Returns true if the two instances of @c extreme_value_distribution will
     * return identical sequences of values given equal generators.
     */
    BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(extreme_value_distribution, lhs, rhs)
    { return lhs._a == rhs._a && lhs._b == rhs._b; }

    /**
     * Returns true if the two instances of @c extreme_value_distribution will
     * return different sequences of values given equal generators.
     */
    BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(extreme_value_distribution)

private:
    RealType _a;
    RealType _b;
};

} // namespace random
} // namespace boost

#endif // BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP


#include <boost/test/unit_test.hpp>

#include "logs.h"
#include "route.h"
#include "track.h"

/*Test that can't be done
because of how the averageSpeed function gets it's data there
are a dealing with negative distance and negative time test (as you can't have
two positions with a negative distance or negative time between them)

*/

using namespace GPS;

BOOST_AUTO_TEST_SUITE( average_speed )

bool correctFileName = true;

BOOST_AUTO_TEST_CASE(divide_with_zero_test)
{
	/*
	Speed = distance divide by time and if distance or time are zero
	then that could cause a problem for the averageSpeed function
	*/

        Track track = Track(LogFiles::GPXTracksDir + "TestNT.gpx", correctFileName);//NT means no time

	//no time test
	BOOST_CHECK_THROW(Track.averageSpeed(true), std::logic_error);

        Track track = Track(LogFiles::GPXTracksDir + "TestND.gpx", correctFileName);//ND means no distance

	//no distance test
	BOOST_CHECK_EQUALS(Track.averageSpeed(true), 0);

}

BOOST_AUTO_TEST_CASE(normal_operation)
{
	/*
		This test is design to see of the function
		can work with the kind of data that it would get
		normally.

		TestNU.gpx has a
		total distance 10
		total rests 2
		total time 10
	*/

        Track track = Track(LogFiles::GPXTracksDir + "TestNU.gpx", correctFileName);//NU means Normal use

	//distance is 10 and time is 10

	//with rests
	/*calculation is 10 / 10 = 1 */
	BOOST_CHECK_EQUALS(Track.averageSpeed(true), 1);

	//without rests
	/*
	calculation is 10 / 8 = 1.25*/
	BOOST_CHECK_EQUALS(Track.averageSpeed(false), 1.25);

}

BOOST_AUTO_TEST_CASE(small_speed_test)
{
	/*
	This test ensures that the result of average speed remains
	accurate to the greatest possible decimal place
	*/

        Track track = Track(LogFiles::GPXTracksDir + "TestSS.gpx", correctFileName);//SS means small speed

	/*
	The reason that it is a greater than test is to check that the
	function is getting a result that is greater than 0. Why
	because the most likely problem that could occur with this function
	is that the result will be rounded to zero.

	*/
	BOOST_CHECK_GT(Track.averageSpeed(true), 0);

	BOOST_CHECK_EQUALS(Track.averageSpeed(true), 0.0000000000001);
}

/*
BOOST_AUTO_TEST_CASE(no_movement_Test)
{
	this test is the same as the no distance test
        Track track = Track(LogFiles::GPXTracksDir + "TestNM.gpx", correctFileName);

	BOOST_CHECK_EQUALS(Track.averageSpeed(true), 0);

}*/

BOOST_AUTO_TEST_CASE(is_route_test)
{

        Track track = Track(LogFiles::GPXRoutesDir + "ABCD.gpx", correctFileName);

	/*
	It is highly possible that a correctly formatted route could be used
	instead of a track because gps program is designed to use both.
	*/

	BOOST_CHECK_THROW(Track.averageSpeed(true), std::invalide_argument);

}

BOOST_AUTO_TEST_CASE(max_distance_test)
{
	bool isFileName = true;
        Track track = Track(LogFiles::GPXTracksDir + "TestVD.gpx", correctFileName);//VD means vast distance

	/*
	This test if the function can calculate large speeds however
	due to the size of the earth it is impossible to get to
	generate a speed that would meet the max value of a double
	why because any two points on earth can't be more than about 20000
	miles away and the smallest period of time is 1 because seconds is an unsigned integer
	which can't be negative
	*/

	BOOST_CHECK_EQUALS(Track.averageSpeed(true), 12430);

}

BOOST_AUTO_TEST_SUITE_END()


/*!
@file
Defines `boost::hana::Monoid`.

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

#ifndef BOOST_HANA_MONOID_HPP
#define BOOST_HANA_MONOID_HPP

#include <boost/hana/fwd/monoid.hpp>

#include <boost/hana/bool.hpp>
#include <boost/hana/constant.hpp>
#include <boost/hana/core/common.hpp>
#include <boost/hana/core/convert.hpp>
#include <boost/hana/core/datatype.hpp>
#include <boost/hana/core/default.hpp>
#include <boost/hana/core/models.hpp>
#include <boost/hana/core/operators.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/core/wrong.hpp>
#include <boost/hana/detail/has_common_embedding.hpp>
#include <boost/hana/detail/std/enable_if.hpp>
#include <boost/hana/detail/std/forward.hpp>
#include <boost/hana/detail/std/is_arithmetic.hpp>
#include <boost/hana/detail/std/is_same.hpp>

namespace boost { namespace hana {
    //////////////////////////////////////////////////////////////////////////
    // Operators
    //////////////////////////////////////////////////////////////////////////
    namespace operators {
        template <typename X, typename Y, typename = typename detail::std::enable_if<
            has_operator<datatype_t<X>, decltype(plus)>::value ||
            has_operator<datatype_t<Y>, decltype(plus)>::value
        >::type>
        constexpr decltype(auto) operator+(X&& x, Y&& y) {
            return hana::plus(detail::std::forward<X>(x),
                              detail::std::forward<Y>(y));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // plus
    //////////////////////////////////////////////////////////////////////////
    template <typename T, typename U, typename>
    struct plus_impl : plus_impl<T, U, when<true>> { };

    template <typename T, typename U, bool condition>
    struct plus_impl<T, U, when<condition>> : default_ {
        template <typename X, typename Y>
        static constexpr void apply(X&&, Y&&) {
            static_assert(wrong<plus_impl<T, U>, X, Y>{},
            "no definition of boost::hana::plus for the given data types");
        }
    };

    // Cross-type overload
    template <typename T, typename U>
    struct plus_impl<T, U, when<
        detail::has_nontrivial_common_embedding<Monoid, T, U>{}
    >> {
        using C = typename common<T, U>::type;
        template <typename X, typename Y>
        static constexpr decltype(auto) apply(X&& x, Y&& y) {
            return hana::plus(to<C>(detail::std::forward<X>(x)),
                              to<C>(detail::std::forward<Y>(y)));
        }
    };

    //////////////////////////////////////////////////////////////////////////
    // zero
    //////////////////////////////////////////////////////////////////////////
    template <typename M, typename>
    struct zero_impl : zero_impl<M, when<true>> { };

    template <typename M, bool condition>
    struct zero_impl<M, when<condition>> : default_ {
        static void apply(...) { }
    };

    //////////////////////////////////////////////////////////////////////////
    // models
    //////////////////////////////////////////////////////////////////////////
    template <typename M>
    struct models_impl<Monoid, M>
        : _integral_constant<bool,
            !is_default<zero_impl<M>>{} &&
            !is_default<plus_impl<M, M>>{}
        >
    { };

    //////////////////////////////////////////////////////////////////////////
    // Model for non-boolean arithmetic data types
    //////////////////////////////////////////////////////////////////////////
    template <typename T>
    struct plus_impl<T, T, when<
        detail::std::is_arithmetic<T>{} && !detail::std::is_same<T, bool>{}
    >> {
        template <typename X, typename Y>
        static constexpr decltype(auto) apply(X&& x, Y&& y)
        { return detail::std::forward<X>(x) + detail::std::forward<Y>(y); }
    };

    template <typename T>
    struct zero_impl<T, when<
        detail::std::is_arithmetic<T>{} && !detail::std::is_same<T, bool>{}
    >> {
        static constexpr T apply()
        { return static_cast<T>(0); }
    };

    //////////////////////////////////////////////////////////////////////////
    // Model for Constants over a Monoid
    //////////////////////////////////////////////////////////////////////////
    template <typename C>
    struct plus_impl<C, C, when<
        _models<Constant, C>{} && _models<Monoid, typename C::value_type>{}
    >> {
        using T = typename C::value_type;
        template <typename X, typename Y>
        struct _constant {
            static constexpr decltype(auto) get() {
                return boost::hana::plus(boost::hana::value<X>(),
                                         boost::hana::value<Y>());
            }
            struct hana { using datatype = detail::CanonicalConstant<T>; };
        };
        template <typename X, typename Y>
        static constexpr decltype(auto) apply(X const&, Y const&)
        { return to<C>(_constant<X, Y>{}); }
    };

    template <typename C>
    struct zero_impl<C, when<
        _models<Constant, C>{} && _models<Monoid, typename C::value_type>{}
    >> {
        using T = typename C::value_type;
        struct _constant {
            static constexpr decltype(auto) get()
            { return boost::hana::zero<T>(); }
            struct hana { using datatype = detail::CanonicalConstant<T>; };
        };
        static constexpr decltype(auto) apply()
        { return to<C>(_constant{}); }
    };
}} // end namespace boost::hana

#endif // !BOOST_HANA_MONOID_HPP


/*    Copyright (c) 2010-2019, Delft University of Technology
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 *
 */

#include <Eigen/Geometry>

#include "Tudat/Astrodynamics/Gravitation/directTidalDissipationAcceleration.h"

namespace tudat
{

namespace gravitation
{

//! Function to compute the acceleration acting on a satellite due to tidal deformation caused by this satellite on host planet.
Eigen::Vector3d computeDirectTidalAccelerationDueToTideOnPlanet(
        const Eigen::Vector6d relativeStateOfBodyExertingTide, const Eigen::Vector3d planetAngularVelocityVector,
        const double currentTidalAccelerationMultiplier, const double timeLag,
        const bool includeDirectRadialComponent )
{
    Eigen::Vector3d relativePosition = relativeStateOfBodyExertingTide.segment( 0, 3 );
    Eigen::Vector3d relativeVelocity = relativeStateOfBodyExertingTide.segment( 3, 3 );

    double distance = relativePosition.norm( );
    double distanceSquared = distance * distance;
    double radialComponentMultiplier = ( includeDirectRadialComponent == true ) ? 1.0 : 0.0;

    return currentTidalAccelerationMultiplier * (
                 radialComponentMultiplier * relativePosition + timeLag * (
                    2.0 * ( relativePosition.dot( relativeVelocity ) * relativePosition / distanceSquared ) +
                    ( relativePosition.cross( planetAngularVelocityVector ) + relativeVelocity ) ) );

}

//! Function to compute the acceleration acting on a satellite due to tidal deformation caused in this satellite by host planet.
Eigen::Vector3d computeDirectTidalAccelerationDueToTideOnSatellite(
        const Eigen::Vector6d relativeStateOfBodyExertingTide,
        const double currentTidalAccelerationMultiplier,
        const double timeLag,const bool includeDirectRadialComponent )
{
    Eigen::Vector3d relativePosition = relativeStateOfBodyExertingTide.segment( 0, 3 );
    Eigen::Vector3d relativeVelocity = relativeStateOfBodyExertingTide.segment( 3, 3 );

    double distance = relativePosition.norm( );
    double distanceSquared = distance * distance;
    double radialComponentMultiplier = ( includeDirectRadialComponent == true ) ? 1.0 : 0.0;

    return currentTidalAccelerationMultiplier * (
                 2.0 * radialComponentMultiplier * relativePosition + timeLag * (
                   7.0 * relativePosition.dot( relativeVelocity ) * relativePosition / distanceSquared ) );

}

//! Function to retrieve all DirectTidalDissipationAcceleration from an AccelerationMap, for specific deformed/deforming bodies
std::vector< std::shared_ptr< DirectTidalDissipationAcceleration > > getTidalDissipationAccelerationModels(
        const basic_astrodynamics::AccelerationMap accelerationModelList, const std::string bodyBeingDeformed,
        const std::vector< std::string >& bodiesCausingDeformation )
{
    // Iterate over all bodies undergoing acceleration
    std::vector< std::shared_ptr< DirectTidalDissipationAcceleration > > selectedDissipationModels;
    for( basic_astrodynamics::AccelerationMap::const_iterator modelIterator1 = accelerationModelList.begin( );
         modelIterator1 != accelerationModelList.end( ); modelIterator1++ )
    {
        std::string bodyUndergoingAcceleration = modelIterator1->first;

        // Iterate over all bodies exerting acceleration
        basic_astrodynamics::SingleBodyAccelerationMap singleBodyAccelerationList = modelIterator1->second;
        for( basic_astrodynamics::SingleBodyAccelerationMap::const_iterator modelIterator2 = singleBodyAccelerationList.begin( );
             modelIterator2 != singleBodyAccelerationList.end( ); modelIterator2++ )
        {
            std::string bodyExertingAcceleration = modelIterator2->first;

            // Iterate over all accelerations being exerted by bodyExertingAcceleration on bodyUndergoingAcceleration
            for( unsigned int i = 0; i < modelIterator2->second.size( ); i++ )
            {
                // Check if acceleration model is due to tidal dissipations
                std::shared_ptr< DirectTidalDissipationAcceleration > currentDissipationAcceleration =
                    std::dynamic_pointer_cast< DirectTidalDissipationAcceleration >( modelIterator2->second.at( i ) );
                if( currentDissipationAcceleration != nullptr )
                {
                    // Check whether model correspionds to input requirements
                    if( currentDissipationAcceleration->getModelTideOnPlanet( ) &&
                            ( bodyExertingAcceleration == bodyBeingDeformed ) )
                    {
                        if( ( std::find( bodiesCausingDeformation.begin( ), bodiesCausingDeformation.end( ),
                                       bodyUndergoingAcceleration ) != bodiesCausingDeformation.end( ) ) ||
                                bodiesCausingDeformation.size( ) == 0 )
                        {
                            selectedDissipationModels.push_back( currentDissipationAcceleration );
                        }
                    }
                    else if( !currentDissipationAcceleration->getModelTideOnPlanet( ) &&
                             ( bodyUndergoingAcceleration == bodyBeingDeformed ) )
                    {
                        if( ( std::find( bodiesCausingDeformation.begin( ), bodiesCausingDeformation.end( ),
                                       bodyExertingAcceleration ) != bodiesCausingDeformation.end( ) ) ||
                                bodiesCausingDeformation.size( ) == 0 )
                        {
                            selectedDissipationModels.push_back( currentDissipationAcceleration );
                        }
                    }
                }
            }
        }
    }
    return selectedDissipationModels;
}

} // namespace gravitation

} // namespace tudat


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

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

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

// #include <boost/simd/constant/expx2c1.hpp>
// #include <boost/simd/constant/expx2c2.hpp>
#include <boost/simd/constant/half.hpp>
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/maxlog.hpp>
#include <boost/simd/constant/real.hpp>
#include <boost/simd/constant/two.hpp>
#include <boost/simd/function/scalar/abs.hpp>
#include <boost/simd/function/scalar/exp.hpp>
#include <boost/simd/function/scalar/floor.hpp>
#include <boost/simd/function/scalar/fma.hpp>
#include <boost/simd/function/scalar/signnz.hpp>
#include <boost/simd/function/scalar/sqr.hpp>
#include <boost/dispatch/function/overload.hpp>
#include <boost/config.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  namespace bs = boost::simd;
  BOOST_DISPATCH_OVERLOAD ( expx2_
                          , (typename A0)
                          , bd::cpu_
                          , bd::scalar_< bd::floating_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( A0 a0) const BOOST_NOEXCEPT
    {
    #ifndef BOOST_SIMD_NO_INFINITIES
      if (is_inf(a0)) return Inf<A0>();
    #endif
      A0 x =  bs::abs(a0);
      const A0 Expx2c1 = Real<A0, 0x4060000000000000ull, 0x42000000UL>();
      const A0 Expx2c2 = Real<A0, 0x3f80000000000000ull, 0x3d000000UL>();
      /* Represent x as an exact multiple of 1/32 plus a residual.  */
      A0 m = Expx2c1 * bs::floor(fma(Expx2c2, x, Half<A0>()));
      x -= m;
      /* x**2 = m**2 + 2mf + f**2 */
      A0 u = sqr(m);
      A0 u1 = fma(Two<A0>() * m, x, sqr(x));
      if ((u+u1) > bs::Maxlog<A0>()) return Inf<A0>();
      /* u is exact, u1 is small.  */
      return exp(u)*exp(u1);
    }
  };

  BOOST_DISPATCH_OVERLOAD ( expx2_
                          , (typename A0)
                          , bd::cpu_
                          , bd::scalar_<bd::floating_<A0> >
                          , bd::scalar_<bd::floating_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( A0 a0, A0 s) const BOOST_NOEXCEPT
    {
      const A0 Expx2c1 = Real<A0, 0x4060000000000000ull, 0x42000000UL>();
      const A0 Expx2c2 = Real<A0, 0x3f80000000000000ull, 0x3d000000UL>();
      A0 sgn =  signnz(s);
      A0 x =  a0*sgn;
    #ifndef BOOST_SIMD_NO_INFINITIES
      if (bs::is_inf(a0)) return bs::Inf<A0>();
    #endif
      // Represent x as an exact multiple of 1/32 plus a residual.
      A0 m = Expx2c1*floor(fma(Expx2c2, x, Half<A0>()));
      A0 f =  x-m;
      // x**2 = m**2 + 2mf + f**2
      A0 u = sgn*sqr(m);
      A0 u1 = sgn*fma(m+m,f,sqr(f));
      // u is exact, u1 is small.
      if (u+u1 > Maxlog<A0>()) return bs::Inf<A0>();
      return exp(u)*exp(u1);
    }
  };
} } }

#endif


#include "coord.h"

#include "adler32.h"
#include "composite-imp.h"
#include "float.h"

#include <boost/static_assert.hpp>

using namespace std;

class Coords {
public:
  typedef Coord T1;
  typedef Coord2 T2;
  typedef Coord4 T4;

  static Coord atan2(Coord a, Coord b) { return Coord(float(::atan2(a.toFloat(), b.toFloat()))); }
  static Coord sin(Coord a) { return cfsin(a); };
  static Coord cos(Coord a) { return cfcos(a); };

  static const Coord tPI;
};
const Coord Coords::tPI = COORDPI;

string Coord::rawstr() const {
  return StringPrintf("%08x%08x", (unsigned int)(d >> 32), (unsigned int)d);
}

Coord coordFromRawstr(const string &lhs) {
  if(lhs.size() != 16) {
    dprintf("%s\n", lhs.c_str());
    CHECK(lhs.size() == 16);
  }
  for(int i = 0; i < lhs.size(); i++)
    CHECK(isdigit(lhs[i]) || (lhs[i] >= 'a' && lhs[i] <= 'f'));
  long long dd = 0;
  for(int i = 0; i < 16; i++) {
    dd *= 16;
    if(isdigit(lhs[i]))
      dd += lhs[i] - '0';
    else
      dd += lhs[i] - 'a' + 10;
  }
  CHECK(coordExplicit(dd).rawstr() == lhs);
  return coordExplicit(dd);
}

Float2 Coord2::toFloat() const { return Float2(x.toFloat(), y.toFloat()); }
Coord2::Coord2(const Float2 &rhs) : x(rhs.x), y(rhs.y) { };
string Coord2::rawstr() const {
  return StringPrintf("%s %s", x.rawstr().c_str(), y.rawstr().c_str());
}

Float4 Coord4::toFloat() const { return Float4(sx.toFloat(), sy.toFloat(), ex.toFloat(), ey.toFloat()); }
string Coord4::rawstr() const {
  return StringPrintf("%s %s %s %s", sx.rawstr().c_str(), sy.rawstr().c_str(), ex.rawstr().c_str(), ey.rawstr().c_str());
}

Coord4::Coord4(const Float4 &rhs) : sx(rhs.sx), sy(rhs.sy), ex(rhs.ex), ey(rhs.ey) { }

/*************
 * Computational geometry
 */

Coord len(const Coord2 &in) { return Coord(len(in.toFloat())); };
Coord2 normalize(const Coord2 &in) { return imp_normalize<Coords>(in); };
Coord dot(const Coord2 &lhs, const Coord2 &rhs) { return lhs.x * rhs.x + lhs.y * rhs.y; };

Coord getAngle(const Coord2 &in) { return imp_getAngle<Coords>(in); };
Coord2 makeAngle(const Coord &in) { return imp_makeAngle<Coords>(in); };

int whichSide(const Coord4 &f4, const Coord2 &pta) { return imp_whichSide<Coords>(f4, pta); };

Coord distanceFromLine(const Coord4 &line, const Coord2 &pt) {
  Coord u = ((pt.x - line.sx) * (line.ex - line.sx) + (pt.y - line.sy) * (line.ey - line.sy)) / ((line.ex - line.sx) * (line.ex - line.sx) + (line.ey - line.sy) * (line.ey - line.sy));
  if(u < 0 || u > 1)
    return min(len(pt - Coord2(line.sx, line.sy)), len(pt - Coord2(line.ex, line.ey)));
  Coord2 ipt = Coord2(line.sx, line.sy) + Coord2(line.ex - line.sx, line.ey - line.sy) * u;
  return len(ipt - pt);
}

int inPath(const Coord2 &point, const vector<Coord2> &path) {
  return imp_inPath<Coords>(point, path);
};

bool roughInPath(const Coord2 &point, const vector<Coord2> &path, int goal) {
  int dx[] = {0, 0, 0, 1, -1, 1, 1, -1, -1};
  int dy[] = {0, 1, -1, 0, 0, 1, -1, 1, -1};
  for(int i = 0; i < 9; i++)
    if((bool)inPath(point + Coord2(dx[i], dy[i]) / 65536, path) == goal)
      return true;
  return false;
}

Coord2 getPointIn(const vector<Coord2> &path) {
  // TODO: find a point inside the polygon in a better fashion
  //GetDifferenceHandler CrashHandler(path, path);
  Coord2 pt;
  bool found = false;
  for(int j = 0; j < path.size() && !found; j++) {
    Coord2 pospt = (path[j] + path[(j + 1) % path.size()] + path[(j + 2) % path.size()]) / 3;
    if(inPath(pospt, path)) {
      pt = pospt;
      found = true;
    }
  }
  CHECK(found);
  return pt;
}

bool pathReversed(const vector<Coord2> &path) {
  return imp_pathReversed<Coords>(path);
}

int getPathRelation(const vector<Coord2> &lhs, const vector<Coord2> &rhs) {
  for(int i = 0; i < lhs.size(); i++) {
    int i2 = (i + 1) % lhs.size();
    for(int j = 0; j < rhs.size(); j++) {
      int j2 = (j + 1) % rhs.size();
      if(linelineintersect(Coord4(lhs[i], lhs[i2]), Coord4(rhs[j], rhs[j2])))
        return PR_INTERSECT;
    }
  }
  bool lir = inPath(getPointIn(lhs), rhs);
  bool ril = inPath(getPointIn(rhs), lhs);
  if(!lir && !ril) {
    return PR_SEPARATE;
  } else if(lir && !ril) {
    return PR_RHSENCLOSE;
  } else if(!lir && ril) {
    return PR_LHSENCLOSE;
  } else if(lir && ril && abs(getArea(lhs)) < abs(getArea(rhs))) {
    return PR_RHSENCLOSE;
  } else if(lir && ril && abs(getArea(lhs)) > abs(getArea(rhs))) {
    return PR_LHSENCLOSE;
  } else {
    // dammit, don't send the same two paths! we deny!
    CHECK(0);
  }
}

Coord getArea(const vector<Coord2> &are) { return imp_getArea<Coords>(are); }
Coord2 getCentroid(const vector<Coord2> &are) { return imp_getCentroid<Coords>(are); }
Coord getPerimeter(const vector<Coord2> &are) {
  Coord totperi = 0;
  for(int i = 0; i < are.size(); i++) {
    int j = (i + 1) % are.size();
    totperi += len(are[i] - are[j]);
  }
  return totperi;
}
Coord4 getBoundBox(const vector<Coord2> &are) {
  Coord4 bbox = startCBoundBox();
  for(int i = 0; i < are.size(); i++)
    addToBoundBox(&bbox, are[i]);
  CHECK(bbox.isNormalized());
  return bbox;
}

bool colinear(const Coord4 &line, const Coord2 &pt) {
  Coord koord = distanceFromLine(line, pt);
  return koord < Coord(0.00001f);
}

Coord2 reflect(const Coord2 &incoming, Coord normal) {
  return imp_reflect<Coords>(incoming, normal);
}
Coord reflect(Coord incoming, Coord normal) {
  return imp_reflect<Coords>(incoming, normal);
}

Coord ang_dist(Coord lhs, Coord rhs) {
  lhs = mod(lhs, COORDPI * 2);
  rhs = mod(rhs, COORDPI * 2);
  Coord v = abs(lhs - rhs);
  if(v > COORDPI)
    return COORDPI * 2 - v;
  else
    return v;
}
Coord ang_approach(const Coord &cur, const Coord &goal, const Coord &amount) {
  Coord jcur = mod(cur, COORDPI * 2);
  Coord jgoal = mod(goal, COORDPI * 2);
  if(abs(jcur - jgoal) > abs(jcur - (jgoal - COORDPI * 2))) {
    jgoal -= COORDPI * 2;
  } else if(abs(jcur - jgoal) > abs(jcur - (jgoal + COORDPI * 2))) {
    jgoal += COORDPI * 2;
  }
  CHECK(ang_dist(cur, goal) >= ang_dist(approach(jcur, jgoal, amount), goal));
  return approach(jcur, jgoal, amount);
}

/*************
 * Bounding box
 */

Coord4 startCBoundBox() { return imp_startBoundBox<Coords>(); };

void addToBoundBox(Coord4 *bbox, const Coord4 &rect) { return imp_addToBoundBox<Coords>(bbox, rect); };
void addToBoundBox(Coord4 *bbox, const vector<Coord2> &line) { return imp_addToBoundBox<Coords>(bbox, line); };

void expandBoundBox(Coord4 *bbox, Coord factor) { return imp_expandBoundBox<Coords>(bbox, factor); };

/*************
 * Math
 */

bool linelineintersect(const Coord4 &lhs, const Coord4 &rhs) { return imp_linelineintersect<Coords>(lhs, rhs); };
Coord linelineintersectpos(const Coord4 &lhs, const Coord4 &rhs) { return imp_linelineintersectpos<Coords>(lhs, rhs); };

Coord approach(Coord start, Coord target, Coord delta, Coord drag) {
  if(!(((start < 0) == (target < 0)) && start < target))
    delta += drag;
  return approach(start, target, delta);
}
Coord2 approach(Coord2 start, Coord2 target, Coord delta) {
  CHECK(delta >= 0);
  Coord2 diff = target - start;
  if(len(diff) <= delta)
    return target;
  return start + diff / len(diff) * delta;
}
Coord2 approach(Coord2 start, Coord2 target, Coord delta, Coord drag) {
  if(target == start)
    return target;
  if(len(start) == 0)
    return approach(start, target, delta);
  return approach(start, target, delta + drag * max(Coord(0), -dot(normalize(start), normalize(target - start))));
}

Coord2 rotate(const Coord2 &in, Coord ang) {
  return imp_rotate<Coords>(in, ang);
}

Coord mod(const Coord &a, const Coord &b) {
  if(a < Coord(0))
    return b - mod(-a, b);
  return coordExplicit(a.d % b.d);
}

Coord2 lerp(const Coord2 &lhs, const Coord2 &rhs, Coord dist) {
  return lhs + (rhs - lhs) * dist;
}
Coord2 lerp(const Coord4 &movement, Coord dist) {
  return lerp(movement.s(), movement.e(), dist);
}
Coord4 lerp(const Coord4 &lhs, const Coord4 &rhs, Coord dist) {
  return lhs + (rhs - lhs) * dist;
}

BOOST_STATIC_ASSERT(sizeof(Coord) == 8);
BOOST_STATIC_ASSERT(sizeof(Coord2) == 16);
BOOST_STATIC_ASSERT(sizeof(Coord4) == 32);

void adler(Adler32 *adl, const Coord &val) { adl->addBytes(&val, sizeof(val)); }
void adler(Adler32 *adl, const Coord2 &val) { adl->addBytes(&val, sizeof(val)); }
void adler(Adler32 *adl, const Coord4 &val) { adl->addBytes(&val, sizeof(val)); }
void adler(Adler32 *adl, const CPosInfo &val) {
  adler(adl, val.pos);
  adler(adl, val.d);
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision;
using namespace std;
int main() {
    cpp_int a, b, c; cin >> a >> b >> c;
    cpp_int ans = a * b * c;
    cout << ans % 1000000007 << endl;
}


#include <boost/geometry.hpp>

#include "snapping.h"

namespace myserver {

using namespace std;
using BgDegree = boost::geometry::cs::spherical_equatorial<boost::geometry::degree>;
using BgPoint = boost::geometry::model::point<double, 2, BgDegree>;
using RtreeValue = pair<BgPoint, string>;
using RTree = boost::geometry::index::rtree<RtreeValue, boost::geometry::index::linear<8>>;

static auto HAVERSINE = boost::geometry::strategy::distance::haversine<double>(6'371'000);
static RTree rtree;

void build_index(myserver::StopMap stops) {
    for (auto pair : stops) {
        auto id = pair.first;
        auto stop = pair.second;
        rtree.insert(make_pair(BgPoint{stop.lon, stop.lat}, id));
    }
}

tuple<string, double, double, float> get_closest_stop(double lon, double lat) {
    vector<RtreeValue> closest_stops;
    BgPoint point{lon, lat};
    rtree.query(boost::geometry::index::nearest(point, 1), back_inserter(closest_stops));
    auto closest_stop_id = closest_stops.front().second;
    auto closest_stop_loc = closest_stops.front().first;
    auto distance = boost::geometry::distance(closest_stop_loc, BgPoint{lon, lat}, HAVERSINE);
    return make_tuple(closest_stop_id, get<0>(closest_stop_loc), get<1>(closest_stop_loc), distance);
}

}  // namespace myserver


#include <boost/math/complex/fabs.hpp>