#include <Ziran/Math/Geometry/SimplexMesh.h>
#include <Ziran/CS/DataStructure/HashTable.h>
#include <Ziran/CS/Util/Debug.h>
#include <Eigen/Core>
#include <algorithm>
#include <array>
#include <queue>

namespace ZIRAN {

template <int dim>
void SimplexMesh<dim>::initializeBoundaryElements()
{
    HashTable<BIV, BIV> face_hash;
    size_t number_elements = indices.size();
    Faces faces;

    for (size_t i = 0; i < number_elements; i++) {
        //go through each element
        //and get all faces for each element
        getFaces(i, faces);

        //for each face, sort indices
        //if the set of indices does not exist, put in hash table
        // if the indices already exists, delete from hash table
        // all faces left are boundary faces
        for (size_t j = 0; j < faces.size(); j++) {
            BIV sorted = faces[j];
            std::sort(sorted.data(), sorted.data() + sorted.size());

            if (!face_hash.erase(sorted))
                face_hash.insert(sorted, faces[j]);
        }
    }
    boundary_indices.clear();
    for (auto it = face_hash.cbegin(); it != face_hash.cend(); it++) {
        boundary_indices.emplace_back(std::move(it->value));
    }
}

template <>
void SimplexMesh<1>::getFaces(
    const size_t element,
    std::array<Vector<int, 1>, 2>& result)
{
    int n0 = indices[element](0);
    int n1 = indices[element](1);
    result[0](0) = n0;
    result[1](0) = n1;
}

template <>
void SimplexMesh<2>::getFaces(
    const size_t element,
    std::array<Vector<int, 2>, 3>& result)
{
    int n0 = indices[element](0);
    int n1 = indices[element](1);
    int n2 = indices[element](2);
    result[0] = Vector<int, 2>(n0, n1);
    result[1] = Vector<int, 2>(n1, n2);
    result[2] = Vector<int, 2>(n2, n0);
}

template <>
void SimplexMesh<3>::getFaces(
    const size_t element,
    std::array<Vector<int, 3>, 4>& result)
{
    int n0 = indices[element](0);
    int n1 = indices[element](1);
    int n2 = indices[element](2);
    int n3 = indices[element](3);
    result[0] = Vector<int, 3>(n0, n1, n2);
    result[1] = Vector<int, 3>(n1, n2, n3);
    result[2] = Vector<int, 3>(n2, n3, n0);
    result[3] = Vector<int, 3>(n3, n0, n1);
}

template <>
void SimplexMesh<1>::constructListOfEdges(StdVector<EIV>& edge_list, HashTable<EIV, int>* edge_hash_ptr)
{

    HashTable<EIV, int> inner_edge_hash;
    if (!edge_hash_ptr)
        edge_hash_ptr = &inner_edge_hash;

    size_t number_elements = indices.size();
    Faces faces;

    edge_list.clear();

    EIV sorted;
    for (size_t i = 0; i < number_elements; ++i) {
        sorted = indices[i];
        std::sort(sorted.data(), sorted.data() + sorted.size());
        auto result = edge_hash_ptr->insert(sorted, (int)edge_list.size());

        if (result.inserted)
            edge_list.emplace_back(sorted);
    }
}

template <>
void SimplexMesh<2>::constructListOfEdges(StdVector<EIV>& edge_list, HashTable<EIV, int>* edge_hash_ptr)
{
    SimplexMesh<2>::constructListOfFaces(edge_list, edge_hash_ptr);
}

template <>
void SimplexMesh<3>::constructListOfEdges(StdVector<EIV>& edge_list, HashTable<EIV, int>* edge_hash_ptr)
{
    HashTable<EIV, int> inner_edge_hash;
    if (!edge_hash_ptr)
        edge_hash_ptr = &inner_edge_hash;

    size_t number_elements = indices.size();
    Faces faces;

    edge_list.clear();

    for (size_t i = 0; i < number_elements; i++) {
        getFaces(i, faces);

        for (size_t j = 0; j < faces.size(); j++) {
            EIV edge;
            for (int k = 0; k < 3; k++) {
                edge(0) = faces[j](k);
                edge(1) = faces[j]((k + 1) % 3);
                EIV sorted = edge;
                std::sort(sorted.data(), sorted.data() + sorted.size());
                auto result = edge_hash_ptr->insert(sorted, (int)edge_list.size());
                if (result.inserted)
                    edge_list.emplace_back(sorted);
            }
        }
    }
}

// template <>
// void SimplexMesh<1>::constructListOfEdges(StdVector<EIV>& edge_list, EEIV* associated_edge_list_begin, EEIV* associated_edge_list_end)
// {
//     // associated edge list doesn't make sense for seg mesh
//     constructListOfEdges(edge_list);
// }

// template <>
// void SimplexMesh<2>::constructListOfEdges(StdVector<EIV>& edge_list, EEIV* associated_edge_list_begin, EEIV* associated_edge_list_end)
// {
//     HashTable<BIV, size_t> face_hash;
//     size_t number_elements = indices.size();
//     Faces faces;

//     for (size_t i = 0; i < number_elements; i++) {
//         getFaces(i, faces);
//         for (size_t j = 0; j < faces.size(); j++) {
//             BIV sorted = faces[j];
//             std::sort(sorted.data(), sorted.data() + sorted.size());
//             auto result = face_hash.insert(sorted, edge_list.size());

//             if (result.inserted)
//                 edge_list.emplace_back(sorted);
//             assert(associated_edge_list_begin + i < associated_edge_list_end);
//             associated_edge_list_begin[i](j) = result.value;
//         }
//     }
// }

// template <>
// void SimplexMesh<3>::constructListOfEdges(StdVector<EIV>& edge_list, EEIV* associated_edge_list_begin, EEIV* associated_edge_list_end)
// {
//     //TODO
//     constructListOfEdges(edge_list);
// }

template <int dim>
void SimplexMesh<dim>::constructListOfFaces(StdVector<BIV>& face_list, HashTable<BIV, int>* face_hash_ptr)
{
    HashTable<BIV, int> inner_face_hash;
    if (!face_hash_ptr)
        face_hash_ptr = &inner_face_hash;

    size_t number_elements = indices.size();
    Faces faces;

    face_list.clear();

    for (size_t i = 0; i < number_elements; i++) {
        getFaces(i, faces);
        for (size_t j = 0; j < faces.size(); j++) {
            BIV sorted = faces[j];
            std::sort(sorted.data(), sorted.data() + sorted.size());
            auto result = face_hash_ptr->insert(sorted, (int)face_list.size());
            if (result.inserted)
                face_list.emplace_back(sorted);
        }
    }
}

template <int dim>
void SimplexMesh<dim>::findSharedFace(const IV& element1, const IV& element2, BIV& face)
{
    int e = 0;
    bool job_done = false;
    for (int i = 0; i < num_vertices && !job_done; i++) {
        for (int j = 0; j < num_vertices && !job_done; j++) {
            if (e == boundary_vertices)
                job_done = true;
            if (element1(i) == element2(j) && !job_done) {
                face(e) = element1(i);
                e++;
            }
        }
    }

    std::sort(face.data(), face.data() + face.size());
}

template <int dim>
void SimplexMesh<dim>::findSharedFaceAndIndex(const IV& element1, const IV& element2, BIV& sorted, BIV* local_index1_ptr, BIV* local_index2_ptr)
{
    BIV inner_local_index1, inner_local_index2;
    if (!local_index1_ptr)
        local_index1_ptr = &inner_local_index1;
    if (!local_index2_ptr)
        local_index2_ptr = &inner_local_index2;

    int find = 0;
    for (int k = 0; k < num_vertices && find < boundary_vertices; k++) {
        for (int l = 0; l < num_vertices && find < boundary_vertices; l++) {
            if (element1(k) == element2(l)) {
                (*local_index1_ptr)(find) = k;
                (*local_index2_ptr)(find) = l;
                sorted(find) = element1(k);
                find++;
                break;
            }
        }
    }
    std::sort(local_index1_ptr->data(), local_index1_ptr->data() + local_index1_ptr->size());
    std::sort(local_index2_ptr->data(), local_index2_ptr->data() + local_index2_ptr->size());
    std::sort(sorted.data(), sorted.data() + sorted.size());
}

template <int dim>
void SimplexMesh<dim>::findUnsortedFace(const IV& element, const BIV& sorted, BIV& face)
{
    int find = 0;
    for (int k = 0; k < num_vertices && find < boundary_vertices; k++) {
        for (int l = 0; l < boundary_vertices && find < boundary_vertices; l++) {
            if (element(k) == sorted(l)) {
                face(find) = element(k);
                find++;
                break;
            }
        }
    }
}

template <int dim>
void SimplexMesh<dim>::constructNeighborVertexList(const StdVector<NIV>& neighbor_list, StdVector<BIV>& neighbor_vertex_list) const
{
    neighbor_vertex_list.clear();
    neighbor_vertex_list.reserve(neighbor_list.size());
    for (int n = 0; n < int(neighbor_list.size()); n++) {
        NIV face = neighbor_list[n];
        IV element1 = indices[face(0)];
        IV element2 = indices[face(1)];
        BIV vertices;
        findSharedFace(element1, element2, vertices);
        neighbor_vertex_list.emplace_back(vertices);
    }
}

template <int dim>
void SimplexMesh<dim>::constructNeighborVertexListInternal()
{
    // if the neighbor_list hasn't been created, then create one.
    if (!is_neighbor_list_created) {
        constructListOfFaceNeighboringElementsInternal(false);
    }

    neighbor_vertex_list.clear();
    neighbor_vertex_list.reserve(neighbor_list.size());
    for (int n = 0; n < int(neighbor_list.size()); n++) {
        NIV face = neighbor_list[n];
        IV element1 = indices[face(0)];
        IV element2 = indices[face(1)];
        BIV vertices;
        findSharedFace(element1, element2, vertices);
        neighbor_vertex_list.emplace_back(vertices);
    }
}

template <int dim>
const char* SimplexMesh<dim>::name()
{
    switch (dim) {
    case 1:
        return "Seg";
        break;
    case 2:
        return "Tri";
        break;
    case 3:
        return "Tet";
        break;
    default:
        ZIRAN_ASSERT("Unsupported Element dimension ", dim);
    }
}

/**
        Construct a list of face touching elements.
        Optional sorting of each element pair.
    */
template <int dim>
void SimplexMesh<dim>::constructListOfFaceNeighboringElements(StdVector<Eigen::Vector2i>& result, const bool sort, HashTable<BIV, Eigen::Vector2i>* face_hash_ptr)
{
    HashTable<BIV, Eigen::Vector2i> inner_face_hash;
    if (!face_hash_ptr)
        face_hash_ptr = &inner_face_hash;

    size_t number_elements = indices.size();
    Faces faces;

    for (size_t i = 0; i < number_elements; i++) {
        getFaces(i, faces);
        for (size_t j = 0; j < faces.size(); j++) {
            BIV sorted = faces[j];
            std::sort(sorted.data(), sorted.data() + sorted.size());

            Eigen::Vector2i* v = face_hash_ptr->get(sorted);
            if (v == nullptr)
                face_hash_ptr->insert(sorted, Eigen::Vector2i(i, -1));
            else {
                ZIRAN_ASSERT((*v)(0) != -1 && (*v)(0) != (int)i && (*v)(1) == -1);
                (*v)(1) = (int)i;
            }
        }
    }

    result.clear();
    for (auto it = face_hash_ptr->cbegin(); it != face_hash_ptr->cend(); it++) {
        Eigen::Vector2i elements = it->value.template head<2>();
        ZIRAN_ASSERT(elements(0) != -1);
        if (elements(1) != -1)
            result.push_back(elements);
    }

    if (sort) {
        for (size_t i = 0; i < result.size(); i++) {
            std::sort(result[i].data(), result[i].data() + result[i].size());
        }
    }
}

template <int dim>
void SimplexMesh<dim>::constructListOfFaceNeighboringElementsInternal(const bool sort, HashTable<BIV, Eigen::Vector2i>* face_hash_ptr)
{
    neighbor_list_sorted = sort;
    HashTable<BIV, Eigen::Vector2i> inner_face_hash;
    if (!face_hash_ptr)
        face_hash_ptr = &inner_face_hash;

    size_t number_elements = indices.size();
    Faces faces;

    for (size_t i = 0; i < number_elements; i++) {
        getFaces(i, faces);
        for (size_t j = 0; j < faces.size(); j++) {
            BIV sorted = faces[j];
            std::sort(sorted.data(), sorted.data() + sorted.size());

            Eigen::Vector2i* v = face_hash_ptr->get(sorted);
            if (v == nullptr)
                face_hash_ptr->insert(sorted, Eigen::Vector2i(i, -1));
            else {
                ZIRAN_ASSERT((*v)(0) != -1 && (*v)(0) != (int)i && (*v)(1) == -1);
                (*v)(1) = (int)i;
            }
        }
    }

    neighbor_list.clear();
    for (auto it = face_hash_ptr->cbegin(); it != face_hash_ptr->cend(); it++) {
        Eigen::Vector2i elements = it->value.template head<2>();
        ZIRAN_ASSERT(elements(0) != -1);
        if (elements(1) != -1)
            neighbor_list.push_back(elements);
    }

    if (sort) {
        for (size_t i = 0; i < neighbor_list.size(); i++) {
            std::sort(neighbor_list[i].data(), neighbor_list[i].data() + neighbor_list[i].size());
        }
    }

    // set flag recording that neighbor_list has been created
    is_neighbor_list_created = true;
}

template <int dim>
void SimplexMesh<dim>::initializeNeighboringElements()
{
    StdVector<Eigen::Vector2i> result;
    constructListOfFaceNeighboringElements(result, false);
    const int num_elements = indices.size();
    connectivity.resize(num_elements, num_elements);
    for (size_t i = 0; i < result.size(); i++) {
        Eigen::Vector2i pair = result[i];
        connectivity.insert(pair(0), pair(1)) = 1;
        connectivity.insert(pair(1), pair(0)) = 1;
    }
    neighboring_initialized = true;
}

// self is not considered as a neighbor
template <int dim>
void SimplexMesh<dim>::initializeVertexToNeighbouringVertices()
{
    if (!vertex_to_neighbor_vertices_initialized) {
        size_t number_elements = indices.size();
        Faces faces;
        for (size_t i = 0; i < number_elements; i++) {
            for (int p = 0; p < dim + 1; p++) {
                int my_index = indices[i](p);
                for (int q = 0; q < dim + 1; q++) {
                    int your_index = indices[i](q);
                    if (p != q) {
                        StdVector<int>& list = vertex_to_neighbor_vertices[my_index];
                        auto found = std::find(std::begin(list), std::end(list), your_index);
                        if (found == list.end())
                            list.emplace_back(your_index);
                    }
                }
            }
        }
        vertex_to_neighbor_vertices_initialized = true;
    }
}

template <int dim>
void SimplexMesh<dim>::initializeVertexToNeighbouringElements()
{
    if (!vertex_to_neighbor_elements_initialized) {
        size_t number_elements = indices.size();
        Faces faces;
        for (size_t i = 0; i < number_elements; i++) {
            for (int p = 0; p < dim + 1; p++) {
                int my_index = indices[i](p);
                StdVector<int>& list = vertex_to_neighbor_elements[my_index];
                auto found = std::find(std::begin(list), std::end(list), i);
                if (found == list.end())
                    list.emplace_back(i);
            }
        }
        vertex_to_neighbor_elements_initialized = true;
    }
}

/**
       Input: index is an element index.
       Input: target is a list of element indicies in the same mesh.
       Output: result is the closest one in the target to the index.
               where the distance is judged by graph connectivity.
    */
template <int dim>
void SimplexMesh<dim>::closestElement(const int index, int& result, const HashTable<int, bool>& target)
{
    if (!neighboring_initialized)
        this->initializeNeighboringElements();
    const int num_nodes = indices.size();
    bool visited[num_nodes];
    for (int i = 0; i < num_nodes; i++) {
        visited[i] = false;
    }

    std::queue<int> index_q;
    index_q.push(index);

    while (!index_q.empty()) {
        int front = index_q.front();
        visited[front] = true;
        //if front is in target, return
        if (target.get(front) != nullptr) {
            result = front;
            return;
        }

        //else, add all its neighboring index to the queue
        for (typename SpMat::InnerIterator it(connectivity, front); it; ++it) {
            ZIRAN_ASSERT(it.value() == 1);
            if (!visited[it.col()]) {
                index_q.push(it.col());
            }
        }

        index_q.pop();
    }

    result = -1;
}

template <int dim>
void SimplexMesh<dim>::findIndexBounds(int& min, int& max) const
{
    min = std::numeric_limits<int>::max();
    max = std::numeric_limits<int>::lowest();
    for (const IV& element : indices) {
        int local_min = element.minCoeff();
        int local_max = element.maxCoeff();
        if (local_min < min)
            min = local_min;
        if (local_max > max)
            max = local_max;
    }
}

template class SimplexMesh<1>;
template class SimplexMesh<2>;
template class SimplexMesh<3>;
} // namespace ZIRAN


