// Boost.Geometry

// Copyright (c) 2021, Oracle and/or its affiliates.

// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_GEOMETRY_STRATEGIES_SIMPLIFY_SPHERICAL_HPP
#define BOOST_GEOMETRY_STRATEGIES_SIMPLIFY_SPHERICAL_HPP

#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/distance/comparable.hpp>
#include <boost/geometry/strategies/distance/detail.hpp>
#include <boost/geometry/strategies/simplify/services.hpp>

#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
#include <boost/geometry/strategies/spherical/point_in_point.hpp>

#include <boost/geometry/strategy/spherical/area.hpp>

namespace boost { namespace geometry
{

namespace strategies { namespace simplify
{

template
<
    typename RadiusTypeOrSphere = double,
    typename CalculationType = void
>
class spherical
    : public strategies::detail::spherical_base<RadiusTypeOrSphere>
{
    using base_t = strategies::detail::spherical_base<RadiusTypeOrSphere>;

public:
    spherical() = default;

    template <typename RadiusOrSphere>
    explicit spherical(RadiusOrSphere const& radius_or_sphere)
        : base_t(radius_or_sphere)
    {}

    // TODO: Replace this if calculate_point_order() is used in simplify
    template <typename Geometry>
    auto area(Geometry const&) const
    {
        return strategy::area::spherical
            <
                typename base_t::radius_type, CalculationType
            >(base_t::radius());
    }

    // For perimeter()
    template <typename Geometry1, typename Geometry2>
    auto distance(Geometry1 const&, Geometry2 const&,
                  distance::detail::enable_if_pp_t<Geometry1, Geometry2> * = nullptr) const
    {
        return strategy::distance::haversine
                <
                    typename base_t::radius_type, CalculationType
                >(base_t::radius());
    }

    // For douglas_peucker
    template <typename Geometry1, typename Geometry2>
    auto distance(Geometry1 const&, Geometry2 const&,
                  distance::detail::enable_if_ps_t<Geometry1, Geometry2> * = nullptr) const
    {
        return strategy::distance::cross_track
            <
                CalculationType,
                strategy::distance::haversine<typename base_t::radius_type, CalculationType>
            >(base_t::radius());
    }

    // For equals()
    template <typename Geometry1, typename Geometry2>
    static auto relate(Geometry1 const&, Geometry2 const&,
                       std::enable_if_t
                            <
                                util::is_pointlike<Geometry1>::value
                             && util::is_pointlike<Geometry2>::value
                            > * = nullptr)
    {
        return strategy::within::spherical_point_point();
    }
};

namespace services
{

template <typename Geometry>
struct default_strategy<Geometry, spherical_equatorial_tag>
{
    using type = strategies::simplify::spherical<>;
};

template <typename P, typename CT, typename S>
struct strategy_converter
    <
        strategy::simplify::douglas_peucker
            <
                P,
                strategy::distance::cross_track<CT, S>
            >
    >
{
    template <typename Strategy>
    static auto get(Strategy const& )
    {
        return strategies::simplify::spherical<typename S::radius_type, CT>();
    }
};

template <typename P, typename CT, typename S>
struct strategy_converter
    <
        strategy::simplify::douglas_peucker
            <
                P,
                strategy::distance::comparable::cross_track<CT, S>
            >
    >
{
    template <typename Strategy>
    static auto get(Strategy const& )
    {
        return strategies::distance::detail::comparable
            <
                strategies::simplify::spherical<typename S::radius_type, CT>
            >();
    }
};

} // namespace services

}} // namespace strategies::simplify

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_STRATEGIES_SIMPLIFY_SPHERICAL_HPP


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

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

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

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

 /*!

    @ingroup group-arithmetic
    Function object implementing max capabilities

    Computes the largest of its parameter.

    @par semantic:
    For any given value @c x and @c y of type @c T:

    @code
    T r = max(x, y);
    @endcode

    is similar to:

    @code
    T r =  (x > y) ? x : y;
    @endcode

    @see maxnum, maxnummag,  maxmag

  **/
  const boost::dispatch::functor<tag::max_> max = {};
} }
#endif

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

#endif


// Copyright (c) 2019 Graphcore Ltd. All rights reserved.
#define BOOST_TEST_MODULE ConstExprFloorTest

#include <boost/test/unit_test.hpp>
#include <filereader.hpp>
#include <memory>
#include <popart/builder.hpp>
#include <popart/dataflow.hpp>
#include <popart/devicemanager.hpp>
#include <popart/half.hpp>
#include <popart/inputshapeinfo.hpp>
#include <popart/ir.hpp>
#include <popart/names.hpp>
#include <popart/ndarraywrapper.hpp>
#include <popart/op/identity.hpp>
#include <popart/session.hpp>
#include <popart/sgd.hpp>
#include <popart/tensordata.hpp>
#include <popart/testdevice.hpp>

using namespace popart;

namespace {

template <typename T> std::vector<char> getRawConstData() {
  //
  // matrix:
  //
  // [1.2 1.4
  //  1.6 1.8]
  //
  // of type determined by template paramater
  //
  std::vector<char> raw_const_data;
  raw_const_data.resize(sizeof(T) * 4);
  T *raw_const_ptr = reinterpret_cast<T *>(raw_const_data.data());
  for (int i = 0; i < 4; ++i) {
    raw_const_ptr[i] = static_cast<T>(1.2f + i * 0.2f);
  }
  return raw_const_data;
}

std::string getTestModelProto(DataType type) {

  // The compute graph :
  //
  // x0 --|
  //      |--- [MATMUL] -- x2 -- [FLOOR] ----------- x3 --|
  //      |                                               |
  // x1 --|                                               | -- [ADD] --x6
  //                                                      |
  // x4 const - [FLOOR] -- x5 -- [CAST to FLOAT] -- c0 ---|
  //
  // This test has 1 non-const floor and 1 const floor to perform

  ConstVoidData const_data;
  std::vector<char> raw_const_data;
  std::string type_string;
  if (type == DataType::FLOAT) {
    raw_const_data = getRawConstData<float>();
    type_string    = "FLOAT";
  }

  else if (type == DataType::INT32) {
    raw_const_data = getRawConstData<int>();
    type_string    = "INT32";
  }

  else if (type == DataType::FLOAT16) {
    raw_const_data = getRawConstData<float16_t>();
    type_string    = "FLOAT16";
  }

  else {
    throw error("this test is not enabled for speficied type");
  }

  // all 3 matrices x0, x1 & x4 are 2x2
  TensorInfo const_info = {type_string, Shape{2, 2}};
  TensorInfo in_info    = {"FLOAT", Shape{2, 2}};
  const_data            = {raw_const_data.data(), const_info};

  auto builder     = Builder::create();
  auto aiOnnx      = builder->aiOnnxOpset9();
  auto aiGraphcore = builder->aiGraphcoreOpset1();

  auto x4   = aiOnnx.constant(const_data, "x4");
  auto x0   = builder->addInputTensor(in_info);
  auto x1   = builder->addInputTensor(in_info);
  auto x2   = aiOnnx.matmul({x0, x1});
  auto x3   = aiOnnx.floor({x2});
  auto x5   = aiOnnx.floor({x4});
  auto c0   = aiOnnx.cast({x5}, "FLOAT");
  auto x6   = aiOnnx.add({x3, c0});
  auto loss = aiGraphcore.identityloss({x6});
  builder->addOutputTensor(x6);
  builder->addOutputTensor(loss);

  auto proto = builder->getModelProto();
  return proto;
}
} // namespace

// Test that the floor is correctly identified for const expression removal
BOOST_AUTO_TEST_CASE(ConstExprTest_Floor0) {

  auto proto       = getTestModelProto(DataType::FLOAT);
  auto model_proto = io::getModelFromString(proto);

  // Create the IR
  auto art       = AnchorReturnType("All");
  TensorId outId = model_proto.graph().output(1).name();
  auto data_flow = DataFlow(1, {{outId, art}});
  auto device    = createTestDevice(TEST_TARGET);

  Ir ir;
  ir.prepare({model_proto,
              InputShapeInfo(),
              data_flow,
              {},
              nullptr,
              *device,
              {}, // no SessionOptions
              Patterns({}).enableRuntimeAsserts(false)});

  // only the one floor (after the matmul) should remain
  BOOST_CHECK(ir.opsOfType(Onnx::AiOnnx::OpSet9::Floor).size() == 1);
}

// Test that the graph output is correct
BOOST_AUTO_TEST_CASE(ConstExprTest_Floor1) {

  auto numerical_accuracy_test = [](popart::DataType type) {
    popart::logging::session::info("In numerical_accuracy_test for type {}",
                                   TensorInfo(type, {1}).data_type());

    auto proto = getTestModelProto(type);

    auto model_proto = io::getModelFromString(proto);

    // Create the IR
    auto art       = AnchorReturnType("All");
    TensorId outId = model_proto.graph().output(0).name();
    auto data_flow = DataFlow(1, {{outId, art}});
    auto optimizer = ConstSGD(0.01);

    auto device = popart::createTestDevice(TEST_TARGET);

    auto session = popart::InferenceSession::createFromOnnxModel(
        proto,
        data_flow,
        device,
        popart::InputShapeInfo(),
        {}, // no session options
        Patterns(PatternsLevel::NoPatterns)
            .enableRuntimeAsserts(false) // no patterns
    );

    // prepare the anchors
    std::vector<float> rawOutputData(4);
    popart::NDArrayWrapper<float> outData(rawOutputData.data(), {2, 2});

    std::map<popart::TensorId, popart::IArray &> anchors = {
        {outId, outData},
    };

    session->prepareDevice();

    std::vector<float> rawInputData0{1.2f, 2.4f, 3.6f, 4.8f};
    std::vector<float> rawInputData1{5.2f, 6.4f, 7.6f, 8.8f};

    //
    // the calculation, done in numpy:
    //
    // In [2]: np.floor(np.dot([[1.2,2.4],[3.6,4.8]], [[5.2,6.4],[7.6,8.8]]))
    //       + np.floor(np.array([[1.2,1.4],[1.6,1.8]]))
    //
    // Out[2]:
    // array([[25., 29. ],
    //        [56., 66.. ]])
    //

    std::vector<float> baseline{25., 29., 56., 66.};

    popart::NDArrayWrapper<float> inData0(rawInputData0.data(), {2, 2});
    popart::NDArrayWrapper<float> inData1(rawInputData1.data(), {2, 2});

    std::map<popart::TensorId, popart::IArray &> inputs = {
        {model_proto.graph().input(0).name(), inData0},
        {model_proto.graph().input(1).name(), inData1}};

    popart::StepIO stepio(inputs, anchors);

    session->run(stepio);

    BOOST_CHECK(std::equal(baseline.data(),
                           baseline.data() + 4,
                           rawOutputData.data()) == true);
  };

  numerical_accuracy_test(DataType::FLOAT);
  numerical_accuracy_test(DataType::FLOAT16);
}


#ifndef Z_PLANE_HPP
#define Z_PLANE_HPP

//STL
#include <vector>

//Eigen
#include <Eigen/Dense>

