/**
 * \copyright
 * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/LICENSE.txt
 */

#include <gtest/gtest.h>

#include <algorithm>
#include <limits>
#include <vector>

#include <Eigen/Eigen>

#include "NumLib/Fem/CoordinatesMapping/NaturalCoordinatesMapping.h"
#include "NumLib/Fem/CoordinatesMapping/ShapeMatrices.h"
#include "NumLib/Fem/ShapeMatrixPolicy.h"

#include "CoordinatesMappingTestData/TestHex8.h"
#include "CoordinatesMappingTestData/TestLine2.h"
#include "CoordinatesMappingTestData/TestLine3.h"
#include "CoordinatesMappingTestData/TestQuad4.h"
#include "CoordinatesMappingTestData/TestTri3.h"

#include "Tests/TestTools.h"

using namespace NumLib;
using namespace CoordinatesMappingTestData;

namespace
{
// Element types to be tested
using TestTypes =
    ::testing::Types<TestLine2, TestLine3, TestTri3, TestQuad4, TestHex8>;
}

template <class T_TEST>
class NumLibFemNaturalCoordinatesMappingTest : public ::testing::Test,
                                               public T_TEST
{
public:
    using ElementType = typename T_TEST::ElementType;
    using ShapeFunctionType = typename T_TEST::ShapeFunctionType;
    static const unsigned dim = T_TEST::dim;
    static const unsigned e_nnodes = T_TEST::e_nnodes;
    static const unsigned global_dim = T_TEST::global_dim;
    // Matrix types
    using NodalVector = typename ::detail::EigenMatrixType<1, e_nnodes>::type;
    using DimNodalMatrix =
        typename ::detail::EigenMatrixType<dim, e_nnodes>::type;
    using DimMatrix = typename ::detail::EigenMatrixType<dim, dim>::type;
    using GlobalDimNodalMatrix =
        typename ::detail::EigenMatrixType<global_dim, e_nnodes>::type;
    // Shape data type
    using ShapeMatricesType = ShapeMatrices<NodalVector, DimNodalMatrix,
                                            DimMatrix, GlobalDimNodalMatrix>;
    // Natural coordinates mapping type
    using NaturalCoordsMappingType =
        NaturalCoordinatesMapping<ElementType, ShapeFunctionType,
                                  ShapeMatricesType>;

public:
    NumLibFemNaturalCoordinatesMappingTest()
        : eps(2 * std::numeric_limits<double>::epsilon())
    {
        // create four elements used for testing
        naturalEle = this->createNaturalShape();
        irregularEle = this->createIrregularShape();
        clockwiseEle = this->createClockWise();
        zeroVolumeEle = this->createZeroVolume();

        // for destructor
        vec_eles.push_back(naturalEle);
        vec_eles.push_back(irregularEle);
        vec_eles.push_back(clockwiseEle);
        vec_eles.push_back(zeroVolumeEle);
        for (auto e : vec_eles)
            for (unsigned i = 0; i < e->getNumberOfNodes(); i++)
                vec_nodes.push_back(e->getNode(i));
    }

    ~NumLibFemNaturalCoordinatesMappingTest() override
    {
        for (auto itr = vec_nodes.begin(); itr != vec_nodes.end(); ++itr)
            delete *itr;
        for (auto itr = vec_eles.begin(); itr != vec_eles.end(); ++itr)
            delete *itr;
    }

    const double eps;
    std::vector<const MeshLib::Node*> vec_nodes;
    std::vector<const ElementType*> vec_eles;
    ElementType* naturalEle;
    ElementType* irregularEle;
    ElementType* clockwiseEle;
    ElementType* zeroVolumeEle;
};

TYPED_TEST_CASE(NumLibFemNaturalCoordinatesMappingTest, TestTypes);

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckFieldSpecification_N)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    // only N
    NaturalCoordsMappingType::template computeShapeMatrices<ShapeMatrixType::N>(
        *this->naturalEle, this->r, shape, this->global_dim);
    ASSERT_FALSE(shape.N.isZero());
    ASSERT_TRUE(shape.dNdr.isZero());
    ASSERT_TRUE(shape.J.isZero());
    ASSERT_TRUE(shape.detJ == .0);
    ASSERT_TRUE(shape.invJ.isZero());
    ASSERT_TRUE(shape.dNdx.isZero());
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckFieldSpecification_DNDR)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    // dNdr
    NaturalCoordsMappingType::template computeShapeMatrices<
        ShapeMatrixType::DNDR>(*this->naturalEle, this->r, shape,
                               this->global_dim);
    ASSERT_TRUE(shape.N.isZero());
    ASSERT_FALSE(shape.dNdr.isZero());
    ASSERT_TRUE(shape.J.isZero());
    ASSERT_TRUE(shape.detJ == .0);
    ASSERT_TRUE(shape.invJ.isZero());
    ASSERT_TRUE(shape.dNdx.isZero());
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckFieldSpecification_N_J)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    // N_J
    shape.setZero();
    NaturalCoordsMappingType::template computeShapeMatrices<
        ShapeMatrixType::N_J>(*this->naturalEle, this->r, shape,
                              this->global_dim);
    ASSERT_FALSE(shape.N.isZero());
    ASSERT_FALSE(shape.dNdr.isZero());
    ASSERT_FALSE(shape.J.isZero());
    ASSERT_FALSE(shape.detJ == .0);
    ASSERT_TRUE(shape.invJ.isZero());
    ASSERT_TRUE(shape.dNdx.isZero());
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest,
           CheckFieldSpecification_DNDR_J)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    // dNdr, J
    NaturalCoordsMappingType::template computeShapeMatrices<
        ShapeMatrixType::DNDR_J>(*this->naturalEle, this->r, shape,
                                 this->global_dim);
    ASSERT_TRUE(shape.N.isZero());
    ASSERT_FALSE(shape.dNdr.isZero());
    ASSERT_FALSE(shape.J.isZero());
    ASSERT_FALSE(shape.detJ == .0);
    ASSERT_TRUE(shape.invJ.isZero());
    ASSERT_TRUE(shape.dNdx.isZero());
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckFieldSpecification_DNDX)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    // DNDX
    shape.setZero();
    NaturalCoordsMappingType::template computeShapeMatrices<
        ShapeMatrixType::DNDX>(*this->naturalEle, this->r, shape, this->dim);
    ASSERT_TRUE(shape.N.isZero());
    ASSERT_FALSE(shape.dNdr.isZero());
    ASSERT_FALSE(shape.J.isZero());
    ASSERT_FALSE(shape.detJ == .0);
    ASSERT_FALSE(shape.invJ.isZero());
    ASSERT_FALSE(shape.dNdx.isZero());
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckFieldSpecification_ALL)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    // ALL
    shape.setZero();
    NaturalCoordsMappingType::computeShapeMatrices(*this->naturalEle, this->r,
                                                   shape, this->global_dim);
    ASSERT_FALSE(shape.N.isZero());
    ASSERT_FALSE(shape.dNdr.isZero());
    ASSERT_FALSE(shape.J.isZero());
    ASSERT_FALSE(shape.detJ == .0);
    ASSERT_FALSE(shape.invJ.isZero());
    ASSERT_FALSE(shape.dNdx.isZero());
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckNaturalShape)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;

    // identical to natural coordinates
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);
    NaturalCoordsMappingType::computeShapeMatrices(*this->naturalEle, this->r,
                                                   shape, this->global_dim);
    double exp_J[TestFixture::dim * TestFixture::dim] = {0.0};
    for (unsigned i = 0; i < this->dim; i++)
        exp_J[i + this->dim * i] = 1.0;

    ASSERT_ARRAY_NEAR(this->nat_exp_N, shape.N.data(), shape.N.size(),
                      this->eps);
    ASSERT_ARRAY_NEAR(this->nat_exp_dNdr, shape.dNdr.data(), shape.dNdr.size(),
                      this->eps);
    ASSERT_ARRAY_NEAR(exp_J, shape.J.data(), shape.J.size(), this->eps);
    ASSERT_ARRAY_NEAR(exp_J, shape.invJ.data(), shape.invJ.size(), this->eps);
    ASSERT_NEAR(1.0, shape.detJ, this->eps);
    ASSERT_ARRAY_NEAR(this->nat_exp_dNdr, shape.dNdx.data(), shape.dNdx.size(),
                      this->eps);
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckIrregularShape)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;

    // irregular shape
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);
    NaturalCoordsMappingType::computeShapeMatrices(*this->irregularEle, this->r,
                                                   shape, this->global_dim);
    // std::cout <<  std::setprecision(16) << shape;

    ASSERT_ARRAY_NEAR(this->nat_exp_N, shape.N.data(), shape.N.size(),
                      this->eps);
    ASSERT_ARRAY_NEAR(this->nat_exp_dNdr, shape.dNdr.data(), shape.dNdr.size(),
                      this->eps);
    ASSERT_ARRAY_NEAR(this->ir_exp_J, shape.J.data(), shape.J.size(),
                      this->eps);
    ASSERT_NEAR(this->ir_exp_detJ, shape.detJ, this->eps);
    ASSERT_ARRAY_NEAR(this->ir_exp_invJ, shape.invJ.data(), shape.invJ.size(),
                      this->eps);
    ASSERT_ARRAY_NEAR(this->ir_exp_dNdx, shape.dNdx.data(), shape.dNdx.size(),
                      this->eps);
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckClockwise)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;

    // clockwise node ordering, which is invalid)
    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    EXPECT_ANY_THROW(NaturalCoordsMappingType::computeShapeMatrices(
        *this->clockwiseEle, this->r, shape, this->global_dim));
}