#pragma once
#ifndef BASIS_ANGULAR_HPP
#define BASIS_ANGULAR_HPP

// c++ libraries
#include <ostream>
//eigen
#include <Eigen/Dense>
// symmetry functions
#include "src/nnp/cutoff.hpp"
#include "src/nnp/symm_angular.hpp"
// serialize
#include "src/mem/serialize.hpp"

#ifndef BASIS_ANGULAR_PRINT_FUNC
#define BASIS_ANGULAR_PRINT_FUNC 0
#endif

struct BasisA{
private:
	double rc_;//cutoff radius
	double norm_;//normalization factor
	PhiAN phiAN_;//type of angular functions
	cutoff::Norm normT_;//normalization scheme
	int nfA_;//number of angular functions
	cutoff::Func* cutoff_;//cutoff function
	PhiA** fA_;//angular functions
	Eigen::VectorXd symm_;//symmetry function
public:
	//==== constructors/destructors ====
	BasisA():normT_(cutoff::Norm::UNKNOWN),phiAN_(PhiAN::UNKNOWN),nfA_(0),fA_(NULL),cutoff_(NULL){}
	BasisA(const BasisA& basisA);
	~BasisA();

	//==== operators ====
	BasisA& operator=(const BasisA& basisA);
	friend std::ostream& operator<<(std::ostream& out, const BasisA& basisA);

	//==== initialization ====
	void init_G3(int nA, cutoff::Norm norm, cutoff::Name tcut, double rcut);
	void init_G4(int nA, cutoff::Norm norm, cutoff::Name tcut, double rcut);

	//==== reading/writing ====
	static void write(const char* file,const BasisA& basis);
	static void read(const char* file, BasisA& basis);
	static void write(FILE* writer,const BasisA& basis);
	static void read(FILE* writer, BasisA& basis);