struct Plane
{
    Eigen::Vector3f n;
    float d;

    Plane()
        : n(Eigen::Vector3f::Zero()), d(0.f)
    {   }

    Plane(const Eigen::Vector3f &n, float d)
        : n(n), d(d)
    {    }
};

typedef std::vector<Plane> PlanesList;

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

#ifndef MTL_UNARY_DOT_INCLUDE
#define MTL_UNARY_DOT_INCLUDE

#include <boost/numeric/mtl/concept/collection.hpp>
#include <boost/numeric/mtl/utility/tag.hpp>
#include <boost/numeric/mtl/utility/category.hpp>
#include <boost/numeric/mtl/vector/lazy_reduction.hpp>
#include <boost/numeric/mtl/vector/reduction.hpp>
#include <boost/numeric/mtl/vector/reduction_functors.hpp>
#include <boost/numeric/mtl/interface/vpt.hpp>

namespace mtl {

    namespace vector {

	template <unsigned long Unroll, typename Value>
	typename Collection<Value>::value_type
	inline unary_dot(const Value& value)
	{
	    vampir_trace<2041> tracer;
	    typedef typename Collection<Value>::value_type result_type;
	    return reduction<Unroll, two_norm_functor, result_type>::apply(value);
	}

	/*! Dot product of a vector with itself, i.e. unary_dot(v) == dot(v, v).

	    Mathematically, it is also identical with the square of the two_norm.
	    However, unary_dot returns the value_type of v while two_norm yields the
	    RealMagnitude type, thus
	    \code
	      two_norm(v) * two_norm(v) == abs(unary_dot(v))
	    \endcode
	    Internally, the computations are performed in RealMagnitude so that
	    unary_dot(v) is more efficient than dot(v, v) for complex vectors.
	    Furthermore, when the dot product is fused with other expressions,
	    the arguments in dot must be different for the correct semantics of
	    certain fusions.

	    Like vector norms, unary_dot is unrolled 8-fold by default.
	    An n-fold unrolling can be generated with two_norm<n>(x).
	    The maximum for n is 8 (it might be increased later).
	**/
	template <typename Value>
	typename Collection<Value>::value_type
	inline unary_dot(const Value& value)
	{   return unary_dot<8>(value);	}

	/// Lazy unary dot product
	/** Used for source-to-source transformations. **/
	template <typename Vector>
	lazy_reduction<Vector, unary_dot_functor> inline lazy_unary_dot(const Vector& v)
	{  return lazy_reduction<Vector, unary_dot_functor>(v); 	}

    } // namespace vector

    using vector::unary_dot;
    using vector::lazy_unary_dot;

} // namespace mtl

#endif // MTL_UNARY_DOT_INCLUDE


/**
 * Copyright (c) 2012 Andreas Heider, Julius Adorf, Markus Grimm
 *
 * MIT License (http://www.opensource.org/licenses/mit-license.php)
 */

#include "tpofinder/util.h"
#include "tpofinder/visualize.h"

#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <cstdlib>
#include <iostream>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace tpofinder;
using namespace std;
namespace bpo = boost::program_options;

int main(int argc, char** argv) {
    string cfile, ofile;
    string tfile, rfile;

    bpo::options_description options;
    options.add_options()
            ("correspondences,c", bpo::value<string > (&cfile), "path to a file "
            "containing point correspondences. This file must be structured "
            "as follows:\n\n"
            "%YAML:1.0\n"
            "train: !!opencv-matrix\n"
            "   rows: 4\n"
            "   cols: 1\n"
            "   dt: \"2f\"\n"
            "   data: [ 260., 157., 268., 305., 436., 291., 442., 158. ]\n"
            "ref: !!opencv-matrix\n"
            "   rows: 4\n"
            "   cols: 1\n"
            "   dt: \"2f\"\n"
            "   data: [ 276., 198., 276., 348., 446., 348., 438., 212. ]\n\n"
            "Here the matrices in 'data' are of the form [x1 y1 x2 y2 ... x4 y4]; "
            "so put the points in the training image into one matrix and the "
            "corresponding points in the reference image into the other.")
            ("out,o", bpo::value<string > (&ofile), "path to a file where the computed "
            "homography shall be written to.")
            ("ref,r", bpo::value<string > (&rfile), "path to reference image (optional).")
            ("train,t", bpo::value<string > (&tfile), "path to train image (optional).");

    bpo::variables_map vm;
    bpo::store(bpo::parse_command_line(argc, argv, options), vm);
    notify(vm);

    Mat ref;
    Mat train;

    if (vm.count("correspondences") == 1) {
        FileStorage in(cfile, FileStorage::READ);
        in["ref"] >> ref;
        in["train"] >> train;
        in.release();
    } else {
        options.print(cerr);
        return -1;
    }

    Mat homography = findHomography(ref, train);
    cout << homography << endl;

    if (!ofile.empty()) {
        writeHomography(ofile, homography);
    }

    if (!rfile.empty() && !tfile.empty()) {
        Mat refImg = imread(rfile);
        Mat trainImg = imread(tfile);

        Mat refPointsImg = refImg.clone();
        Mat trainPointsImg = trainImg.clone();
        for (int i = 0; i < ref.rows; i++) {
            circle(refPointsImg, ref.at<Point2f>(i), 3, Scalar(255, 0, 0), CV_FILLED);
            circle(trainPointsImg, train.at<Point2f>(i), 3, Scalar(255, 0, 0), CV_FILLED);
        }
        imshow("keys on reference image", refPointsImg);
        imshow("keys on training image", trainPointsImg);

        Mat out = blend(refImg, trainImg, homography);
        string name = str(boost::format("homography: [%s] %s -> %s [%s]") % cfile % rfile % tfile % ofile);
        imshow(name, out);
        waitKey(0);
    }

    return 0;
}


#include "mkl.h"
#include <string>
#include <fstream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <iostream>

void loadCSVFile(std::string &filePath, float *&d, float *&e, int &size)
{
    std::ifstream stream;
    stream.open(filePath);
    std::string temp;
    std::vector<std::string> tempStringContainer;

    if (stream.is_open())
    {
        std::getline(stream, temp);
        size = std::stoi(temp);

        d = new float[size];
        e = new float[size - 1];

        std::getline(stream, temp);
        boost::split(tempStringContainer, temp, boost::is_any_of(", "));
        for (int i = 0; i < size; i++)
        {
            d[i] = std::stof(tempStringContainer[i]);
        }
        tempStringContainer.clear();

        std::getline(stream, temp);
        boost::split(tempStringContainer, temp, boost::is_any_of(", "));
        for (int i = 0; i < size - 1; i++)
        {
            e[i] = std::stof(tempStringContainer[i]);
        }
    }
}

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

    std::string filePath = argv[1];

    const float abstol = 0.001;
    float *d;
    float *e;

    int eigenValsAmount;
    int foundBlocks; //nsplit
    int size;

    loadCSVFile(filePath, d, e, size);

    float *foundEigenVals = new float[size];
    int *iblock = new int[size];
    int *isplit = new int[size];

    int info = LAPACKE_sstebz('A', 'E', size, 0.5, 0.5, 0.5, 0.5, abstol, d, e, &eigenValsAmount, &foundBlocks, foundEigenVals, iblock, isplit);

    for (int i = 0; i < eigenValsAmount; i++)
    {
        std::cout << foundEigenVals[i] << '\n';
    }
    delete d;
    delete e;
    delete foundEigenVals;
    delete iblock;
    delete isplit;

    return 0;
}


#ifndef INCLUDED_numeric_random_HH
#define INCLUDED_numeric_random_HH

#include "scheme/numeric/util.hh"
#include <Eigen/Geometry>
#include <random>

namespace scheme { namespace numeric {

// implements UniformRandomBitGenerator
class FastRandom {

public:
	typedef unsigned long result_type;

	result_type x, y, z;

	FastRandom( result_type seed1, result_type seed2, result_type seed3 )
	: x( seed1 ), y( seed2 ), z( seed3 )
	{}

	result_type min() {
		return 0;
	}

	result_type max() {
		return std::numeric_limits<unsigned long>::max();
	}
		//https://stackoverflow.com/questions/1640258/need-a-fast-random-generator-for-c
	unsigned long xorshf96(void) {          //period 2^96-1
	unsigned long t;
	    x ^= x << 16;
	    x ^= x >> 5;
	    x ^= x << 1;

		t = x;
		x = y;
		y = z;
		z = t ^ x ^ y;

		return z;
	}

	result_type operator()() {
		return xorshf96();
	}
};

}}

#endif


// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test

// Copyright (c) 2016-2017, Oracle and/or its affiliates.

// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_TEST_MODULE
#define BOOST_TEST_MODULE test_distance_geographic_pl_l
#endif

#include <boost/geometry/core/srs.hpp>
#include <boost/test/included/unit_test.hpp>

#include "test_distance_geo_common.hpp"

typedef bg::cs::geographic<bg::degree> cs_type;
typedef bg::model::point<double, 2, cs_type> point_type;
typedef bg::model::segment<point_type> segment_type;
typedef bg::model::multi_point<point_type> multi_point_type;
typedef bg::model::segment<point_type> segment_type;
typedef bg::model::linestring<point_type> linestring_type;
typedef bg::model::multi_linestring<linestring_type> multi_linestring_type;

namespace services = bg::strategy::distance::services;
typedef bg::default_distance_result<point_type>::type return_type;

typedef bg::srs::spheroid<double> stype;

// Strategies for point-point distance

typedef bg::strategy::distance::andoyer<stype> andoyer_pp;
typedef bg::strategy::distance::thomas<stype> thomas_pp;
typedef bg::strategy::distance::vincenty<stype> vincenty_pp;

// Strategies for point-segment distance

typedef bg::strategy::distance::geographic_cross_track<bg::strategy::andoyer, stype, double>
        andoyer_strategy;

typedef bg::strategy::distance::geographic_cross_track<bg::strategy::thomas, stype, double>
        thomas_strategy;

typedef bg::strategy::distance::geographic_cross_track<bg::strategy::vincenty, stype, double>
        vincenty_strategy;

//===========================================================================

template <typename Strategy>
inline bg::default_distance_result<point_type>::type
pp_distance(std::string const& wkt1,
            std::string const& wkt2,
            Strategy const& strategy)
{
    point_type p1, p2;
    bg::read_wkt(wkt1, p1);
    bg::read_wkt(wkt2, p2);
    return bg::distance(p1, p2, strategy);
}

template <typename Strategy>
inline bg::default_distance_result<point_type>::type
ps_distance(std::string const& wkt1,
            std::string const& wkt2,
            Strategy const& strategy)
{
    point_type p;
    segment_type s;
    bg::read_wkt(wkt1, p);
    bg::read_wkt(wkt2, s);
    return bg::distance(p, s, strategy);
}

//===========================================================================