TYPED_TEST(NumLibFemNaturalCoordinatesMappingTest, CheckZeroVolume)
{
    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
    using NaturalCoordsMappingType =
        typename TestFixture::NaturalCoordsMappingType;

    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);

    EXPECT_ANY_THROW(NaturalCoordsMappingType::computeShapeMatrices(
        *this->zeroVolumeEle, this->r, shape, this->global_dim));
}

TEST(NumLib, FemNaturalCoordinatesMappingLineY)
{
    using NodalVector = ::detail::EigenMatrixType<1, 2>::type;
    using DimNodalMatrix = ::detail::EigenMatrixType<1, 2>::type;
    using DimMatrix = ::detail::EigenMatrixType<1, 1>::type;
    using GlobalDimNodalMatrix = ::detail::EigenMatrixType<2, 2>::type;
    // Shape data type
    using ShapeMatricesType = ShapeMatrices<NodalVector, DimNodalMatrix,
                                            DimMatrix, GlobalDimNodalMatrix>;
    using MappingType =
        NaturalCoordinatesMapping<MeshLib::Line, ShapeLine2, ShapeMatricesType>;
    double r[] = {0.5};
    auto line = TestLine2::createY();
    static const unsigned dim = 1;
    static const unsigned e_nnodes = 2;
    ShapeMatricesType shape(dim, 2, e_nnodes);
    MappingType::computeShapeMatrices(*line, r, shape, 2);

    double exp_J[dim * dim] = {0.0};
    for (unsigned i = 0; i < dim; i++)
        exp_J[i + dim * i] = 1.0;

    const double eps(std::numeric_limits<double>::epsilon());
    ASSERT_ARRAY_NEAR(TestLine2::nat_exp_N, shape.N.data(), shape.N.size(),
                      eps);
    ASSERT_ARRAY_NEAR(TestLine2::nat_exp_dNdr, shape.dNdr.data(),
                      shape.dNdr.size(), eps);
    ASSERT_ARRAY_NEAR(exp_J, shape.J.data(), shape.J.size(), eps);
    ASSERT_ARRAY_NEAR(exp_J, shape.invJ.data(), shape.invJ.size(), eps);
    ASSERT_NEAR(1.0, shape.detJ, eps);
    double exp_dNdx[2 * e_nnodes] = {0, 0, -0.5, 0.5};
    ASSERT_ARRAY_NEAR(exp_dNdx, shape.dNdx.data(), shape.dNdx.size(), eps);

    for (auto n = 0u; n < line->getNumberOfNodes(); ++n)
        delete line->getNode(n);
    delete line;
}


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

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

TTS_CASE_TPL("Check eve::cyl_bessel_y behavior", EVE_TYPE)
{

  auto eve__cyl_bessel_y =  [](auto n, auto x) { return eve::cyl_bessel_y(n, x); };
  auto boost_cyl_bessel_y =  [](auto n, auto x) { return boost::math::cyl_neumann(n, x); };
  if constexpr( eve::platform::supports_invalids )
  {
    TTS_ULP_EQUAL(eve__cyl_bessel_y(T(2), eve::inf(eve::as<T>())), eve::zero(eve::as<T>()), 0);
    TTS_ULP_EQUAL(eve__cyl_bessel_y(T(3), eve::nan(eve::as<T>())), eve::nan(eve::as<T>()), 0);
  }

  for(int i=1; i < 2; i*= 2)
  {
    TTS_ULP_EQUAL(eve__cyl_bessel_y(T(i), T(10)), T(boost_cyl_bessel_y(i, 10)), 10);
    TTS_ULP_EQUAL(eve__cyl_bessel_y(T(i), T(5)), T(boost_cyl_bessel_y(i, 5)), 10);
    TTS_ULP_EQUAL(eve__cyl_bessel_y(T(i), T(2)), T(boost_cyl_bessel_y(i, 2)), 10);
    TTS_ULP_EQUAL(eve__cyl_bessel_y(T(i), T(1)), T(boost_cyl_bessel_y(i, 1)), 10);
  }
}


//=======================================================================
// Copyright (c) 2013 Piotr Wygocki
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
/**
 * @file n_queens_solution.hpp
 * @brief
 * @author Piotr Wygocki
 * @version 1.0
 * @date 2014-01-02
 */
#ifndef PAAL_N_QUEENS_SOLUTION_HPP
#define PAAL_N_QUEENS_SOLUTION_HPP

#include "paal/utils/irange.hpp"

#include <boost/iterator/counting_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/numeric.hpp>

#include <vector>

namespace paal {
namespace local_search {

/**
 * @brief Adapts vector representing n queen problem to class
 * able to efficiently compute gain of given move
 *
 * @tparam NQueensPositionsVector
 */
template <typename NQueensPositionsVector> struct n_queens_solution_adapter {
    typedef typename boost::counting_iterator<int> QueensIterator;

    /**
     * @brief constructor
     *
     * @param pos
     */
    n_queens_solution_adapter(NQueensPositionsVector &pos)
        : m_queen_position(pos),
          m_numeber_attacing_diagonal_negative(boost::distance(pos), 0),
          m_numeber_attacing_diagonal_nonnegative(boost::distance(pos), 0),
          m_numeber_attacing_counter_diagonal(2 * boost::distance(pos), 0) {
        for (auto q : irange(boost::distance(pos))) {
            increase(q);
        }
    }

    /**
     * @brief begin of the queens positions' collection
     *
     * @return
     */
    QueensIterator begin() const { return QueensIterator(0); }

    /**
     * @brief end of the queens positions' collection
     *
     * @return
     */
    QueensIterator end() const {
        return QueensIterator(m_queen_position.size());
    }

    /**
     * @brief swaps two queens positions
     *
     * @param xLeft
     * @param xRight
     */
    void swap_queens(int xLeft, int xRight) {
        int leftPosition = m_queen_position[xLeft];
        put_queen(xLeft, m_queen_position[xRight]);
        put_queen(xRight, leftPosition);
    }

    /**
     * @brief get number of queens attacing (x,y) position
     *
     * @param x
     * @param y
     *
     * @return
     */
    int get_num_attacing(int x, int y) const {
        return m_numeber_attacing_counter_diagonal[x + y] + get_diagonal(x, y);
    }

    /**
     * @brief return y for xth queen
     *
     * @param x
     *
     * @return
     */
    int get_y(int x) const { return m_queen_position[x]; }

    /**
     * @brief computes total number of conflicts on the board
     *
     * @return
     */
    int obj_fun() const {
        auto attacingNr = [](int sum, int n) { return sum + n * (n - 1) / 2; };
        int sum = boost::accumulate(m_numeber_attacing_counter_diagonal, 0,
                                    attacingNr);
        sum = boost::accumulate(m_numeber_attacing_diagonal_negative, sum,
                                attacingNr);
        return boost::accumulate(m_numeber_attacing_diagonal_nonnegative, sum,
                                 attacingNr);
    }

  private:

    /**
     * @brief puts xth queen on position y
     *
     * @param x
     * @param y
     */
    void put_queen(int x, int y) {
        decrease(x);
        m_queen_position[x] = y;
        increase(x);
    }

    /**
     * @brief get diagonal counter for diagonal of the xth queen
     *
     * @param x
     *
     * @return
     */
    int &get_diagonal(int x) { return get_diagonal(x, m_queen_position[x]); }

    /**
     * @brief gets diagonal crossing (x,y) position
     *
     * @param x
     * @param y
     *
     * @return
     */
    int &get_diagonal(int x, int y) {
        if (x >= y) {
            return m_numeber_attacing_diagonal_negative[x - y];
        } else {
            return m_numeber_attacing_diagonal_nonnegative[y - x];
        }
    }

    /**
     * @brief const version of get_diagonal(x,y)
     *
     * @param x
     * @param y
     *
     * @return
     */
    int get_diagonal(int x, int y) const {
        if (x >= y) {
            return m_numeber_attacing_diagonal_negative[x - y];
        } else {
            return m_numeber_attacing_diagonal_nonnegative[y - x];
        }
    }

    /**
     * @brief decrease diagonals counters fo xth queen
     *
     * @param x
     */
    void decrease(int x) {
        --m_numeber_attacing_counter_diagonal[x + m_queen_position[x]];
        --get_diagonal(x);
    }

    /**
     * @brief decrese diagonal counter for the xth queen
     *
     * @param x
     */
    void increase(int x) {
        ++m_numeber_attacing_counter_diagonal[x + m_queen_position[x]];
        ++get_diagonal(x);
    }

    NQueensPositionsVector &m_queen_position;
    std::vector<int> m_numeber_attacing_diagonal_negative;
    std::vector<int> m_numeber_attacing_diagonal_nonnegative;
    std::vector<int> m_numeber_attacing_counter_diagonal;
};

} //!local_search
} //!paal

#endif // PAAL_N_QUEENS_SOLUTION_HPP


#include <metaSMT/backend/Boolector.hpp>
#include <metaSMT/DirectSolver_Context.hpp>
#include <metaSMT/frontend/QF_BV.hpp>

#include <boost/timer.hpp>
#include <iostream>

static unsigned width = 32;

static const unsigned repeat= 10;
static const unsigned limit = 10000;

static unsigned data[limit];

static unsigned all_valids = 0;

