#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Eigen_solver_traits.h>
#include <CGAL/Mean_curvature_flow_skeletonization.h>
#include <CGAL/iterator.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Bbox_3.h>

#include <boost/property_map/property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <CGAL/boost/iterator/transform_iterator.hpp>

#include <Eigen/SparseLU>
#include <Eigen/Sparse>

#include <fstream>
#include <map>

typedef CGAL::Simple_cartesian<double>                                    Kernel;
typedef Kernel::Point_3                                                    Point;
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron;

typedef boost::graph_traits<Polyhedron>::vertex_descriptor    vertex_descriptor;

typedef CGAL::Eigen_solver_traits<
        Eigen::SparseLU<
        CGAL::Eigen_sparse_matrix<double>::EigenType,
        Eigen::COLAMDOrdering<int> >  >                         SparseLU_solver;

typedef CGAL::Eigen_solver_traits<
        Eigen::SimplicialLDLT<
        CGAL::Eigen_sparse_matrix<double>::EigenType
         >  >                                             SimplicialLDLT_solver;

typedef CGAL::Default                                                         D;

// The input of the skeletonization algorithm must be a pure triangular closed
// mesh and has only one component.
bool is_mesh_valid(Polyhedron& pMesh)
{
  if (!pMesh.is_closed())
  {
    std::cerr << "The mesh is not closed.";
    return false;
  }
  if (!pMesh.is_pure_triangle())
  {
    std::cerr << "The mesh is not a pure triangle mesh.";
    return false;
  }

  // the algorithm is only applicable on a mesh
  // that has only one connected component
  std::size_t num_component;
  CGAL::Counting_output_iterator output_it(&num_component);
  CGAL::internal::corefinement::extract_connected_components(pMesh, output_it);
  ++output_it;
  if (num_component != 1)
  {
    std::cerr << "The mesh is not a single closed mesh. It has "
              << num_component << " components.";
    return false;
  }
  return true;
}

int main()
{
  Polyhedron mesh;
  std::ifstream input(CGAL::data_file_path("meshes/elephant.off"));

  if ( !input || !(input >> mesh) || mesh.empty() ) {
    std::cerr << "Cannot open data/elephant.off" << std::endl;
    return EXIT_FAILURE;
  }
  if (!is_mesh_valid(mesh)) {
    return EXIT_FAILURE;
  }

  int NTEST = 10;
  double sum = 0;
  for (int i = 0; i < NTEST; i++)
  {
    typedef CGAL::Mean_curvature_flow_skeletonization<Polyhedron, D, D, SparseLU_solver> MCF_skel;
    MCF_skel::Skeleton skeleton;

    CGAL::Timer timer;
    timer.start();
    MCF_skel mcf_skel(mesh);
    mcf_skel(skeleton);
    timer.stop();
    sum += timer.time();
  }
  std::cout << "Time of SparseLU: " << sum / NTEST << "\n";

  sum = 0;
  for (int i = 0; i < NTEST; i++)
  {
    typedef CGAL::Mean_curvature_flow_skeletonization<Polyhedron, D, D, SimplicialLDLT_solver> MCF_skel;
    MCF_skel::Skeleton skeleton;

    CGAL::Timer timer;
    timer.start();
    MCF_skel mcf_skel(mesh);
    mcf_skel(skeleton);
    timer.stop();
    sum += timer.time();
  }
  std::cout << "Time of SimplicialLDLT: " << sum / NTEST << "\n";

  return EXIT_SUCCESS;
}


#include <iostream>
#include <NTL/ZZ>
#include <NTL/ZZ_p>
#include <NTL/ZZ_px>
#include <sum.h>

using namespace NTL;

EC::EC(ZZ a, ZZ b, ZZ p)
{
	ZZ_p::init(p);
}

Point EC::sum(Point p1, Point p2)
{
	ZZ_p u = p2.y - p1.y;
        ZZ_p uu = u * u;
      	ZZ_p v = p2.x - p1.x;
      	ZZ_p vv = v * v;
	ZZ_p vvv = v * vv;
	ZZ_p R = vv * p1.x;
	ZZ_p A = uu - vvv - 2*R;
      	ZZ_p x3 = v * A;
      	ZZ_p y3 = u * (R - A) - vvv * p1.y;
      	ZZ_p Z3 = vvv;
	return EC:Point{x3, y3, z3};
}

struct EC::Point{
	ZZ_p x, y, z;
};


//==================================================================================================
/**
  EVE - Expressive Vector Engine
  Copyright : EVE Contributors & Maintainers
  SPDX-License-Identifier: MIT
**/
//==================================================================================================
#include <eve/function/heuman_lambda.hpp>
#include <boost/math/special_functions/heuman_lambda.hpp>
#include <eve/function/next.hpp>
#include <eve/function/prev.hpp>
#include <eve/function/is_denormal.hpp>
#include <eve/constant/nan.hpp>
#include <eve/constant/inf.hpp>
#include <eve/constant/minf.hpp>
#include <eve/constant/minlog.hpp>
#include <eve/platform.hpp>

#include <cmath>

TTS_CASE_TPL("Check eve::heuman_lambda return type", EVE_TYPE)
{
  TTS_EXPR_IS(eve::heuman_lambda(T(0), T(0)), T);
}

TTS_CASE_TPL("Check eve::heuman_lambda behavior two parameter", EVE_TYPE)
{
  using v_t = eve::element_type_t<T>;
  using eve::as;
  if constexpr( eve::platform::supports_invalids )
  {
   TTS_IEEE_EQUAL(eve::heuman_lambda(eve::pio_4(as<T>()), eve::nan(eve::as<T>())) , eve::nan(eve::as<T>()) );
   TTS_ULP_EQUAL(eve::heuman_lambda(eve::pio_2(as<T>()), T(1)) , eve::one(eve::as<T>()), 0.5);
   TTS_ULP_EQUAL(eve::heuman_lambda(eve::pio_2(as<T>()), T(-1)), eve::one(eve::as<T>()), 0.5);
  }

  TTS_ULP_EQUAL( eve::heuman_lambda(eve::pio_2(as<T>()), T( 0.)),  eve::one(eve::as<T>()), 0.5);
  TTS_ULP_EQUAL( eve::heuman_lambda(eve::pio_2(as<T>()), T( 0.5)), eve::one(eve::as<T>()), 4);
  TTS_ULP_EQUAL( eve::heuman_lambda(eve::pio_2(as<T>()), T( 0.9)), eve::one(eve::as<T>()), 4.55);

  TTS_ULP_EQUAL( eve::heuman_lambda(eve::pio_4(as<T>()), T( 0.)),  T(boost::math::heuman_lambda(v_t(0)  , eve::pio_4(as<v_t>()))), 1.0);
  TTS_ULP_EQUAL( eve::heuman_lambda(eve::pio_4(as<T>()), T( 0.5)), T(boost::math::heuman_lambda(v_t(0.5), eve::pio_4(as<v_t>()))), 2.0);
  TTS_ULP_EQUAL( eve::heuman_lambda(eve::pio_4(as<T>()), T( 0.9)), T(boost::math::heuman_lambda(v_t(0.9), eve::pio_4(as<v_t>()))), 1.5);

}


#include <fstream>
#include <assert.h>
#include <stdlib.h>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/plod_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/graph/graph_traits.hpp>

void printUsageAndExit()
{
  printf("%s", "Usage:./plodg x\n");
  printf("%s", "x is the size of the graph\n");
  exit(0);
}

int main(int argc, char *argv[])
{

  /* " The Power Law Out Degree (PLOD) algorithm generates a scale-free graph from three parameters, n, alpha, and beta.
  [...] The value of beta controls the y-intercept of the curve, so that increasing beta increases the average degree of vertices (credit = beta*x^-alpha).
  [...] The value of alpha controls how steeply the curve drops off, with larger values indicating a steeper curve. */
  // From Boost documentation http://www.boost.org/doc/libs/1_47_0/libs/graph/doc/plod_generator.html

  // we use setS aka std::set for edges storage
  // so we have at most one edges between 2 vertices
  // the extra cost is O(log(E/V)).
  typedef boost::adjacency_list<boost::setS> Graph;
  typedef boost::plod_iterator<boost::minstd_rand, Graph> SFGen;

  if (argc < 2) printUsageAndExit();
  int size = atoi (argv[1]);
  assert (size > 1 && size < INT_MAX);
  double alpha = 2.57; // It is known that web graphs have alpha ~ 2.72.
  double beta = size*512+1024; // This will give an average degree ~ 15

  // generation
  std::cout << "generating ... "<<'\n';
  boost::minstd_rand gen;
  Graph g(SFGen(gen, size, alpha, beta, false), SFGen(), size);
  boost::graph_traits<Graph>::edge_iterator edge, edge_end;

  std::cout << "vertices : "      << num_vertices(g) <<'\n';
  std::cout << "edges : "         << num_edges(g) <<'\n';
  std::cout << "average degree : "<< static_cast<float>(num_edges(g))/num_vertices(g)<< '\n';
  // Print in matrix coordinate real general format
  std::cout << "writing ... "<<'\n';
  std::stringstream tmp;
  tmp <<"local_test_data/plod_graph_" << size << ".mtx";
  const std::string filename = tmp.str();
  std::ofstream fout(tmp.str().c_str()) ;

  if (argv[2]==NULL)
  {
    // Power law out degree with random weights
    fout << "%%MatrixMarket matrix coordinate real general\n";
    fout << num_vertices(g) <<' '<< num_vertices(g)  <<' '<< num_edges(g) << '\n';
    float val;
    for( boost::tie(edge, edge_end) = boost::edges(g); edge != edge_end; ++edge)
    {
      val = (rand()%10)+(rand()%100)*(1e-2f);
      fout << boost::source(*edge, g) << ' ' << boost::target(*edge, g)<< ' ' << val << '\n';
    }
  }
  else if (argv[2][0]=='i')
  {
    // Power law in degree (ie the transpose will have a power law)
    // -- Edges only --
    // * Wraning * edges will be unsorted, use sort_edges.cpp to sort the dataset.
    fout << num_vertices(g) <<' '<< num_edges(g) << '\n';
    for( boost::tie(edge, edge_end) = boost::edges(g); edge != edge_end; ++edge)
      fout <<boost::target(*edge, g)<< ' ' << boost::source(*edge, g) << '\n';
  }
  else if (argv[2][0]=='o')
  {
    // Power law out degree
    // -- Edges only --
    fout << num_vertices(g) <<' '<< num_edges(g) << '\n';
    for( boost::tie(edge, edge_end) = boost::edges(g); edge != edge_end; ++edge)
      fout << boost::source(*edge, g) << ' ' << boost::target(*edge, g)<< '\n';
  }
  else printUsageAndExit();

  fout.close();
  std::cout << "done!"<<'\n';
  return 0;
}


// Boost.Geometry (aka GGL, Generic Geometry Library)
//
// Copyright (c) 2010 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <algorithms/test_equals.hpp>

#include <boost/geometry/multi/algorithms/area.hpp>
#include <boost/geometry/multi/algorithms/equals.hpp>

#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>

#include <boost/geometry/domains/gis/io/wkt/read_wkt_multi.hpp>