template <typename Strategy_pp, typename Strategy_ps>
void test_distance_point_segment(Strategy_pp const& strategy_pp,
                                 Strategy_ps const& strategy_ps)
{

#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "point/segment distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries<point_type, segment_type> tester;

    tester::apply("p-s-01",
                  "POINT(0 0)",
                  "SEGMENT(2 0,3 0)",
                  pp_distance("POINT(0 0)", "POINT(2 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-02",
                  "POINT(2.5 3)",
                  "SEGMENT(2 0,3 0)",
                  pp_distance("POINT(2.5 3)", "POINT(2.49777 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-03",
                  "POINT(2 0)",
                  "SEGMENT(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-s-04",
                  "POINT(3 0)",
                  "SEGMENT(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-s-05",
                  "POINT(2.5 0)",
                  "SEGMENT(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-s-06",
                  "POINT(3.5 3)",
                  "SEGMENT(2 0,3 0)",
                  pp_distance("POINT(3 0)", "POINT(3.5 3)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-07",
                  "POINT(15 80)",
                  "SEGMENT(10 15,30 15)",
                  7204174.8264546748,
                  strategy_ps);
    tester::apply("p-s-08",
                  "POINT(15 10)",
                  "SEGMENT(10 15,30 15)",
                  571412.71247283253,
                  strategy_ps);
    tester::apply("p-s-09",
                  "POINT(5 10)",
                  "SEGMENT(10 15,30 15)",
                  pp_distance("POINT(5 10)", "POINT(10 15)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-10",
                  "POINT(35 10)",
                  "SEGMENT(10 15,30 15)",
                  pp_distance("POINT(35 10)", "POINT(30 15)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-11",
                  "POINT(5 10)",
                  "SEGMENT(30 15,10 15)",
                  pp_distance("POINT(5 10)", "POINT(10 15)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-12",
                  "POINT(35 10)",
                  "SEGMENT(30 15,10 15)",
                  pp_distance("POINT(35 10)", "POINT(30 15)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-right-up",
                  "POINT(3.5 3)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(3 2)", "POINT(3.5 3)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-left-up",
                  "POINT(1.5 3)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(2 2)", "POINT(1.5 3)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-up-1",
                  "POINT(2 3)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(2.0003 2)", "POINT(2 3)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-up-2",
                  "POINT(3 3)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(2.9997 2)", "POINT(3 3)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-right-down",
                  "POINT(3.5 1)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(3 2)", "POINT(3.5 1)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-left-down",
                  "POINT(1.5 1)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(2 2)", "POINT(1.5 1)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-down-1",
                  "POINT(2 1)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(2.0003 2)", "POINT(2 1)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-down-2",
                  "POINT(3 1)",
                  "SEGMENT(2 2,3 2)",
                  pp_distance("POINT(2.9997 2)", "POINT(3 1)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-south",
                  "POINT(3 -1)",
                  "SEGMENT(2 -2,3 -2)",
                  pp_distance("POINT(2.9997 -2)", "POINT(3 -1)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-antimeridian-1",
                  "POINT(3 1)",
                  "SEGMENT(220 2,3 2)",
                  pp_distance("POINT(3 2)", "POINT(3 1)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-antimeridian-2",
                  "POINT(220 1)",
                  "SEGMENT(220 2,3 2)",
                  pp_distance("POINT(220 2)", "POINT(220 1)", strategy_pp),
                  strategy_ps);

    // equator special case
    tester::apply("p-s-eq1",
                  "POINT(2.5 0)",
                  "SEGMENT(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-s-eq2",
                  "POINT(2.5 2)",
                  "SEGMENT(2 0,3 0)",
                  pp_distance("POINT(2.5 0)", "POINT(2.5 2)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-eq3",
                  "POINT(2 2)",
                  "SEGMENT(2 0,3 0)",
                  pp_distance("POINT(2 0)", "POINT(2 2)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-eq4",
                  "POINT(3 2)",
                  "SEGMENT(2 0,3 0)",
                  pp_distance("POINT(3 0)", "POINT(3 2)", strategy_pp),
                  strategy_ps);

    // meridian special case
    tester::apply("p-s-mer1",
                  "POINT(2.5 2)",
                  "SEGMENT(2 2,2 4)",
                  pp_distance("POINT(2.5 2)", "POINT(2 2)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-mer3",
                  "POINT(2.5 5)",
                  "SEGMENT(2 2,2 4)",
                  pp_distance("POINT(2.5 5)", "POINT(2 4)", strategy_pp),
                  strategy_ps);

    //degenerate segment
    tester::apply("p-s-deg",
                  "POINT(1 80)",
                  "SEGMENT(0 0,0 0)",
                  pp_distance("POINT(0 0)", "POINT(1 80)", strategy_pp),
                  strategy_ps);

    //point on segment
    tester::apply("p-s-deg",
                  "POINT(0 80)",
                  "SEGMENT(0 0,0 90)",
                  0,
                  strategy_ps);

    // very small distances to segment
    tester::apply("p-s-07",
                  "POINT(90 1e-3)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 1e-3)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-08",
                  "POINT(90 1e-4)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 1e-4)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-09",
                  "POINT(90 1e-5)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 1e-5)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-10",
                  "POINT(90 1e-6)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 1e-6)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-11",
                  "POINT(90 1e-7)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 1e-7)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-12",
                  "POINT(90 1e-8)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 1e-8)", strategy_pp),
                  strategy_ps);

    // very large distance to segment
    tester::apply("p-s-13",
                  "POINT(90 90)",
                  "SEGMENT(0.5 0,175.5 0)",
                  pp_distance("POINT(90 0)", "POINT(90 90)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-14",
                  "POINT(90 90)",
                  "SEGMENT(0.5 -89,175.5 -89)",
                  pp_distance("POINT(90 -89)", "POINT(90 90)", strategy_pp),
                  strategy_ps);
    // degenerate segment
    tester::apply("p-s-15",
                  "POINT(90 90)",
                  "SEGMENT(0.5 -90,175.5 -90)",
                  pp_distance("POINT(0.5 -90)", "POINT(90 90)", strategy_pp),
                  strategy_ps);
    tester::apply("p-s-16",
                  "POINT(90 90)",
                  "SEGMENT(0.5 -90,175.5 -90)",
                  pp_distance("POINT(90 -90)", "POINT(90 90)", strategy_pp),
                  strategy_ps);
    // equatorial segment
    tester::apply("p-s-17",
                  "POINT(90 90)",
                  "SEGMENT(0 0,175.5 0)",
                  pp_distance("POINT(90 90)", "POINT(0 0)", strategy_pp),
                  strategy_ps);
    // segment pass by pole
    tester::apply("p-s-18",
                  "POINT(90 90)",
                  "SEGMENT(0 0,180 0)",
                  0,
                  strategy_ps);

}

template <typename Strategy_pp, typename Strategy_ps>
void test_distance_point_segment_no_thomas(Strategy_pp const& strategy_pp,
                                           Strategy_ps const& strategy_ps)
{

#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "point/segment distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries<point_type, segment_type> tester;

    // thomas strategy is failing for those test cases

    // meridian special case
    tester::apply("p-s-mer2",
                  "POINT(2.5 3)",
                  "SEGMENT(2 2,2 4)",
                  pp_distance("POINT(2.5 3)", "POINT(2 3.000114792872075)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-mer4",
                  "POINT(1 80)",
                  "SEGMENT(0 0,0 90)",
                  pp_distance("POINT(1 80)", "POINT(0 80.00149225834545)", strategy_pp),
                  strategy_ps);

    // Half meridian segment passing through pole
    tester::apply("p-s-19",
                  "POINT(90 89)",
                  "SEGMENT(0 0,180 0)",
                  pp_distance("POINT(90 89)", "POINT(90 90)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-20",
                  "POINT(80 89)",
                  "SEGMENT(0 0,180 0)",
                  pp_distance("POINT(80 89)", "POINT(0 89.82633489283377)", strategy_pp),
                  strategy_ps);

    tester::apply("p-s-20",
                  "POINT(80 89)",
                  "SEGMENT(0 -1,180 1)",
                  pp_distance("POINT(80 89)", "POINT(0 89.82633489283377)", strategy_pp),
                  strategy_ps);
}

//===========================================================================

template <typename Strategy_pp, typename Strategy_ps>
void test_distance_point_linestring(Strategy_pp const& strategy_pp,
                                    Strategy_ps const& strategy_ps)
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "point/linestring distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries<point_type, linestring_type> tester;

    tester::apply("p-l-01",
                  "POINT(0 0)",
                  "LINESTRING(2 0,2 0)",
                  pp_distance("POINT(0 0)", "POINT(2 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-l-02",
                  "POINT(0 0)",
                  "LINESTRING(2 0,3 0)",
                  pp_distance("POINT(0 0)", "POINT(2 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-l-03",
                  "POINT(2.5 3)",
                  "LINESTRING(2 0,3 0)",
                  pp_distance("POINT(2.5 3)", "POINT(2.5 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-l-04",
                  "POINT(2 0)",
                  "LINESTRING(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-l-05",
                  "POINT(3 0)",
                  "LINESTRING(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-l-06",
                  "POINT(2.5 0)",
                  "LINESTRING(2 0,3 0)",
                  0,
                  strategy_ps);
    tester::apply("p-l-07",
                  "POINT(7.5 10)",
                  "LINESTRING(1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9 0)",
                  ps_distance("POINT(7.5 10)", "SEGMENT(7 0,8 0)", strategy_ps),
                  strategy_ps);
    tester::apply("p-l-08",
                  "POINT(7.5 10)",
                  "LINESTRING(1 1,2 1,3 1,4 1,5 1,6 1,7 1,20 2,21 2)",
                  ps_distance("POINT(7.5 10)", "SEGMENT(7 1,20 2)", strategy_ps),
                  strategy_ps);
}

void test_distance_point_linestring_strategies()
{
    typedef test_distance_of_geometries<point_type, linestring_type> tester;

    tester::apply("p-l-03",
                  "POINT(2.5 3)",
                  "LINESTRING(2 1,3 1)",
                  221147.24332788656,
                  vincenty_strategy());

    tester::apply("p-l-03",
                  "POINT(2.5 3)",
                  "LINESTRING(2 1,3 1)",
                  221147.36682199029,
                  thomas_strategy());

    tester::apply("p-l-03",
                  "POINT(2.5 3)",
                  "LINESTRING(2 1,3 1)",
                  221144.76527049288,
                  andoyer_strategy());
}

//===========================================================================

template <typename Strategy_pp, typename Strategy_ps>
void test_distance_point_multilinestring(Strategy_pp const& strategy_pp,
                                         Strategy_ps const& strategy_ps)
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "point/multilinestring distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries
        <
            point_type, multi_linestring_type
        > tester;

    tester::apply("p-ml-01",
                  "POINT(0 0)",
                  "MULTILINESTRING((-5 0,-3 0),(2 0,3 0))",
                  pp_distance("POINT(0 0)", "POINT(2 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-ml-02",
                  "POINT(2.5 3)",
                  "MULTILINESTRING((-5 0,-3 0),(2 0,3 0))",
                  pp_distance("POINT(2.5 3)", "POINT(2.5 0)", strategy_pp),
                  strategy_ps);
    tester::apply("p-ml-03",
                  "POINT(2 0)",
                  "MULTILINESTRING((-5 0,-3 0),(2 0,3 0))",
                  0,
                  strategy_ps);
    tester::apply("p-ml-04",
                  "POINT(3 0)",
                  "MULTILINESTRING((-5 0,-3 0),(2 0,3 0))",
                  0,
                  strategy_ps);
    tester::apply("p-ml-05",
                  "POINT(2.5 0)",
                  "MULTILINESTRING((-5 0,-3 0),(2 0,3 0))",
                  0,
                  strategy_ps);
    tester::apply("p-ml-06",
                  "POINT(7.5 10)",
                  "MULTILINESTRING((-5 0,-3 0),(2 0,3 0,4 0,5 0,6 0,20 1,21 1))",
                  ps_distance("POINT(7.5 10)", "SEGMENT(6 0,20 1)", strategy_ps),
                  strategy_ps);
    tester::apply("p-ml-07",
                  "POINT(-8 10)",
                  "MULTILINESTRING((-20 10,-19 11,-18 10,-6 0,-5 0,-3 0),(2 0,6 0,20 1,21 1))",
                  ps_distance("POINT(-8 10)", "SEGMENT(-6 0,-18 10)", strategy_ps),
                  strategy_ps);
}

//===========================================================================

template <typename Strategy_pp, typename Strategy_ps>
void test_distance_linestring_multipoint(Strategy_pp const& strategy_pp,
                                         Strategy_ps const& strategy_ps)
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "linestring/multipoint distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries
        <
            linestring_type, multi_point_type
        > tester;

    tester::apply("l-mp-01",
                  "LINESTRING(2 0,0 2,100 80)",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  ps_distance("POINT(1 1)", "SEGMENT(2 0,0 2)", strategy_ps),
                  strategy_ps);

    tester::apply("l-mp-02",
                  "LINESTRING(4 0,0 4,100 80)",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  ps_distance("POINT(1 1)", "SEGMENT(0 4,4 0)", strategy_ps),
                  strategy_ps);
    tester::apply("l-mp-03",
                  "LINESTRING(1 1,2 2,100 80)",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  0,
                  strategy_ps);
    tester::apply("l-mp-04",
                  "LINESTRING(3 3,4 4,100 80)",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  pp_distance("POINT(1 1)", "POINT(3 3)", strategy_pp),
                  strategy_ps);
    tester::apply("l-mp-05",
                  "LINESTRING(0 0,10 0,10 10,0 10,0 0)",
                  "MULTIPOINT(1 -1,80 80,5 0,150 90)",
                  0,
                  strategy_ps);
}

//===========================================================================
template <typename Strategy_pp, typename Strategy_ps>
void test_distance_multipoint_multilinestring(Strategy_pp const& strategy_pp,
                                              Strategy_ps const& strategy_ps)
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "multipoint/multilinestring distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries
        <
            multi_point_type, multi_linestring_type
        > tester;

    tester::apply("mp-ml-01",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "MULTILINESTRING((2 0,0 2),(2 2,3 3))",
                  ps_distance("POINT(1 1)", "SEGMENT(2 0,0 2)", strategy_ps),
                  strategy_ps);
    tester::apply("mp-ml-02",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "MULTILINESTRING((3 0,0 3),(4 4,5 5))",
                  ps_distance("POINT(1 1)", "SEGMENT(3 0,0 3)", strategy_ps),
                  strategy_ps);
    tester::apply("mp-ml-03",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "MULTILINESTRING((4 4,5 5),(1 1,2 2))",
                  0,
                  strategy_ps);
    tester::apply("mp-ml-04",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "MULTILINESTRING((4 4,3 3),(4 4,5 5))",
                  pp_distance("POINT(1 1)", "POINT(3 3)", strategy_pp),
                  strategy_ps);
}

//===========================================================================

template <typename Strategy_pp, typename Strategy_ps>
void test_distance_multipoint_segment(Strategy_pp const& strategy_pp,
                                      Strategy_ps const& strategy_ps)
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "multipoint/segment distance tests" << std::endl;
#endif
    typedef test_distance_of_geometries<multi_point_type, segment_type> tester;

    tester::apply("mp-s-01",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "SEGMENT(2 0,0 2)",
                  ps_distance("POINT(1 1)", "SEGMENT(2 0,0 2)", strategy_ps),
                  strategy_ps);
    tester::apply("mp-s-02",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "SEGMENT(0 -3,1 -10)",
                  pp_distance("POINT(0 0)", "POINT(0 -3)", strategy_pp),
                  strategy_ps);
    tester::apply("mp-s-03",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "SEGMENT(1 1,2 2)",
                  0,
                  strategy_ps);
    tester::apply("mp-s-04",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "SEGMENT(3 3,4 4)",
                  pp_distance("POINT(1 1)", "POINT(3 3)", strategy_pp),
                  strategy_ps);
    tester::apply("mp-s-05",
                  "MULTIPOINT(0 0,1 0,0 1,1 1)",
                  "SEGMENT(0.5 -3,1 -10)",
                  pp_distance("POINT(1 0)", "POINT(0.5 -3)", strategy_pp),
                  strategy_ps);
}

//===========================================================================

template <typename Point, typename Strategy>
void test_empty_input_pointlike_linear(Strategy const& strategy)
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << std::endl;
    std::cout << "testing on empty inputs... " << std::flush;
#endif
    bg::model::linestring<Point> line_empty;
    bg::model::multi_point<Point> multipoint_empty;
    bg::model::multi_linestring<bg::model::linestring<Point> > multiline_empty;

    Point point = from_wkt<Point>("POINT(0 0)");
    bg::model::linestring<Point> line =
        from_wkt<bg::model::linestring<Point> >("LINESTRING(0 0,1 1)");

    // 1st geometry is empty
    //test_empty_input(multipoint_empty, line, strategy);

    // 2nd geometry is empty
    test_empty_input(point, line_empty, strategy);
    test_empty_input(point, multiline_empty, strategy);

    // both geometries are empty
    //test_empty_input(multipoint_empty, line_empty, strategy);
    //test_empty_input(multipoint_empty, multiline_empty, strategy);

#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::cout << "done!" << std::endl;
#endif
}

//===========================================================================
//===========================================================================
//===========================================================================

BOOST_AUTO_TEST_CASE( test_all_point_segment )
{
    //TODO: Operations with multipoints need geographic pt-box strategy
    //before activating

    test_distance_point_segment(vincenty_pp(), vincenty_strategy());
    test_distance_point_segment(thomas_pp(), thomas_strategy());
    test_distance_point_segment(andoyer_pp(), andoyer_strategy());

    test_distance_point_segment_no_thomas(vincenty_pp(), vincenty_strategy());
    //test_distance_point_segment_no_thomas(thomas_pp(), thomas_strategy());
    test_distance_point_segment_no_thomas(andoyer_pp(), andoyer_strategy());

    test_distance_point_linestring(vincenty_pp(), vincenty_strategy());
    test_distance_point_linestring(thomas_pp(), thomas_strategy());
    test_distance_point_linestring(andoyer_pp(), andoyer_strategy());
    test_distance_point_linestring_strategies();

    test_distance_point_multilinestring(vincenty_pp(), vincenty_strategy());
    test_distance_point_multilinestring(thomas_pp(), thomas_strategy());
    test_distance_point_multilinestring(andoyer_pp(), andoyer_strategy());

    //    test_distance_linestring_multipoint(vincenty_pp(), vincenty_strategy());
    //    test_distance_linestring_multipoint(thomas_pp(), thomas_strategy());
    //    test_distance_linestring_multipoint(andoyer_pp(), andoyer_strategy());

    //    test_distance_multipoint_multilinestring(vincenty_pp(), vincenty_strategy());
    //    test_distance_multipoint_multilinestring(thomas_pp(), thomas_strategy());
    //    test_distance_multipoint_multilinestring(andoyer_pp(), andoyer_strategy());

    //    test_distance_multipoint_segment(vincenty_pp(), vincenty_strategy());
    //    test_distance_multipoint_segment(thomas_pp(), thomas_strategy());
    //    test_distance_multipoint_segment(andoyer_pp(), andoyer_strategy());

    test_empty_input_pointlike_linear<point_type>(vincenty_strategy());
}


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

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#include <boost/simd/pack.hpp>
#include <boost/simd/function/quadrant.hpp>
#include <boost/simd/function/toint.hpp>
#include <boost/simd/meta/cardinal_of.hpp>
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/minf.hpp>
#include <boost/simd/constant/mone.hpp>
#include <boost/simd/constant/nan.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/function/bitwise_cast.hpp>
#include <boost/simd/function/bitwise_and.hpp>
#include <boost/simd/function/is_even.hpp>
#include <simd_test.hpp>

template <typename T, int N, typename Env>
void test(Env& runtime)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;

  using p_t = bs::pack<T, N>;

  T a1[N];
  T b[N];
  for(int i = 0; i < N; ++i)
  {
    a1[i] = T(i);
    b[i] = bs::quadrant(a1[i]) ;
  }
  p_t aa1(&a1[0], &a1[0]+N);
  p_t bb (&b[0], &b[0]+N);
  STF_EQUAL(bs::quadrant(aa1), bb);
}

STF_CASE_TPL("Check quadrant on pack" , STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  using p_t = bs::pack<T>;
  static const std::size_t N = bs::cardinal_of<p_t>::value;
  test<T, N>(runtime);
  test<T, N/2>(runtime);
  test<T, N*2>(runtime);
}

STF_CASE_TPL (" quadrant real",  STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;

   using bs::quadrant;
  using p_t = bs::pack<T>;

   using r_t = decltype(quadrant(T()));
   using iT =  bd::as_integer_t<T>;
   STF_TYPE_IS(r_t, T);

  for(iT i=0; i < 128; i++)
  {
    STF_EQUAL(quadrant(p_t(i)), p_t(i&iT(3)));
  }
} // end of test for floating_


/*
 * Copyright 2020 INRIA
 */

#ifndef __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__
#define __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__

#include "eigenpy/eigenpy.hpp"
#include "eigenpy/eigen-to-python.hpp"

#include <Eigen/Core>
#include <Eigen/Eigenvalues>

#include "eigenpy/utils/scalar-name.hpp"

namespace eigenpy
{

  template<typename _MatrixType>
  struct SelfAdjointEigenSolverVisitor
  : public boost::python::def_visitor< SelfAdjointEigenSolverVisitor<_MatrixType> >
  {

    typedef _MatrixType MatrixType;
    typedef typename MatrixType::Scalar Scalar;
    typedef Eigen::SelfAdjointEigenSolver<MatrixType> Solver;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      namespace bp = boost::python;
      cl
      .def(bp::init<>("Default constructor"))
      .def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
                                       "Default constructor with memory preallocation"))
      .def(bp::init<MatrixType,bp::optional<int> >(bp::args("matrix","options"),
                                                   "Computes eigendecomposition of given matrix"))

      .def("eigenvalues",&Solver::eigenvalues,bp::arg("self"),
           "Returns the eigenvalues of given matrix.",
           bp::return_internal_reference<>())
      .def("eigenvectors",&Solver::eigenvectors,bp::arg("self"),
           "Returns the eigenvectors of given matrix.",
           bp::return_internal_reference<>())

      .def("compute",&SelfAdjointEigenSolverVisitor::compute_proxy<MatrixType>,
           bp::args("self","matrix"),
           "Computes the eigendecomposition of given matrix.",
           bp::return_value_policy<bp::reference_existing_object>())
      .def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix, int options))&Solver::compute,
           bp::args("self","matrix","options"),
           "Computes the eigendecomposition of given matrix.",
           bp::return_self<>())

      .def("computeDirect",&SelfAdjointEigenSolverVisitor::computeDirect_proxy,
           bp::args("self","matrix"),
           "Computes eigendecomposition of given matrix using a closed-form algorithm.",
           bp::return_self<>())
      .def("computeDirect",(Solver & (Solver::*)(const MatrixType & matrix, int options))&Solver::computeDirect,
           bp::args("self","matrix","options"),
           "Computes eigendecomposition of given matrix using a closed-form algorithm.",
           bp::return_self<>())

      .def("operatorInverseSqrt",&Solver::operatorInverseSqrt,bp::arg("self"),
           "Computes the inverse square root of the matrix.")
      .def("operatorSqrt",&Solver::operatorSqrt,bp::arg("self"),
           "Computes the inverse square root of the matrix.")

      .def("info",&Solver::info,bp::arg("self"),
           "NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
      ;
    }

    static void expose()
    {
      static const std::string classname = "SelfAdjointEigenSolver" + scalar_name<Scalar>::shortname();
      expose(classname);
    }

    static void expose(const std::string & name)
    {
      namespace bp = boost::python;
      bp::class_<Solver>(name.c_str(),
                         bp::no_init)
      .def(SelfAdjointEigenSolverVisitor());
    }

  private:

    template<typename MatrixType>
    static Solver & compute_proxy(Solver & self, const Eigen::EigenBase<MatrixType> & matrix)
    {
      return self.compute(matrix);
    }

    static Solver & computeDirect_proxy(Solver & self, const MatrixType & matrix)
    {
      return self.computeDirect(matrix);
    }

  };

} // namespace eigenpy

#endif // ifndef __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__


//This is a test for atoms problem with optimum chosen cutoff radius for rhs assembly optimization
//The test will run both rhs assembly versions i.e. optimized rhs assembly and without optimization to compare directly the results
//This is a 3D test

#include <deal.II/base/logstream.h>
#include <deal.II/base/parameter_handler.h>
#include <fstream>
#include <step_50.h>

using namespace dealii;
using namespace Step50;

template <int dim>
class Test_LaplaceProblem : public Step50::LaplaceProblem<dim>
{
protected:
  using Step50::LaplaceProblem<dim>::read_lammps_input_file;
  using Step50::LaplaceProblem<dim>::refine_grid;
  using Step50::LaplaceProblem<dim>::setup_system;
  using Step50::LaplaceProblem<dim>::rhs_assembly_optimization;
  using Step50::LaplaceProblem<dim>::assemble_system;
  using Step50::LaplaceProblem<dim>::assemble_multigrid;
  using Step50::LaplaceProblem<dim>::solve;
  using Step50::LaplaceProblem<dim>::output_results;
  using Step50::LaplaceProblem<dim>::pack_function;
  using Step50::LaplaceProblem<dim>::unpack_function;
  using Step50::LaplaceProblem<dim>::prepare_for_coarsening_and_refinement;
  using Step50::LaplaceProblem<dim>::project_cell_data;

  const bool flag_rhs_assembly;
  const unsigned int degree;
  ParameterHandler &prm;
  unsigned int number_of_global_refinement , number_of_adaptive_refinement_cycles;
  double domain_size_left , domain_size_right;
  std::string Problemtype, PreconditionerType, LammpsInputFilename;
  double r_c, nonzero_density_radius_parameter;

public:
  Test_LaplaceProblem (const unsigned int Degree , ParameterHandler &prm,
                       const std::string &Problemtype, const std::string &PreconditionerType, const std::string &LammpsInputFile,
                       const double &domain_size_left, const double &domain_size_right, const unsigned int &number_of_global_refinement,
                       const unsigned int &number_of_adaptive_refinement_cycles,
                       const double &r_c, const double &nonzero_density_radius_parameter,
                       const bool &flag_rhs_assembly_) : Step50::LaplaceProblem<dim> (Degree , prm ,Problemtype,
                             PreconditionerType, LammpsInputFile,
                             domain_size_left, domain_size_right,
                             number_of_global_refinement,
                             number_of_adaptive_refinement_cycles,
                             r_c, nonzero_density_radius_parameter,
                             flag_rhs_assembly_),
    flag_rhs_assembly(flag_rhs_assembly_),
    degree(Degree),
    prm(prm),
    number_of_global_refinement(number_of_global_refinement),
    number_of_adaptive_refinement_cycles(number_of_adaptive_refinement_cycles),
    domain_size_left(domain_size_left),
    domain_size_right(domain_size_right),
    Problemtype(Problemtype),
    PreconditionerType(PreconditionerType),
    LammpsInputFilename(LammpsInputFile),
    r_c(r_c),
    nonzero_density_radius_parameter(nonzero_density_radius_parameter)
  { }

  ~Test_LaplaceProblem();
  void run ();

};

template class Test_LaplaceProblem<2>;
template class Test_LaplaceProblem<3>;

template <int dim>
Test_LaplaceProblem<dim>::~Test_LaplaceProblem ()
{
  Step50::LaplaceProblem<dim>::triangulation.clear();
  Step50::LaplaceProblem<dim>::mg_dof_handler.clear();
  if (flag_rhs_assembly)
    Step50::LaplaceProblem<dim>::charges_list_for_each_cell.clear();
}

template <int dim>
void Test_LaplaceProblem<dim>::run()
{
  Timer timer (Step50::LaplaceProblem<dim>::triangulation.get_communicator(), true);
//    timer.start();
  Step50::LaplaceProblem<dim>::pcout << "Dimension:	" << dim << std::endl;

  Step50::LaplaceProblem<dim>::read_lammps_input_file(LammpsInputFilename);
  for (unsigned int cycle=0; cycle<number_of_adaptive_refinement_cycles; ++cycle)
    {
      Step50::LaplaceProblem<dim>::pcout << "Cycle " << cycle << ':' << std::endl;

      if (cycle == 0)
        {
          GridGenerator::hyper_cube (Step50::LaplaceProblem<dim>::triangulation,domain_size_left,domain_size_right);

          Step50::LaplaceProblem<dim>::triangulation.refine_global (number_of_global_refinement);
        }
      else
        Step50::LaplaceProblem<dim>::refine_grid ();

      Step50::LaplaceProblem<dim>::pcout << "   Number of active cells:       "<< Step50::LaplaceProblem<dim>::triangulation.n_global_active_cells() << std::endl;

      if (cycle == 0)
        Step50::LaplaceProblem<dim>::setup_system ();

      Step50::LaplaceProblem<dim>::pcout << "   Number of degrees of freedom: " << Step50::LaplaceProblem<dim>::mg_dof_handler.n_dofs() << " (by level: ";
      for (unsigned int level=0; level<Step50::LaplaceProblem<dim>::triangulation.n_global_levels(); ++level)
        Step50::LaplaceProblem<dim>::pcout << Step50::LaplaceProblem<dim>::mg_dof_handler.n_dofs(level) << (level == Step50::LaplaceProblem<dim>::triangulation.n_global_levels()-1 ? ")" : ", ");
      Step50::LaplaceProblem<dim>::pcout << std::endl;

      if ((cycle == 0) && (flag_rhs_assembly))
        Step50::LaplaceProblem<dim>::rhs_assembly_optimization();

      Step50::LaplaceProblem<dim>::assemble_system ();

      // Print the charges densities i.e. system rhs norms to compare with rhs optimization
      Step50::LaplaceProblem<dim>::pcout << "   L2 rhs norm " << std::setprecision(10) << std::scientific << Step50::LaplaceProblem<dim>::system_rhs.l2_norm() << std::endl;
      Step50::LaplaceProblem<dim>::pcout << "   LInfinity rhs norm " << std::setprecision(10) << std::scientific << Step50::LaplaceProblem<dim>::system_rhs.linfty_norm() << std::endl;

      if (PreconditionerType == "GMG")
        Step50::LaplaceProblem<dim>::assemble_multigrid ();

      Step50::LaplaceProblem<dim>::solve ();
      Step50::LaplaceProblem<dim>::output_results (cycle);
    }
  timer.stop();
  Step50::LaplaceProblem<dim>::pcout << "\nElapsed wall time: " << timer.wall_time() << " seconds.\n"<<std::endl;
  timer.reset();
}

void check ()
{

  ParameterHandler prm;
  ParameterReader param(prm);
  param.declare_parameters();

  std::ostringstream oss;
  oss << "subsection Geometry" << std::endl
      <<"    set Number of global refinement = 4 "<< std::endl
      << "    set Domain limit left = -5" << std::endl
      << "    set Domain limit right = 5" << std::endl
      <<"end" <<std::endl
      <<"subsection Misc"<<std::endl
      << "    set Number of Adaptive Refinement = 8" << std::endl
      << "    set smoothing length = 0.5" << std::endl
      << "    set Nonzero Density radius parameter around each charge = 3.5" << std::endl
      <<"end"<<std::endl
      << "    set Polynomial degree = 1" << std::endl
      <<"subsection Solver input data"<<std::endl
      << "    set Preconditioner = GMG" << std::endl
      <<"end"<<std::endl
      <<"subsection Problem Selection"<<std::endl
      << "    set Problem = GaussianCharges" << std::endl
      << "    set Dimension = 3" << std::endl
      <<"end"<<std::endl
      <<"subsection Lammps data"<<std::endl
      << "  set Lammps input file = " << SOURCE_DIR << "/atom_2.data" << std::endl
      <<"end"<<std::endl;

  prm.parse_input_from_string(oss.str().c_str());

  prm.enter_subsection ("Geometry");
  unsigned int number_of_global_refinement =prm.get_integer("Number of global refinement");
  double domain_size_left     = prm.get_double ("Domain limit left");
  double domain_size_right     = prm.get_double ("Domain limit right");
  prm.leave_subsection ();

  prm.enter_subsection ("Misc");
  unsigned int number_of_adaptive_refinement_cycles      = prm.get_integer ("Number of Adaptive Refinement");
  double r_c = prm.get_double ("smoothing length");
  double nonzero_density_radius_parameter = prm.get_double("Nonzero Density radius parameter around each charge");
  prm.leave_subsection ();

  const unsigned int Degree = prm.get_integer("Polynomial degree");

  prm.enter_subsection("Solver input data");
  std::string PreconditionerType = (prm.get("Preconditioner"));
  prm.leave_subsection();

  prm.enter_subsection("Problem Selection");
  std::string Problemtype= (prm.get("Problem"));
  const unsigned int d = prm.get_integer("Dimension");
  prm.leave_subsection();

  prm.enter_subsection("Lammps data");
  std::string LammpsInputFile = (prm.get("Lammps input file"));
  prm.leave_subsection();

  bool flag_rhs_assembly;

  if (d == 2)
    {
      flag_rhs_assembly = true;
      Test_LaplaceProblem<2> test_laplace_problem_with_rhs_optimization(Degree , prm ,Problemtype, PreconditionerType,
          LammpsInputFile, domain_size_left, domain_size_right,
          number_of_global_refinement, number_of_adaptive_refinement_cycles,
          r_c, nonzero_density_radius_parameter, flag_rhs_assembly);
      test_laplace_problem_with_rhs_optimization.run();
      test_laplace_problem_with_rhs_optimization.~Test_LaplaceProblem();

      flag_rhs_assembly = false;
      Test_LaplaceProblem<2> test_laplace_problem(Degree , prm ,Problemtype, PreconditionerType, LammpsInputFile, domain_size_left,
                                                  domain_size_right, number_of_global_refinement, number_of_adaptive_refinement_cycles,
                                                  r_c, nonzero_density_radius_parameter, flag_rhs_assembly);
      test_laplace_problem.run();
      test_laplace_problem.~Test_LaplaceProblem();

    }
  else if (d == 3)
    {
      flag_rhs_assembly = true;
      Test_LaplaceProblem<3> test_laplace_problem_with_rhs_optimization(Degree , prm ,Problemtype, PreconditionerType,
          LammpsInputFile, domain_size_left, domain_size_right,
          number_of_global_refinement, number_of_adaptive_refinement_cycles,
          r_c, nonzero_density_radius_parameter, flag_rhs_assembly);
      test_laplace_problem_with_rhs_optimization.run();
      test_laplace_problem_with_rhs_optimization.~Test_LaplaceProblem();

      flag_rhs_assembly = false;
      Test_LaplaceProblem<3> test_laplace_problem(Degree , prm ,Problemtype, PreconditionerType, LammpsInputFile, domain_size_left,
                                                  domain_size_right, number_of_global_refinement, number_of_adaptive_refinement_cycles,
                                                  r_c, nonzero_density_radius_parameter, flag_rhs_assembly);
      test_laplace_problem.run();
      test_laplace_problem.~Test_LaplaceProblem();

    }
  else if (d != 2 && d != 3)
    {
      AssertThrow(false, ExcMessage("Only 2d and 3d dimensions are supported."));
    }

}

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

  dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 2);

  check ();

  return 0;
}


//==============================================================================
//         Copyright 2003 - 2014   LASMEA UMR 6602 CNRS/UBP
//         Copyright 2009 - 2014   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
//==============================================================================
// cover for functor inrad in simd mode
#include <nt2/trigonometric/include/functions/inrad.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <cmath>
#include <iostream>
#include <nt2/sdk/unit/args.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/cover.hpp>
#include <vector>

NT2_TEST_CASE_TPL(inrad_0,  NT2_SIMD_REAL_TYPES)
{
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;

  using nt2::unit::args;
  const std::size_t NR = args("samples", NT2_NB_RANDOM_TEST);
  const double ulpd = args("ulpd",  1.0);

  const T min = args("min", T(-2000));
  const T max = args("max", T(2000));
  std::cout << "Argument samples #0 chosen in range: [" << min << ",  " << max << "]" << std::endl;
  NT2_CREATE_BUF(a0,T, NR, min, max);

  std::vector<T> ref(NR);
  for(std::size_t i=0; i!=NR; ++i)
    ref[i] = T(nt2::inrad(a0[i]));

  NT2_COVER_ULP_EQUAL(nt2::tag::inrad_, ((vT, a0)), ref, ulpd);

}


#ifndef ASLAM_BACKEND_SCALAR_EXPRESSION_NODE_HPP
#define ASLAM_BACKEND_SCALAR_EXPRESSION_NODE_HPP

#include <aslam/backend/JacobianContainer.hpp>
#include <boost/shared_ptr.hpp>
#include <Eigen/Core>
#include <aslam/backend/VectorExpressionNode.hpp>

namespace aslam {
  namespace backend {

    /**
     * \class ScalarExpressionNode
     * \brief The superclass of all classes representing scalar points.
     */
    class ScalarExpressionNode
    {
    public:
      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

      ScalarExpressionNode();
      virtual ~ScalarExpressionNode();

      /// \brief Evaluate the scalar matrix.
      double toScalar() const;

      /// \brief Evaluate the Jacobians
      void evaluateJacobians(JacobianContainer & outJacobians) const;

      /// \brief Evaluate the Jacobians and apply the chain rule.
      void evaluateJacobians(JacobianContainer & outJacobians, const Eigen::MatrixXd & applyChainRule) const;
      void getDesignVariables(DesignVariable::set_t & designVariables) const;
    protected:
      // These functions must be implemented by child classes.
      virtual double toScalarImplementation() const = 0;
      virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians) const = 0;
      virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians, const Eigen::MatrixXd & applyChainRule) const = 0;
      virtual void getDesignVariablesImplementation(DesignVariable::set_t & designVariables) const = 0;
    };

      class ScalarExpressionNodeMultiply : public ScalarExpressionNode
      {
      public:
          EIGEN_MAKE_ALIGNED_OPERATOR_NEW

          ScalarExpressionNodeMultiply(boost::shared_ptr<ScalarExpressionNode> lhs,
                                       boost::shared_ptr<ScalarExpressionNode> rhs);
          virtual ~ScalarExpressionNodeMultiply();
      protected:
          // These functions must be implemented by child classes.
          virtual double toScalarImplementation() const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians) const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians, const Eigen::MatrixXd & applyChainRule) const;
          virtual void getDesignVariablesImplementation(DesignVariable::set_t & designVariables) const;

          boost::shared_ptr<ScalarExpressionNode> _lhs;
          boost::shared_ptr<ScalarExpressionNode> _rhs;

    };

      class ScalarExpressionNodeDivide : public ScalarExpressionNode
      {
      public:
          EIGEN_MAKE_ALIGNED_OPERATOR_NEW

          ScalarExpressionNodeDivide(boost::shared_ptr<ScalarExpressionNode> lhs,
                                       boost::shared_ptr<ScalarExpressionNode> rhs);
          virtual ~ScalarExpressionNodeDivide();
      protected:
          // These functions must be implemented by child classes.
          virtual double toScalarImplementation() const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians) const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians, const Eigen::MatrixXd & applyChainRule) const;
          virtual void getDesignVariablesImplementation(DesignVariable::set_t & designVariables) const;

          boost::shared_ptr<ScalarExpressionNode> _lhs;
          boost::shared_ptr<ScalarExpressionNode> _rhs;

    };

      class ScalarExpressionNodeAdd : public ScalarExpressionNode
      {
      public:
          EIGEN_MAKE_ALIGNED_OPERATOR_NEW

          ScalarExpressionNodeAdd(boost::shared_ptr<ScalarExpressionNode> lhs,
                                  boost::shared_ptr<ScalarExpressionNode> rhs,
                                  double multiplyRhs = 1.0);
          virtual ~ScalarExpressionNodeAdd();

       protected:
          // These functions must be implemented by child classes.
          virtual double toScalarImplementation() const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians) const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians, const Eigen::MatrixXd & applyChainRule) const;
          virtual void getDesignVariablesImplementation(DesignVariable::set_t & designVariables) const;

          boost::shared_ptr<ScalarExpressionNode> _lhs;
          boost::shared_ptr<ScalarExpressionNode> _rhs;
          double _multiplyRhs;
    };

      class ScalarExpressionNodeConstant  : public ScalarExpressionNode
      {
      public:
          EIGEN_MAKE_ALIGNED_OPERATOR_NEW

          ScalarExpressionNodeConstant(double s);
          virtual ~ScalarExpressionNodeConstant();

      protected:
          // These functions must be implemented by child classes.
          virtual double toScalarImplementation() const{return _s;}
        virtual void evaluateJacobiansImplementation(JacobianContainer & /* outJacobians */) const{}
        virtual void evaluateJacobiansImplementation(JacobianContainer & /* outJacobians */, const Eigen::MatrixXd & /* applyChainRule */) const{}
        virtual void getDesignVariablesImplementation(DesignVariable::set_t & /* designVariables */) const{}

          double _s;
      };

      class ScalarExpressionNodeFromVectorExpression : public ScalarExpressionNode
      {
      public:
          EIGEN_MAKE_ALIGNED_OPERATOR_NEW

          ScalarExpressionNodeFromVectorExpression(boost::shared_ptr<VectorExpressionNode<1> > lhs);
          virtual ~ScalarExpressionNodeFromVectorExpression();

       protected:
          // These functions must be implemented by child classes.
          virtual double toScalarImplementation() const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians) const;
          virtual void evaluateJacobiansImplementation(JacobianContainer & outJacobians, const Eigen::MatrixXd & applyChainRule) const;
          virtual void getDesignVariablesImplementation(DesignVariable::set_t & designVariables) const;

          boost::shared_ptr<VectorExpressionNode<1> > _lhs;
    };

  } // namespace backend
} // namespace aslam