	//==== member access ====
	cutoff::Func* cutoff(){return cutoff_;}
	const cutoff::Func* cutoff()const{return cutoff_;}
	double& rc(){return rc_;}
	const double& rc()const{return rc_;}
	const int& nfA()const{return nfA_;}
	PhiAN& phiAN(){return phiAN_;}
	const PhiAN& phiAN()const{return phiAN_;}
	cutoff::Norm& normT(){return normT_;}
	const cutoff::Norm& normT()const{return normT_;}
	PhiA& fA(int i){return *fA_[i];}
	const PhiA& fA(int i)const{return *fA_[i];}
	Eigen::VectorXd& symm(){return symm_;}
	const Eigen::VectorXd& symm()const{return symm_;}

	//==== member functions ====
	void clear();
	void symm(double cos, const double d[3]);
	void force(double& phi, double* eta, double cos, const double d[3], const double* dEdG)const;

	//==== static functions ====
	static double norm(cutoff::Norm normT, double rc);
};

bool operator==(const BasisA& basis1, const BasisA& basis2);
inline bool operator!=(const BasisA& basis1, const BasisA& basis2){return !(basis1==basis2);}

namespace serialize{

	//**********************************************
	// byte measures
	//**********************************************

	template <> int nbytes(const BasisA& obj);

	//**********************************************
	// packing
	//**********************************************

	template <> int pack(const BasisA& obj, char* arr);

	//**********************************************
	// unpacking
	//**********************************************

	template <> int unpack(BasisA& obj, const char* arr);

}

#endif


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

    @copyright 2016 NumScale SAS

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

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

  /*!

    @ingroup group-arithmetic
    This function object computes the absolute value of the difference of its parameters.

    @par Header <boost/simd/function/dist.hpp>

    @par Notes

    The result may be negative for signed integers as @ref abs(@ref Valmin) is undefined.
    To avoid the problem you can apply to dist the saturated_ decorator (See
    @ref group-decorator.)

    @par Decorators

     - saturated_ garanties that @c saturated_(dist)(x, y)) will
       never be strictly less than 0.

    @see  ulpdist, abs

    @par Example:

      @snippet dist.cpp dist

    @par Possible output:

      @snippet dist.txt dist

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

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

#endif


// Copyright Michael Drexl 2005, 2006.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://boost.org/LICENSE_1_0.txt)

// Example use of the resource-constrained shortest paths algorithm.
#include <boost/config.hpp>

#ifdef BOOST_MSVC
#  pragma warning(disable: 4267)
#endif

#include <boost/graph/adjacency_list.hpp>

#include <boost/graph/r_c_shortest_paths.hpp>
#include <iostream>

using namespace boost;

struct SPPRC_Example_Graph_Vert_Prop
{
  SPPRC_Example_Graph_Vert_Prop( int n = 0, int e = 0, int l = 0 )
  : num( n ), eat( e ), lat( l ) {}
  int num;
  // earliest arrival time
  int eat;
  // latest arrival time
  int lat;
};

struct SPPRC_Example_Graph_Arc_Prop
{
  SPPRC_Example_Graph_Arc_Prop( int n = 0, int c = 0, int t = 0 )
  : num( n ), cost( c ), time( t ) {}
  int num;
  // traversal cost
  int cost;
  // traversal time
  int time;
};

typedef adjacency_list<vecS,
                       vecS,
                       directedS,
                       SPPRC_Example_Graph_Vert_Prop,
                       SPPRC_Example_Graph_Arc_Prop>
  SPPRC_Example_Graph;

// data structures for spp without resource constraints:
// ResourceContainer model
struct spp_no_rc_res_cont
{
  spp_no_rc_res_cont( int c = 0 ) : cost( c ) {};
  spp_no_rc_res_cont& operator=( const spp_no_rc_res_cont& other )
  {
    if( this == &other )
      return *this;
    this->~spp_no_rc_res_cont();
    new( this ) spp_no_rc_res_cont( other );
    return *this;
  }
  int cost;
};

bool operator==( const spp_no_rc_res_cont& res_cont_1,
                 const spp_no_rc_res_cont& res_cont_2 )
{
  return ( res_cont_1.cost == res_cont_2.cost );
}

bool operator<( const spp_no_rc_res_cont& res_cont_1,
                const spp_no_rc_res_cont& res_cont_2 )
{
  return ( res_cont_1.cost < res_cont_2.cost );
}

// ResourceExtensionFunction model
class ref_no_res_cont
{
public:
  inline bool operator()( const SPPRC_Example_Graph& g,
                          spp_no_rc_res_cont& new_cont,
                          const spp_no_rc_res_cont& old_cont,
                          graph_traits
                            <SPPRC_Example_Graph>::edge_descriptor ed ) const
  {
    new_cont.cost = old_cont.cost + g[ed].cost;
    return true;
  }
};

// DominanceFunction model
class dominance_no_res_cont
{
public:
  inline bool operator()( const spp_no_rc_res_cont& res_cont_1,
                          const spp_no_rc_res_cont& res_cont_2 ) const
  {
    // must be "<=" here!!!
    // must NOT be "<"!!!
    return res_cont_1.cost <= res_cont_2.cost;
    // this is not a contradiction to the documentation
    // the documentation says:
    // "A label $l_1$ dominates a label $l_2$ if and only if both are resident
    // at the same vertex, and if, for each resource, the resource consumption
    // of $l_1$ is less than or equal to the resource consumption of $l_2$,
    // and if there is at least one resource where $l_1$ has a lower resource
    // consumption than $l_2$."
    // one can think of a new label with a resource consumption equal to that
    // of an old label as being dominated by that old label, because the new
    // one will have a higher number and is created at a later point in time,
    // so one can implicitly use the number or the creation time as a resource
    // for tie-breaking
  }
};
// end data structures for spp without resource constraints:

// data structures for shortest path problem with time windows (spptw)
// ResourceContainer model
struct spp_spptw_res_cont
{
  spp_spptw_res_cont( int c = 0, int t = 0 ) : cost( c ), time( t ) {}
  spp_spptw_res_cont& operator=( const spp_spptw_res_cont& other )
  {
    if( this == &other )
      return *this;
    this->~spp_spptw_res_cont();
    new( this ) spp_spptw_res_cont( other );
    return *this;
  }
  int cost;
  int time;
};

bool operator==( const spp_spptw_res_cont& res_cont_1,
                 const spp_spptw_res_cont& res_cont_2 )
{
  return ( res_cont_1.cost == res_cont_2.cost
           && res_cont_1.time == res_cont_2.time );
}

bool operator<( const spp_spptw_res_cont& res_cont_1,
                const spp_spptw_res_cont& res_cont_2 )
{
  if( res_cont_1.cost > res_cont_2.cost )
    return false;
  if( res_cont_1.cost == res_cont_2.cost )
    return res_cont_1.time < res_cont_2.time;
  return true;
}

// ResourceExtensionFunction model
class ref_spptw
{
public:
  inline bool operator()( const SPPRC_Example_Graph& g,
                          spp_spptw_res_cont& new_cont,
                          const spp_spptw_res_cont& old_cont,
                          graph_traits
                            <SPPRC_Example_Graph>::edge_descriptor ed ) const
  {
    const SPPRC_Example_Graph_Arc_Prop& arc_prop =
      get( edge_bundle, g )[ed];
    const SPPRC_Example_Graph_Vert_Prop& vert_prop =
      get( vertex_bundle, g )[target( ed, g )];
    new_cont.cost = old_cont.cost + arc_prop.cost;
    int& i_time = new_cont.time;
    i_time = old_cont.time + arc_prop.time;
    i_time < vert_prop.eat ? i_time = vert_prop.eat : 0;
    return i_time <= vert_prop.lat ? true : false;
  }
};

// DominanceFunction model
class dominance_spptw
{
public:
  inline bool operator()( const spp_spptw_res_cont& res_cont_1,
                          const spp_spptw_res_cont& res_cont_2 ) const
  {
    // must be "<=" here!!!
    // must NOT be "<"!!!
    return res_cont_1.cost <= res_cont_2.cost
           && res_cont_1.time <= res_cont_2.time;
    // this is not a contradiction to the documentation
    // the documentation says:
    // "A label $l_1$ dominates a label $l_2$ if and only if both are resident
    // at the same vertex, and if, for each resource, the resource consumption
    // of $l_1$ is less than or equal to the resource consumption of $l_2$,
    // and if there is at least one resource where $l_1$ has a lower resource
    // consumption than $l_2$."
    // one can think of a new label with a resource consumption equal to that
    // of an old label as being dominated by that old label, because the new
    // one will have a higher number and is created at a later point in time,
    // so one can implicitly use the number or the creation time as a resource
    // for tie-breaking
  }
};
// end data structures for shortest path problem with time windows (spptw)

// example graph structure and cost from
// http://www.boost.org/libs/graph/example/dijkstra-example.cpp
enum nodes { A, B, C, D, E };
char name[] = "ABCDE";

int main()
{
  SPPRC_Example_Graph g;

  add_vertex( SPPRC_Example_Graph_Vert_Prop( A, 0, 0 ), g );
  add_vertex( SPPRC_Example_Graph_Vert_Prop( B, 5, 20 ), g );
  add_vertex( SPPRC_Example_Graph_Vert_Prop( C, 6, 10 ), g );
  add_vertex( SPPRC_Example_Graph_Vert_Prop( D, 3, 12 ), g );
  add_vertex( SPPRC_Example_Graph_Vert_Prop( E, 0, 100 ), g );

  add_edge( A, C, SPPRC_Example_Graph_Arc_Prop( 0, 1, 5 ), g );
  add_edge( B, B, SPPRC_Example_Graph_Arc_Prop( 1, 2, 5 ), g );
  add_edge( B, D, SPPRC_Example_Graph_Arc_Prop( 2, 1, 2 ), g );
  add_edge( B, E, SPPRC_Example_Graph_Arc_Prop( 3, 2, 7 ), g );
  add_edge( C, B, SPPRC_Example_Graph_Arc_Prop( 4, 7, 3 ), g );
  add_edge( C, D, SPPRC_Example_Graph_Arc_Prop( 5, 3, 8 ), g );
  add_edge( D, E, SPPRC_Example_Graph_Arc_Prop( 6, 1, 3 ), g );
  add_edge( E, A, SPPRC_Example_Graph_Arc_Prop( 7, 1, 5 ), g );
  add_edge( E, B, SPPRC_Example_Graph_Arc_Prop( 8, 1, 4 ), g );

  // the unique shortest path from A to E in the dijkstra-example.cpp is
  // A -> C -> D -> E
  // its length is 5
  // the following code also yields this result

  // with the above time windows, this path is infeasible
  // now, there are two shortest paths that are also feasible with respect to
  // the vertex time windows:
  // A -> C -> B -> D -> E and
  // A -> C -> B -> E
  // however, the latter has a longer total travel time and is therefore not
  // pareto-optimal, i.e., it is dominated by the former path
  // therefore, the code below returns only the former path

  // spp without resource constraints
  graph_traits<SPPRC_Example_Graph>::vertex_descriptor s = A;
  graph_traits<SPPRC_Example_Graph>::vertex_descriptor t = E;

  std::vector
    <std::vector
      <graph_traits<SPPRC_Example_Graph>::edge_descriptor> >
        opt_solutions;
  std::vector<spp_no_rc_res_cont> pareto_opt_rcs_no_rc;

  r_c_shortest_paths
  ( g,
    get( &SPPRC_Example_Graph_Vert_Prop::num, g ),
    get( &SPPRC_Example_Graph_Arc_Prop::num, g ),
    s,
    t,
    opt_solutions,
    pareto_opt_rcs_no_rc,
    spp_no_rc_res_cont( 0 ),
    ref_no_res_cont(),
    dominance_no_res_cont(),
    std::allocator
      <r_c_shortest_paths_label
        <SPPRC_Example_Graph, spp_no_rc_res_cont> >(),
    default_r_c_shortest_paths_visitor() );

  std::cout << "SPP without resource constraints:" << std::endl;
  std::cout << "Number of optimal solutions: ";
  std::cout << static_cast<int>( opt_solutions.size() ) << std::endl;
  for( int i = 0; i < static_cast<int>( opt_solutions.size() ); ++i )
  {
    std::cout << "The " << i << "th shortest path from A to E is: ";
    std::cout << std::endl;
    for( int j = static_cast<int>( opt_solutions[i].size() ) - 1; j >= 0; --j )
      std::cout << name[source( opt_solutions[i][j], g )] << std::endl;
    std::cout << "E" << std::endl;
    std::cout << "Length: " << pareto_opt_rcs_no_rc[i].cost << std::endl;
  }
  std::cout << std::endl;

  // spptw
  std::vector
    <std::vector
      <graph_traits<SPPRC_Example_Graph>::edge_descriptor> >
        opt_solutions_spptw;
  std::vector<spp_spptw_res_cont> pareto_opt_rcs_spptw;

  r_c_shortest_paths
  ( g,
    get( &SPPRC_Example_Graph_Vert_Prop::num, g ),
    get( &SPPRC_Example_Graph_Arc_Prop::num, g ),
    s,
    t,
    opt_solutions_spptw,
    pareto_opt_rcs_spptw,
    spp_spptw_res_cont( 0, 0 ),
    ref_spptw(),
    dominance_spptw(),
    std::allocator
      <r_c_shortest_paths_label
        <SPPRC_Example_Graph, spp_spptw_res_cont> >(),
          default_r_c_shortest_paths_visitor() );

  std::cout << "SPP with time windows:" << std::endl;
  std::cout << "Number of optimal solutions: ";
  std::cout << static_cast<int>( opt_solutions.size() ) << std::endl;
  for( int i = 0; i < static_cast<int>( opt_solutions.size() ); ++i )
  {
    std::cout << "The " << i << "th shortest path from A to E is: ";
    std::cout << std::endl;
    for( int j = static_cast<int>( opt_solutions_spptw[i].size() ) - 1;
         j >= 0;
         --j )
      std::cout << name[source( opt_solutions_spptw[i][j], g )] << std::endl;
    std::cout << "E" << std::endl;
    std::cout << "Length: " << pareto_opt_rcs_spptw[i].cost << std::endl;
    std::cout << "Time: " << pareto_opt_rcs_spptw[i].time << std::endl;
  }

  // utility function check_r_c_path example
  std::cout << std::endl;
  bool b_is_a_path_at_all = false;
  bool b_feasible = false;
  bool b_correctly_extended = false;
  spp_spptw_res_cont actual_final_resource_levels( 0, 0 );
  graph_traits<SPPRC_Example_Graph>::edge_descriptor ed_last_extended_arc;
  check_r_c_path( g,
                  opt_solutions_spptw[0],
                  spp_spptw_res_cont( 0, 0 ),
                  true,
                  pareto_opt_rcs_spptw[0],
                  actual_final_resource_levels,
                  ref_spptw(),
                  b_is_a_path_at_all,
                  b_feasible,
                  b_correctly_extended,
                  ed_last_extended_arc );
  if( !b_is_a_path_at_all )
    std::cout << "Not a path." << std::endl;
  if( !b_feasible )
    std::cout << "Not a feasible path." << std::endl;
  if( !b_correctly_extended )
    std::cout << "Not correctly extended." << std::endl;
  if( b_is_a_path_at_all && b_feasible && b_correctly_extended )
  {
    std::cout << "Actual final resource levels:" << std::endl;
    std::cout << "Length: " << actual_final_resource_levels.cost << std::endl;
    std::cout << "Time: " << actual_final_resource_levels.time << std::endl;
    std::cout << "OK." << std::endl;
  }

  return 0;
}


// 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.

#ifndef MTL_VECTOR_CROSS_INCLUDE
#define MTL_VECTOR_CROSS_INCLUDE

#include <boost/numeric/mtl/concept/std_concept.hpp>
#include <boost/numeric/mtl/vector/dense_vector.hpp>
#include <boost/numeric/mtl/interface/vpt.hpp>

namespace mtl { namespace vector {

    namespace detail {

	// Result type of cross product
	template <typename Vector1, typename Vector2>
	struct cross_result
	{
	    typedef typename Multiplicable<typename Collection<Vector1>::value_type,
					   typename Collection<Vector2>::value_type>::result_type value;
	    typedef dense_vector<value>  type;
	};
    }

/// Cross product
/** Only exists for 3 and 7 dimensions.
    Consider specialization for fixed-size types
 **/