template <typename P>
void test_all()
{
    std::string case1 = "MULTIPOLYGON(((0 0,0 7,4 2,2 0,0 0)))";
    std::string case1_p     = "POLYGON((0 0,0 7,4 2,2 0,0 0))";

    typedef bg::model::polygon<P> polygon;
    typedef bg::model::multi_polygon<polygon> mp;
    test_geometry<mp, mp>("c1", case1, case1, true);

    test_geometry<mp, mp>("c2",
            "MULTIPOLYGON(((0 0,0 7.01,4 2,2 0,0 0)))",
            case1, false);

    // Different order == equal
    test_geometry<mp, mp>("c3",
            "MULTIPOLYGON(((0 0,0 7,4 2,2 0,0 0)),((10 10,10 12,12 10,10 10)))",
            "MULTIPOLYGON(((10 10,10 12,12 10,10 10)),((0 0,0 7,4 2,2 0,0 0)))",
            true);

    // check different types
    test_geometry<polygon, mp>("c1_p_mp", case1_p, case1, true);
    test_geometry<mp, polygon>("c1_mp_p", case1, case1_p, true);

}

int test_main( int , char* [] )
{
    test_all<bg::model::d2::point_xy<double> >();

#ifdef HAVE_TTMATH
    test_all<bg::model::d2::point_xy<ttmath_big> >();
#endif

    return 0;
}


// (C) Copyright Andrew Sutton 2007
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

//[closeness_centrality_example
#include <iostream>
#include <iomanip>

#include <boost/graph/undirected_graph.hpp>
#include <boost/graph/exterior_property.hpp>
#include <boost/graph/floyd_warshall_shortest.hpp>
#include <boost/graph/closeness_centrality.hpp>
#include <boost/graph/property_maps/constant_property_map.hpp>
#include "helper.hpp"

using namespace std;
using namespace boost;

// The Actor type stores the name of each vertex in the graph.
struct Actor
{
    string name;
};

// Declare the graph type and its vertex and edge types.
typedef undirected_graph<Actor> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef graph_traits<Graph>::edge_descriptor Edge;

// The name map provides an abstract accessor for the names of
// each vertex. This is used during graph creation.
typedef property_map<Graph, string Actor::*>::type NameMap;

// Declare a matrix type and its corresponding property map that
// will contain the distances between each pair of vertices.
typedef exterior_vertex_property<Graph, int> DistanceProperty;
typedef DistanceProperty::matrix_type DistanceMatrix;
typedef DistanceProperty::matrix_map_type DistanceMatrixMap;

// Declare the weight map so that each edge returns the same value.
typedef constant_property_map<Edge, int> WeightMap;

// Declare a container and its corresponding property map that
// will contain the resulting closeness centralities of each
// vertex in the graph.
typedef boost::exterior_vertex_property<Graph, float> ClosenessProperty;
typedef ClosenessProperty::container_type ClosenessContainer;
typedef ClosenessProperty::map_type ClosenessMap;

int
main(int argc, char *argv[])
{
    // Create the graph and a property map that provides access to[
    // tha actor names.
    Graph g;
    NameMap nm(get(&Actor::name, g));

    // Read the graph from standard input.
    read_graph(g, nm, cin);

    // Compute the distances between all pairs of vertices using
    // the Floyd-Warshall algorithm. Note that the weight map is
    // created so that every edge has a weight of 1.
    DistanceMatrix distances(num_vertices(g));
    DistanceMatrixMap dm(distances, g);
    WeightMap wm(1);
    floyd_warshall_all_pairs_shortest_paths(g, dm, weight_map(wm));

    // Compute the closeness centrality for graph.
    ClosenessContainer cents(num_vertices(g));
    ClosenessMap cm(cents, g);
    all_closeness_centralities(g, dm, cm);

    // Print the closeness centrality of each vertex.
    graph_traits<Graph>::vertex_iterator i, end;
    for(tie(i, end) = vertices(g); i != end; ++i) {
        cout << setw(12) << setiosflags(ios::left)
             << g[*i].name << get(cm, *i) << endl;
    }

    return 0;
}
//]


/* Tags: Delaunay Triangulation, Union-Find, Connected Components, Closest Neighbor

  Key idea: 1:1 correspondence between points being connected (connected components in EMST)
                <==>
                we can move between the disks of the points
                (for a radius >= 2 * minimal distance betw. them)
            Can copy code from the EMST template, and adapt:
            * three UF structures, one for the given radius U_p,
              U_a: minimum power needed to execute _all_ missions
              U_b: minimum power needed to execute same set of missions as with inital p
            * First connect components of U_p with edges <= p
            * then see, for each mission, if 4*distance <= p and
              components are connected, mission can be executed
            * If can be executed: enlarge U_b until it is covered
            * In any case: enlarge U_a until it is covered

*/
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/Triangulation_face_base_2.h>
#include <boost/pending/disjoint_sets.hpp>
#include <vector>
#include <tuple>
#include <algorithm>
#include <iostream>

// Epic kernel is enough, no constructions needed, provided the squared distance
// fits into a double (!)
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
// we want to store an index with each vertex
typedef std::size_t                                            Index;
typedef CGAL::Triangulation_vertex_base_with_info_2<Index,K>   Vb;
typedef CGAL::Triangulation_face_base_2<K>                     Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb>            Tds;
typedef CGAL::Delaunay_triangulation_2<K,Tds>                  Triangulation;

// As edges are not explicitly represented in the triangulation, we extract them
// from the triangulation to be able to sort and process them. We store the
// indices of the two endpoints, first the smaller, second the larger, and third
// the squared length of the edge. The i-th entry, for i=0,... of a tuple t can
// be accessed using std::get<i>(t).
typedef std::tuple<Index,Index,double> Edge;
typedef std::vector<Edge> EdgeV;

void solve() {
  Index n, m;
  double p;
  std::cin >> n >> m >> p;

  // read points
  typedef std::pair<K::Point_2,Index> IPoint;
  std::vector<IPoint> jammers;
  jammers.reserve(n);
  for (Index i = 0; i < n; ++i) {
    int x, y;
    std::cin >> x >> y;
    jammers.push_back({K::Point_2(x, y), i});
  }
  // construct triangulation
  Triangulation t;
  t.insert(jammers.begin(), jammers.end());

  // extract edges and sort by (squared) length
  // This step takes O(n log n) time (for the sorting).
  EdgeV edges;
  edges.reserve(3*n); // there can be no more in a planar graph
  for (auto e = t.finite_edges_begin(); e != t.finite_edges_end(); ++e) {
    Index i1 = e->first->vertex((e->second+1)%3)->info();
    Index i2 = e->first->vertex((e->second+2)%3)->info();
    // ensure smaller index comes first
    if (i1 > i2) std::swap(i1, i2);
    edges.emplace_back(i1, i2, t.segment(e).squared_length());
  }
  std::sort(edges.begin(), edges.end(),
      [](const Edge& e1, const Edge& e2) -> bool {
        return std::get<2>(e1) < std::get<2>(e2);
            });

  // setup and initialize union-find data structure for initial power
  boost::disjoint_sets_with_storage<> uf_p(n);
  for (EdgeV::const_iterator e = edges.begin(); e != edges.end(); ++e) {
    // determine components of endpoints
    Index c1 = uf_p.find_set(std::get<0>(*e));
    Index c2 = uf_p.find_set(std::get<1>(*e));
    double squared_dist = std::get<2>(*e);
    if (squared_dist <= p){
      if(c1 != c2) {
       // this edge connects two different components => part of the emst
        uf_p.link(c1, c2);
      }
    } else {
      break;
    }
  }

  K::FT a = 0, b = 0;
  // setup and initialize union-find data structure for
  // a: minimum power needed to execute _all_ missions
  // b: minimum power needed to execute same set of missions as with inital p

  boost::disjoint_sets_with_storage<> uf_a(n);
  boost::disjoint_sets_with_storage<> uf_b(n);

  // we continously enlarge the tree components for a and b,
  // so we need to remember where we left off for new missions
  EdgeV::const_iterator e_iter_a = edges.begin();
  EdgeV::const_iterator e_iter_b = edges.begin();
  Index n_components_a = n;
  Index n_components_b = n;
  for (Index j = 0; j < m; j++) {
    int x0, y0, x1, y1; std::cin >> x0 >> y0 >> x1 >> y1;
    auto sj = K::Point_2(x0, y0);
    auto tj = K::Point_2(x1, y1);

    auto vertex_sj = t.nearest_vertex(sj);
    auto vertex_tj = t.nearest_vertex(tj);
    double dist_sj = CGAL::squared_distance(sj, vertex_sj->point());
    double dist_tj = CGAL::squared_distance(tj, vertex_tj->point());
    K::FT max_dist_start = 4 * std::max(dist_sj, dist_tj);

    Index vi0 = vertex_sj->info();
    Index vi1 = vertex_tj->info();

    // mission is possible with intial power
    if(max_dist_start <= p && uf_p.find_set(vi0) == uf_p.find_set(vi1)) {
      std::cout << "y";
      double squared_dist_needed = 0;
      // since covered, increase the tree of b until points are connected
      while(uf_b.find_set(vi0) != uf_b.find_set(vi1) && e_iter_b != edges.end()
            && n_components_b != 0) {
        Index c1 = uf_b.find_set(std::get<0>(*e_iter_b));
        Index c2 = uf_b.find_set(std::get<1>(*e_iter_b));
        squared_dist_needed = std::get<2>(*e_iter_b);
        if(c1 != c2) {
          // this edge connects two different components
          uf_b.link(c1, c2);
          n_components_b--;
        }
        e_iter_b++;
      }
      b = std::max({squared_dist_needed, max_dist_start, b});
    } else {
      std::cout << "n";
    }

    // same as above but for trees a
    double squared_dist_needed = 0;
    // since covered, increase the tree of b until points are connected
    while(uf_a.find_set(vi0) != uf_a.find_set(vi1) && e_iter_a != edges.end()
           && n_components_a != 0) {
      Index c1 = uf_a.find_set(std::get<0>(*e_iter_a));
      Index c2 = uf_a.find_set(std::get<1>(*e_iter_a));
      squared_dist_needed = std::get<2>(*e_iter_a);
      if(c1 != c2) {
        // this edge connects two different components
        uf_a.link(c1, c2);
        n_components_a--;
      }
      e_iter_a++;
    }
    a = std::max({squared_dist_needed, max_dist_start, a});
  }

  std::cout << "\n" << a << "\n" << b << "\n";
}

int main()
{
  std::ios_base::sync_with_stdio(false);
  std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(0);
  std::size_t t;
  for (std::cin >> t; t > 0; --t) solve();
  return 0;
}


/*! Little utility to generate a camflow grid.
 *  Laurence McGlashan (lrm29@cam.ac.uk)
 */

#include "boost/program_options.hpp"
#include <boost/math/distributions/triangular.hpp>
#include <boost/math/distributions/normal.hpp>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>

using namespace boost::program_options;
using namespace boost::math;
using namespace std;