#endif /* ASLAM_BACKEND_EUCLIDEAN_EXPRESSION_NODE_HPP */


/*
 * Copyright 2009-2021 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE beadtriple_test

// Standard includes
#include <string>
#include <tuple>

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include "votca/csg/bead.h"
#include "votca/csg/beadtriple.h"
#include "votca/csg/topology.h"

using namespace std;
using namespace votca::csg;

BOOST_AUTO_TEST_SUITE(beadtriple_test)

BOOST_AUTO_TEST_CASE(test_beadtriple_constructor) {

  Topology top;

  string bead_type_name = "CG";

  string name = "dummy1";
  votca::Index resnr = 0;
  double mass = 1.0;
  double charge = -1.0;

  top.CreateBead(Bead::spherical, name, bead_type_name, resnr, mass, charge);

  name = "dummy2";
  resnr = 0;
  mass = 1.0;
  charge = -1.0;

  top.CreateBead(Bead::spherical, name, bead_type_name, resnr, mass, charge);

  name = "dummy3";
  resnr = 0;
  mass = 1.0;
  charge = -1.0;

  top.CreateBead(Bead::spherical, name, bead_type_name, resnr, mass, charge);

  Eigen::Vector3d dist12(0.1, 0.2, 0.3);
  Eigen::Vector3d dist13(0.2, 0.4, 0.3);
  Eigen::Vector3d dist23(0.1, 0.2, 0.0);

  BeadTriple testtriple(top.getBead(0), top.getBead(1), top.getBead(2), dist12,
                        dist13, dist23);

  double d12ref = 0.3741657;
  double d13ref = 0.5385165;
  double d23ref = 0.2236068;

  double d12 = testtriple.dist12();
  double d13 = testtriple.dist13();
  double d23 = testtriple.dist23();

  BOOST_CHECK_CLOSE(d12, d12ref, 1e-4);
  BOOST_CHECK_CLOSE(d13, d13ref, 1e-4);
  BOOST_CHECK_CLOSE(d23, d23ref, 1e-4);
}

BOOST_AUTO_TEST_SUITE_END()


// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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 <geometry_test_common.hpp>

#include <boost/core/ignore_unused.hpp>

#include <boost/geometry/geometries/concepts/segment_concept.hpp>

#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>

#include <boost/geometry/geometries/adapted/c_array.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>

#include <test_common/test_point.hpp>
#include <test_geometries/custom_segment.hpp>

BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian)
BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)

template <typename P>
void test_all()
{
    typedef bg::model::referring_segment<P> S;

    P p1;
    P p2;
    S s(p1, p2);
    BOOST_CHECK_EQUAL(&s.first, &p1);
    BOOST_CHECK_EQUAL(&s.second, &p2);

    // Compilation tests, all things should compile.
    BOOST_CONCEPT_ASSERT( (bg::concepts::ConstSegment<S>) );
    BOOST_CONCEPT_ASSERT( (bg::concepts::Segment<S>) );

    typedef typename bg::coordinate_type<S>::type T;
    typedef typename bg::point_type<S>::type SP;
    boost::ignore_unused<T, SP>();

    //std::cout << sizeof(typename coordinate_type<S>::type) << std::endl;

    typedef bg::model::referring_segment<P const> refseg_t;
    //BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<refseg_t>) );

    refseg_t seg(p1, p2);

    typedef typename bg::coordinate_type<refseg_t>::type CT;
    typedef typename bg::point_type<refseg_t>::type CSP;
    boost::ignore_unused<CT, CSP>();
}

template <typename S>
void test_custom()
{
    S seg;
    bg::set<0,0>(seg, 1);
    bg::set<0,1>(seg, 2);
    bg::set<1,0>(seg, 3);
    bg::set<1,1>(seg, 4);

    BOOST_CHECK_EQUAL((bg::get<0, 0>(seg)), 1);
    BOOST_CHECK_EQUAL((bg::get<0, 1>(seg)), 2);
    BOOST_CHECK_EQUAL((bg::get<1, 0>(seg)), 3);
    BOOST_CHECK_EQUAL((bg::get<1, 1>(seg)), 4);
}

template <typename P>
void test_constexpr()
{
    typedef bg::model::segment<P> S;
    constexpr S s = S{ {1, 2, 3}, {4, 5} };
    constexpr auto c1 = bg::get<0, 0>(s);
    constexpr auto c2 = bg::get<1, 2>(s);
    BOOST_CHECK_EQUAL(c1, 1);
    BOOST_CHECK_EQUAL(c2, 0);
    BOOST_CHECK_EQUAL((bg::get<0, 0>(s)), 1);
    BOOST_CHECK_EQUAL((bg::get<0, 1>(s)), 2);
    BOOST_CHECK_EQUAL((bg::get<0, 2>(s)), 3);
    BOOST_CHECK_EQUAL((bg::get<1, 0>(s)), 4);
    BOOST_CHECK_EQUAL((bg::get<1, 1>(s)), 5);
    BOOST_CHECK_EQUAL((bg::get<1, 2>(s)), 0);
}

int test_main(int, char* [])
{
    test_all<int[3]>();
    test_all<float[3]>();
    test_all<double[3]>();
    //test_all<test_point>();
    test_all<bg::model::point<int, 3, bg::cs::cartesian> >();
    test_all<bg::model::point<float, 3, bg::cs::cartesian> >();
    test_all<bg::model::point<double, 3, bg::cs::cartesian> >();

    test_custom<test::custom_segment>();
    test_custom<test::custom_segment_of<bg::model::point<double, 2, bg::cs::cartesian> > >();
    test_custom<test::custom_segment_of<test::custom_point_for_segment> >();
    test_custom<test::custom_segment_4>();

    test_constexpr<bg::model::point<double, 3, bg::cs::cartesian> >();

    return 0;
}


/**
* @file       tutorial.cpp
*
* @brief      Simple tutorial program to illustrate Zerocoin usage.
*
* @author     Ian Miers, Christina Garman and Matthew Green
* @date       June 2013
*
* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
* @license    This project is released under the MIT license.
**/
// Copyright (c) 2017-2018 The SDC developers