template <typename Vector1, typename Vector2>
typename detail::cross_result<Vector1, Vector2>::type
inline cross(const Vector1& v1, const Vector2& v2)
{
    vampir_trace<2002> tracer;
    MTL_THROW_IF((size(v1) != 3 && size(v1) != 7 ) || size(v1) != size(v2), incompatible_size());

    typename detail::cross_result<Vector1, Vector2>::type result(size(v1));

    if (size(v1) == 3)
	for (unsigned i= 0; i < 3; i++) {
	    unsigned k= (i+1) % 3, l= (i+2) % 3;
	    result[i]= v1[k] * v2[l] - v1[l] * v2[k];
	}
    else  // must be 7 thus
	for (unsigned i= 0; i < 7; i++) {
	    unsigned k= (i+1) % 7, l= (i+3) % 7;
	    result[i]= v1[k] * v2[l] - v1[l] * v2[k];

	    k= (i+2) % 7, l= (i+6) % 7;
	    result[i]+= v1[k] * v2[l] - v1[l] * v2[k];

	    k= (i+4) % 7, l= (i+5) % 7;
	    result[i]+= v1[k] * v2[l] - v1[l] * v2[k];
	}
    return result;
}

}} // namespace mtl::vector

#endif // MTL_VECTOR_CROSS_INCLUDE


// #include <iostream>
#include <typeinfo>
#include <boost/hana/experimental/printable.hpp>

// #define USE_
#include <gem/tensor.hpp>

#include <fstream>
#include <cereal/cereal.hpp>
#include <cereal/archives/xml.hpp>

using namespace gem;
using namespace boost::hana;
// using namespace boost::hana::experimental;

// template <typename T>
// inline auto operator<<(std::ostream& os, const boost::hana::type<T>& type)
//     -> std::ostream&
// {
//     os << boost::hana::experimental::print(type);
//     return os;
// }