int main(int argc, char *argv[])
{

    cout << argv[0] << " by Laurence McGlashan\n" << endl;

    string outputFile = "grid.inp";
    string distType;
    double stMixFrac = -1;
    int numberOfCells, numberOfCellsLower, numberOfCellsUpper = -1;

    {
        // Parse arguments.
        options_description desc("Allowed options for program");
        desc.add_options()
            ("help", "Show this help message.")
            ("stoich", value<double>(), "Stoichiometric mixture fraction.")
            ("outputFile", value<string>(), "Output file for grid.")
            ("cells", value<int>(), "Number of cells.")
            ("distribution", value<string>(), "Type of distribution to weight points against (triangular|normal).");

        variables_map vm;
        store(parse_command_line(argc, argv, desc), vm);
        notify(vm);

        if (vm.count("help")) {
            cout << desc << "\n";
            return 1;
        }

        if (vm.count("stoich")) {
            stMixFrac = vm["stoich"].as<double>();
            if (stMixFrac <= 0)
                throw std::logic_error("Stochiometric mixture fraction must be greater than 0.\n");
            cout<< "Stochiometric mixture fraction is " << stMixFrac << ".\n";
        } else {
            throw std::logic_error("Stochiometric mixture fraction was not provided.\n");
        }

        if (vm.count("cells")) {
            numberOfCells = vm["cells"].as<int>();
            if (numberOfCells <= 0)
                throw std::logic_error("Number of cells must be greater than 2.\n");
            if (numberOfCells%2 != 0)
                throw std::logic_error("Number of cells must be even.\n");
            cout<< "Number of cells is " << numberOfCells << ".\n";
        } else {
            throw std::logic_error("Number of cells was not provided.\n");
        }

        if (vm.count("distribution")) {
            distType = vm["distribution"].as<string>();
            if (distType != "triangular" && distType != "normal")
                    throw std::logic_error("Distribution " + distType + " not available.\n");
            cout<< "Distribution used will be " << distType << ".\n";
        } else {
            throw std::logic_error("Distribution was not provided.\n");
        }

        if (vm.count("outputFile")) {
            outputFile = vm["outputFile"].as<string>();
            cout<< "Grid will be output to "
                << outputFile << ".\n";
        } else {
            cout<< "outputFile was not provided. Use default of grid.inp.\n";
        }
    }

    // Calculate the grid here. The values are the cell edges.
    vector<double> grid;
    grid.push_back(0.0);
    grid.push_back(stMixFrac);
    grid.push_back(1.0);

    numberOfCellsLower = numberOfCells/2.0;
    numberOfCellsUpper = numberOfCells/2.0;

    //////////// Generate grid here ///////////

    // Construct uniform grid.
    for (size_t i=1; i<numberOfCellsLower; ++i)
    {
            grid.push_back(2.0*i*stMixFrac/numberOfCells);
    }
    for (size_t i=1; i<numberOfCellsUpper; ++i)
    {
            grid.push_back(stMixFrac + 2.0*i*(1.0-stMixFrac)/numberOfCells);
    }

    // Sort the values.
    sort(grid.begin(), grid.end());

    if (distType == "triangular")
    {
        triangular s(0.0,stMixFrac,1.0);
        double max = pdf(s,stMixFrac);
        for (size_t i=1; i<=numberOfCells; ++i)
        {
            grid[i] = stMixFrac + (grid[i]-stMixFrac)*(1.0-pdf(s,grid[i])/max);
        }
    }

    if (distType == "normal")
    {
        normal s(stMixFrac,0.5);
        vector<double> spacingFactor, pdfSaved;

        for (size_t i=0; i<=numberOfCells; ++i)
            pdfSaved.push_back(pdf(s,grid[i]));

        for (size_t i=0; i<numberOfCells; ++i)
            spacingFactor.push_back(abs(pdfSaved[i+1] - pdfSaved[i]));

        double normalise = accumulate(spacingFactor.begin(),spacingFactor.end(),0.0);
        for (size_t i=1; i<numberOfCells; ++i)
            grid[i] = grid[i-1] + abs(pdfSaved[i]-pdfSaved[i-1])/normalise;
    }

    //////////// End Generate grid here ///////

    // Sort the values.
    sort(grid.begin(), grid.end());

    // Output the grid.
    ofstream out;
    out.open(outputFile.c_str(), ios::trunc);
    if (out.good())
    {
        for (size_t i=0; i<grid.size(); ++i)
        {
            out << setprecision(10) << grid[i] << endl;
        }
    }

    cout << "\nProgram End." << endl;

    return 0;

}


#ifndef QUADRATICPROBLEM_H
#define QUADRATICPROBLEM_H

#include <CoMISo/Config/config.hh>
#include <CoMISo/Utils/StopWatch.hh>
#include <vector>
#include <CoMISo/NSolver/NProblemInterface.hh>
#include <Base/Code/Quality.hh>
LOW_CODE_QUALITY_SECTION_BEGIN
#include <Eigen/Eigen>
#include <Eigen/Core>
#include <Eigen/Sparse>
LOW_CODE_QUALITY_SECTION_END

//== NAMESPACES ===============================================================

namespace COMISO {

// this problem optimizes the quadratic functional 0.5*x^T A x -x^t b + c
class QuadraticProblem : public COMISO::NProblemInterface
{
public:

  // Sparse Matrix Type
  //  typedef Eigen::DynamicSparseMatrix<double,Eigen::ColMajor> SMatrixNP;

  QuadraticProblem()
  : A_(0,0), b_(Eigen::VectorXd::Index(0)), c_(0.0)
  {

  }

  QuadraticProblem(SMatrixNP& _A, Eigen::VectorXd& _b, const double _c)
  : A_(_A), c_(_c)
  {
    if(A_.rows() != A_.cols())
      std::cerr << "Warning: matrix not square in QuadraticProblem" << std::endl;
    b_ = _b;
    x_ = Eigen::VectorXd::Zero(A_.cols());
  }

  // number of unknowns
  virtual int n_unknowns()
  {
     return A_.rows();
  }

  // initial value where the optimization should start from
  virtual void initial_x(double* _x)
  {
        for( int i=0; i<this->n_unknowns(); ++i)
            _x[i] = x_[i];
  }

  // function evaluation at location _x
  virtual double eval_f( const double* _x )
  {
    Eigen::Map<const Eigen::VectorXd> x(_x, this->n_unknowns());

    return (double)(x.transpose()*A_*x)*0.5 - (double)(x.transpose()*b_) + c_;
  }

  // gradient evaluation at location _x
  virtual void   eval_gradient( const double* _x, double*    _g)
  {
    Eigen::Map<const Eigen::VectorXd> x(_x, this->n_unknowns());
    Eigen::Map<Eigen::VectorXd> g(_g, this->n_unknowns());

    g = A_*x - b_;
   }

  // hessian matrix evaluation at location _x
  virtual void   eval_hessian ( const double* _x, SMatrixNP& _H)
  {
    _H = A_;
  }

  // print result
  virtual void   store_result ( const double* _x               )
  {
    Eigen::Map<const Eigen::VectorXd> x(_x, this->n_unknowns());
    x_ = x;
  }

  // get current solution
  Eigen::VectorXd& x() { return x_;}

  // advanced properties
  virtual bool   constant_hessian() const { return true; }

  void set_A(const SMatrixNP& _A)
  {
    A_ = _A;
    if(A_.rows() != A_.cols())
        std::cerr << "Warning: matrix not square in QuadraticProblem" << std::endl;
    x_ = Eigen::VectorXd::Zero(A_.cols());
  }

  void set_b(const Eigen::VectorXd& _b)
  {
    b_ = _b;
  }

  void set_c( const double _c)
  {
    c_ = _c;
  }

private:

  // quadratic problem 0.5*x^T A x -x^t b + c
 SMatrixNP       A_;
 Eigen::VectorXd b_;
 double          c_;
 // current solution, which is also used as initial value
 Eigen::VectorXd x_;
};

//=============================================================================
} // namespace COMISO
//=============================================================================

#endif // QUADRATICPROBLEM_H


#include "pch.h"
#include "CalculatorCore.h"
#include <stack>
#include <sstream>
#include <string>
#include <unordered_map>
#include <boost/multiprecision/cpp_dec_float.hpp>

using namespace std;
using namespace boost::multiprecision;

auto op_dict = unordered_map<char, int>{
    {'\n', 0},
    {')',  0},
    {'&',  1},
    {'|',  1},
    {'+',  2},
    {'-',  2},
    {'*',  3},
    {'/',  3},
    {'!',  4},
    {'(',  5}
};

auto __calculator(stringstream& in, bool isInitial) -> cpp_dec_float_100 {
    auto ops = stack<char>();
    auto nums = stack<cpp_dec_float_100>();
    auto calculate = [&] {
        if (nums.empty())
            throw runtime_error("Invalid expression");
        auto op = ops.top();
        ops.pop();
        auto res = (cpp_dec_float_100)0;
        if (op == '!') {
            auto x = nums.top();
            nums.pop();
            res = !x;
            nums.push(res);
            return;
        }
        if (nums.size() < 2)
            throw runtime_error("Invalid expression");
        auto y = nums.top();
        nums.pop();
        auto x = nums.top();
        nums.pop();
        if (op == '+')
            res = x + y;
        else if (op == '-')
            res = x - y;
        else if (op == '*')
            res = x * y;
        else if (op == '&')
            res = x && y;
        else if (op == '|')
            res = x || y;
        else {
            if (y == 0)
                throw runtime_error("Math error");
            res = x / y;
        }
        nums.push(res);
    };
    while (!in.eof()) {
        if (isdigit(in.peek())) {
            auto temp = string();
            while (isdigit(in.peek()))
                temp += (char)in.get();
            nums.push(cpp_dec_float_100(temp));
            continue;
        }
        auto temp = (char)in.get();
        auto priority = op_dict[temp];
        if (priority == 2) {
            while (op_dict[in.peek()] == 2)
                temp = temp == in.get() ? '+' : '-';
            if (nums.empty())
                nums.push(0);
        }
        else if (priority == 3) {
            auto ch = '+';
            while (op_dict[in.peek()] == 2)
                ch = ch == in.get() ? '+' : '-';
            if (!nums.empty() && ch == '-') {
                auto temp_num = nums.top();
                nums.pop();
                nums.push(-temp_num);
            }
        }
        if (temp == '(') {
            nums.push(__calculator(in, false));
            continue;
        }
        while (!ops.empty() && priority <= op_dict[ops.top()])
            calculate();
        if (temp == ')') {
            if (isInitial)
                throw runtime_error("Invalid expression");
            break;
        }
        if (temp == '\n')
            break;
        ops.push(temp);
    }
    if (!ops.empty() || nums.size() != 1)
        throw runtime_error("Invalid expression");
    return nums.top();
}

auto calculator(stringstream& in) -> cpp_dec_float_100 {
    return __calculator(in, true);
}


///////////////////////////////////////////////////////////////////////////////
// statistics::survival::data::example::data.cpp                             //
//                                                                           //
//  Copyright 2009 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#include <vector>
#include <ostream>
#include <fstream>
#include <stdexcept>
#include <string> //needed?
#include <algorithm>
#include <iterator>
#include <boost/tuple/tuple.hpp>
#include <boost/range.hpp>
#include <boost/assert.hpp>
#include <boost/foreach.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/iterator/range_cycle.hpp>
#include <boost/statistics/survival/data/include.hpp>
#include <libs/statistics/survival/data/example/data.h>