#include <boost/test/unit_test.hpp>
#include <string>
#include <iostream>
#include <fstream>
// #include <curses.h>
#include <exception>
#include "streams.h"
#include "libzerocoin/bignum.h"
#include "libzerocoin/ParamGeneration.h"
#include "libzerocoin/Denominations.h"
#include "libzerocoin/Coin.h"
#include "libzerocoin/CoinSpend.h"
#include "libzerocoin/Accumulator.h"

using namespace std;

#define COINS_TO_ACCUMULATE     5
#define DUMMY_TRANSACTION_HASH  0 // in real life these would be uint256 hashes
#define DUMMY_ACCUMULATOR_ID    0 // in real life these would be uint256 hashes

//
// We generated this for testing only. Don't use it in production!
//
#define TUTORIAL_TEST_MODULUS   "a8852ebf7c49f01cd196e35394f3b74dd86283a07f57e0a262928e7493d4a3961d93d93c90ea3369719641d626d28b9cddc6d9307b9aabdbffc40b6d6da2e329d079b4187ff784b2893d9f53e9ab913a04ff02668114695b07d8ce877c4c8cac1b12b9beff3c51294ebe349eca41c24cd32a6d09dd1579d3947e5c4dcc30b2090b0454edb98c6336e7571db09e0fdafbd68d8f0470223836e90666a5b143b73b9cd71547c917bf24c0efc86af2eba046ed781d9acb05c80f007ef5a0a5dfca23236f37e698e8728def12554bc80f294f71c040a88eff144d130b24211016a97ce0f5fe520f477e555c9997683d762aff8bd1402ae6938dd5c994780b1bf6aa7239e9d8101630ecfeaa730d2bbc97d39beb057f016db2e28bf12fab4989c0170c2593383fd04660b5229adcd8486ba78f6cc1b558bcd92f344100dff239a8c00dbc4c2825277f24bdd04475bcc9a8c39fd895eff97c1967e434effcb9bd394e0577f4cf98c30d9e6b54cd47d6e447dcf34d67e48e4421691dbe4a7d9bd503abb9"