int main(void) {

    // auto dim1 = Dim<0> {2};
    // auto dim2 = Dim<2> {};

    // // dim1 = dim1 * 2;
    // constexpr size_t v = dim2;

    // std::cout << (dim1 == 0) << std::endl;
    // std::cout << dim2 << std::endl;
    // std::cout << dim1 + dim2 << std::endl;
    // // std::cout << typeid(dim1 + dim2).name() << std::endl;
    // std::cout << sizeof(dim1) << std::endl;
    // std::cout << sizeof(dim2) << std::endl;

    auto m = MatrixXd(10, 20);
    std::cout << m << std::endl;

    std::ofstream file {"out.xml"};
    cereal::XMLOutputArchive archive {file};
    std::cout << gem::type(m.size()) << std::endl;

    archive(CEREAL_NVP(m.size()));

    // std::cout << print(m.size().type) << std::endl;
 //    std::cout << m << std::endl;
 //    std::cout << m2<< std::endl;
    // constexpr auto m2(m);

 //    // std::cout << sizeof(m.dim[0_c].type) << std::endl;
 //    std::cout << sizeof(m2) << std::endl;
 //    // std::cout << sizeof(m.dim) << std::endl;
 //    // std::cout << m.dim[0_c].type << std::endl;
 //    // std::cout << m2.dim[0_c] << std::endl;
 //    // std::cout << m2.dim[1_c] << std::endl;
 //    // std::cout << m2.dim[2_c] << std::endl;
 //    // m.dim[0_c] = 1;
	// std::cout << m.n_dims << std::endl;

	// std::cout << m2.rows() << std::endl;
	// std::cout << m2.cols() << std::endl;
	// std::cout << m2.size() << std::endl;

    // for (int i = 0; i < m.dim(1_c); ++i) {
    // 	std::cout << i << std::endl;
    // }

	// std::cout << Dim<size_t>(10ul, 2_c, 0_c) << std::endl;
    // m "1:2, 3:4"

    // auto dim1 = Dim<unsigned long>(10);
    // auto dim2 = Dim<unsigned long>(10_c);
    // auto dim3 = Dim<unsigned long>(10_c);

    // std::cout << typeid(dim2 * dim2).name() << std::endl;
    // std::cout << dim2 * dim3 << std::endl;
    // std::cout << (mult(dim1, mult(dim2, dim3)) == mult(mult(dim1, dim2), dim3)) << std::endl;
    // std::cout << plus(dim1, dim2) << std::endl;
    // std::cout << (mult(dim1, one<decltype>()) == dim1 << std::endl;
    // boost::hana::mult_impl<decltype(dim2), decltype(dim3)>::apply(dim2, dim3);
    // std::cout << dim2 << std::endl;
    // std::cout << mult(dim2, dim3) << std::endl;
    // mult(dim1, mult(dim2, dim3));
    // std::cout << dim2 * dim3 << std::endl;

    return 0;
}


#ifndef DUNE_OSEEN_NEW_BICGSTAB_HH
#define DUNE_OSEEN_NEW_BICGSTAB_HH

#include <dune/stuff/common/print.hh>
#include <dune/stuff/common/logging.hh>

#include <limits>
#include <cmath>
#include <utility>
#include <boost/format.hpp>

namespace Dune {

template < class PressureDiscreteFunctionType, class OperatorType >
class NewBicgStab {

public:
	typedef std::pair < int , double >
		ReturnValueType;

    NewBicgStab(const OperatorType& op,
				const double relLimit,
				const double absLimit,
				const unsigned int max_iter,
                const unsigned int solverVerbosity )
		: operator_(op),
		  relLimit_(relLimit),
		  absLimit_(absLimit),
		  max_iter_(max_iter),
          solverVerbosity_(solverVerbosity)
	{}

	//! for bfg interface compliance
	void setAbsoluteLimit( const double  ){}

	void apply(const PressureDiscreteFunctionType& rhs, PressureDiscreteFunctionType& dest ) const
	{
		ReturnValueType info;
		apply( rhs, dest, info );
	}

	void apply(const PressureDiscreteFunctionType& rhs, PressureDiscreteFunctionType& dest, ReturnValueType& info ) const
	{
		unsigned int iteration = 1;
		const std::string cg_name( "OuterCG");
        auto& logDebug = DSC_LOG_DEBUG;

		PressureDiscreteFunctionType residuum( "residuum", dest.space() );
		PressureDiscreteFunctionType start_residuum( "start_residuum", dest.space() );
		PressureDiscreteFunctionType s( "s", dest.space() );
		PressureDiscreteFunctionType t( "t", dest.space() );
		PressureDiscreteFunctionType v( "v", dest.space() );
		PressureDiscreteFunctionType search_direction( "search_direction", dest.space() );

		// r^0 = - S * p^0 + rhs
		operator_.apply( dest, residuum );
		if ( solverVerbosity_ > 3 )
            DSC::printFunctionMinMax( logDebug, residuum );
		residuum -= rhs;
		residuum *= -1.;

		// r_^0 = r^0
		start_residuum.assign( residuum );
		search_direction.assign( residuum );

		double rho(0);
		double delta(0); //norm of residuum

		double alpha,omega,last_rho;
		alpha = omega = last_rho  = std::numeric_limits<double>::max();

		PressureDiscreteFunctionType residuum_T( "s", dest.space() );
		residuum_T.assign( start_residuum );//??

		if ( solverVerbosity_ > 2 )
			DSC_LOG_INFO << " -- \n";

		while( iteration < max_iter_) {
			rho = residuum_T.scalarProductDofs( residuum );
			if ( rho == 0.0 ) {
				if ( solverVerbosity_ > 3 )
					logDebug << boost::format( "%s: abort, theta = %e") % cg_name % rho << std::endl;
				break;
			}
			assert( !std::isnan(rho) );
			assert( std::isfinite(rho) );

			if ( iteration == 1 ) {
				search_direction.assign( start_residuum );
			}
			else {
				const double beta = (rho/last_rho) * (alpha/omega);
				search_direction *= beta;
				search_direction.axpy( -beta*omega, v );
				search_direction += residuum;
			}

			operator_.apply( search_direction, v );//v=S*p
			alpha = rho/ residuum_T.scalarProductDofs( v );
			assert( !std::isnan(alpha) );
			assert( std::isfinite(alpha) );

			s.assign( residuum );
			s.axpy( -alpha, v );
			const double s_norm = std::sqrt( s.scalarProductDofs( s ) );
			if ( s_norm < absLimit_ ) {
				dest.axpy( alpha, search_direction );
				logDebug << boost::format( "%s: iter %i\taborted: s: %e") % cg_name % iteration % s_norm << std::endl;
				break;
			}
			operator_.apply( s, t );
			omega = t.scalarProductDofs( s ) / t.scalarProductDofs( t );

			if ( solverVerbosity_ > 3 )
                DSC::printFunctionMinMax( logDebug, search_direction );
			dest.axpy( alpha, search_direction );
			if ( solverVerbosity_ > 3 )
                DSC::printFunctionMinMax( logDebug, dest );
			dest.axpy( omega, s );

			residuum.assign( s );
			residuum.axpy( - omega, t );

			delta = std::sqrt( residuum.scalarProductDofs( residuum ) );
			if ( delta < absLimit_ ) {
				logDebug << boost::format( "%s: aborted, iter %i\tres %e") % cg_name % iteration % delta << std::endl;
				break;
			}

			if ( solverVerbosity_ > 3 ) {
				logDebug << boost::format( "%s: iter %i\tres %e alpha %e \trho %e") % cg_name % iteration
							% delta % alpha %  rho << std::endl;
                DSC::printFunctionMinMax( logDebug, dest );
			}
			assert( omega != 0.0 );

			last_rho = rho;
			iteration++;
		} //end while

		info = ReturnValueType( iteration, rho );
	}

	const OperatorType& operator_;
	const double relLimit_;
	const double absLimit_;
	const unsigned int max_iter_;
	const unsigned int solverVerbosity_;
};

} //namespace Dune

#endif // DUNE_OSEEN_NEW_BICGSTAB_HH

/** Copyright (c) 2012, Rene Milk
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those
 * of the authors and should not be interpreted as representing official policies,
 * either expressed or implied, of the FreeBSD Project.
**/


#ifndef TMXPP_TILE_ID_HPP
#define TMXPP_TILE_ID_HPP

#include <cstdint>
#include <boost/hana/integral_constant.hpp>
#include <tmxpp/Constrained.hpp>
#include <tmxpp/Flip.hpp>

namespace tmxpp {

using Local_tile_id = Closed_interval<
    std::int_least32_t, boost::hana::long_<0>, boost::hana::long_<0x1FFF'FFFE>>;

using Global_tile_id = Closed_interval<
    std::int_least32_t, boost::hana::long_<1>, boost::hana::long_<0x1FFF'FFFF>>;

struct Flipped_tile_id {
    Flip flip;
    Global_tile_id id;
};

inline bool operator==(Flipped_tile_id l, Flipped_tile_id r) noexcept
{
    return l.flip == r.flip && l.id == r.id;
}
inline bool operator!=(Flipped_tile_id l, Flipped_tile_id r) noexcept
{
    return !(l == r);
}

} // namespace tmxpp

#endif // TMXPP_TILE_ID_HPP


#include <NTL/lzz_pX.h>

NTL_CLIENT

#define ITER (500)

void multest()
{
   cerr << "mul";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long da = RandomBnd(5000) + 100;
      long db = RandomBnd(5000) + 100;

      zz_pX a, b, c1, c2;

      random(a, da);
      random(b, db);

      if (deg(a) < 80 || deg(b) < 80) {
         cerr << "*";
         continue;
      }

      FFTMul(c1, a, b);
      PlainMul(c2, a, b);

      if (c1 != c2) {
         cerr << "******* oops\n";
         break;
      }
   }

   cerr << "\n";
}

void sqrtest()
{
   cerr << "sqr";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long da = RandomBnd(5000) + 100;
      long db = RandomBnd(5000) + 100;

      zz_pX a, b, c1, c2;

      random(a, da);

      if (deg(a) < 80) {
         cerr << "*";
         continue;
      }

      FFTSqr(c1, a);
      PlainMul(c2, a, a);

      if (c1 != c2) {
         cerr << "******* oops\n";
         break;
      }
   }

   cerr << "\n";
}

void mulmodtest()
{
   cerr << "mulmod";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long n = RandomBnd(5000) + 300;
      long da = RandomBnd(n)+1;
      long db = RandomBnd(n)+1;

      if (RandomBnd(2)) { da = n; db = n; }

      zz_pX f;
      random(f, n);
      SetCoeff(f, n);
      zz_pXModulus F(f);

      zz_pX a, b, c1, c2;
      random(a, da);
      random(b, db);

      MulMod(c1, a, b, F);
      PlainMul(c2, a, b);
      rem(c2, c2, f);

      if (c1 != c2) {
         cerr << "******** oops\n";
         break;
      }
   }

   cerr << "\n";
}