void example_data(std::ostream& out){
    out << "-> example_data : ";

    // Steps shown in this example:
    //
    // Records creation
    // Events creation
    // I/O
    // Statistics

    using namespace boost;
    using namespace statistics;
    namespace surv = statistics::survival;

    // [ Types ]
    typedef unsigned val_; // do not modify
    typedef std::vector<val_> vals_;

    // Records
    typedef surv::data::record<val_> record_;
    typedef std::vector<record_> records_;
    typedef range_iterator<records_>::type it_record_;

    // Events
    typedef surv::data::event<val_> event_;
    typedef std::vector<event_> events_;
    typedef range_iterator<events_>::type it_event_;

    // I/O
    typedef boost::archive::text_oarchive oa_;
    typedef boost::archive::text_iarchive ia_;

    // Covariates
    typedef val_                                    x_;
    typedef vals_                                   r_x_;
    typedef range_cycle<>                           range_cycle_;
    typedef range_cycle_::apply<r_x_>::type         x_cycle_;

    // Statistics
    typedef surv::data::mean_event<val_>            me_;
    typedef std::vector<me_>                        mes_;
    typedef surv::data::mean_events_by_covariate<val_,x_> mes_by_x_;

    // [ Constants ]
    const unsigned n_record = 4;
    const val_ entry_bound = n_record - 1;
    const val_ fail_time = 2;

    // [ Records ]
    records_ records;
    events_ events;
    for(val_ i = 0; i<n_record; i++){
        val_ entry_t = i;
        record_ record(entry_t,fail_time);
        records.push_back(record);
    }

    out << " records : ";
    for(val_ i = 0; i<n_record; i++){
        out << records[i] << ' ';
    }

    // [ Events ]

    surv::data::events(
        begin(records),
        end(records),
        entry_bound,
        std::back_inserter(events)
    );

    // Analysis for n_record = 4 and entry_bound = 3;
    //      e       ft      dt     ft<=dt  min(ft,dt)
    //      0       2       3       1       2
    //      1       2       2       1       2
    //      2       2       1       0       1
    //      3       2       0       NA      NA

    BOOST_ASSERT(size(events) == entry_bound);
    out << " events : ";
    BOOST_FOREACH(const event_& e,events){
        out << e << ' ';
    }

    // [ I/O ]
    const char* path = "./serialized_events";

    {
        // Save events
        std::ofstream ofs(path);
        oa_ oa(ofs);
        BOOST_FOREACH(const event_& e,events){
            oa << e;
            ofs.flush();
        }
    }
    val_ n = size(events);
    events_ events2;
    {
        // Recover events
        event_ tmp;
        std::ifstream ifs(path);
        if(ifs.good()){
            ia_ ia(ifs);
            val_ j = 0;
            //while(true){ //TODO
            while(j<n){
                ia >> tmp;
                events2.push_back(tmp);
                // TODO
                //if (ifs.eof()) break;
                //if (ifs.fail()){
                //    throw std::runtime_error("error reading");
                //}
                ++j;
            }
        }else{
            std::string str = "error opening : ";
            str.append( path );
            throw std::runtime_error(str);
        }
    }
    BOOST_ASSERT(n == size(events2));
    for(val_ i = 0; i<n; i++){
        BOOST_ASSERT(events[i] == events2[i]);
    }

    // [ Statistics ]
    // Assume the records were generated conditional on the following
    // covariates:
    r_x_ r_x;
    {
        using namespace boost::assign;
        r_x += 1, 2;
    }
    x_cycle_ x_cycle = range_cycle_::make(r_x,0,n_record);
    out << "size(x_cycle) = " << size(x_cycle) << std::endl;
    BOOST_ASSERT( size(x_cycle)>=size(events) );
    // Resize x_cycle to a size that matches that of events
    x_cycle.advance_end(
        - (size(x_cycle) - size(events))
    );
    BOOST_ASSERT( size(x_cycle)==size(events) );

    mes_by_x_ mes_by_x(r_x);
    mes_by_x(
        boost::begin(x_cycle),
        boost::end(x_cycle),
        boost::begin(events)
    );

    mes_ mes;
    mes_by_x.tails(std::back_inserter(mes));

    // Analysis for n_record = 4 and entry_bound = 3;
    //      x       ft<=dt  min(ft,dt)
    //      1       1       2
    //      2       1       2
    //      1       0       1
    // -------------------------------
    //      1       1/2=0   3/2 = 1         // Remember, val_ = unsigned,
    //      2       1       2               // not a float

    out << "mean_events : ";
    std::copy(
        boost::begin( mes ),
        boost::end( mes ),
        std::ostream_iterator<me_>(out," ")
    );

    vals_ flat_mes;
    surv::data::vectorize_events(
        boost::begin( mes ),
        boost::end( mes ),
        std::back_inserter( flat_mes )
    );

    out << "flattened mean_events : ";
    std::copy(
        boost::begin( flat_mes ),
        boost::end( flat_mes ),
        std::ostream_iterator<val_>(out," ")
    );

//    // Dont try this here because val_ = unsigned, but you get the idea
//    surv::data::logit_log(
//        boost::begin(flat_mes),
//        boost::end(flat_mes),
//        std::back_inserter(flat_mes),
//        0.01,
//        0.01
//    );
    out << "<-" << std::endl;
}


/*!
 * \file complex.hpp
 * \author Jun Yoshida
 * \copyright (c) 2020 Jun Yoshida.
 * The project is released under the 2-clause BSD License.
 * \date August, 2020: created
 */

#pragma once

#include <cstdint>
#include <array>
#include <queue>

#include <Eigen/Dense>

#include "hnf.hpp"

//* Debug
#include "debug/debug.hpp"
//*/

namespace khover {

//! Representation of abelian groups by direct sums of cyclic groups.
struct AbGroupCyc {
    //! Rank of the free part.
    std::size_t freerank;
    //! A list of torsions.
    std::vector<int> torsions;

    //! Check if the group is torion-free
    inline bool isTorFree() const noexcept {
        return torsions.empty();
    }

    //! Check if the group is finite (<=> trivial after tensored with Q)
    inline bool isFinite() const noexcept {
        return freerank == 0;
    }

    //! Check if the group is trivial
    inline bool isZero() const noexcept {
        return isFinite() && isTorFree();
    }

    //! Pretty printer
    std::string pretty() const noexcept {
        std::string str_free
            = freerank == 0 ? std::string{} : freerank == 1 ? std::string("Z") : "Z^" + std::to_string(freerank);
        std::string str_tor{};

        for(int t : torsions) {
            if (!str_tor.empty())
                str_tor += "+";
            str_tor += "Z/" + std::to_string(t);
        }

        if(str_free.empty() && str_tor.empty())
            return std::string("0");
        else if (str_free.empty())
            return str_tor;
        else if (str_tor.empty())
            return str_free;
        else
            return str_free + "+" + str_tor;
    }
};

//! Representation of abelian groups by representation matrices.
class AbelianGroup {
public:
    using integer_t = int64_t;
    using matrix_t = Eigen::Matrix<integer_t,Eigen::Dynamic,Eigen::Dynamic>;

private:
    //! The presentation matrix, which is kept to be a column HNF.
    matrix_t m_repMat;
    //! The least rank of the free part of the abelian group.
    std::size_t m_freerk;

public:
    //! Default constructor.
    AbelianGroup() noexcept : m_repMat(0,0), m_freerk(0) {}

    //! Constructor from a presentation matrix.
    //! Represent an abelian group by a presentation matrix.
    //! \tparam IsColHNF If IsColHNF::value == true, then repMat must be in the column HNF. Otherwise, its column HNF is computed.
    template <class Derived, class IsColHNF>
    AbelianGroup(Eigen::MatrixBase<Derived> const& repMat, IsColHNF, std::size_t freerk = 0) noexcept
        : m_repMat(repMat), m_freerk(freerk)
    {
        if constexpr(!IsColHNF::value) {
            auto rk = hnf_LLL<khover::colops>(m_repMat, {}, {});
            if(rk) {
                m_repMat = m_repMat.leftCols(*rk).eval();
            }
            else {
                ERR_MSG("Something bad happended.");
            }
        }
    }

    //! Nothing special to do in destructor.
    ~AbelianGroup() = default;

    //! Get the number of generators.
    inline std::size_t ngens() const noexcept {
        return m_repMat.rows() + m_freerk;
    }

    //! Get the number of relations.
    inline std::size_t nrels() const noexcept { return m_repMat.cols(); }

    //! Get the presentation matrix.
    inline auto get_repmatrix() const noexcept {
        return (matrix_t(ngens(),nrels()) << m_repMat, matrix_t::Zero(m_freerk, m_repMat.cols())).finished();
    }

    //! Reduce the number of generators and relations by computing the Hermite normal form of the representation matrix.
    //! This will suffice in order to compute the rank of the free part.
    //! \param post Homomorphisms whose domains are *this*. They will be transformed so that their domains will be the reduced one.
    //! \param pre Homomorphisms whose codomains are *this*. They will be transformed so that their codomains will be the reduced one.
    //! \return If the function fails to compute HNF correctly, or if the homomorphisms are wrong, then it returns false.
    template <class...Posts, class...Pres>
    bool reduce(
        std::tuple<Posts&...> const & posts,
        std::tuple<Pres&...> const & pres
        ) noexcept
    {
        static_assert(
            std::conjunction_v<
            std::bool_constant<Posts::ColsAtCompileTime == Eigen::Dynamic>...
            >,
            "The function may change the number of columns of matrices in the posts parameter, so make sure they have dynamic numbers of columns.");

        static_assert(
            std::conjunction_v<
            std::bool_constant<Pres::RowsAtCompileTime == Eigen::Dynamic>...
            >,
            "The function may change the number of rows of matrices in the posts parameter, so make sure they have dynamic numbers of rows.");

        /*
         * Take columns with pivot = 1 to left
         */
        // The rank of the presentation matrix over Q (the field of rationals).
        std::size_t rk = 0;
        // The number of columns with pivot = 1.
        std::size_t upivs = 0;

        // Traverse pivots
        using Ops = khover::colops;
        for(std::size_t i=0; i < Ops::size(m_repMat) && rk < Ops::dual_t::size(m_repMat); ++i) {
            // A column with pivot 1 is found.
            if (Ops::at(m_repMat, rk).coeff(i) == 1) {
                // If there is a column with non-unit pivot on left, swap with it.
                if (rk > upivs) {
                    Ops::swap(m_repMat, rk, upivs);
                }
                // If the pivot is below diagonal, raise it.
                if (i > upivs) {
                    Ops::dual_t::swap(m_repMat, i, upivs);
                    khover::for_each_tuple(
                        pres,
                        [i,upivs](auto& u) {
                            Ops::dual_t::swap(u, i, upivs);
                        });
                    khover::for_each_tuple(
                        posts,
                        [i,upivs](auto& v) {
                            Ops::swap(v, i, upivs);
                        });
                }
                ++upivs;
                ++rk;
            }
            // A column with pivot != 1 is found.
            else if (Ops::at(m_repMat, rk).coeff(i) != 0) {
                ++rk;
            }
        }

        // Reduce homomorphisms
        matrix_t redPiv_mat
            = matrix_t::Identity(
                m_repMat.rows() + m_freerk,
                m_repMat.rows() + m_freerk
                ).bottomRows(m_repMat.rows() + m_freerk - upivs);
        redPiv_mat.block(0, 0, m_repMat.rows() - upivs, upivs).noalias()
            = - m_repMat.bottomLeftCorner(m_repMat.rows() - upivs, upivs);

        khover::for_each_tuple(
            pres,
            [&](auto& u) {
                u = redPiv_mat.bottomRows(m_repMat.rows() + m_freerk - upivs) * u;
            } );
        khover::for_each_tuple(
            posts,
            [upivs](auto& v) {
                v = v.rightCols(v.cols() - upivs); //v.block(0, upivs, v.rows(), v.cols()-upivs).eval();
            } );

        // Forget thw row/columns with unital pivots.
        m_freerk += m_repMat.rows() - rk;
        m_repMat = m_repMat.block(upivs, upivs, m_repMat.rows() - upivs, rk - upivs).eval();
        rk -= upivs;

        // Compute the row HNF
        if (!hnf_LLL<khover::rowops>(m_repMat,posts, pres))
            return false;

        // Reduce the presentation matrix again.
        m_repMat = m_repMat.topRows(rk).eval();

        // Keep the presentation matrix in column HNF.
        khover::hnf_LLL<khover::colops>(m_repMat, {}, {});

        // Finish successfully.
        return true;
    }