int run_metaSMT () {
  using namespace metaSMT;
  using namespace metaSMT::logic;
  using namespace metaSMT::logic::QF_BV;

  metaSMT::DirectSolver_Context<metaSMT::solver::Boolector> ctx;

  bitvector a = new_bitvector(width);
  bitvector b = new_bitvector(width);
  bitvector c = new_bitvector(2*width);

  bitvector zero = new_bitvector(width);
  assertion( ctx, equal(zero, bvuint(0,width)) );
  assertion( ctx, nequal(a, bvuint(1,width)) );
  assertion( ctx, nequal(b, bvuint(1,width)) );

  assertion( ctx, equal(c, bvmul( concat(zero, a), concat(zero,b)) ));

  int valids = 0;
  for (unsigned i = 0; i < limit; ++i) {
    assumption( ctx, equal(c, bvuint(data[i], 2*width)) );

    if( solve( ctx) ) {
      valids++;
    }
  }

  return valids;
}

int run_btor () {

  Btor* btor = boolector_new();
  boolector_enable_inc_usage(btor);
  boolector_enable_model_gen(btor);

  BtorNode* a = boolector_var(btor, width, "a");
  BtorNode* b = boolector_var(btor, width, "b");
  BtorNode* c = boolector_var(btor, 2*width, "c");

  BtorNode* zero = boolector_var(btor,width, "zero");
  boolector_assert( btor, boolector_eq(btor, zero, boolector_zero(btor, width)) );
  boolector_assert( btor, boolector_ne(btor, a, boolector_unsigned_int(btor, 1, width)) );
  boolector_assert( btor, boolector_ne(btor, b, boolector_unsigned_int(btor, 1, width)) );

  boolector_assert( btor, boolector_eq(btor,
        c, boolector_mul(btor,
          boolector_concat(btor, zero, a),
          boolector_concat(btor, zero, b))
        ));

  int valids = 0;
  for (unsigned i = 0; i < limit; ++i) {
    boolector_assume( btor, boolector_eq(btor, c,
          boolector_unsigned_int(btor, data[i], 2*width)) );

    if( boolector_sat( btor ) == BOOLECTOR_SAT ) {
      valids++;
    }
  }

  boolector_delete(btor);
  return valids;
}

double run(
      int (fun) ()
  )
{
  boost::timer timer;
  timer.restart();
  for (unsigned i = 0; i < repeat; ++i) {
    all_valids += fun();
  }
  return timer.elapsed();
}

void result( std::string const & name, double time) {
  std::cout << name << " ran " << (limit*repeat) << " in "
    << time << "s"
    << " (" << limit << " in " << (time/repeat) <<"s"
    << ", 1 in " << (time/repeat/limit) <<"s"
    << ")"
    << std::endl;
}

int main(int argc, const char *argv[])
{
  if(argc != 2) {
    std::cout << "usage: " << argv[0] << " <magic number> # even = boolector;metaSMT, odd = metaSMT;boolector " << std::endl;
    exit(1);
  }

  time_t seed = time(0);
  srand(seed);
  std::cout << "seed: " << seed << std::endl;

  std::vector<unsigned> data (limit);
  for (unsigned i = 0; i < limit; ++i) {
    data[i] = (unsigned long long)rand()%(1ull<<(width+1));
  }

  double mtime=0.0;
  double btime=0.0;

  if ( atoi(argv[1]) & 1u) {

  std::cout << "Running metaSMT" << std::endl;
  mtime = run(run_metaSMT);

  std::cout << "Running Boolector" << std::endl;
  btime = run( run_btor);
  } else {

  std::cout << "Running Boolector" << std::endl;
  btime += run( run_btor);

  std::cout << "Running metaSMT" << std::endl;
  mtime += run(run_metaSMT);

  }

  result( "metaSMT", mtime);
  result( "boolector", btime);

  return  mtime + btime + all_valids == 0;
}


/* Copyright (C) 2019-2020 IBM Corp.
 * This program is 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. See accompanying LICENSE file.
 */
#include <NTL/ZZ.h>
#include <algorithm>
#include <complex>

#include <helib/norms.h>
#include <helib/helib.h>
#include <helib/debugging.h>

#include "gtest/gtest.h"
#include "test_common.h"

namespace {
struct Parameters
{
  Parameters(long m, long r, long L, double epsilon) :
      m(m), r(r), L(L), epsilon(epsilon){};

  const long m;
  const long r;
  const long L;
  const double epsilon;

  friend std::ostream& operator<<(std::ostream& os, const Parameters& params)
  {
    return os << "{"
              << "m=" << params.m << ","
              << "r=" << params.r << ","
              << "L=" << params.L << ","
              << "epsilon=" << params.epsilon << "}";
  }
};

// Utility functions for the tests

// Compute the L-infinity distance between two vectors
double calcMaxDiff(const std::vector<std::complex<double>>& v1,
                   const std::vector<std::complex<double>>& v2)
{
  if (helib::lsize(v1) != helib::lsize(v2)) {
    throw std::runtime_error("Vector sizes differ.");
  }

  double maxDiff = 0.0;
  for (long i = 0; i < helib::lsize(v1); i++) {
    double diffAbs = std::abs(v1[i] - v2[i]);
    if (diffAbs > maxDiff)
      maxDiff = diffAbs;
  }
  return maxDiff;
}
// Compute the max relative difference between two vectors
double calcMaxRelDiff(const std::vector<std::complex<double>>& v1,
                      const std::vector<std::complex<double>>& v2)
{
  if (helib::lsize(v1) != helib::lsize(v2)) {
    throw std::runtime_error("Vector sizes differ.");
  }

  // Compute the largest-magnitude value in the vector
  double maxAbs = 0.0;
  for (auto& x : v1) {
    if (std::abs(x) > maxAbs)
      maxAbs = std::abs(x);
  }
  if (maxAbs < 1e-10)
    maxAbs = 1e-10;

  double maxDiff = 0.0;
  for (long i = 0; i < helib::lsize(v1); i++) {
    double relDiff = std::abs(v1[i] - v2[i]) / maxAbs;
    if (relDiff > maxDiff)
      maxDiff = relDiff;
  }

  return maxDiff;
}

inline bool cx_equals(const std::vector<std::complex<double>>& v1,
                      const std::vector<std::complex<double>>& v2,
                      double epsilon)
{
  return (calcMaxDiff(v1, v2) < epsilon);
}

void negateVec(std::vector<std::complex<double>>& p1)
{
  for (auto& x : p1)
    x = -x;
}
void conjVec(std::vector<std::complex<double>>& p1)
{
  for (auto& x : p1)
    x = conj(x);
}
void add(std::vector<std::complex<double>>& to,
         const std::vector<std::complex<double>>& from)
{
  if (to.size() < from.size())
    to.resize(from.size(), 0);
  for (std::size_t i = 0; i < from.size(); i++)
    to[i] += from[i];
}
void add(std::vector<std::complex<double>>& to, double from)
{
  for (std::size_t i = 0; i < to.size(); i++)
    to[i] += from;
}
void sub(std::vector<std::complex<double>>& to,
         const std::vector<std::complex<double>>& from)
{
  if (to.size() < from.size())
    to.resize(from.size(), 0);
  for (std::size_t i = 0; i < from.size(); i++)
    to[i] -= from[i];
}
void mul(std::vector<std::complex<double>>& to,
         const std::vector<std::complex<double>>& from)
{
  if (to.size() < from.size())
    to.resize(from.size(), 0);
  for (std::size_t i = 0; i < from.size(); i++)
    to[i] *= from[i];
}
void mul(std::vector<std::complex<double>>& to, double from)
{
  for (std::size_t i = 0; i < to.size(); i++)
    to[i] *= from;
}
void rotate(std::vector<std::complex<double>>& p, long amt)
{
  long sz = p.size();
  std::vector<std::complex<double>> tmp(sz);
  for (long i = 0; i < sz; i++)
    tmp[((i + amt) % sz + sz) % sz] = p[i];
  p = tmp;
}

class TestCKKS : public ::testing::TestWithParam<Parameters>
{
protected:
  const long m;         // Zm*
  const long r;         // bit precision
  const long L;         // Number of bits
  const double epsilon; // error threshold

  helib::Context context;
  helib::SecKey secretKey;
  const helib::PubKey publicKey;
  const helib::EncryptedArrayCx& ea;

  TestCKKS() :
      m(GetParam().m),
      r(GetParam().r),
      L(GetParam().L),
      epsilon(GetParam().epsilon),
      context(m, /*p=*/-1, r),
      secretKey((context.scale = 4,
                 helib::buildModChain(context, L, /*c=*/2),
                 context)),
      publicKey((secretKey.GenSecKey(),
                 helib::addSome1DMatrices(secretKey),
                 secretKey)),
      ea(context.ea->getCx())
  {}

  virtual void SetUp() override
  {
    if (helib_test::verbose) {
      ea.getPAlgebra().printout();
      std::cout << "r = " << context.alMod.getR() << std::endl;
      std::cout << "ctxtPrimes=" << context.ctxtPrimes
                << ", specialPrimes=" << context.specialPrimes << std::endl
                << std::endl;
    }

    helib::setupDebugGlobals(&secretKey, context.ea);
  }