void sqrmodtest()
{
   cerr << "sqrmod";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long n = RandomBnd(5000) + 300;
      long da = RandomBnd(n)+1;
      long db = RandomBnd(n)+1;

      if (RandomBnd(2)) { da = n; db = n; }

      zz_pX f;
      random(f, n);
      SetCoeff(f, n);
      zz_pXModulus F(f);

      zz_pX a, b, c1, c2;
      random(a, da);
      random(b, db);

      SqrMod(c1, a, F);

      PlainMul(c2, a, a);
      rem(c2, c2, f);

      if (c1 != c2) {
         cerr << "******** oops\n";
         break;
      }
   }

   cerr << "\n";
}

void mulmod1test()
{
   cerr << "mulmod1";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long n = RandomBnd(5000) + 300;
      long da = RandomBnd(n)+1;
      long db = RandomBnd(n)+1;

      if (RandomBnd(2)) { da = n; db = n; }

      zz_pX f;
      random(f, n);
      SetCoeff(f, n);
      zz_pXModulus F(f);

      zz_pX a, b, c1, c2;
      random(a, da);
      random(b, db);

      zz_pXMultiplier bb;
      build(bb, b, F);

      MulMod(c1, a, bb, F);

      PlainMul(c2, a, b);
      rem(c2, c2, f);

      if (c1 != c2) {
         cerr << "******** oops\n";
         break;
      }
   }

   cerr << "\n";
}

namespace NTL {

void CopyReverse(zz_pX& x, const zz_pX& a, long lo, long hi);

}

struct zz_pXTransMultiplier {
   zz_pX f0, fbi, b;
   long shamt, shamt_fbi, shamt_b;
};

void build(zz_pXTransMultiplier& B, const zz_pX& b, const zz_pXModulus& F)
{
   long db = deg(b);

   if (db >= F.n) LogicError("build TransMultiplier: bad args");

   zz_pX t;

   LeftShift(t, b, F.n-1);
   div(t, t, F);

   // we optimize for low degree b

   long d;

   d = deg(t);
   if (d < 0)
      B.shamt_fbi = 0;
   else
      B.shamt_fbi = F.n-2 - d;

   CopyReverse(B.fbi, t, 0, d);

   // The following code optimizes the case when
   // f = X^n + low degree poly

   trunc(t, F.f, F.n);
   d = deg(t);
   if (d < 0)
      B.shamt = 0;
   else
      B.shamt = d;

   CopyReverse(B.f0, t, 0, d);

   if (db < 0)
      B.shamt_b = 0;
   else
      B.shamt_b = db;

   CopyReverse(B.b, b, 0, db);
}

void TransMulMod(zz_pX& x, const zz_pX& a, const zz_pXTransMultiplier& B,
               const zz_pXModulus& F)
{
   if (deg(a) >= F.n) LogicError("TransMulMod: bad args");

   zz_pX t1, t2;

   mul(t1, a, B.b);
   RightShift(t1, t1, B.shamt_b);

   mul(t2, a, B.f0);
   RightShift(t2, t2, B.shamt);
   trunc(t2, t2, F.n-1);

   mul(t2, t2, B.fbi);
   if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi);
   trunc(t2, t2, F.n-1);
   LeftShift(t2, t2, 1);

   sub(x, t1, t2);
}

void UpdateMap(vec_zz_p& x, const vec_zz_p& a,
         const zz_pXTransMultiplier& B, const zz_pXModulus& F)
{
   zz_pX xx;
   TransMulMod(xx, to_zz_pX(a), B, F);
   x = xx.rep;
}

void updatetest()
{
   cerr << "update";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long n = RandomBnd(5000) + 300;
      long da = RandomBnd(n)+1;
      long db = RandomBnd(n)+1;

      if (RandomBnd(2)) { da = n; db = n; }

      zz_pX f;
      random(f, n);
      SetCoeff(f, n);
      zz_pXModulus F(f);

      zz_pX a, b;
      random(a, da);
      random(b, db);

      zz_pXMultiplier bb1;
      build(bb1, b, F);

      zz_pXTransMultiplier bb2;
      build(bb2, b, F);

      Vec<zz_p> x1, x2;

      UpdateMap(x1, a.rep, bb1, F);
      UpdateMap(x2, a.rep, bb2, F);

      if (x1 != x2) {
         cerr << "******** oops\n";
         break;
      }
   }

   cerr << "\n";
}

void divremtest()
{
   cerr << "divrem";
   for (long iter = 0; iter < ITER; iter++) {
      if (iter % 100 == 0) cerr << ".";

      long n = RandomBnd(5000) + 300;
      long dq = RandomBnd(n);

      zz_pX f;
      random(f, n);
      SetCoeff(f, n);
      zz_pXModulus F(f);

      zz_pX a, q, r, q1, r1;

      random(a, 2*n-1);

      DivRem(q, r, a, F);
      rem(r1, a, F);
      div(q1, a, F);

      if (deg(r) >= n || a != q*f + r || q != q1 || r != r1) {
         cerr << "******** oops\n";
         break;
      }
   }

   cerr << "\n";
}

int main()
{
   long p;
   p = GenPrime_long(NTL_SP_NBITS);

   zz_p::init(p);

   multest();
   sqrtest();
   mulmodtest();
   sqrmodtest();
   mulmod1test();
   divremtest();
   updatetest();

   zz_p::FFTInit(0);

   cerr << "FFT Prime\n";

   multest();
   sqrtest();
   mulmodtest();
   sqrmodtest();
   mulmod1test();
   divremtest();
   updatetest();

}


/*
 * Chrono: measure time duration between two points with boost.datetime
 *
 * Copyright (c) 2012 Jérémie Decock
 *
 * Required: boost.datetime library
 * Usage: g++ chrono.cc
 *
 */

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

int main() {

    boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time();

    // Do something...
    for(double x=0.0 ; x<10.0 ; x+=0.0000001) {
        double y = std::sqrt(x);
    }

    boost::posix_time::ptime end_time = boost::posix_time::microsec_clock::local_time();
    boost::posix_time::time_duration delta_time = end_time - start_time;

    std::cout << delta_time.total_milliseconds() << "ms" << std::endl;

    return 0;
}


/*
	Copyright 2014 Kristina Simpson <sweet.kristas@gmail.com>

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

		http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
*/

#pragma once

#include <tuple>
#include <boost/graph/astar_search.hpp>
#include <boost/graph/adjacency_list.hpp>

#include "geometry.hpp"
#include "game_state.hpp"
#include "hex_logical_fwd.hpp"

namespace hex
{
	typedef float cost;
	typedef point node_type;
	typedef boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS, boost::no_property, boost::property<boost::edge_weight_t, cost>> hex_graph;
	typedef boost::property_map<hex_graph, boost::edge_weight_t>::type WeightMap;
	typedef hex_graph::vertex_descriptor vertex;
	typedef hex_graph::edge_descriptor edge_descriptor;
	typedef std::pair<point, point> edge;

	struct graph_t
	{
		graph_t(size_t size) : graph(size) {}
		hex_graph graph;
		std::map<point, int> reverse_map;
		std::vector<point> vertices;
	};
	typedef std::shared_ptr<graph_t> hex_graph_ptr;

	typedef std::vector<point> result_path;

	hex_graph_ptr create_cost_graph(const game::state& gs, const point& src, float max_cost);
	hex_graph_ptr create_graph(const game::state& gs, int x=0, int y=0, int w=0, int h=0);
	result_list find_available_moves(hex_graph_ptr graph, const point& src, float max_cost);
	result_path find_path(hex_graph_ptr graph, const point& src, const point& dst);
}