    //! Compute the abelian group in the form of the pair of the free rank and the list of torsions.
    //! \remark The result is not necessarily in the normal form.
    AbGroupCyc
    compute() noexcept {
        do {
            reduce({}, {});
        } while(!m_repMat.isDiagonal());

        auto diag = m_repMat.diagonal();
        std::vector<int> torsions{};
        std::size_t r = 0;

        for(int i = 0; i < diag.size(); ++i) {
            if (diag.coeff(i) == 0)
                ++r;
            else if(std::abs(diag.coeff(i)) != 1)
                torsions.push_back(std::abs(diag.coeff(i)));
        }

        return {r+m_freerk, std::move(torsions)};
    }

    //! Compute the image of a homomorphism whose codomain is this abelian group.
    //! \tparam ReturnMorphism If ReturnMorphism::value == true, then the function also returns the matrix representing the morphism from the image to this group.
    template <class Derived, class DoesReturnMorphism = std::false_type>
    auto
    image(
        Eigen::MatrixBase<Derived> const& morph,
        DoesReturnMorphism = DoesReturnMorphism{}
        ) const noexcept
        -> std::conditional_t<
            DoesReturnMorphism::value,
            std::optional<std::pair<AbelianGroup,matrix_t>>,
            std::optional<AbelianGroup>
            >
    {
        // If the number of rows doesn't agree, return immediately.
        if(morph.rows() != static_cast<int>(m_freerk) + m_repMat.rows()) {
            ERR_MSG("Incompatible rows:"
                    << morph.rows() << " != "
                    << static_cast<int>(m_freerk) + m_repMat.rows());
            return std::nullopt;
        }

        // Sum of the images of the homomorphism and the representation matrix.
        matrix_t sumspace(morph.rows(), morph.cols() + m_repMat.cols());
        sumspace << morph, get_repmatrix();

        // Compute the column HNF of the sumspace.
        matrix_t u = matrix_t::Identity(sumspace.cols(), sumspace.cols());
        auto rk = hnf_LLL<khover::colops>(sumspace, std::tie(u), {});

        // Error occured.
        if(!rk) {
            ERR_MSG("Failed to compute HNF.");
            return std::nullopt;
        }

        // Return the resulting abelian group together with the homomorphism from it.
        if constexpr (DoesReturnMorphism::value) {
            return std::make_pair(
                AbelianGroup(
                    u.topRightCorner(*rk, m_repMat.cols()),
                    std::false_type{}),
                sumspace.leftCols(*rk)
                );
        }
        else {
            return AbelianGroup(
                u.topRightCorner(*rk, m_repMat.cols()),
                std::false_type{});
        }
    }
};

} // end namespace khover


/**
 * @file test_Mesh.cc
 * @brief Unitest module for the bunny_mesh/Mesh.h file.
 * @version 1.0
 * @date 2019-02-10
 *
 * @copyright Copyright (c) 2019 Pedro Henrique S. Perrusi
 *
 */
#include "gtest/gtest.h"

#include "bunny_mesh/data_io.h"
#include "bunny_mesh/Mesh.h"

#include <Eigen/Dense>
#include <math.h>
#include <iostream>

using namespace bunny_mesh;

// eigen default value for a very small number
const double precision = Eigen::NumTraits<double>::dummy_precision();

TEST(Mesh, SingleFaceNormal)
{
    // defines simple vertices matrix
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Create a triangle mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    singleFaceMesh.ComputeNormals();

    // define expected output:
    bunny_dataIO::Point3DMatrixType expectedFaceNormals(1,3);
    expectedFaceNormals << 0.0, 0.0, 1.0;

    bunny_dataIO::Point3DMatrixType expectedVerticeNormals(3,3);
    expectedVerticeNormals << 0.0, 0.0, 1.0,
                              0.0, 0.0, 1.0,
                              0.0, 0.0, 1.0;

    // test them...
    // size assertions:
    ASSERT_EQ(faces.rows(), singleFaceMesh.getFaceNormals().rows());
    ASSERT_EQ(vertices.rows(), singleFaceMesh.getVerticeNormals().rows());
    // norm assertions:
    ASSERT_TRUE(expectedFaceNormals.isApprox(singleFaceMesh.getFaceNormals()));
    ASSERT_TRUE(expectedVerticeNormals.isApprox(singleFaceMesh.getVerticeNormals()));
}

TEST(Mesh, SingleFaceNormalized)
{
    // defines simple vertices matrix
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0,  // (x=0,y=0,z=0)
                10.0, 0.0, 0.0, // (x=10,y=0,z=0)
                0.0, 10.0, 0.0; // (x=0,y=10,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Create a triangle mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    singleFaceMesh.ComputeNormals();

    // define expected output:
    bunny_dataIO::Point3DMatrixType expectedFaceNormals(1,3);
    expectedFaceNormals << 0.0, 0.0, 1.0;

    bunny_dataIO::Point3DMatrixType expectedVerticeNormals(3,3);
    expectedVerticeNormals << 0.0, 0.0, 1.0,
                              0.0, 0.0, 1.0,
                              0.0, 0.0, 1.0;

    // test them...
    // size assertions:
    ASSERT_EQ(faces.rows(), singleFaceMesh.getFaceNormals().rows());
    ASSERT_EQ(vertices.rows(), singleFaceMesh.getVerticeNormals().rows());
    // norm assertions:
    ASSERT_TRUE(expectedFaceNormals.isApprox(singleFaceMesh.getFaceNormals()));
    ASSERT_TRUE(expectedVerticeNormals.isApprox(singleFaceMesh.getVerticeNormals()));
}

TEST(MESH, ObjectAngle)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 0.0, 1.0, 0.0;

    // expected angle
    double angle = M_PI_2;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // eigen default value for a very small number
    const double precision = Eigen::NumTraits<double>::dummy_precision();

    ASSERT_TRUE(abs(singleFaceMesh.objectAngle() - M_PI_2) < precision);
}

TEST(MESH, ObjectAngleNormalized)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 0.0, 10.0, 0.0;

    // expected angle
    double angle = M_PI_2;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // eigen default value for a very small number
    const double precision = Eigen::NumTraits<double>::dummy_precision();

    ASSERT_TRUE(abs(singleFaceMesh.objectAngle() - M_PI_2) < precision);
}

TEST(MESH, RotationAxis_orientationY)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 0.0, 1.0, 0.0;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // expected result
    bunny_dataIO::Point3DType expected;
    expected << -1, 0, 0;

    ASSERT_TRUE(expected.isApprox(singleFaceMesh.RotationAxis()));
}

TEST(MESH, RotationAxis_orientationX)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 1.0, 0.0, 0.0;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // expected result
    bunny_dataIO::Point3DType expected;
    expected << 0, 1, 0;

    ASSERT_TRUE(expected.isApprox(singleFaceMesh.RotationAxis()));
}

TEST(MESH, RotationAxisNormalized)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 0.0, 10.0, 0.0;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // expected result
    bunny_dataIO::Point3DType expected;
    expected << -1, 0, 0;

    ASSERT_TRUE(expected.isApprox(singleFaceMesh.RotationAxis()));
}

TEST(MESH, matchObjectOrientationX)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 1.0, 0.0, 0.0;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // array to transform
    bunny_dataIO::Point3DType verticeX, verticeY, verticeZ;
    verticeX << 1, 0, 0;
    verticeY << 0, 1, 0;
    verticeZ << 0, 0, 1;

    // expected result
    bunny_dataIO::Point3DType expectedX, expectedY, expectedZ;
    expectedX << 0, 0, -1;
    expectedY << 0, 1, 0;
    expectedZ << 1, 0, 0;

    ASSERT_TRUE(expectedX.isApprox(singleFaceMesh.matchObjectOrientation(verticeX)));
    ASSERT_TRUE(expectedY.isApprox(singleFaceMesh.matchObjectOrientation(verticeY)));
    ASSERT_TRUE(expectedZ.isApprox(singleFaceMesh.matchObjectOrientation(verticeZ)));
}

TEST(MESH, matchObjectOrientationY)
{
    // Simple object:
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Add a orientation:
    bunny_dataIO::Point3DType orientation;
    orientation << 0.0, 1.0, 0.0;

    // create Mesh
    TriangleMesh singleFaceMesh(vertices, faces);
    // set orientation
    singleFaceMesh.setOrientation(orientation);

    // array to transform
    bunny_dataIO::Point3DType verticeX, verticeY, verticeZ;
    verticeX << 1, 0, 0;
    verticeY << 0, 1, 0;
    verticeZ << 0, 0, 1;

    // expected result
    bunny_dataIO::Point3DType expectedX, expectedY, expectedZ;
    expectedX << 1, 0, 0;
    expectedY << 0, 0, -1;
    expectedZ << 0, 1, 0;

    ASSERT_TRUE(expectedX.isApprox(singleFaceMesh.matchObjectOrientation(verticeX)));
    ASSERT_TRUE(expectedY.isApprox(singleFaceMesh.matchObjectOrientation(verticeY)));
    ASSERT_TRUE(expectedZ.isApprox(singleFaceMesh.matchObjectOrientation(verticeZ)));
}

TEST(Mesh, verticesIntoWorld)
{
    // defines simple vertices matrix
    bunny_dataIO::Point3DMatrixType vertices(3,3);
    vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
                1.0, 0.0, 0.0, // (x=1,y=0,z=0)
                0.0, 1.0, 0.0; // (x=0,y=1,z=0)

    // denines a single face
    bunny_dataIO::IndexMatrixType faces(1, 3);
    faces << 0, 1, 2;

    // Create a triangle mesh
    TriangleMesh singleFaceMesh(vertices, faces);

    // define a non-standard orientation to the object
    bunny_dataIO::Point3DType orientation;
    orientation << 1.0, 0.0, 0.0;
    singleFaceMesh.setOrientation(orientation);

    // define expected output:
    bunny_dataIO::Point3DMatrixType expectedVertices(3,3);
    expectedVertices << 0.0, 0.0, 0.0,
                        0.0, 0.0, -1.0,
                        0.0, 1.0, 0.0;

    bunny_dataIO::printArray(singleFaceMesh.getVerticesIntoWorld());

    ASSERT_TRUE(expectedVertices.isApprox(singleFaceMesh.getVerticesIntoWorld()));
}

// TEST(Mesh, NonDefaultOrientationNormals)
// {
//     // defines simple vertices matrix
//     bunny_dataIO::Point3DMatrixType vertices(3,3);
//     vertices << 0.0, 0.0, 0.0, // (x=0,y=0,z=0)
//                 1.0, 0.0, 0.0, // (x=1,y=0,z=0)
//                 0.0, 1.0, 0.0; // (x=0,y=1,z=0)

//     // denines a single face
//     bunny_dataIO::IndexMatrixType faces(1, 3);
//     faces << 0, 1, 2;

//     // Create a triangle mesh
//     TriangleMesh singleFaceMesh(vertices, faces);

//     // define a non-standard orientation to the object
//     bunny_dataIO::Point3DType orientation;
//     orientation << 0, 1, 0;
//     singleFaceMesh.setOrientation(orientation);
//     // compute normals
//     singleFaceMesh.ComputeNormals();

//     // define expected output:
//     bunny_dataIO::Point3DMatrixType expectedFaceNormals(1,3);
//     expectedFaceNormals << 0.0, 1.0, 0.0;

//     bunny_dataIO::Point3DMatrixType expectedVerticeNormals(3,3);
//     expectedVerticeNormals << 1.0, 0.0, 0.0,
//                               1.0, 0.0, 0.0,
//                               1.0, 0.0, 0.0;