//
// The following routine exercises most of the core functions of
// the library. We've commented it as well as possible to give
// you the flavor of how libzerocoin works.
//
// For details on Zerocoin integration, see the libzerocoin wiki
// at: https://github.com/Zerocoin/libzerocoin/wiki
//

bool
ZerocoinTutorial()
{
	// The following simple code illustrates the call flow for Zerocoin
	// applications. In a real currency network these operations would
	// be split between individual payers/payees, network nodes and miners.
	//
	// For each call we specify the participant who would use it.

	// Zerocoin uses exceptions (based on the runtime_error class)
	// to indicate all sorts of problems. Always remember to catch them!

	try {

		/********************************************************************/
		// What is it:      Parameter loading
		// Who does it:     ALL ZEROCOIN PARTICIPANTS
		// What it does:    Loads a trusted Zerocoin modulus "N" and
		//                  generates all associated parameters from it.
		//                  We use a hardcoded "N" that we generated using
		//                  the included 'paramgen' utility.
		/********************************************************************/

		// Load a test modulus from our hardcoded string (above)
		CBigNum testModulus;
		testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS));

		// Set up the Zerocoin Params object
		libzerocoin::ZerocoinParams* params = new libzerocoin::ZerocoinParams(testModulus);

		cout << "Successfully loaded parameters." << endl;

		/********************************************************************/
		// What is it:      Coin generation
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Generates a new 'zerocoin' coin using the
		//                  public parameters. Once generated, the client
		//                  will transmit the public portion of this coin
		//                  in a ZEROCOIN_MINT transaction. The inputs
		//                  to this transaction must add up to the zerocoin
		//                  denomination plus any transaction fees.
		/********************************************************************/

		// The following constructor does all the work of minting a brand
		// new zerocoin. It stores all the private values inside the
		// PrivateCoin object. This includes the coin secrets, which must be
		// stored in a secure location (wallet) at the client.
        libzerocoin::PrivateCoin newCoin(params, libzerocoin::CoinDenomination::ZQ_ONE);

		// Get a copy of the 'public' portion of the coin. You should
		// embed this into a Zerocoin 'MINT' transaction along with a series
		// of currency inputs totaling the assigned value of one zerocoin.
		libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin();

		cout << "Successfully minted a zerocoin." << endl;

		// Serialize the public coin to a CDataStream object.
		CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoin << pubCoin;

		/********************************************************************/
		// What is it:      Coin verification
		// Who does it:     TRANSACTION VERIFIERS
		// What it does:    Verifies the structure of a zerocoin obtained from
		//                  a ZEROCOIN_MINT transaction. All coins must be
		//                  verified before you operate on them.
		//                  Note that this is only part of the transaction
		//                  verification process! The client must also check
		//                  that (1) the inputs to the transaction are valid
		//                  and add up to the value of one zerocoin, (2) that
		//                  this particular zerocoin has not been minted before.
		/********************************************************************/

		// Deserialize the public coin into a fresh object.
		libzerocoin::PublicCoin pubCoinNew(params, serializedCoin);

		// Now make sure the coin is valid.
		if (!pubCoinNew.validate()) {
			// If this returns false, don't accept the coin for any purpose!
			// Any ZEROCOIN_MINT with an invalid coin should NOT be
			// accepted as a valid transaction in the block chain.
			cout << "Error: coin is not valid!";
		}

		cout << "Deserialized and verified the coin." << endl;

		/********************************************************************/
		// What is it:      Accumulator computation
		// Who does it:     ZEROCOIN CLIENTS & TRANSACTION VERIFIERS
		// What it does:    Collects a number of PublicCoin values drawn from
		//                  the block chain and calculates an accumulator.
		//                  This accumulator is incrementally computable;
		//                  you can stop and serialize it at any point
		//                  then continue accumulating new transactions.
		//                  The accumulator is also order-independent, so
		//                  the same coins can be accumulated in any order
		//                  to give the same result.
		//                  WARNING: do not accumulate the same coin twice!
		/********************************************************************/

		// Create an empty accumulator object
        libzerocoin::Accumulator accumulator(params,libzerocoin::CoinDenomination::ZQ_ONE);

		// Add several coins to it (we'll generate them here on the fly).
		for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) {
            libzerocoin::PrivateCoin testCoin(params, libzerocoin::CoinDenomination::ZQ_ONE);
			accumulator += testCoin.getPublicCoin();
		}

		// Serialize the accumulator object.
		//
		// If you're using Accumulator Checkpoints, each miner would
		// start by deserializing the accumulator checkpoint from the
		// previous block (or creating a new Accumulator if no previous
		// block exists). It will then add all the coins in the new block,
		// then serialize the resulting Accumulator object to obtain the
		// new checkpoint. All block verifiers should do the same thing
		// to check their work.
		CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION);
		serializedAccumulator << accumulator;

		// Deserialize the accumulator object
		libzerocoin::Accumulator newAccumulator(params, serializedAccumulator);

		// We can now continue accumulating things into the accumulator
		// we just deserialized. For example, let's put in the coin
		// we generated up above.
		newAccumulator += pubCoinNew;

		cout << "Successfully accumulated coins." << endl;

		/********************************************************************/
		// What is it:      Coin spend
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Create a new transaction that spends a Zerocoin.
		//                  The user first authors a transaction specifying
		//                  a set of destination addresses (outputs). They
		//                  next compute an Accumulator over all coins in the
		//                  block chain (see above) and a Witness based on the
		//                  coin to be spent. Finally they instantiate a CoinSpend
		//                  object that 'signs' the transaction with a special
		//                  zero knowledge signature of knowledge over the coin
		//                  data, Witness and Accumulator.
		/********************************************************************/

		// We are going to spend the coin "newCoin" that we generated at the
		// top of this function.
		//
		// We'll use the accumulator we constructed above. This contains
		// a set of coins, but does NOT include the coin "newCoin".
		//
		// To generate the witness, we start with this accumulator and
		// add the public half of the coin we want to spend.
		libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin());

		// Add the public half of "newCoin" to the Accumulator itself.
		accumulator += newCoin.getPublicCoin();

		// At this point we should generate a ZEROCOIN_SPEND transaction to
		// send to the network. This network should include a set of outputs
		// totalling to the value of one zerocoin (minus transaction fees).

		// Construct the CoinSpend object. This acts like a signature on the
		// transaction.
        libzerocoin::CoinSpend spend(params, params, newCoin, accumulator, 0, witness, 0, libzerocoin::SpendType::SPEND);//(0) - Presstab

		// This is a sanity check. The CoinSpend object should always verify,
		// but why not check before we put it onto the wire?
		if (!spend.Verify(accumulator)) {
			cout << "ERROR: Our new CoinSpend transaction did not verify!" << endl;
			return false;
		}

		// Serialize the CoinSpend object into a buffer.
		CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoinSpend << spend;

		cout << "Successfully generated a coin spend transaction." << endl;

		/********************************************************************/
		// What is it:      Coin spend verification
		// Who does it:     ALL PARTIES
		// What it does:    Verifies that a CoinSpend signature is correct
		//                  with respect to a ZEROCOIN_SPEND transaction hash.
		//                  The client must also extract the serial number from
		//                  the CoinSpend and verify that this serial number has
		//                  not previously appeared in another ZEROCOIN_SPEND
		//                  transaction.
		/********************************************************************/

		// Deserialize the CoinSpend intro a fresh object
		libzerocoin::CoinSpend newSpend(params, params, serializedCoinSpend);

		// Create a new metadata object to contain the hash of the received
		// ZEROCOIN_SPEND transaction. If we were a real client we'd actually
		// compute the hash of the received transaction here.

		// If we were a real client we would now re-compute the Accumulator
		// from the information given in the ZEROCOIN_SPEND transaction.
		// For our purposes we'll just use the one we calculated above.
		//
		// Verify that the spend is valid with respect to the Accumulator
		// and the Metadata
		if (!newSpend.Verify(accumulator)) {
			cout << "ERROR: The CoinSpend transaction did not verify!" << endl;
			return false;
		}

		// Pull the serial number out of the CoinSpend object. If we
		// were a real Zerocoin client we would now check that the serial number
		// has not been spent before (in another ZEROCOIN_SPEND) transaction.
		// The serial number is stored as a CBigNum.
		CBigNum serialNumber = newSpend.getCoinSerialNumber();

		cout << "Successfully verified a coin spend transaction." << endl;
		cout << endl << "Coin serial number is:" << endl << serialNumber << endl;

		// We're done
		return true;

	} catch (runtime_error &e) {
		cout << e.what() << endl;
		return false;
	}

	return false;
}