/*Copyright (c) 2019, Suliman Alsowelim
All rights reserved.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
#import <opencv2/opencv.hpp>
#import "fingerprint.h"
#include <iostream>
#include <algorithm>
#include <vector>
#include <limits>
#include <iterator>
#include <iostream>
#include <typeinfo>
#include <math.h>
#include <chrono>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/uuid/sha1.hpp>
#include <fstream>

using boost::property_tree::ptree;
using namespace std;

int DEFAULT_FAN_VALUE = 15;
int MIN_HASH_TIME_DELTA = 0;
int MAX_HASH_TIME_DELTA = 200;
int FINGERPRINT_REDUCTION = 20;
int PEAK_NEIGHBORHOOD_SIZE = 20;
float DEFAULT_AMP_MIN = 10;
int DEFAULT_WINDOW_SIZE = 4096;
float DEFAULT_OVERLAP_RATIO = 0.5;
float FS = 44100.0;

std::vector<std::vector<float>> stride_windows(const std::vector<float>& data, size_t blocksize, size_t overlap){
  //https://stackoverflow.com/questions/21344296/striding-windows/21345055
  std::vector<std::vector<float>> res;
  size_t minlen = (data.size() - overlap)/(blocksize - overlap);
  auto start = data.begin();
  for (size_t i=0; i<blocksize; ++i)
  {
    res.emplace_back(std::vector<float>());
    std::vector<float>& block = res.back();
    auto it = start++;
    for (size_t j=0; j<minlen; ++j)
    {
      block.push_back(*it);
      std::advance(it,(blocksize-overlap));
    }
  }
  return res;
}

int detrend(std::vector<std::vector<float>>& data){
  size_t nocols = data[0].size();
  size_t norows = data.size();
  float mean = 0;
  for (size_t i=0; i<nocols; ++i){
    for (size_t j=0; j<norows; ++j){
      mean = mean + data[j][i];
    }
  }
  mean = mean/(norows*nocols);
  for (size_t i=0; i<nocols; ++i){
    for (size_t j=0; j<norows; ++j){
      data[j][i] = data[j][i] - mean;
    }
  }
  return 0;
}

std::vector<float> create_window(int wsize){
  std::vector<float> res;
  float multiplier;
  for (int i = 0; i < wsize; i++) {
    multiplier = 0.5 - 0.5 *(cos(2.0*M_PI*i/(wsize-1)));
    res.emplace_back(multiplier);
  }
  return res;
}

void apply_window(std::vector<float> &hann_window,std::vector<std::vector<float>>& data){
  size_t nocols = data[0].size();
  size_t norows = data.size();
  for (size_t i=0; i<nocols; ++i){
    for (size_t j=0; j<norows; ++j){
      data[j][i] = data[j][i] * hann_window[j];
    }
  }

}

std::string get_sha1(const std::string& p_arg)
{
  boost::uuids::detail::sha1 sha1;
  sha1.process_bytes(p_arg.data(), p_arg.size());
  unsigned hash[5] = {0};
  sha1.get_digest(hash);
  // Back to string
  char buf[41] = {0};
  for (int i = 0; i < 5; i++)
  {
    std::sprintf(buf + (i << 3), "%08x", hash[i]);
  }

  return std::string(buf);
}

std::string generate_hashes(vector<pair<int,int>> &v_in){
  //sorting
  //https://stackoverflow.com/questions/279854/how-do-i-sort-a-vector-of-pairs-based-on-the-second-element-of-the-pair
  std::sort(v_in.begin(), v_in.end(), [](auto &left, auto &right) {
    if (left.second == right.second)
      return left.first < right.first;
    return left.second < right.second;
  });
  std::ostringstream buf;
  buf << "[";
  for(int i=0; i<v_in.size(); i++){
    for(int j=1; j<DEFAULT_FAN_VALUE; j++){
      if ((i+j) < v_in.size()){
        int freq1 = v_in[i].first;
        int freq2 = v_in[i+j].first;
        int time1 = v_in[i].second;
        int time2 = v_in[i+j].second;
        int t_delta = time2 - time1;
        if ((t_delta >= MIN_HASH_TIME_DELTA) and (t_delta <= MAX_HASH_TIME_DELTA)){
          char buffer [100];
          snprintf(buffer, sizeof(buffer),"%d|%d|%d", freq1,freq2,t_delta);
          std::string to_be_hashed = buffer;
          std::string hash_result = get_sha1(to_be_hashed).erase(FINGERPRINT_REDUCTION,40);
          ptree pt;
          pt.put ("hash", hash_result);
          pt.put ("offset", time1);
          if(buf.str() != "["){
            buf << ",";
          }
          write_json(buf, pt, false);
        }
      }
    }
  }
  buf << "]";
  return buf.str();
}

vector<pair<int,int>> get_2D_peaks (cv::Mat  data){
  /* generate binary structure and apply maximum filter*/
  cv::Mat tmpkernel = cv::getStructuringElement(cv::MORPH_CROSS,cv::Size(3,3),cv::Point(-1,-1));
  cv::Mat kernel = cv::Mat(PEAK_NEIGHBORHOOD_SIZE*2+1,PEAK_NEIGHBORHOOD_SIZE*2+1, CV_8U, uint8_t(0));
  kernel.at<uint8_t>(PEAK_NEIGHBORHOOD_SIZE,PEAK_NEIGHBORHOOD_SIZE) = uint8_t(1);
  cv::dilate(kernel, kernel, tmpkernel,cv::Point(-1, -1), PEAK_NEIGHBORHOOD_SIZE,1,1);
  cv::Mat d1;
  cv::dilate(data, d1, kernel);/* d1 now contain m1 with max filter applied */
  /* generate eroded background */
  cv::Mat background = (data == 0); // 255 if element == 0 , 0 otherwise
  cv::Mat local_max = (data == d1); // 255 if true, 0 otherwise
  cv::Mat eroded_background;
  cv::erode(background, eroded_background, kernel);
  cv::Mat detected_peaks = local_max - eroded_background;
  /* now detected peaks.size == m1.size .. iterate through m1. get amp where peak == 255 (true), get indices i,j as well.*/
  vector<pair<int,int>> freq_time_idx_pairs;
  for(int i=0; i<data.rows; ++i){
    for(int j=0; j<data.cols; ++j){
      if ((detected_peaks.at<uint8_t>(i, j) == 255) and (data.at<float>(i,j) > DEFAULT_AMP_MIN)) {
        freq_time_idx_pairs.push_back(std::make_pair(i,j));
      }
    }
  }

  return freq_time_idx_pairs;

}

void max_filter(std::vector<std::vector<float>>& data){
  //https://gist.github.com/otmb/014107e7b6c6d6a79f0ac1ccc456580a
  cv::Mat m1(data.size(), data.at(0).size(), CV_32F);
  for(int i=0; i<m1.rows; ++i)
    for(int j=0; j<m1.cols; ++j)
      m1.at<float>(i, j) = data.at(i).at(j);

  /* generate binary structure and apply maximum filter*/
  cv::Mat tmpkernel = cv::getStructuringElement(cv::MORPH_CROSS,cv::Size(3,3),cv::Point(-1,-1));
  cv::Mat kernel = cv::Mat(PEAK_NEIGHBORHOOD_SIZE*2+1,PEAK_NEIGHBORHOOD_SIZE*2+1, CV_8U, uint8_t(0));
  kernel.at<uint8_t>(PEAK_NEIGHBORHOOD_SIZE,PEAK_NEIGHBORHOOD_SIZE) = uint8_t(1);
  cv::dilate(kernel, kernel, tmpkernel,cv::Point(-1, -1), PEAK_NEIGHBORHOOD_SIZE,1,1);
  cv::Mat d1;
  cv::dilate(m1, d1, kernel);
  /* d1 now contain m1 with max filter applied */
  /* generate eroded background */
  cv::Mat background = (m1 == 0);
  cv::Mat local_max = (m1 == d1);
  cv::Mat eroded_background;
  cv::erode(background, eroded_background, kernel);
  cv::Mat detected_peaks = local_max - eroded_background;
  vector<pair<int,int>> freq_time_idx_pairs;
  for(int i=0; i<m1.rows; ++i){
    for(int j=0; j<m1.cols; ++j){
      if ((detected_peaks.at<uint8_t>(i, j) == 255) and (m1.at<float>(i,j) > DEFAULT_AMP_MIN)) {
        freq_time_idx_pairs.push_back(std::make_pair(i,j));
      }
    }
  }
}

std::string fingerprint (float * data, int data_size){
  std::vector<float> vec(&data[0], data + data_size);
  // see mlab.py on how to decide number of frequencies
  int max_freq = 0; //onesided
  if (DEFAULT_WINDOW_SIZE % 2 == 0){
    max_freq =  int(std::floor(DEFAULT_WINDOW_SIZE / 2)) + 1;
  }else{
      max_freq =  int(std::floor((DEFAULT_WINDOW_SIZE+1) / 2));
  }

  std::vector<std::vector<float>> blocks = stride_windows(vec, DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE*DEFAULT_OVERLAP_RATIO);
  std::vector<float> hann_window = create_window(DEFAULT_WINDOW_SIZE);
  apply_window(hann_window,blocks);

  cv::Mat dst(blocks[0].size(),blocks.size(), CV_32F);
  for(int i=0; i<dst.rows; ++i)
    for(int j=0; j<dst.cols; ++j){
      dst.at<float>(i, j) = blocks[j][i];
    }
  cv::dft(dst,dst,cv::DftFlags::DFT_COMPLEX_OUTPUT+cv::DftFlags::DFT_ROWS,0);
  cv::mulSpectrums(dst,dst,dst,0,true);

  cv::Mat dst2(max_freq,blocks.at(0).size(), CV_32F);
  for(int i=0; i<max_freq; ++i)
    for(int j=0; j<dst2.cols; ++j){
      dst2.at<float>(i, j) = dst.ptr<float>(j)[2*i];
    }

  for(int i=1; i<dst2.rows -1; ++i)
    for(int j=0; j<dst2.cols; ++j)
      dst2.at<float>(i, j) = dst2.at<float>(i, j)*2;

  dst2 = dst2 * (1.0/FS);
  float sum = 0.0;
  float tmp = 0.0;
  for(unsigned int i = 0; i < hann_window.size(); i++){
    if(hann_window[i] < 0)
      tmp = hann_window[i]* -1;
    else
      tmp = hann_window[i];
    sum = sum + (tmp*tmp);
  }
  dst2 = dst2 * (1.0/sum);
  //see https://github.com/worldveil/dejavu/issues/118
  float threshold = 0.00000001;
  for(int i=0; i<dst2.rows; ++i){
    for(int j=0; j<dst2.cols; ++j){
      if ((dst2.at<float>(i, j)) < threshold){
        dst2.at<float>(i, j) = threshold;
      }
      dst2.at<float>(i, j) = 10 * log10(dst2.at<float>(i, j));
    }
  }

  vector<pair<int,int>> v_in = get_2D_peaks(dst2);
  std::string json = generate_hashes(v_in);
  return json;
}