//     bunny_dataIO::printArray(singleFaceMesh.getFaceNormals());

//     bunny_dataIO::printArray(singleFaceMesh.getVerticeNormals());

//     // test them...
//     // size assertions:
//     ASSERT_EQ(faces.rows(), singleFaceMesh.getFaceNormals().rows());
//     ASSERT_EQ(vertices.rows(), singleFaceMesh.getVerticeNormals().rows());
//     // norm assertions:
//     ASSERT_TRUE(expectedFaceNormals.isApprox(singleFaceMesh.getFaceNormals()));
//     ASSERT_TRUE(expectedVerticeNormals.isApprox(singleFaceMesh.getVerticeNormals()));
// }


#include "problemes.h"
#include "arithmetique.h"

#include <fstream>

#include <boost/algorithm/string.hpp>
#include <numeric>

typedef unsigned long long nombre;

ENREGISTRER_PROBLEME(22, "Names scores") {
    // Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing
    // over five-thousand first names, begin by sorting it into alphabetical order.
    // Then working out the alphabetical value for each name, multiply this value by its alphabetical
    // position in the list to obtain a name score.
    //
    // For example, when the list is sorted into alphabetical order, COLIN, which is worth
    // 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a
    // score of 938 × 53 = 49714.
    //
    // What is the total of all the name scores in the file?
    std::ifstream ifs("data/p022_names.txt");
    std::string entree;
    ifs >> entree;
    std::vector<std::string> names;
    boost::split(names, entree, boost::is_any_of(","));
    std::sort(names.begin(), names.end());
    nombre compteur = 0;
    nombre resultat = 0;
    for (const auto &name: names) {
        nombre score = std::accumulate(name.begin(), name.end(), 0ULL, [](const nombre &n, char c) {
            if (c != '"')
                return n + 1 + static_cast<nombre>(c - 'A');
            return n;
        });
        resultat += (++compteur * score);
    }
    return std::to_string(resultat);
}


// Copyright Paul A. Bristow 2013
// Copyright John Maddock 2013
// Copyright Christopher Kormanyos

// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

// Examples of std::numeric_limits usage as snippets for multiprecision documentation at multiprecision.qbk.

// Includes text as Quickbook comments.

#include <boost/assert.hpp>

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

#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/next.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp> // is decimal.
#include <boost/multiprecision/cpp_bin_float.hpp> // is binary.

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp> // Boost.Test
#include <boost/test/tools/floating_point_comparison.hpp>

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <limits> // numeric_limits
#include <iomanip>
#include <locale>

// static long double const log10Two = 0.30102999566398119521373889472449L; // log10(2.)
// It is more portable useful to use a Boost macro
// See https://www.boost.org/doc/libs/release/libs/config/doc/html/boost_config/boost_macro_reference.html
static constexpr long double log10Two = 0.30102999566398119521373889472449L;
// which expands to static constexpr on standard C++11 and up, but static const on earlier versions.

  /*`By default, output would only show the standard 6 decimal digits,
 so set precision to show all 50 significant digits, including any trailing zeros.
 This is generally useful to show the implicit precision of the type of the value.
*/

template <typename T>
int max_digits10()
{
   int significand_digits = std::numeric_limits<T>::digits;
  // constexpr int significand_digits = std::numeric_limits<T>::digits;
   return static_cast<int>(ceil(1 + significand_digits * log10Two));
} // template <typename T> int max_digits10()

// Used to test max_digits10<>() function below.

BOOST_AUTO_TEST_CASE(test_numeric_limits_snips)
{
#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(BOOST_MSVC) && (BOOST_MSVC == 1600))
  try
  {

// Example of portable way to get `std::numeric_limits<T>::max_digits10`.
//[max_digits10_1

/*`For example, to be portable (including obselete platforms) for type `T` where `T` may be:
 `float`, `double`, `long double`, `128-bit quad type`, `cpp_bin_float_50` ...
*/

  typedef float T;

  std::cout.precision(std::numeric_limits<T>::max_digits10);
  std::cout.precision(std::numeric_limits<T>::digits10);
  std::cout.setf(std::ios_base::showpoint); // Append any trailing zeros,
  // or more memorably
  std::cout << std::showpoint << std::endl; //

  std::cout << "std::cout.precision(max_digits10) = " << std::cout.precision() << std::endl; // 9

  double x = 1.2345678901234567889;

  std::cout << "x = " << x << std::endl; //

/*`which should output:

  std::cout.precision(max_digits10) = 9
  x = 1.23456789
*/

//] [/max_digits10_1]

  {
//[max_digits10_2

  double write = 2./3; // Any arbitrary value that cannot be represented exactly.
  double read = 0;
  std::stringstream s;
  s.precision(std::numeric_limits<double>::digits10); // or `float64_t` for 64-bit IEE754 double.
  s << write;
  s >> read;
  if(read != write)
  {
    std::cout <<  std::setprecision(std::numeric_limits<double>::digits10)
      << read << " != " << write << std::endl;
  }

//] [/max_digits10_2]
  // 0.666666666666667 != 0.666666666666667
  }

  {
//[max_digits10_3

  double pi = boost::math::double_constants::pi;
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  std::cout << pi << std::endl; // 3.1415926535897931

//] [/max_digits10_3]
  }
  {
//[max_digits10_4
/*`and similarly for a much higher precision type:
*/

  using namespace boost::multiprecision;

  typedef number<cpp_dec_float<50> > cpp_dec_float_50; // 50 decimal digits.

  // or using boost::multiprecision::cpp_dec_float_50;

  cpp_dec_float_50 pi = boost::math::constants::pi<cpp_dec_float_50>();
  std::cout.precision(std::numeric_limits<cpp_dec_float_50>::max_digits10);
  std::cout << pi << std::endl;
  // 3.141592653589793238462643383279502884197169399375105820974944592307816406
//] [/max_digits10_4]
  }

  {
//[max_digits10_5

  for (int i = 2; i < 15; i++)
  {
    std::cout << std::setw(std::numeric_limits<int>::max_digits10)
      << boost::math::factorial<double>(i)  << std::endl;
  }

//] [/max_digits10_5]
  }

  }
  catch(const std::exception& ex)
  {
    std::cout << "Caught Exception " << ex.what() << std::endl;
  }

  {
//[max_digits10_6

  typedef double T;

  bool denorm = std::numeric_limits<T>::denorm_min() < (std::numeric_limits<T>::min)();
  BOOST_MP_ASSERT(denorm);

//] [/max_digits10_6]
  }

  {
    unsigned char c = 255;
    std::cout << "char c = " << (int)c << std::endl;
  }

  {
//[digits10_1
    std::cout
      << std::setw(std::numeric_limits<short>::digits10 +1 +1) // digits10+1, and +1 for sign.
      << std::showpos << (std::numeric_limits<short>::max)() // +32767
      << std::endl
      << std::setw(std::numeric_limits<short>::digits10 +1 +1)
      << (std::numeric_limits<short>::min)() << std::endl;   // -32767
//] [/digits10_1]
  }

  {
//[digits10_2
    std::cout
      << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
      << std::showpos << (std::numeric_limits<unsigned short>::max)() //  65535
      << std::endl
      << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
      << (std::numeric_limits<unsigned short>::min)() << std::endl;   //      0
//] [/digits10_2]
  }

  std::cout <<std::noshowpos << std::endl;

  {
//[digits10_3
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  double d =  1e15;
  double dp1 = d+1;
  std::cout << d << "\n" << dp1 << std::endl;
  // 1000000000000000
  // 1000000000000001
  std::cout <<  dp1 - d << std::endl; // 1
//] [/digits10_3]
  }

  {
//[digits10_4
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  double d =  1e16;
  double dp1 = d+1;
  std::cout << d << "\n" << dp1 << std::endl;
  // 10000000000000000
  // 10000000000000000
    std::cout << dp1 - d << std::endl; // 0 !!!
//] [/digits10_4]
  }

  {
//[epsilon_1
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  double d = 1.;
  double eps = std::numeric_limits<double>::epsilon();
  double dpeps = d+eps;
  std::cout << std::showpoint // Ensure all trailing zeros are shown.
    << d << "\n"           // 1.0000000000000000
    << dpeps << std::endl; // 2.2204460492503131e-016
  std::cout << dpeps - d   // 1.0000000000000002
    << std::endl;
//] [epsilon_1]
  }

  {
//[epsilon_2
  double one = 1.;
  double nad = boost::math::float_next(one);
  std::cout << nad << "\n"  //  1.0000000000000002
    << nad - one // 2.2204460492503131e-016
    << std::endl;
//] [epsilon_2]
  }
  {
//[epsilon_3
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  double d = 1.;
  double eps = std::numeric_limits<double>::epsilon();
  double dpeps = d + eps/2;

  std::cout << std::showpoint // Ensure all trailing zeros are shown.
    << dpeps << "\n"       // 1.0000000000000000
    << eps/2 << std::endl; // 1.1102230246251565e-016
  std::cout << dpeps - d   // 0.00000000000000000
    << std::endl;
//] [epsilon_3]
  }

  {
    typedef double RealType;
//[epsilon_4
/*`A tolerance might be defined using this version of epsilon thus:
*/
    RealType tolerance = boost::math::tools::epsilon<RealType>() * 2;
//] [epsilon_4]
    (void)tolerance; // warning suppression
  }

  {
    bool b =
//[digits10_5
    -(std::numeric_limits<double>::max)() == std::numeric_limits<double>::lowest();
//] [/digits10_5]
    (void)b;  // warning suppression
  }

  {
//[denorm_min_1
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  if (std::numeric_limits<double>::has_denorm == std::denorm_present)
  {
    double d = std::numeric_limits<double>::denorm_min();

      std::cout << d << std::endl; //  4.9406564584124654e-324

      int exponent;

      double significand = frexp(d, &exponent);
      std::cout << "exponent = " << std::hex << exponent << std::endl; //  fffffbcf
      std::cout << "significand = " << std::hex << significand << std::endl; // 0.50000000000000000
  }
  else
  {
    std::cout << "No denormalization. " << std::endl;
  }
//] [denorm_min_1]
  }

  {
//[round_error_1
    double round_err = std::numeric_limits<double>::epsilon() // 2.2204460492503131e-016
                     * std::numeric_limits<double>::round_error(); // 1/2
    std::cout << round_err << std::endl; // 1.1102230246251565e-016
//] [/round_error_1]
  }

  {
    typedef double T;
//[tolerance_1
/*`For example, if we want a tolerance that might suit about 9 arithmetical operations,
say sqrt(9) = 3,  we could define:
*/

    T tolerance =  3 * std::numeric_limits<T>::epsilon();

/*`This is very widely used in Boost.Math testing
with Boost.Test's macro `BOOST_CHECK_CLOSE_FRACTION`
*/

    T expected = 1.0;
    T calculated = 1.0 + std::numeric_limits<T>::epsilon();

    BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);

//] [/tolerance_1]
  }

#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32))
  {
//[tolerance_2

  using boost::multiprecision::number;
  using boost::multiprecision::cpp_dec_float;
  using boost::multiprecision::et_off;

  typedef number<cpp_dec_float<50>, et_off > cpp_dec_float_50; // 50 decimal digits.
/*`[note that Boost.Test does not yet allow floating-point comparisons with expression templates on,
so the default expression template parameter has been replaced by `et_off`.]
*/

  cpp_dec_float_50 tolerance =  3 * std::numeric_limits<cpp_dec_float_50>::epsilon();
  cpp_dec_float_50 expected = boost::math::constants::two_pi<cpp_dec_float_50>();
  cpp_dec_float_50 calculated = 2 * boost::math::constants::pi<cpp_dec_float_50>();

  BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);