BOOST_AUTO_TEST_SUITE(tutorial_libzerocoin)
BOOST_AUTO_TEST_CASE(tutorial_libzerocoin_tests)
{
	cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl;

	ZerocoinTutorial();
}
BOOST_AUTO_TEST_SUITE_END()


// Copyright John Maddock 2006.
// Copyright Paul A. Bristow 2007, 2009
//  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)

#include <boost/math/concepts/real_concept.hpp>
#include <boost/test/test_exec_monitor.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/array.hpp>
#include "functor.hpp"

#include "test_erf_hooks.hpp"
#include "handle_test_result.hpp"
#include "table_type.hpp"

#ifndef SC_
#define SC_(x) static_cast<typename table_type<T>::type>(BOOST_JOIN(x, L))
#endif

template <class Real, class T>
void do_test_erf(const T& data, const char* type_name, const char* test_name)
{
   typedef typename T::value_type row_type;
   typedef Real                   value_type;

   typedef value_type (*pg)(value_type);
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   pg funcp = boost::math::erf<value_type>;
#else
   pg funcp = boost::math::erf;
#endif

   boost::math::tools::test_result<value_type> result;

   std::cout << "Testing " << test_name << " with type " << type_name
      << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";

   //
   // test erf against data:
   //
   result = boost::math::tools::test_hetero<Real>(
      data,
      bind_func<Real>(funcp, 0),
      extract_result<Real>(1));
   handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::erf", test_name);
#ifdef TEST_OTHER
   if(::boost::is_floating_point<value_type>::value){
      funcp = other::erf;
      result = boost::math::tools::test_hetero<Real>(
         data,
         bind_func<Real>(funcp, 0),
         extract_result<Real>(1));
      print_test_result(result, data[result.worst()], result.worst(), type_name, "other::erf");
   }
#endif
   //
   // test erfc against data:
   //
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   funcp = boost::math::erfc<value_type>;
#else
   funcp = boost::math::erfc;
#endif
   result = boost::math::tools::test_hetero<Real>(
      data,
      bind_func<Real>(funcp, 0),
      extract_result<Real>(2));
   handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::erfc", test_name);
#ifdef TEST_OTHER
   if(::boost::is_floating_point<value_type>::value){
      funcp = other::erfc;
      result = boost::math::tools::test_hetero<Real>(
         data,
         bind_func<Real>(funcp, 0),
         extract_result<Real>(2));
      print_test_result(result, data[result.worst()], result.worst(), type_name, "other::erfc");
   }
#endif
   std::cout << std::endl;
}