int main () {
  std::system("ffmpeg -hide_banner -loglevel panic -i test.mp3 -f s16le -acodec pcm_s16le -ss 0 -ac 1 -ar 22050 - > raw_data ");
  //https://www.daniweb.com/programming/software-development/threads/128352/read-a-raw-pcm-file-and-then-play-it-with-sound-in-c-or-c
  //https://stackoverflow.com/questions/49161854/reading-raw-audio-file
  std::fstream f_in;
  short speech;
  float data[200000];
  f_in.open("raw_data", std::ios::in | std::ios::binary);
  int i = 0;
  while (true) {
    f_in.read((char *)&speech, 2);
    if (!f_in.good()){
       break;
    }
    data[i] = speech;
    i++;
  }
  f_in.close();
  std::string json =  fingerprint(data,i);
  cout << json << std::endl;
  return 0;
}


#include "Log.h"
#include "Face.h"
#include <Eigen/Dense>
#include "EdgePoint.h"
#include "Face2D.h"

namespace Geotree
{
  Face::Face(const Vector3d v0, const Vector3d v1, const Vector3d v2, int _index)
    : index(_index), point0(v0), point1(v1), point2(v2)
  {
    getNormal();
  }

  bool Face::intersect(const Segment segment, std::vector <Point> &points) const
  {
    Vector3d U = segment.end - segment.begin;
    Vector3d W = segment.begin - point0;

    double D = normal.dot(U);
    double N = normal.dot(W);

    if (D == 0) // segment parallell to plane
    {
      return false;
    }

    double sI = -N/D;

    if (sI < 0.0 || sI > 1.0) // segment outside plane
    {
      return false;
    }

    Vector3d vector = segment.begin - N/D * U;

    if (!isInside(vector))
    {
      return false;
    }

    Point point(vector);
    point.facesMesh0.insert(this->index);
    point.facesMesh1.insert(segment.face0);
    point.facesMesh1.insert(segment.face1);
    point.face0edge = segment.face0edge;
    point.face1edge = segment.face1edge;
    points.push_back(point);

    return true;
  }

  void Face::getNormal()
  {
    normal = (point1 - point0).cross(point2 - point0).normalized();
  }

  bool Face::isInside(const Vector3d point) const
  {
    double dot = normal.dot(point - point0);

    // is point on face plane
    if (dot > 1.0e-14 && dot < -1.0e-14)
    {
      return false;
    }

    Vector3d e1 = point1 - point0;
    Vector3d e2 = point2 - point1;
    Vector3d e3 = point0 - point2;

    Vector3d c1 = point - point0;
    Vector3d c2 = point - point1;
    Vector3d c3 = point - point2;

    double r1 = normal.dot(e1.cross(c1));
    double r2 = normal.dot(e2.cross(c2));
    double r3 = normal.dot(e3.cross(c3));

    if (r1 < 0.0 || r2 < 0.0 || r3 < 0.0)
    {
      return false;
    }

    return true;
  }

  std::vector<Segment> Face::getSegments()
  {
    std::vector<Segment> segments;
    segments.push_back(Segment(point0, point1, 0));
    segments.push_back(Segment(point1, point2, 1));
    segments.push_back(Segment(point2, point0, 2));
    return segments;
  }

  bool Face::connected(const Vector3d point) const
  {
    if (this->point0 == point
	|| this->point1 == point
	|| this->point2 == point)
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  bool Face::connected(const Face face) const
  {
    if (connected(face.point0)) return true;
    else if (connected(face.point1)) return true;
    else if (connected(face.point2)) return true;
    else return false;
  }

  double Face::lengthside(Axis axis)
  {
    double min = point0[axis];
    double max = point0[axis];

    if (point1[axis] < min) min = point1[axis];
    if (point1[axis] > max) max = point1[axis];

    if (point2[axis] < min) min = point2[axis];
    if (point2[axis] > max) max = point2[axis];

    return max - min;
  }

  Axis Face::shortestside()
  {
    double dX = lengthside(X);
    double dY = lengthside(Y);
    double dZ = lengthside(Z);

    if (dX < dY)
    {
      if (dX < dZ)
      {
	return X;
      }
      else
      {
	return Z;
      }
    }
    else if (dY < dZ)
    {
      return Y;
    }
    else
    {
      return Z;
    }
  }

  std::vector <Matrix<int, Dynamic, 3>> Face::split(std::vector <std::set<Point>> paths)
  {
    std::vector <Matrix<int, Dynamic, 3>> groups;

    std::vector <EdgePoint> edgepoints;

    for (std::set<Point> path : paths)
    {
      EdgePoint ep0(*path.begin());
      EdgePoint ep1(*path.end());

      edgepoints.push_back(ep0);
      edgepoints.push_back(ep1);
    }

    Face2D face2d(*this);

    Log().debug() << face2d.dropaxis;

    // sort edge points
    (void) &paths;
    return groups;
  }
}


//  ========================================================================
//  Author: Youhua Xu
//  Date:   Jan-7, 2017
//
//  Supernovae data structures and nuisance parameters
//
//  JLA is defined in another independent source file
//  ========================================================================

#ifndef __SNE_SNLS3__
#define __SNE_SNLS3__

#include <string>
#include <armadillo>
#include <imcmc/imcmc.hpp>
#include <imcmc/parser++.hpp>

#include "ParamList.hpp"

struct SNe_SNLS{

    DataInfo    data_info;

    int         sne_num;            //  472

    double 	    pecz;               // = 0.001 --> 300 km/sec

    bool        use_four_disp;      // if true, then use four dispersion for each subset
    double      intrinsicdisp;      //  0.13
    double      intrinsicdisp0;     //  0.0675
    double      intrinsicdisp1;     //  0.1133
    double      intrinsicdisp2;     //  0.0815
    double      intrinsicdisp3;     //  0.0989

    bool        twoscriptmfit;      //  default is set to false
    double      scriptmcut;         //  10
    double      scriptMB1, scriptMB2;   // used only if twoscriptmfit == True

    bool        marg_scriptm;   // default true, to be consistent with SNLS3 papers
    arma::vec   K1;
    arma::vec   K2;

    SNe_SNLS(); // do nothing
    ~SNe_SNLS(); // do nothing

//  lightcurvae data
    std::vector<std::string>  sne_name;
    std::vector<int>          set;

    arma::vec   zcmb, zhel, dz;
    arma::vec   mb, dmb;
    arma::vec   s, ds;
    arma::vec   c, dc;
    arma::vec   var3, dvar3;
    arma::vec   cov_m_s;
    arma::vec   cov_m_c;
    arma::vec   cov_s_c;

//  covariance matrix,
    arma::mat   cov_mB_mB;
    arma::mat   cov_mB_alpha;
    arma::mat   cov_mB_beta;
    arma::mat   cov_alpha_alpha;
    arma::mat   cov_alpha_beta;
    arma::mat   cov_beta_beta;

//  store pre-computed variable
    arma::vec   pre_vars;

//  every time alpha, beta, scriptMB been changed, the cov_tot will be updated
    double      alpha, beta, scriptMB;
    arma::mat   cov_tot, icov_tot;
    void        ReadCov( arma::mat& covmat, std::string& covmat_file );
    void        UpdateCov();
    void        UpdateNuisance( imcmc::imcmc_double par );
    void        SaveTotalCov( std::string tot_cov_fname );

    arma::vec   get_zcmb();
    arma::vec   get_zhel();
    double      max_z();

    void        Init( std::string& dataset );
};

struct SNe_SNLS_Mock{
    DataInfo    data_info;
    int         sne_num;
    bool        has_err;
    bool        use_full_cov;
	bool		invert_err; // used to check randomness of the direction of w transition
    arma::vec   z;
    arma::vec   mb, dmb;
    arma::mat   covmat_inv;
    SNe_SNLS_Mock();
    ~SNe_SNLS_Mock();
    void Init( std::string& dataset );
};

double Likelihood_SNe_SNLS( imcmc::imcmc_double&    param,
                            double&                 lndet,
                            double&                 chisq,
                            void*                   model,
                            void*                   data,
                            imcmc::istate&          state );

double Likelihood_SNe_SNLS_Mock(imcmc::imcmc_double&    param,
                                double&                 lndet,
                                double&                 chisq,
                                void*                   model,
                                void*                   data,
                                imcmc::istate&          state );

#endif  //  __SNE_SNLS3__


#include <Rcpp.h>
#include <boost/compute.hpp>

using namespace Rcpp;

namespace compute = boost::compute;

// [[Rcpp::export]]
float OpenclReduce(std::vector<float>& h_x) {

    // get the default compute device
    compute::device device = compute::system::default_device();

    // create a compute context and command queue
    compute::context context(device);
    compute::command_queue queue(context, device);

    // allocate memory on the device
    compute::vector<float> d_x(h_x.size(), context);

    // copy data from the host to the device
    compute::copy(h_x.begin(), h_x.end(), d_x.begin(), queue);

    // calculate the sum and save the result back to the host
    float total;
    compute::reduce(d_x.begin(), d_x.end(), &total, queue);

    return total;
}


//==================================================================================================
/**
  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#include <boost/simd/function/scalar/slide.hpp>
#include <scalar_test.hpp>

namespace bs = boost::simd;

STF_CASE_TPL( "Check unary slide behavior", STF_NUMERIC_TYPES )
{
  STF_EQUAL( bs::slide< 0>(T(42)), T(42) );
}

STF_CASE_TPL( "Check binary slide behavior", STF_NUMERIC_TYPES )
{
  STF_EQUAL( bs::slide<-1>(T(13),T(37)), T(37)  );
  STF_EQUAL( bs::slide< 0>(T(13),T(37)), T(13)  );
  STF_EQUAL( bs::slide<+1>(T(13),T(37)), T(37)  );
}


#include "../include/catch.hpp"

#include <armadillo>

TEST_CASE("read binary file", "[armadillo]")
{
  arma::mat x;
  x.load("rmodel.h5");
  REQUIRE(arma::size(x) == arma::size(24, 24));
}