//] [/tolerance_2]
  }

  {
//[tolerance_3

  using boost::multiprecision::cpp_bin_float_quad;

  cpp_bin_float_quad tolerance =  3 * std::numeric_limits<cpp_bin_float_quad>::epsilon();
  cpp_bin_float_quad expected = boost::math::constants::two_pi<cpp_bin_float_quad>();
  cpp_bin_float_quad calculated = 2 * boost::math::constants::pi<cpp_bin_float_quad>();

  BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);

//] [/tolerance_3]
  }

  {
//[tolerance_4

  using boost::multiprecision::cpp_bin_float_oct;

  cpp_bin_float_oct tolerance =  3 * std::numeric_limits<cpp_bin_float_oct>::epsilon();
  cpp_bin_float_oct expected = boost::math::constants::two_pi<cpp_bin_float_oct>();
  cpp_bin_float_oct calculated = 2 * boost::math::constants::pi<cpp_bin_float_oct>();

  BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);

//] [/tolerance_4]
  }

  {
//[nan_1]

/*`NaN can be used with binary multiprecision types like `cpp_bin_float_quad`:
*/
  using boost::multiprecision::cpp_bin_float_quad;

  if (std::numeric_limits<cpp_bin_float_quad>::has_quiet_NaN == true)
  {
    cpp_bin_float_quad NaN =  std::numeric_limits<cpp_bin_float_quad>::quiet_NaN();
    std::cout << "cpp_bin_float_quad NaN is "  << NaN << std::endl; //   cpp_bin_float_quad NaN is nan

    cpp_bin_float_quad expected = NaN;
    cpp_bin_float_quad calculated = 2 * NaN;
    // Comparisons of NaN's always fail:
    bool b = expected == calculated;
    std::cout << b << std::endl;
    BOOST_CHECK_NE(expected, expected);
    BOOST_CHECK_NE(expected, calculated);
  }
  else
  {
    std::cout << "Type " << typeid(cpp_bin_float_quad).name() << " does not have NaNs!" << std::endl;
  }

//]  [/nan_1]
  }

  {
//[facet_1]

/*`
See [@boost:/libs/math/example/nonfinite_facet_sstream.cpp]
and we also need

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

Then we can equally well use a multiprecision type cpp_bin_float_quad:

*/
  using boost::multiprecision::cpp_bin_float_quad;

  typedef cpp_bin_float_quad T;

  using boost::math::nonfinite_num_put;
  using boost::math::nonfinite_num_get;
  {
    std::locale old_locale;
    std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
    std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
    std::stringstream ss;
    ss.imbue(new_locale);
    T inf = std::numeric_limits<T>::infinity();
    ss << inf; // Write out.
   BOOST_MP_ASSERT(ss.str() == "inf");
    T r;
    ss >> r; // Read back in.
    BOOST_MP_ASSERT(inf == r); // Confirms that the floating-point values really are identical.
    std::cout << "infinity output was " << ss.str() << std::endl;
    std::cout << "infinity input was " << r << std::endl;
  }

/*`
``
  infinity output was inf
  infinity input was inf
``
Similarly we can do the same with NaN (except that we cannot use `assert` (because any comparisons with NaN always return false).
*/
  {
    std::locale old_locale;
    std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
    std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
    std::stringstream ss;
    ss.imbue(new_locale);
    T n;
    T NaN = std::numeric_limits<T>::quiet_NaN();
    ss << NaN; // Write out.
    BOOST_MP_ASSERT(ss.str() == "nan");
    std::cout << "NaN output was " << ss.str() << std::endl;
    ss >> n; // Read back in.
    std::cout << "NaN input was " << n << std::endl;
  }
/*`
``
  NaN output was nan
  NaN input was nan
``
*/
//]  [/facet_1]
  }

#endif
#endif
} // BOOST_AUTO_TEST_CASE(test_numeric_limits_snips)


/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
* Copyright (c) QuantStack                                                 *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#include <benchmark/benchmark.h>

#ifdef HAS_XTENSOR
#include "xtensor/xnoalias.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xrandom.hpp"
#include "xtensor/xfixed.hpp"
#include "xtensor/xarray.hpp"
#endif

#ifdef HAS_EIGEN
#include <Eigen/Dense>
#include <Eigen/Core>
#endif

#ifdef HAS_XTENSOR
template <std::size_t N, std::size_t M>
void Add2dFixed_XTensor(benchmark::State& state)
{
    using namespace xt;

    xtensor_fixed<double, xshape<N, M>> a = random::rand<double>({N, M});
    xtensor_fixed<double, xshape<N, M>> b = random::rand<double>({N, M});

    for (auto _ : state)
    {
        xtensor_fixed<double, xshape<N, M>> res;
        xt::noalias(res) = a + b;
        benchmark::DoNotOptimize(res.data());
    }
}
BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 3, 3);
BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 8, 8);
BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 64, 64);
BENCHMARK_TEMPLATE(Add2dFixed_XTensor, 512, 512);
#endif

#ifdef HAS_EIGEN
template <std::size_t N, std::size_t M>
void Add2dFixed_Eigen(benchmark::State& state)
{
    using namespace Eigen;
    Matrix<double, N, M> a = Matrix<double, N, N>::Random(N, M);
    Matrix<double, N, M> b = Matrix<double, N, N>::Random(N, M);

    for (auto _ : state)
    {
        Matrix<double, N, M> res;
        res.noalias() = a + b;
        benchmark::DoNotOptimize(res.data());
    }
}
BENCHMARK_TEMPLATE(Add2dFixed_Eigen, 3, 3);
BENCHMARK_TEMPLATE(Add2dFixed_Eigen, 8, 8);
BENCHMARK_TEMPLATE(Add2dFixed_Eigen, 64, 64);
#endif


/*
replay
Software Library

Copyright (c) 2010-2019 Marius Elvert

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.

*/

#ifndef replay_math_hpp
#define replay_math_hpp

#include <boost/math/special_functions/sign.hpp>
#include <replay/interval.hpp>

namespace replay
{

/** generic linear interpolation.
    \ingroup Math
*/
template <class type, class delta_type> inline constexpr type lerp(type a, type b, delta_type x)
{
    return a + x * (b - a);
}

/** Math related functions.
*/
namespace math
{

/** default numerical error tolerance.
    \ingroup Math
*/
float const default_epsilon = 0.000001f;

/** multiply a only by the sign of b.
    \ingroup Math
*/
inline void mult_ref_by_sign(float& a, float b)
{
    a = boost::math::copysign(a, a * b);
}

/** multiply a only by the sign of b.
    \ingroup Math
*/
inline void mult_by_sign(float a, float b, float& result)
{
    result = boost::math::copysign(a, a * b);
}

/** copies the sign.
    \ingroup Math
*/
inline float copy_sign(float value, float sign)
{
    return boost::math::copysign(value, sign);
}

/** return true if the value is within a threshold of zero.
    \ingroup Math
*/
inline bool fuzzy_zero(float value, float epsilon)
{
    return std::abs(value) < epsilon;
}

/** return true if the value is within a threshold of zero.
    \ingroup Math
*/
inline bool fuzzy_zero(float value)
{
    return std::abs(value) < default_epsilon;
}

/** Return true if a is within a treshold of b.
    This is used to compare floating point numbers.
    \ingroup Math
*/
inline bool fuzzy_equals(float a, float b, float epsilon = default_epsilon)
{
    return std::abs(a - b) < epsilon;
}

/** check if the value is in the range. borders count as in.
    \ingroup Math
*/
template <class T> inline bool in_range(T value, interval<T> const& range)
{
    return (range[0] <= value) && (value <= range[1]);
}

/** check if the value is in the range. borders count as in.
    \ingroup Math
*/
template <class T> inline bool in_range(T value, const T left, const T right)
{
    return (left <= value) && (value <= right);
}

/** check whether two intervals intersect.
    \ingroup Math
*/
template <class T> inline bool intervals_intersect(interval<T> const& a, interval<T> const& b)
{
    return a[1] > b[0] && a[0] < b[1];
}

/** clamp a value into the range [-abs,abs]
    \ingroup Math
*/
template <class T> inline constexpr T clamp_absolute(const T value, const T abs)
{
    if (value < -abs)
        return -abs;
    else if (value > abs)
        return abs;
    else
        return value;
}

/** Clamp a value into a range.
    \ingroup Math
*/
template <class T> inline constexpr T clamp(T value, interval<T> const& range)
{
    if (value < range[0])
        return range[0];
    else if (value > range[1])
        return range[1];
    else
        return value;
}

/** Saturate the value, i.e., clamp it into the [0..1] range.
    \param x Value to be saturated.
    \ingroup Math
*/
inline constexpr float saturate(float x)
{
    if (x < 0.f)
        return 0.f;
    else
        return std::min(x, 1.f);
}

/** Perform a smooth hermite blend between two edge values.
    Returns 0 for values smaller than edge0 and 1 for values greater than edge1.
    Values in between are interpolated by the polynomial x*x*(3-2*x).
    \ingroup Math
*/
inline float smoothstep(float edge0, float edge1, float x)
{
    // Early out to avoid divisions by zero if edge0==edge1.
    if (x <= edge0)
        return 0.f;
    else if (x >= edge1)
        return 1.f;

    // Do actual interpolation in-between edges.
    x = (x - edge0) / (edge1 - edge0);
    return x * x * (3.0f - 2.f * x);
}

/** find the sign.
    \ingroup Math
*/
inline unsigned int sign(float value) // returns 1 for - and 0 for +
{
    return value < 0.f ? 1 : 0;
}

/** compare signs.
    \ingroup Math
*/
inline unsigned int same_sign(float a, float b)
{
    return a * b < 0.f ? 0 : 1;
}

/** convert radians to degrees.
    \ingroup Math
*/
inline constexpr float convert_to_degrees(float radians)
{
    constexpr float factor = 180.f / 3.14159265358979323846f;
    return radians * factor;
}

/** convert degrees to radians.
    \ingroup Math
*/
inline constexpr float convert_to_radians(float degrees)
{
    constexpr float factor = 3.14159265358979323846f / 180.f;
    return degrees * factor;
}

/** returns true if the given integer is a power of two.
    \ingroup Math
*/
inline bool is_pow2(unsigned int Number)
{
    return (Number & (Number - 1)) == 0;
}

/** returns true if the given integer is a power of two.
    \ingroup Math
*/
inline bool is_pow2(int Number)
{
    return Number > 0 && is_pow2(static_cast<unsigned int>(Number));
}

/** compute the square.
    \ingroup Math
*/
template <class T> inline constexpr T square(T p)
{
    return p * p;
}

/** Solve a quadratic equation of the form: a*x^2+b*x+c=0
    \ingroup Math
*/
unsigned int solve_quadratic_eq(float a, float b, float c, interval<>& result, float epsilon);

/** interpolation functions.
    \ingroup Math
*/
namespace interpolate
{

/** linear
*/
template <class type, class delta_type> inline type linear(const type a, const type b, const delta_type x)
{
    return a + x * (b - a);
}

/** cubic
*/
template <class type, class delta_type>
inline type cubic(const type& a, const type& b, const type& c, const type& d, const delta_type x)
{
    // 6 mults, 8 adds

    const type P = (d - c) - (a - b);
    const type Q = (a - b) - P;

    return ((P * x + Q) * x + (c - a)) * x + b;
}

/** bicubic
*/
template <class type, class delta_type>
inline type bicubic(const type& v11,
                    const type& v21,
                    const type& v31,
                    const type& v41,
                    const type& v12,
                    const type& v22,
                    const type& v32,
                    const type& v42,
                    const type& v13,
                    const type& v23,
                    const type& v33,
                    const type& v43,
                    const type& v14,
                    const type& v24,
                    const type& v34,
                    const type& v44,
                    const delta_type x,
                    const delta_type y)
{
    return cubic(cubic(v14, v13, v12, v11, y), cubic(v24, v23, v22, v21, y), cubic(v34, v33, v32, v31, y),
                 cubic(v44, v43, v42, v41, y), x);
}
}
}
}