  virtual void TearDown() override { helib::cleanupDebugGlobals(); }
};

TEST_P(TestCKKS, negatingCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2;
  NTL::ZZX poly;
  NTL::xdouble rf, pm;

  ea.random(vd1);
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  ea.encode(poly, vd1, /*size=*/1.0);
  c1.negate();
  ea.decrypt(c1, secretKey, vd2);

  negateVec(vd1);

  EXPECT_TRUE(cx_equals(vd2, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd2)=" << helib::largestCoeff(vd2)
      << ", maxDiff=" << calcMaxDiff(vd1, vd2) << std::endl
      << std::endl;
  EXPECT_EQ(rf, c1.getRatFactor());
  EXPECT_EQ(pm, c1.getPtxtMag());
}

TEST_P(TestCKKS, addingPolyConstantToCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;
  NTL::ZZX poly;
  NTL::xdouble rf, pm;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  ea.encode(poly, vd2, /*size=*/1.0);
  c1.addConstantCKKS(poly);
  ea.decrypt(c1, secretKey, vd3);

  add(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3)
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
}

TEST_P(TestCKKS, addingNegatedPolyConstantToCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;
  NTL::ZZX poly;
  NTL::xdouble rf, pm;

  ea.random(vd1);
  ea.random(vd2);
  negateVec(vd2);
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  ea.encode(poly, vd2, /*size=*/1.0);
  c1.addConstantCKKS(poly);
  ea.decrypt(c1, secretKey, vd3);

  add(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3) << std::endl
      << ", maxDiff=" << calcMaxDiff(vd1, vd3)
      << ", maxRelDiff=" << calcMaxRelDiff(vd1, vd3) << std::endl
      << std::endl;
}

TEST_P(TestCKKS, multiplyingPolyConstantToCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;
  NTL::ZZX poly;
  NTL::xdouble rf, pm;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  ea.encode(poly, vd2, /*size=*/1.0);
  c1.multByConstantCKKS(poly);
  ea.decrypt(c1, secretKey, vd3);

  mul(vd1, vd2);
  rf *= ea.encodeScalingFactor();

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3)
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
  EXPECT_EQ(rf, c1.getRatFactor());
  EXPECT_EQ(pm, c1.getPtxtMag());
}

TEST_P(TestCKKS, addingDoubleToCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2;
  NTL::xdouble rf, pm;
  std::vector<double> vd(1);
  ea.random(vd);

  ea.random(vd1);
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  c1.addConstantCKKS(vd[0]);
  ea.decrypt(c1, secretKey, vd2);

  add(vd1, vd[0]);

  EXPECT_TRUE(cx_equals(vd2, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd2)=" << helib::largestCoeff(vd2)
      << ", maxDiff=" << calcMaxDiff(vd1, vd2) << std::endl
      << std::endl;
}

TEST_P(TestCKKS, multiplyingDoubleToCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd0;
  NTL::xdouble rf, pm;
  std::vector<double> vd(1);
  ea.random(vd);

  ea.random(vd1);
  vd0 = vd1;
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  c1.multByConstantCKKS(vd[0]);
  ea.decrypt(c1, secretKey, vd2);

  mul(vd1, vd[0]);
  rf /= std::abs(vd[0]);
  pm *= std::abs(vd[0]);

  EXPECT_TRUE(cx_equals(vd2, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd2)=" << helib::largestCoeff(vd2)
      << ", maxDiff=" << calcMaxDiff(vd1, vd2) << std::endl
      << ", ptxtMag=" << c1.getPtxtMag() << std::endl
      << ", vd[0]=" << vd[0] << std::endl;
  EXPECT_EQ(rf, c1.getRatFactor());
  EXPECT_EQ(pm, c1.getPtxtMag());
}

TEST_P(TestCKKS, gettingTheComplexConjugateWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2;
  NTL::xdouble rf, pm;
  NTL::ZZX poly;

  ea.random(vd1);
  ea.encrypt(c1, publicKey, vd1);
  rf = c1.getRatFactor();
  pm = c1.getPtxtMag();
  ea.encode(poly, vd1, /*size=*/1.0);
  c1.complexConj();
  ea.decrypt(c1, secretKey, vd2);

  conjVec(vd1);

  EXPECT_TRUE(cx_equals(vd2, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd2)=" << helib::largestCoeff(vd2)
      << ", maxDiff=" << calcMaxDiff(vd1, vd2) << std::endl
      << std::endl;
  EXPECT_EQ(rf, c1.getRatFactor());
  EXPECT_EQ(pm, c1.getPtxtMag());
}

TEST_P(TestCKKS, rotatingCiphertextWorks)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1, vd2;
  NTL::xdouble rf, pm;
  NTL::ZZX poly;

  ea.random(vd1);
  ea.encrypt(c1, publicKey, vd1);
  pm = c1.getPtxtMag();
  ea.encode(poly, vd1, /*size=*/1.0);
  ea.rotate(c1, 3);
  ea.decrypt(c1, secretKey, vd2);
  // TODO: understand how this affects ratfactor and add appropriate expectation
  rotate(vd1, 3);
  // vd1 is now the expected result

  EXPECT_TRUE(cx_equals(vd2, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd2)=" << helib::largestCoeff(vd2)
      << ", maxDiff=" << calcMaxDiff(vd1, vd2) << std::endl
      << std::endl;
  EXPECT_EQ(pm, c1.getPtxtMag());
}

TEST_P(TestCKKS, addingCiphertextsWorks)
{
  helib::Ctxt c1(publicKey), c2(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  ea.encrypt(c2, publicKey, vd2);
  c1 += c2;
  ea.decrypt(c1, secretKey, vd3);

  add(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3)
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
}

TEST_P(TestCKKS, subtractingCiphertextsWorks)
{
  helib::Ctxt c1(publicKey), c2(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  ea.encrypt(c2, publicKey, vd2);
  c1 -= c2;
  ea.decrypt(c1, secretKey, vd3);

  sub(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3)
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
}

TEST_P(TestCKKS, rawMultiplicationOfCiphertextsWorks)
{
  helib::Ctxt c1(publicKey), c2(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  ea.encrypt(c2, publicKey, vd2);
  NTL::xdouble expectedPtxtMag = c1.getPtxtMag() * c2.getPtxtMag();
  c1 *= c2;
  ea.decrypt(c1, secretKey, vd3);

  mul(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3)
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
  EXPECT_EQ(expectedPtxtMag, c1.getPtxtMag());
}

TEST_P(TestCKKS, highLevelMultiplicationOfCiphertextsWorks)
{
  helib::Ctxt c1(publicKey), c2(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  ea.encrypt(c2, publicKey, vd2);
  NTL::xdouble expectedPtxtMag = c1.getPtxtMag() * c2.getPtxtMag();
  c1.multiplyBy(c2);
  ea.decrypt(c1, secretKey, vd3);

  mul(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, NTL::conv<double>(epsilon)))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3)
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
  EXPECT_EQ(expectedPtxtMag, c1.getPtxtMag());
}

TEST_P(
    TestCKKS,
    multiplyingCiphertextByNegativeConstantAndThenAddingToOtherCiphertextWorks)
{
  helib::Ctxt c1(publicKey), c2(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3, vd4;
  NTL::ZZX poly;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  ea.encrypt(c2, publicKey, vd2);
  c1.multByConstantCKKS(std::make_pair<long, long>(-5, 2));
  c1 += c2;
  ea.decrypt(c1, secretKey, vd4);

  mul(vd1, std::vector<std::complex<double>>(ea.size(), -5 / 2.0));
  add(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd4, vd1, epsilon))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd4)=" << helib::largestCoeff(vd4) << std::endl
      << ", maxDiff=" << calcMaxDiff(vd1, vd4) << std::endl
      << std::endl;
}

TEST_P(TestCKKS, multiplyingByConstantNeverProducesNegativeRatFactor)
{
  helib::Ctxt c1(publicKey);
  std::vector<std::complex<double>> vd1;

  ea.random(vd1);
  ea.encrypt(c1, publicKey, vd1);
  c1.multByConstantCKKS(-2.0);

  EXPECT_GT(c1.getRatFactor(), 0);
}

TEST_P(TestCKKS, multiplyBySmallNegativeConstantFollowedByOperationWorks)
{
  helib::Ctxt c1(publicKey), c2(publicKey);
  std::vector<std::complex<double>> vd1, vd2, vd3;

  ea.random(vd1);
  ea.random(vd2);
  ea.encrypt(c1, publicKey, vd1);
  ea.encrypt(c2, publicKey, vd2);
  c1.multByConstantCKKS(-2.0 / 10.0);
  c1 -= c2;
  ea.decrypt(c1, secretKey, vd3);

  mul(vd1, -2.0 / 10.0);
  sub(vd1, vd2);

  EXPECT_TRUE(cx_equals(vd3, vd1, epsilon))
      << "  max(vd1)=" << helib::largestCoeff(vd1)
      << ", max(vd3)=" << helib::largestCoeff(vd3) << std::endl
      << ", maxDiff=" << calcMaxDiff(vd1, vd3) << std::endl
      << std::endl;
}

TEST(TestCKKS, buildingCKKSContextWithMAsNotAPowerOfTwoThrows)
{
  EXPECT_THROW(helib::Context context(99, -1, 20), helib::InvalidArgument);
}

INSTANTIATE_TEST_SUITE_P(typicalParameters,
                         TestCKKS,
                         ::testing::Values(
                             // SLOW
                             Parameters(1024, 20, 150, 0.01)
                             // FAST
                             // Parameters(128, 20, 150, 0.01)
                             ));

} // namespace


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

  @copyright 2016 NumScale SAS

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

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

 /*!

    @ingroup group-arithmetic
    Function object implementing itrunc capabilities

    Convert to integer by saturated truncation.

    This is a convenience alias of @ref saturated_(toint)
  **/
  Value itrunc(Value const & v0);
} }
#endif

#include <boost/simd/function/scalar/itrunc.hpp>
#include <boost/simd/function/simd/ifix.hpp>

#endif


//==================================================================================================
/*!

  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/constant/eps.hpp>
#include <boost/simd/as.hpp>
#include <scalar_test.hpp>

STF_CASE_TPL( "Check eps behavior for integral types"
            , (std::uint8_t)(std::uint16_t)(std::uint32_t)(std::uint64_t)
              (std::int8_t)(std::int16_t)(std::int32_t)(std::int64_t)
            )
{
  using boost::simd::as;
  using boost::simd::detail::eps;
  using boost::simd::Eps;

  STF_TYPE_IS(decltype(Eps<T>()), T);
  STF_EQUAL(Eps<T>(), T(1));
  STF_EQUAL(eps( as(T{}) ),T(1));
}

STF_CASE_TPL( "Check eps behavior for double type"
            , (double)
            )
{
  using boost::simd::as;
  using boost::simd::detail::eps;
  using boost::simd::Eps;

  STF_TYPE_IS(decltype(Eps<T>()), T);
  STF_IEEE_EQUAL(Eps<T>(), 2.220446049250313e-16);
  STF_IEEE_EQUAL(eps( as(T{}) ), 2.220446049250313e-16);
}
STF_CASE_TPL( "Check eps behavior for float type"
            , (float)
            )
{
  using boost::simd::as;
  using boost::simd::detail::eps;
  using boost::simd::Eps;

  STF_TYPE_IS(decltype(Eps<T>()), T);
  STF_IEEE_EQUAL(Eps<T>(),   T(1.192092895507843e-07));
  STF_IEEE_EQUAL(eps( as(T{}) ),   T(1.192092895507813e-07));
}


#ifndef STAN_MATH_PRIM_SCAL_PROB_VON_MISES_RNG_HPP
#define STAN_MATH_PRIM_SCAL_PROB_VON_MISES_RNG_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_finite.hpp>
#include <stan/math/prim/scal/err/check_greater.hpp>
#include <stan/math/prim/scal/err/check_nonnegative.hpp>
#include <stan/math/prim/scal/err/check_positive_finite.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/variate_generator.hpp>

namespace stan {
namespace math {

/** \ingroup prob_dists
 * Return a von Mises random variate for the given location and concentration
 * using the specified random number generator.
 *
 * mu and kappa can each be a scalar or a vector. Any non-scalar
 * inputs must be the same length.
 *
 * The algorithm used in von_mises_rng is a modified version of the
 * algorithm in:
 *
 * Efficient Simulation of the von Mises Distribution
 * D. J. Best and N. I. Fisher
 * Journal of the Royal Statistical Society. Series C (Applied Statistics),
 * Vol. 28, No. 2 (1979), pp. 152-157
 *
 * See licenses/stan-license.txt for Stan license.
 *
 * @tparam T_loc Type of location parameter
 * @tparam T_conc Type of concentration parameter
 * @tparam RNG type of random number generator
 * @param mu (Sequence of) location parameter(s)
 * @param kappa (Sequence of) positive concentration parameter(s)
 * @param rng random number generator
 * @return (Sequence of) von Mises random variate(s)
 * @throw std::domain_error if mu is infinite or kappa is nonpositive
 * @throw std::invalid_argument if non-scalar arguments are of different
 * sizes
 */
template <typename T_loc, typename T_conc, class RNG>
inline typename VectorBuilder<true, double, T_loc, T_conc>::type von_mises_rng(
    const T_loc& mu, const T_conc& kappa, RNG& rng) {
  using boost::random::uniform_real_distribution;
  using boost::variate_generator;
  static const char* function = "von_mises_rng";

  check_finite(function, "mean", mu);
  check_positive_finite(function, "inverse of variance", kappa);
  check_consistent_sizes(function, "Location parameter", mu,
                         "Concentration Parameter", kappa);

  scalar_seq_view<T_loc> mu_vec(mu);
  scalar_seq_view<T_conc> kappa_vec(kappa);
  size_t N = max_size(mu, kappa);
  VectorBuilder<true, double, T_loc, T_conc> output(N);

  variate_generator<RNG&, uniform_real_distribution<> > uniform_rng(
      rng, uniform_real_distribution<>(0.0, 1.0));

  for (size_t n = 0; n < N; ++n) {
    double r = 1 + std::pow((1 + 4 * kappa_vec[n] * kappa_vec[n]), 0.5);
    double rho = 0.5 * (r - std::pow(2 * r, 0.5)) / kappa_vec[n];
    double s = 0.5 * (1 + rho * rho) / rho;

    bool done = false;
    double W;
    while (!done) {
      double Z = std::cos(pi() * uniform_rng());
      W = (1 + s * Z) / (s + Z);
      double Y = kappa_vec[n] * (s - W);
      double U2 = uniform_rng();
      done = Y * (2 - Y) - U2 > 0;

      if (!done) {
        done = std::log(Y / U2) + 1 - Y >= 0;
      }
    }

    double U3 = uniform_rng() - 0.5;
    double sign = ((U3 >= 0) - (U3 <= 0));

    //  it's really an fmod() with a positivity constraint
    output[n]
        = sign * std::acos(W)
          + std::fmod(std::fmod(mu_vec[n], 2 * pi()) + 2 * stan::math::pi(),
                      2 * pi());
  }

  return output.data();
}

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


#ifndef Interpolators__2D_InterpolatorBase_hpp
#define Interpolators__2D_InterpolatorBase_hpp

/** @file InterpolatorBase.hpp
  * @author C.D. Clark III
  * @date 12/24/16
  */

#include <memory>
#include <vector>
#include <Eigen/Dense>

namespace _2D {

template<typename T>
struct RealTypeOf { using type = double; };
template<template<typename> class T,typename R>
struct RealTypeOf<T<R>> { using type = R; };

/** @class
  * @brief A base class for 2D interpolators that provides default implementations of the interface.
  * @author C.D. Clark III
  *
  * This class provides an implementation for the setData method as well as adding a few additional
  * useful methods, including derivative and integral methods.
  */
template<class Derived, typename Real = typename RealTypeOf<Derived>::type>
class InterpolatorBase
{
  public:
    using VectorType = Eigen::Matrix<Real,Eigen::Dynamic,1>;
    using MapType = Eigen::Map<const VectorType>;
    // types used to view data as 2D coordinates
    using MatrixType = typename Eigen::Matrix<Real,Eigen::Dynamic,Eigen::Dynamic>;
    using _2DVectorView = Eigen::Map<const VectorType,Eigen::Unaligned,Eigen::InnerStride<Eigen::Dynamic>>;
    using _2DMatrixView = Eigen::Map<const MatrixType,Eigen::Unaligned,Eigen::Stride<Eigen::Dynamic,Eigen::Dynamic>>;

  protected:

    std::vector<Real> xData, yData, zData;        // data storage
    std::unique_ptr<MapType> xView, yView, zView; // map view of the data

    // these maps are used to view the x,y,z data as two coordinate vectors and a function matrix, instead of three vectors.
    std::unique_ptr<_2DVectorView> X,Y;
    std::unique_ptr<_2DMatrixView> Z;

  private:
    // making constructors private and the derived class a friend
    // helps to make sure that the derived class actually
    // passes itself as the template argument.
    friend Derived;

    InterpolatorBase(){ }

    InterpolatorBase( const InterpolatorBase& rhs )
    :xData(rhs.xData)
    ,yData(rhs.yData)
    ,zData(rhs.zData)
    ,xView( rhs.xView ? new MapType( xData.data(), xData.size() ) : nullptr )
    ,yView( rhs.xView ? new MapType( yData.data(), yData.size() ) : nullptr )
    ,zView( rhs.zView ? new MapType( zData.data(), zData.size() ) : nullptr )
    {
      this->setup2DDataViews();
    }

    // we use the copy-swap idiom for copy assignment
    friend void swap( InterpolatorBase& lhs, InterpolatorBase& rhs)
    {
      std::swap( lhs.xData, rhs.xData );
      std::swap( lhs.yData, rhs.yData );
      std::swap( lhs.zData, rhs.zData );
      std::swap( lhs.xView, rhs.xView );
      std::swap( lhs.yView, rhs.yView );
      std::swap( lhs.zView, rhs.zView );
      std::swap( lhs.X, rhs.X);
      std::swap( lhs.Y, rhs.Y);
      std::swap( lhs.Z, rhs.Z);
    }

    InterpolatorBase& operator=(InterpolatorBase rhs)
    {
      swap(*this,rhs);
      return *this;
    }

  public:

    std::vector<Real> getXData() const { return xData; }
    std::vector<Real> getYData() const { return yData; }
    std::vector<Real> getZData() const { return zData; }

    template<typename I>
    void setData( I n, const Real *x, const Real *y, const Real *z);

    // this template is ambiguous with the pointer template above,
    // wo we want to disable it for pointers
    template<typename XT, typename YT, typename ZT>
    typename std::enable_if<!std::is_pointer<YT>::value>::type
    setData( const XT &x, const YT &y, const ZT &z );

  protected:
    void checkData() const; ///< Check that data has been initialized and throw exception if not.
    void setup2DDataViews(); ///< Setups up 2D views of 1D data arrays

  private:
    // callSetupInterpolator will call a function named setupInterpolator in the derived class, if
    // it exists. this is just some template magic to detect if the derived class has implemented a
    // setupInterpolator function, and to call it if it does.

    template<typename T>
    struct has_setupInterpolator
    {
      private:
        typedef std::true_type yes;
        typedef std::false_type no;

        template<typename U> static auto test(int) -> decltype(std::declval<U>().setupInterpolator(),yes());
        template<typename  > static no   test(...);

      public:
        static constexpr bool value = std::is_same<decltype(test<T>(0)),yes>::value;
    };

    template<typename T>
    typename std::enable_if<has_setupInterpolator<T>::value>::type
    callSetupInterpolator(){ static_cast<Derived*>(this)->setupInterpolator(); }

    template<typename T>
    typename std::enable_if<!has_setupInterpolator<T>::value>::type
    callSetupInterpolator(){ }

};

template<class Derived, typename Real>
void
InterpolatorBase<Derived,Real>::checkData() const
{
  if(!this->xView || !this->yView || !this->zView)
    throw std::logic_error("Interpolator data is not initialized. Did you call setData()?");
  if(this->xView->size() == 0 || this->yView->size() == 0 || this->zView->size() == 0)
    throw std::logic_error("Interpolator data is zero size. Did you call setData() with non-zero sized vectors?");
}

template<class Derived, typename Real>
void
InterpolatorBase<Derived,Real>::setup2DDataViews()
{
  // make sure data has actually been initialized
  if( !xView || !yView || !zView )
    return;

  // setup 2D view of the data
  // We need to figure out what the x and y dimensions are.
  int N = zView->size();
  int Nx = 0, Ny = 0;
  // Ny will be the number of elements that have the same x coordinate
  Real xlast = (*xView)(0);
  while( Ny < N-1 && fabs((*xView)(Ny)-xlast) < 1e-40 )
    Ny++;
  Nx = N/Ny;

  // consecutive values in the x data are separated by Ny, so this is the inner stride for X
  X.reset( new _2DVectorView( xView->data(), Nx, Eigen::InnerStride<Eigen::Dynamic>(Ny) ) );

  // consecutive values in the y data are next to each other, so the stride is just 1
  Y.reset( new _2DVectorView( yView->data(), Ny, Eigen::InnerStride<Eigen::Dynamic>(1) ) );

  // Eigen defaults to COLUMN MAJOR
  // consecutive elements in a column are separated by Ny (this is the inner stride)
  // consecutive elements in a row are located next to each other (this is the outer stride)
  // Stride object takes outer,inner as arguments.
  Z.reset( new _2DMatrixView( zView->data(), Nx, Ny, Eigen::Stride<Eigen::Dynamic,Eigen::Dynamic>(1,Ny) ) );
}

/**
 * Reads data from x, y, and z arrays. Arrays should all be the same length with each element corresponding to a data point.
 * Basically, x[i], y[i], and z[i] should correspond to the first, second, and third columns of a gnuplot file.
 */
template<class Derived, typename Real>
template<typename I>
void
InterpolatorBase<Derived,Real>::setData( I n, const Real *x, const Real *y, const Real *z )
{
  xData.clear();
  yData.clear();
  zData.clear();
  std::copy( x, x+n, std::back_inserter(xData) );
  std::copy( y, y+n, std::back_inserter(yData) );
  std::copy( z, z+n, std::back_inserter(zData) );

  this->xView.reset( new MapType( xData.data(), n ) );
  this->yView.reset( new MapType( yData.data(), n ) );
  this->zView.reset( new MapType( zData.data(), n ) );

  this->setup2DDataViews();
  this->callSetupInterpolator<Derived>();
}

template<class Derived, typename Real>
template<typename XT, typename YT, typename ZT>
typename std::enable_if<!std::is_pointer<YT>::value>::type
InterpolatorBase<Derived,Real>::setData( const XT &x, const YT &y, const ZT &z )
{
  this->setData( x.size(), x.data(), y.data(), z.data() );
}

}

#endif // include protector


#include <boost/test/unit_test.hpp>

#include <boost/atomic.hpp>

#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>

#include <ctime>

#include "ringsig.h"
#include "chainparams.h"

using namespace boost::chrono;

// test_yes --log_level=all  --run_test=ringsig_tests

clock_t totalGenerate;
clock_t totalVerify;
clock_t start, stop;

void testRingSigs(int nRingSize)
{
    uint8_t *pPubkeys = (uint8_t*) malloc(sizeof(uint8_t) * EC_COMPRESSED_SIZE * nRingSize);
    uint8_t *pSigc    = (uint8_t*) malloc(sizeof(uint8_t) *     EC_SECRET_SIZE * nRingSize);
    uint8_t *pSigr    = (uint8_t*) malloc(sizeof(uint8_t) *     EC_SECRET_SIZE * nRingSize);

    BOOST_REQUIRE(NULL != pPubkeys);
    BOOST_REQUIRE(NULL != pSigc);
    BOOST_REQUIRE(NULL != pSigr);

    CKey key[nRingSize];
    for (int i = 0; i < nRingSize; ++i)
    {
        key[i].MakeNewKey(true);

        CPubKey pk = key[i].GetPubKey();

        memcpy(&pPubkeys[i * EC_COMPRESSED_SIZE], pk.begin(), EC_COMPRESSED_SIZE);
    };

    uint256 preimage;
    BOOST_CHECK(1 == RAND_bytes((uint8_t*) preimage.begin(), 32));
    //BOOST_MESSAGE("Txn preimage: " << HexStr(preimage));

    //BOOST_MESSAGE("nRingSize: " << nRingSize);
    int iSender = GetRandInt(nRingSize);
    //BOOST_MESSAGE("sender: " << iSender);

    ec_secret sSpend;
    ec_point pkSpend;
    ec_point keyImage;

    memcpy(&sSpend.e[0], key[iSender].begin(), EC_SECRET_SIZE);

    BOOST_REQUIRE(0 == SecretToPublicKey(sSpend, pkSpend));

    BOOST_REQUIRE(0 == generateKeyImage(pkSpend, sSpend, keyImage));

    start = clock();
    BOOST_REQUIRE(0 == generateRingSignature(keyImage, preimage, nRingSize, iSender, sSpend, pPubkeys, pSigc, pSigr));
    stop = clock();
    totalGenerate += stop - start;

    start = clock();
    BOOST_REQUIRE(0 == verifyRingSignature(keyImage, preimage, nRingSize, pPubkeys, pSigc, pSigr));
    stop = clock();
    totalVerify += stop - start;

    int sigSize = EC_COMPRESSED_SIZE + EC_SECRET_SIZE + (EC_SECRET_SIZE + EC_SECRET_SIZE + EC_COMPRESSED_SIZE) * nRingSize;

    BOOST_MESSAGE("nRingSize " << nRingSize << ", sigSize: " << bytesReadable(sigSize));

    if (pPubkeys)
        free(pPubkeys);
    if (pSigc)
        free(pSigc);
    if (pSigr)
        free(pSigr);
};

void testRingSigABs(int nRingSize)
{
    uint8_t *pPubkeys = (uint8_t*) malloc(sizeof(uint8_t) * EC_COMPRESSED_SIZE * nRingSize);
    uint8_t *pSigS    = (uint8_t*) malloc(sizeof(uint8_t) *     EC_SECRET_SIZE * nRingSize);

    BOOST_CHECK(NULL != pPubkeys);
    BOOST_CHECK(NULL != pSigS);

    CKey key[nRingSize];
    for (int i = 0; i < nRingSize; ++i)
    {
        key[i].MakeNewKey(true);

        CPubKey pk = key[i].GetPubKey();

        memcpy(&pPubkeys[i * EC_COMPRESSED_SIZE], pk.begin(), EC_COMPRESSED_SIZE);
    };

    uint256 preimage;
    BOOST_CHECK(1 == RAND_bytes((uint8_t*) preimage.begin(), 32));
    //BOOST_MESSAGE("Txn preimage: " << HexStr(preimage));

    int iSender = GetRandInt(nRingSize);
    //BOOST_MESSAGE("sender: " << iSender);

    ec_point pSigC;

    ec_secret sSpend;
    ec_point pkSpend;
    ec_point keyImage;

    memcpy(&sSpend.e[0], key[iSender].begin(), EC_SECRET_SIZE);

    BOOST_CHECK(0 == SecretToPublicKey(sSpend, pkSpend));

    BOOST_REQUIRE(0 == generateKeyImage(pkSpend, sSpend, keyImage));

    start = clock();
    BOOST_REQUIRE(0 == generateRingSignatureAB(keyImage, preimage, nRingSize, iSender, sSpend, pPubkeys, pSigC, pSigS));
    stop = clock();
    totalGenerate += stop - start;

    start = clock();
    BOOST_REQUIRE(0 == verifyRingSignatureAB(keyImage, preimage, nRingSize, pPubkeys, pSigC, pSigS));
    stop = clock();
    totalVerify += stop - start;

    int sigSize = EC_COMPRESSED_SIZE + EC_SECRET_SIZE + EC_SECRET_SIZE + (EC_SECRET_SIZE + EC_COMPRESSED_SIZE) * nRingSize;

    BOOST_MESSAGE("nRingSize " << nRingSize << ", sigSize: " << bytesReadable(sigSize));

    if (pPubkeys)
        free(pPubkeys);
    if (pSigS)
        free(pSigS);

};

BOOST_AUTO_TEST_SUITE(ringsig_tests)

BOOST_AUTO_TEST_CASE(ringsig)
{
    SelectParams(CChainParams::REGTEST);

    BOOST_REQUIRE(0 == initialiseRingSigs());

    BOOST_MESSAGE("testRingSigs");

    for (int k = 1; k < 6; ++k)
    {
        //BOOST_MESSAGE("ringSize " << (k % 126 + 2));
        testRingSigs(k % 126);
    };
    BOOST_MESSAGE("ringSize " << 199);
    testRingSigs(199);

    BOOST_MESSAGE("totalGenerate " << (double(totalGenerate) / CLOCKS_PER_SEC));
    BOOST_MESSAGE("totalVerify   " << (double(totalVerify)   / CLOCKS_PER_SEC));

    totalGenerate = 0;
    totalVerify = 0;
    BOOST_MESSAGE("testRingSigABs");

    for (int k = 2; k < 6; ++k)
    {
        BOOST_MESSAGE("ringSize " << (k % 126));
        testRingSigABs(k % 126);
    };
    BOOST_MESSAGE("ringSize " << 199);
    testRingSigABs(199);

    BOOST_MESSAGE("totalGenerate " << (double(totalGenerate) / CLOCKS_PER_SEC));
    BOOST_MESSAGE("totalVerify   " << (double(totalVerify)   / CLOCKS_PER_SEC));

    BOOST_CHECK(0 == finaliseRingSigs());

    SelectParams(CChainParams::MAIN);
}

BOOST_AUTO_TEST_SUITE_END()


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   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
//==============================================================================
#define NT2_UNIT_MODULE "nt2::constants true/false"

#include <nt2/include/constants/true_false.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/meta/cardinal_of.hpp>
#include <nt2/sdk/simd/logical.hpp>

////////////////////////////////////////////////////////////////////////////////
// Test value of true/false constant
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE_TPL( true_false_integer_value, BOOST_SIMD_SIMD_TYPES )
{
  typedef BOOST_SIMD_DEFAULT_EXTENSION ext_t;
  typedef boost::simd::native< nt2::logical<T>, ext_t> dst_t;

  for(std::size_t i=0; i< nt2::meta::cardinal_of<dst_t>::value;++i)
    NT2_TEST_EQUAL( (nt2::False<dst_t>())[i], nt2::logical<T>(false) );

  for(std::size_t i=0; i< nt2::meta::cardinal_of<dst_t>::value;++i)
    NT2_TEST_EQUAL( (nt2::True<dst_t>())[i], nt2::logical<T>(true) );
}


//------------------------------------------------------------------------------
/// \file IOMonad_tests.cpp
/// \author Ernest Yeung
//------------------------------------------------------------------------------
#include "Categories/Monads/IOMonad.h"

#include <boost/test/unit_test.hpp>
#include <iostream>

using Categories::Monads::IOMonad::IO;

BOOST_AUTO_TEST_SUITE(Categories)
BOOST_AUTO_TEST_SUITE(Monads)
BOOST_AUTO_TEST_SUITE(IOMonad_tests)

// Test morphisms.

IO print_hello()
{
  std::cout << "IO Hello ";
  return IO();
}

IO print_world()
{
  std::cout << "World IO\n";
  return IO();
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(IOMonadAsClassDoesOperations)
{
  {
    IO my_io = IO();

    my_io = my_io.do_operation(print_hello).do_operation(print_world);
    my_io.do_operation(print_hello).do_operation(print_world);

    BOOST_TEST(true);
  }
}

BOOST_AUTO_TEST_SUITE_END() // IOMonad_tests
BOOST_AUTO_TEST_SUITE_END() // Monads
BOOST_AUTO_TEST_SUITE_END() // Categories


#include <Eigen/Core>

#include <numpy_eigen/boost_python_headers.hpp>
Eigen::Matrix<int, 6, 3> test_int_6_3(const Eigen::Matrix<int, 6, 3> & M)
{
	return M;
}
void export_int_6_3()
{
	boost::python::def("test_int_6_3",test_int_6_3);
}


/********************************************************************************
 * Copyright 2009 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * 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.
 ********************************************************************************/

#ifndef RW_MATH_Q_HPP
#define RW_MATH_Q_HPP

/**
 * @file Q.hpp
 */

#if !defined(SWIG)
#include <rw/common/Serializable.hpp>
#include <rw/core/PropertyMap.hpp>
#include <rw/core/macros.hpp>

#include <Eigen/Core>
#include <boost/serialization/split_free.hpp>
#include <vector>
#endif

namespace rw { namespace math {

    /**
     * @brief Configuration vector
     */
    class Q
    {
      private:
      public:
        //! Eigen vector used as internal datastructure.
        typedef Eigen::Matrix< double, Eigen::Dynamic, 1 > Base;

        //! Value type.
        typedef double value_type;

        /**
         * @brief A configuration of vector of length \b dim.
         */
        Q (size_t dim) : _vec (dim) {}

        Q (const Q& q) : _vec (q._vec) {}

        /**
         * @brief Default constructor.
         *
         * The vector will be of dimension zero.
         */
        Q () : _vec ((Base::Index) 0) {}

        /**
         * @brief Construct a configuration vector from a std::vector
         * expression.
         *
         * @param r [in] An expression for a vector of doubles
         */
        Q (const std::vector< double >& r);

        /**
         * @brief Creates a Q  initialized with values from \b values
         * @param n [in] this value describes the length of the conficuration. This behavior is
         * depreacted. if RW_Q_USE_NEW_CONSTRUCTOR is not defined an exception is thrown if the
         * number of extra arguments doesn't match the value. if RW_Q_USE_NEW_CONSTRUCTOR is defined
         * n is counted as a value unless it matches the extra number of arguments.
         * @param args [in] the values of the configuration
         * @deprecated the use of n to describe length is deprecated.
         */
        template< typename... ARGS > explicit Q (size_t n, ARGS... args) : _vec (n)
        {
            int i = 0;
            ParamExpansion (i, args...);
            //_vec(i--) = arg0;
            if (i == 0) {
                _vec (i--) = n;
            }
        }

        /**
         * @brief Creates a Q  initialized with values from \b values
         * @param n [in] this value describes the length of the conficuration. This behavior is
         * depreacted. if RW_Q_USE_NEW_CONSTRUCTOR is not defined an exception is thrown if the
         * number of extra arguments doesn't match the value. if RW_Q_USE_NEW_CONSTRUCTOR is defined
         * n is counted as a value unless it matches the extra number of arguments.
         * @param args [in] the values of the configuration
         * @deprecated the use of n to describe length is deprecated.
         */
        template< typename... ARGS > explicit Q (int n, ARGS... args) : _vec (n)
        {
            int i = 0;
            ParamExpansion (i, args...);
            //_vec(i--) = arg0;
            if (i == 0) {
                _vec (i--) = n;
            }
        }

        /**
         * @brief Creates a Q  initialized with values from \b values
         * @param arg0 [in] first value
         * @param args [in] the values of the configuration
         */
        template< typename... ARGS > explicit Q (double arg0, ARGS... args)
        {
            int i = 1;
            ParamExpansion (i, args...);
            //_vec(i--) = arg1;
            _vec (i--) = arg0;
        }
#if defined(SWIG)
        Q_SWIG_CONSTRUCTORS;
#endif
        /**
         * @brief Construct from Eigen base.
         * @param q [in] Eigen base.
         */
        Q (const Base& q) : _vec (q.rows ())
        {
            for (int i = 0; i < q.size (); i++)
                _vec (i) = q (i, 0);
        }

        //! @brief Destructor.
        virtual ~Q ();

        /**
         * @brief Returns Q of length \b n initialized with 0's
         */
        static Q zero (std::size_t n)
        {
            return Q (Eigen::Matrix< double, Eigen::Dynamic, 1 >::Zero (n));
        }

        /**
         * @brief The dimension of the configuration vector.
         */
        size_t size () const { return _vec.rows (); }

        /**
         * @brief True if the configuration is of dimension zero.
         */
        bool empty () const { return size () == 0; }

        /**
         * @brief Accessor for the internal Eigen vector state.
         */
        const Base& e () const { return _vec; }

        /**
         * @brief Accessor for the internal Eigen vector state.
         */
        Base& e () { return _vec; }

        /**
         * @brief Extracts a sub part (range) of this Q.
         * @param start [in] Start index
         * @param cnt [in] the number of elements to include
         * @return
         */
        const Q getSubPart (size_t start, size_t cnt) const
        {
            RW_ASSERT (start + cnt <= size ());

            Q res (cnt);
            for (size_t i = 0; i < cnt; i++) {
                res (i) = (*this)[start + i];
            }
            return res;
        }

        /**
         * @brief Set subpart of vector.
         * @param index [in] the initial index.
         * @param part [in] the part to insert beginning from \b index.
         */
        void setSubPart (size_t index, const Q& part)
        {
            RW_ASSERT (index + part.size () <= size ());
            for (size_t i = 0; i < part.size (); i++) {
                (*this)[index + i] = part (i);
            }
        }

        //----------------------------------------------------------------------
        // Norm utility methods

        /**
         * @brief Returns the Euclidean norm (2-norm) of the configuration
         * @return the norm
         */
        double norm2 () const
        {
            return _vec.norm ();
            // return norm_2(m());
        }

        /**
         * @brief Returns the Manhatten norm (1-norm) of the configuration
         * @return the norm
         */
        double norm1 () const
        {
            return _vec.lpNorm< 1 > ();
            // return norm_1(m());
        }

        /**
         * @brief Returns the infinte norm (\f$\inf\f$-norm) of the configuration
         * @return the norm
         */
        double normInf () const
        {
            return _vec.lpNorm< Eigen::Infinity > ();
            // return norm_inf(m());
        }

        //----------------------------------------------------------------------
        // Various operators
#if !defined(SWIG)
        /**
         * @brief Returns reference to vector element
         * @param i [in] index in the vector
         * @return const reference to element
         */
        const double& operator() (size_t i) const { return _vec (i); }

        /**
         * @brief Returns reference to vector element
         * @param i [in] index in the vector
         * @return reference to element
         */
        double& operator() (size_t i) { return _vec (i); }

        /**
         * @brief Returns reference to vector element
         * @param i [in] index in the vector
         * @return const reference to element
         */
        const double& operator[] (size_t i) const { return _vec (i); }

        /**
         * @brief Returns reference to vector element
         * @param i [in] index in the vector
         * @return reference to element
         */
        double& operator[] (size_t i) { return _vec (i); }
#else
        ARRAYOPERATOR (double);
#endif

        /**
         * @brief Scalar division.
         */
        const Q operator/ (double s) const { return Q (_vec / s); }

        /**
         * @brief Scalar multiplication.
         */
        const Q operator* (double s) const { return Q (_vec * s); }

        /**
         * @brief Scalar multiplication.
         */
        friend const Q operator* (double s, const Q& v) { return Q (s * v.e ()); }

#if !defined(SWIGPYTHON)
        /**
         * @brief Scalar division.
         */
        friend const Q operator/ (double s, const Q& v)
        {
            Q res = v;
            for (size_t i = 0; i < v.size (); i++)
                res (i) = s / v (i);
            return res;
        }
#endif

        /**
         * @brief Vector subtraction.
         */
        const Q operator- (const Q& b) const { return Q (_vec - b.e ()); }

        /**
         * @brief Vector addition.
         */
        const Q operator+ (const Q& b) const { return Q (_vec + b.e ()); }

        /**
         * @brief Compares \b this and \b q2 for equality.
         *
         * \b this and \b q2 are considered equal if and only if they have equal
         * length and if q1(i) == q2(i) for all i.
         * @param q2 [in]
         * @return True if this equals q2, false otherwise.
         */
        bool operator== (const Q& q2) const;

        /**
         * @brief Inequality operator
         * The inverse of operator==().
         */
        inline bool operator!= (const Q& q2) const { return !((*this) == q2); }

        /**
         * @brief Scalar multiplication.
         */
        Q& operator*= (double s)
        {
            _vec *= s;
            return *this;
        }

        /**
         * @brief Scalar division.
         */
        Q& operator/= (double s)
        {
            _vec /= s;
            return *this;
        }

        /**
         * @brief Vector addition.
         */
        Q& operator+= (const Q& v)
        {
            _vec += v.e ();
            return *this;
        }

        /**
         * @brief Vector subtraction.
         */
        Q& operator-= (const Q& v)
        {
            _vec -= v.e ();
            return *this;
        }

        /**
         * @brief Unary minus.
         */
        Q operator- () const { return Q (-_vec); }

        /**
         * @brief Compares whether this is less than \b q
         *
         * The less operator is defined such that the first index is the most significant. That is
         * if (*this)[0] < q[0] then true is returned. If (*this)[0] > q[0] false is returned and
         * only if (*this)[0] == q[0] is the next index considered.
         */
        bool operator< (const Q& q) const
        {
            RW_ASSERT (size () == q.size ());
            for (size_t i = 0; i < size (); i++) {
                if (_vec[i] < q[i])
                    return true;
                else if (_vec[i] > q[i])
                    return false;
            }
            return false;
        }

        /**
         * @brief Convert to a standard vector.
         * @param v [out] the result.
         */
        void toStdVector (std::vector< double >& v) const
        {
            v.resize (size ());
            for (size_t i = 0; i < size (); i++) {
                v[i] = _vec[i];
            }
        }

        /**
         * @brief Convert to a standard vector.
         * @return the result.
         */
        std::vector< double > toStdVector () const
        {
            std::vector< double > v (size ());
            toStdVector (v);
            return v;
        }
#if defined(SWIG)
        TOSTRING ();
#endif

      private:
        void ParamExpansion (int& i)
        {
            if (_vec.rows () == 0) {
                _vec = Base (i--);
            }
            else if (i == 0) {
                // do noting
            }
            else if (_vec.rows () != i) {
#ifndef RW_Q_USE_NEW_CONSTRUCTOR
                if (_vec.rows () < i) {
                    RW_THROW ("n.size ("
                              << _vec.rows () << ") != args.size (" << i << "). "
                              << "#define RW_Q_USE_NEW_CONSTRUCTOR if you want 'n' to be an "
                              << "argumeent instead of the size of the configuration");
                }
#else
                _vec = Base (i + 1);
#endif
            }
            else {
                i--;
            }
        }

        template< typename T > void ParamExpansion (int& i, T arg)
        {
            ParamExpansion (++i);
            _vec (i--) = arg;
        }

        template< typename T, typename... ARGS > void ParamExpansion (int& i, T arg, ARGS... args)
        {
            ParamExpansion (++i, args...);
            _vec (i--) = arg;
        }

        Base _vec;
    };

    /**
     * @brief Creates a Q of length \b n and initialized with values from \b values
     * The method reads n values from \b values and do not check whether reading out of bounds
     * @param n [in] Length of q.
     * @param values [in] Values to initialize with
     */
    template<> Q::Q (size_t n, double* values);

    /**
     * @brief Creates a Q of length \b n and initialized with values from \b values
     * The method reads n values from \b values and do not check whether reading out of bounds
     * @param n [in] Length of q.
     * @param values [in] Values to initialize with
     */
    template<> Q::Q (size_t n, const double* values);

    /**
     * @brief Creates a Q of length \b n and initialized with values from \b values
     * The method reads n values from \b values and do not check whether reading out of bounds
     * @param n [in] Length of q.
     * @param values [in] Values to initialize with
     */
    template<> Q::Q (int n, double* values);

    /**
     * @brief Creates a Q of length \b n and initialized with values from \b values
     * The method reads n values from \b values and do not check whether reading out of bounds
     * @param n [in] Length of q.
     * @param values [in] Values to initialize with
     */
    template<> Q::Q (int n, const double* values);

    /**
     * @brief Creates a Q of length \b n and initialize all values in \Q to \b value
     * @param n [in] Length of q.
     * @param value [in] Value to initialize
     */
    template<> Q::Q (int n, double values);

    /**
     * @brief Creates a Q of length \b n and initialize all values in \Q to \b value
     * @param n [in] Length of q.
     * @param value [in] Value to initialize
     */
    template<> Q::Q (size_t n, double values);

    /**
     * @brief Streaming operator.
     *
     * @relates Q
     */
    std::ostream& operator<< (std::ostream& out, const Q& v);

#if !defined(SWIG)
    /**
     * @brief Input streaming operator
     *
     * Parse input stream according to how operator<< streams out
     *
     * @relates Q
     * @param in [in] Input stream
     * @param q [in] Target of q read in
     * @return reference to \b in
     */
    std::istream& operator>> (std::istream& in, Q& q);
#endif

    /**
     * @brief The dot product (inner product) of \b a and \b b.
     * @relates Q
     */
    double dot (const Q& a, const Q& b);

    /**
     * @brief concatenates q1 onto q2 such that the returned q has
     * the configurations of q1 in [0;q1.size()[ and has q2 in
     * [q1.size();q1.size()+q2.size()[
     * @param q1 [in] the first Q
     * @param q2 [in] the second Q
     * @return the concatenation of q1 and q2
     */
    rw::math::Q concat (const Q& q1, const Q& q2);

    /*@}*/
}}    // namespace rw::math

namespace rw { namespace core {
    //! @copydoc rw::core::PropertyMap::findProperty(const std::string& identifier) const
    template<>
    rw::core::Ptr< Property< rw::math::Q > >
    PropertyMap::findProperty (const std::string& identifier) const;
}}    // namespace rw::core

namespace rw { namespace common {
    class OutputArchive;
    class InputArchive;
    namespace serialization {
        /**
         * @copydoc rw::common::serialization::write
         * @relatedalso rw::math::Q
         */
        template<>
        void write (const rw::math::Q& sobject, rw::common::OutputArchive& oarchive,
                    const std::string& id);

        /**
         * @copydoc rw::common::serialization::read
         * @relatedalso rw::math::Q
         */
        template<>
        void read (rw::math::Q& sobject, rw::common::InputArchive& iarchive, const std::string& id);
    }    // namespace serialization
}}       // namespace rw::common

namespace boost { namespace serialization {
    /**
     * @brief Boost serialization.
     * @param archive [in] the boost archive to read from or write to.
     * @param q [in/out] the vector to read/write.
     * @param version [in] class version (currently version 0).
     * @relatedalso rw::math::Q
     */
    template< class Archive >
    void serialize (Archive& archive, rw::math::Q& q, const unsigned int version)
    {
        split_free (archive, q, version);    // split into load and save
    }

    /**
     * @brief Boost serialization.
     * @param archive [in] the boost archive to write to.
     * @param q [in] the vector to write.
     * @param version [in] class version (currently version 0).
     * @relatedalso rw::math::Q
     */
    template< class Archive >
    void save (Archive& archive, const rw::math::Q& q, const unsigned int version)
    {
        const rw::math::Q::Base& e = q.e ();
#if BOOST_VERSION >= 105900
        archive << e.size ();
#else
        rw::math::Q::Base::Index size = e.size ();
        archive << size;
#endif
        for (rw::math::Q::Base::Index i = 0; i < e.size (); i++) {
            archive << e[i];
        }
    }

    /**
     * @brief Boost serialization.
     * @param archive [in] the boost archive to read from.
     * @param q [out] the vector to read.
     * @param version [in] class version (currently version 0).
     * @relatedalso rw::math::Q
     */
    template< class Archive >
    void load (Archive& archive, rw::math::Q& q, const unsigned int version)
    {
        rw::math::Q::Base& e = q.e ();
        rw::math::Q::Base::Index size;
        archive >> size;
        e.resize (size);
        for (rw::math::Q::Base::Index i = 0; i < size; i++) {
            archive >> e[i];
        }
    }
}}    // namespace boost::serialization

#endif    // end include guard