template <class Real, class T>
void do_test_erf_inv(const T& data, const char* type_name, const char* test_name)
{
   typedef typename T::value_type row_type;
   typedef Real                   value_type;

   typedef value_type (*pg)(value_type);

   boost::math::tools::test_result<value_type> result;
   std::cout << "Testing " << test_name << " with type " << type_name
      << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
   //
   // test erf_inv against data:
   //
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   pg funcp = boost::math::erf_inv<value_type>;
#else
   pg funcp = boost::math::erf_inv;
#endif
   result = boost::math::tools::test_hetero<Real>(
      data,
      bind_func<Real>(funcp, 0),
      extract_result<Real>(1));
   handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::erf_inv", test_name);
   std::cout << std::endl;
}

template <class Real, class T>
void do_test_erfc_inv(const T& data, const char* type_name, const char* test_name)
{
   typedef typename T::value_type row_type;
   typedef Real                   value_type;

   typedef value_type (*pg)(value_type);
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   pg funcp = boost::math::erf<value_type>;
#else
   pg funcp = boost::math::erf;
#endif

   boost::math::tools::test_result<value_type> result;
   std::cout << "Testing " << test_name << " with type " << type_name
      << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
   //
   // test erfc_inv against data:
   //
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   funcp = boost::math::erfc_inv<value_type>;
#else
   funcp = boost::math::erfc_inv;
#endif
   result = boost::math::tools::test_hetero<Real>(
      data,
      bind_func<Real>(funcp, 0),
      extract_result<Real>(1));
   handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::erfc_inv", test_name);
   std::cout << std::endl;
}

template <class T>
void test_erf(T, const char* name)
{
   //
   // The actual test data is rather verbose, so it's in a separate file
   //
   // The contents are as follows, each row of data contains
   // three items, input value a, input value b and erf(a, b):
   //
#  include "erf_small_data.ipp"

   do_test_erf<T>(erf_small_data, name, "Erf Function: Small Values");

#  include "erf_data.ipp"

   do_test_erf<T>(erf_data, name, "Erf Function: Medium Values");

#  include "erf_large_data.ipp"

   do_test_erf<T>(erf_large_data, name, "Erf Function: Large Values");

#  include "erf_inv_data.ipp"

   do_test_erf_inv<T>(erf_inv_data, name, "Inverse Erf Function");

#  include "erfc_inv_data.ipp"

   do_test_erfc_inv<T>(erfc_inv_data, name, "Inverse Erfc Function");

#  include "erfc_inv_big_data.ipp"

   if(std::numeric_limits<T>::min_exponent <= -4500)
   {
      do_test_erfc_inv<T>(erfc_inv_big_data, name, "Inverse Erfc Function: extreme values");
   }
}

template <class T>
void test_spots(T, const char* t)
{
   std::cout << "Testing basic sanity checks for type " << t << std::endl;
   //
   // basic sanity checks, tolerance is 10 epsilon expressed as a percentage:
   //
   T tolerance = boost::math::tools::epsilon<T>() * 1000;
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(0.125)), static_cast<T>(0.85968379519866618260697055347837660181302041685015L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(0.5)), static_cast<T>(0.47950012218695346231725334610803547126354842424204L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(1)), static_cast<T>(0.15729920705028513065877936491739074070393300203370L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(5)), static_cast<T>(1.5374597944280348501883434853833788901180503147234e-12L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(-0.125)), static_cast<T>(1.1403162048013338173930294465216233981869795831498L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(-0.5)), static_cast<T>(1.5204998778130465376827466538919645287364515757580L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erfc(static_cast<T>(0)), static_cast<T>(1), tolerance);

   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(0.125)), static_cast<T>(0.14031620480133381739302944652162339818697958314985L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(0.5)), static_cast<T>(0.52049987781304653768274665389196452873645157575796L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(1)), static_cast<T>(0.84270079294971486934122063508260925929606699796630L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(5)), static_cast<T>(0.9999999999984625402055719651498116565146166211099L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(-0.125)), static_cast<T>(-0.14031620480133381739302944652162339818697958314985L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(-0.5)), static_cast<T>(-0.52049987781304653768274665389196452873645157575796L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::erf(static_cast<T>(0)), static_cast<T>(0), tolerance);

   tolerance = boost::math::tools::epsilon<T>() * 100 * 200; // 200 eps %.
#if defined(__CYGWIN__)
   // some platforms long double is only reliably accurate to double precision:
   if(sizeof(T) == sizeof(long double))
      tolerance = boost::math::tools::epsilon<double>() * 100 * 200; // 200 eps %.
#endif

   for(T i = -0.95f; i < 1; i += 0.125f)
   {
      T inv = boost::math::erf_inv(i);
      T b = boost::math::erf(inv);
      BOOST_CHECK_CLOSE(b, i, tolerance);
   }
   for(T j = 0.125f; j < 2; j += 0.125f)
   {
      T inv = boost::math::erfc_inv(j);
      T b = boost::math::erfc(inv);
      BOOST_CHECK_CLOSE(b, j, tolerance);
   }
}