#endif


// 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 <cstdlib>
#include <boost/numeric/mtl/mtl.hpp>
#include <boost/numeric/itl/itl.hpp>

void test_dynam_vector()
{
    std::cout<<"\n---test: operations for vectors of dynam. size---";

    typedef mtl::dense_vector<double> vector;
    vector v1(10,5.), v2(10,0.), v3(10);

    v1[7]=3.;

    v2[2]=2.;
    std::cout<<"\nv1="<<v1;
    std::cout<<"\nv2="<<v2;

    v3= v1 + 5. * v2 - dot(v1,v2) * v2;
    std::cout << "\nv3=v1+5.*v2-mtl::dot(v1,v2)*v2=" << v3;
    v3/= 5.;
    std::cout << "\nv3/=5. is " << v3;
    std::cout << "\nv3 has size=" << size(v3);
}

void test_stat_vector()
{
    std::cout<<"\n---test: operations for vectors of fixed size---";
    typedef mtl::vec::parameters<mtl::tag::col_major, mtl::vec::fixed::dimension<10> > dimension;
    typedef mtl::dense_vector<double, dimension> vector;
    vector v1, v2, v3;
    v1=5.;
    v1[7]=3.;
    v2=0.;
    v2[2]=2.;
    std::cout<<"\nv1="<<v1;
    std::cout<<"\nv2="<<v2;
    v3=v1+5.*v2-mtl::dot(v1,v2)*v2;
    std::cout<<"\nv3=v1+5.*v2-mtl::dot(v1,v2)*v2="<<v3;
    v3/=5.;
    std::cout<<"\nv3/=5. is "<<v3;
    std::cout << "\nv3 has size=" << mtl::static_size<vector>::value;
}

void test_stat_matrix()
{
    std::cout<<"\n---test: operations for matrices of stat. size---";
    typedef mtl::mat::parameters<mtl::tag::row_major, mtl::index::c_index, mtl::fixed::dimensions<3, 3> > matrix_parameters;
    typedef mtl::dense2D<double, matrix_parameters>  matrix_type;

    matrix_type A, B, C;

    mtl::mat::diagonal_setup(A, 2. );

    B=5.;
    mtl::mat::inserter<matrix_type> ins(B);
    ins[1][0]<<2.;

    B(0,1)=3.;

    std::cout<<"\nA="<<A;
    std::cout<<"\nB="<<B;
    std::cout<<"\nmatrices A,B,C have size=("<<mtl::static_num_rows<matrix_type>::value<<","<<mtl::static_num_cols<matrix_type>::value<<")";
    std::cout<<"\nmatrix B has one-norm ="<<mtl::one_norm(B);

    invert_diagonal(A);
    std::cout<<"\ninverto of diagonal matrix A is="<<A;

    C=A+B;
    B += A;
    C = 5.*B -A;
    C=A*B;
    mtl::dense_vector<mtl::Collection<matrix_type>::value_type> eigenvalues;
    eigenvalues= eigenvalue_symmetric(A);
    std::cout<<"\nmatrix A has trace ="<<trace(A);
}

void test_dynam_matrix()
{
    std::cout<<"\n---test: operations for matrices of dynam. size---";
    typedef mtl::dense2D<double>  MATRIX;

    MATRIX A(3,3),B(3,3),C(3,3);

    mtl::mat::diagonal_setup(A, 2. );

    B=5.;
    mtl::mat::inserter<MATRIX> ins(B);
    ins[1][0]<<2.;

    B(0,1)=3.;

    std::cout<<"\nA="<<A;
    std::cout<<"\nB="<<B;
    std::cout<<"\nMatrix A has size=("<<A.num_rows()<<","<<A.num_cols()<<")";
    std::cout<<"\nmatrix B has one-norm ="<<mtl::one_norm(B);

    invert_diagonal(A);
    std::cout<<"\ninvert of diagonal matrix A is="<<A;

    C=A+B;
    B += A;
    C = 5.*B -A;
    C=A*B;
    mtl::dense_vector<mtl::Collection<MATRIX>::value_type > eigenvalues;
    eigenvalues=eigenvalue_symmetric(A);
}

void test_compressed_matrix()
{

    std::cout<<"\n---test: operations for compressed matrices ---";
    typedef mtl::compressed2D<double>  MATRIX;

    MATRIX A(3,3),B(3,3),C(3,3);

    mtl::mat::diagonal_setup(A, 2. );

    {
	mtl::mat::inserter<MATRIX> ins(B);
	ins[1][0]<<2.;
	ins[0][1]<<3.;
    }

    std::cout<<"\nA="<<A;
    std::cout<<"\nB="<<B;
    std::cout<<"\nMatrix A has size=("<<A.num_rows()<<","<<A.num_cols()<<")";
    std::cout<<"\nmatrix B has one-norm ="<<mtl::one_norm(B);

    invert_diagonal(A);
    std::cout<<"\ninverto of diagonal matrix A is="<<A;

    C=A+B;
    std::cout<<"\nC=A+B="<<C;

    B += A;
    std::cout<<"\nB+=A; B="<<B;

    C = 5.*B -A;
    std::cout<<"\nC = 5.*B -A="<<C;

    C=A*B;
    std::cout<<"\nC = A*B="<<C;

    mtl::dense_vector<mtl::Collection<MATRIX>::value_type > eigenvalues;
    eigenvalues= eigenvalue_symmetric(A);
}

void test_dynam_vector_and_matrix()
{

    std::cout<<"\n---test: operations for vectors and matrices of dynam. size---";

    typedef mtl::dense_vector<double> vector;
    vector v1(10,5.), v2(10,0.), v3(10);
    v1[7]=3.;

    typedef mtl::dense2D<double> matrix;
    matrix A(10,10);
    A=10.;

    v2+=A*v1;
    v3=A*v2;
}

void test_stat_vector_and_matrix()
{
    std::cout<<"\n---test: operations for vectors and matrices of fixed size---";

    typedef mtl::vec::parameters<mtl::tag::col_major, mtl::vec::fixed::dimension<3> > dimension;
    // typedef mtl::parameters<mtl::tag::col_major, mtl::fixed::dimension<10> > dimension;
    typedef mtl::vec::dense_vector<double, dimension> vector;
    vector v1,v2,v3;
    v1=2.; v2=0.;

    typedef mtl::mat::parameters<mtl::tag::row_major, mtl::index::c_index, mtl::fixed::dimensions<3, 3> > matrix_parameters;
    typedef mtl::dense2D<double, matrix_parameters>  matrix;

    matrix A;
    A=10.;
    v2+=A*v1;
    v3=A*v2;
}

void test_compressed_matrix_and_vector()
{

    std::cout<<"\n---test: operations for vectors and compressed matrices ---";

    typedef mtl::compressed2D<double>  matrix;
    matrix A(10,10);

    mtl::mat::diagonal_setup(A, 10. );

    typedef mtl::vec::parameters<mtl::tag::col_major, mtl::vec::fixed::dimension<10> > dimension;
    typedef mtl::vec::dense_vector<double, dimension> vector;
    vector v1,v2,v3;
    v1=2.;v2=0.;
    std::cout<<"\nA="<<A;
    std::cout<<"\nv1="<<v1;
    std::cout<<"\nv2="<<v2;
    v2+=A*v1;
    std::cout<<"\nv2+=A*v1; v2="<<v2;

    v3=A*v2;
    std::cout<<"\nv3=A*v2="<<v3;
}

void test_solver()
{
    std::cout<<"\n---test: solver CG with iLU on compresed matrix ---";
    using namespace mtl;
    using namespace itl;
    const int size=5, N=size*size;

    typedef compressed2D<double> MATRIX;
    MATRIX A(N,N);
    mat::laplacian_setup(A,size,size);

    typedef dense_vector<double> vector;
    vector x(N,1.),b(N);
    b=A*x; x=0.;
    std::cout<<"\nA="<<A;
    std::cout<<"\nb="<<b;

    pc::ilu_0<MATRIX>  Precond(A);
    noisy_iteration<double> iter(b, 500, 1.e-6);
    cg(A, x, b, Precond, iter);
    if(iter.error_code()!=0) {
	std::cout<<"\nInterpolation matrix:\n"<<A;
	std::cerr<<"\nERROR: unsolvable system, error code="<<iter.error_code(); exit(EXIT_FAILURE);
    }
    std::cout<<"\nFor compressed matrix A="<<A;
    std::cout<<"\nCG solver with iLU, b="<<b;
}

int main()
{
    test_dynam_vector();
    test_dynam_matrix();
    test_stat_vector();
    test_stat_matrix();
    test_dynam_matrix();
    test_compressed_matrix();
    test_dynam_vector_and_matrix();
    test_stat_vector_and_matrix();
    test_compressed_matrix_and_vector();
    test_solver();
    std::cout << "\nNo errors detected.\n";

    return 0;
}


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef NT2_EXPONENTIAL_FUNCTIONS_GENERIC_SQRT1PM1_HPP_INCLUDED
#define NT2_EXPONENTIAL_FUNCTIONS_GENERIC_SQRT1PM1_HPP_INCLUDED

#include <nt2/exponential/functions/sqrt1pm1.hpp>
#include <nt2/include/functions/simd/tofloat.hpp>
#include <nt2/include/functions/simd/sqrt.hpp>
#include <nt2/include/functions/simd/oneplus.hpp>
#include <nt2/include/functions/simd/minusone.hpp>
#include <nt2/include/functions/simd/abs.hpp>
#include <nt2/include/functions/simd/is_less.hpp>
#include <nt2/include/functions/simd/tofloat.hpp>
#include <nt2/include/functions/simd/if_else.hpp>
#include <nt2/include/functions/simd/divides.hpp>
#include <nt2/include/constants/half.hpp>
#include <boost/dispatch/meta/as_floating.hpp>

namespace nt2 { namespace ext
{
  NT2_FUNCTOR_IMPLEMENTATION( nt2::tag::sqrt1pm1_, tag::cpu_
                            , (A0)
                            , (generic_< arithmetic_<A0> >)
                            )
  {
    typedef typename boost::dispatch::meta::as_floating<A0>::type result_type;
    NT2_FUNCTOR_CALL(1)
    {
      return nt2::minusone(nt2::sqrt(oneplus(nt2::tofloat(a0))));
    }
  };

  NT2_FUNCTOR_IMPLEMENTATION( nt2::tag::sqrt1pm1_, tag::cpu_
                            , (A0)
                            , (generic_< floating_<A0> >)
                            )
  {
    typedef A0 result_type;
    NT2_FUNCTOR_CALL(1)
    {
      A0 tmp =  nt2::sqrt(oneplus(a0));
      return  nt2::if_else(lt(nt2::abs(a0),  nt2::Half<A0>()),
                           a0/ nt2::oneplus(tmp),
                           nt2::minusone(tmp));
    }
  };
} }

#endif