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

// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.

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

#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP

#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>

namespace geofeatures_boost {} namespace boost = geofeatures_boost; namespace geofeatures_boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_convex
{

struct ring_is_convex
{
    template <typename Ring>
    static inline bool apply(Ring const& ring)
    {
        typedef typename geometry::point_type<Ring>::type point_type;
        typedef typename strategy::side::services::default_strategy
        <
            typename cs_tag<point_type>::type
        >::type side_strategy_type;

        std::size_t n = geofeatures_boost::size(ring);
        if (geofeatures_boost::size(ring) < core_detail::closure::minimum_ring_size
                                    <
                                        geometry::closure<Ring>::value
                                    >::value)
        {
            // (Too) small rings are considered as non-concave, is convex
            return true;
        }

        // Walk in clockwise direction, consider ring as closed
        // (though closure is not important in this algorithm - any dupped
        //  point is skipped)
        typedef detail::normalized_view<Ring const> view_type;
        view_type view(ring);

        typedef geometry::ever_circling_range_iterator<view_type const> it_type;
        it_type previous(view);
        it_type current(view);
        current++;

        std::size_t index = 1;
        while (equals::equals_point_point(*current, *previous) && index < n)
        {
            current++;
            index++;
        }

        if (index == n)
        {
            // All points are apparently equal
            return true;
        }

        it_type next = current;
        next++;
        while (equals::equals_point_point(*current, *next))
        {
            next++;
        }

        // We have now three different points on the ring
        // Walk through all points, use a counter because of the ever-circling
        // iterator
        for (std::size_t i = 0; i < n; i++)
        {
            int const side = side_strategy_type::apply(*previous, *current, *next);
            if (side == 1)
            {
                // Next is on the left side of clockwise ring:
                // the piece is not convex
                return false;
            }

            previous = current;
            current = next;

            // Advance next to next different point
            // (because there are non-equal points, this loop is not infinite)
            next++;
            while (equals::equals_point_point(*current, *next))
            {
                next++;
            }
        }
        return true;
    }
};

}} // namespace detail::is_convex
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    typename Geometry,
    typename Tag = typename tag<Geometry>::type
>
struct is_convex : not_implemented<Tag>
{};

template <typename Box>
struct is_convex<Box, box_tag>
{
    static inline bool apply(Box const& )
    {
        // Any box is convex (TODO: consider spherical boxes)
        return true;
    }
};

template <typename Box>
struct is_convex<Box, ring_tag> : detail::is_convex::ring_is_convex
{};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

// TODO: variants

// TODO: documentation / qbk
template<typename Geometry>
inline bool is_convex(Geometry const& geometry)
{
    return dispatch::is_convex<Geometry>::apply(geometry);
}

}} // namespace geofeatures_boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP


//==================================================================================================
/*!
  @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_ENUMERATE_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_ENUMERATE_HPP_INCLUDED

namespace boost { namespace simd
{
#if defined(DOXYGEN_ONLY)
  /*!
    @ingroup group-swar
    Generates a value containing sequentially increasing elements, starting with @c seed and
    repetitively evaluating @c seed+=step.

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

    @par SIMD Semantic:
    For any type @c T and integral constant @c N, the following code:
    @code
    auto r = enumerate<boost::simd::pack<T,N>>(seed, step);
    @endcode
    is equivalent to:
    @code
    boost::simd::pack<T,N> r{seed, seed+step, ..., seed+(N-1)*step};
    @endcode

    @param seed Initial value of store, equals to @c 0 by default.
    @param step Increment to apply on each subsequent generated value, equals to @c 1 by default.
    @return A value containing the sequence of value generated from @c seed and @c step
  **/
  Value enumerate(const ScalarValue& seed = 0, const ScalarValue& step = 1);
#endif
} }

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

#endif


//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//
#pragma once

#include <armnn/Tensor.hpp>
#include <armnn/utility/Assert.hpp>
#include <armnnUtils/FloatingPointComparison.hpp>

#include <QuantizeHelper.hpp>

#include <boost/multi_array.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/test/unit_test.hpp>

#include <array>
#include <cmath>
#include <vector>

constexpr float g_FloatCloseToZeroTolerance = 1.0e-6f;

template<typename T, bool isQuantized = true>
struct SelectiveComparer
{
    static bool Compare(T a, T b)
    {
        return (std::max(a, b) - std::min(a, b)) <= 1;
    }

};

template<typename T>
struct SelectiveComparer<T, false>
{
    static bool Compare(T a, T b)
    {
        // If a or b is zero, percent_tolerance does an exact match, so compare to a small, constant tolerance instead.
        if (a == 0.0f || b == 0.0f)
        {
            return std::abs(a - b) <= g_FloatCloseToZeroTolerance;
        }

        if (std::isinf(a) && a == b)
        {
            return true;
        }

        if (std::isnan(a) && std::isnan(b))
        {
            return true;
        }

        // For unquantized floats we use a tolerance of 1%.
        return armnnUtils::within_percentage_tolerance(a, b);
    }
};

template<typename T>
bool SelectiveCompare(T a, T b)
{
    return SelectiveComparer<T, armnn::IsQuantizedType<T>()>::Compare(a, b);
};

template<typename T>
bool SelectiveCompareBoolean(T a, T b)
{
    return (((a == 0) && (b == 0)) || ((a != 0) && (b != 0)));
};

template <typename T, std::size_t n>
boost::test_tools::predicate_result CompareTensors(const boost::multi_array<T, n>& a,
                                                   const boost::multi_array<T, n>& b,
                                                   bool compareBoolean = false,
                                                   bool isDynamic = false)
{
    if (!isDynamic)
    {
        // Checks they are same shape.
        for (unsigned int i = 0;
             i < n;
             i++)
        {
            if (a.shape()[i] != b.shape()[i])
            {
                boost::test_tools::predicate_result res(false);
                res.message() << "Different shapes ["
                              << a.shape()[i]
                              << "!="
                              << b.shape()[i]
                              << "]";
                return res;
            }
        }
    }

    // Now compares element-wise.

    // Fun iteration over n dimensions.
    std::array<unsigned int, n> indices;
    for (unsigned int i = 0; i < n; i++)
    {
        indices[i] = 0;
    }

    std::stringstream errorString;
    int numFailedElements = 0;
    constexpr int maxReportedDifferences = 3;

    while (true)
    {
        bool comparison;
        // As true for uint8_t is non-zero (1-255) we must have a dedicated compare for Booleans.
        if(compareBoolean)
        {
            comparison = SelectiveCompareBoolean(a(indices), b(indices));
        }
        else
        {
            comparison = SelectiveCompare(a(indices), b(indices));
        }

        if (!comparison)
        {
            ++numFailedElements;

            if (numFailedElements <= maxReportedDifferences)
            {
                if (numFailedElements >= 2)
                {
                    errorString << ", ";
                }
                errorString << "[";
                for (unsigned int i = 0; i < n; ++i)
                {
                    errorString << indices[i];
                    if (i != n - 1)
                    {
                        errorString << ",";
                    }
                }
                errorString << "]";

                errorString << " (" << +a(indices) << " != " << +b(indices) << ")";
            }
        }

        ++indices[n - 1];
        for (unsigned int i=n-1; i>0; i--)
        {
            if (indices[i] == a.shape()[i])
            {
                indices[i] = 0;
                ++indices[i - 1];
            }
        }

        if (indices[0] == a.shape()[0])
        {
            break;
        }
    }

    boost::test_tools::predicate_result comparisonResult(true);
    if (numFailedElements > 0)
    {
        comparisonResult = false;
        comparisonResult.message() << numFailedElements << " different values at: ";
        if (numFailedElements > maxReportedDifferences)
        {
            errorString << ", ... (and " << (numFailedElements - maxReportedDifferences) << " other differences)";
        }
        comparisonResult.message() << errorString.str();
    }

    return comparisonResult;
}

// Creates a boost::multi_array with the shape defined by the given TensorInfo.
template <typename T, std::size_t n>
boost::multi_array<T, n> MakeTensor(const armnn::TensorInfo& tensorInfo)
{
    std::array<unsigned int, n> shape;

    for (unsigned int i = 0; i < n; i++)
    {
        shape[i] = tensorInfo.GetShape()[i];
    }

    return boost::multi_array<T, n>(shape);
}

// Creates a boost::multi_array with the shape defined by the given TensorInfo and contents defined by the given vector.
template <typename T, std::size_t n>
boost::multi_array<T, n> MakeTensor(
    const armnn::TensorInfo& tensorInfo, const std::vector<T>& flat, bool isDynamic = false)
{
    if (!isDynamic)
    {
        ARMNN_ASSERT_MSG(flat.size() == tensorInfo.GetNumElements(), "Wrong number of components supplied to tensor");
    }

    std::array<unsigned int, n> shape;

    // NOTE: tensorInfo.GetNumDimensions() might be different from n
    const unsigned int returnDimensions = static_cast<unsigned int>(n);
    const unsigned int actualDimensions = tensorInfo.GetNumDimensions();

    const unsigned int paddedDimensions =
        returnDimensions > actualDimensions ? returnDimensions - actualDimensions : 0u;

    for (unsigned int i = 0u; i < returnDimensions; i++)
    {
        if (i < paddedDimensions)
        {
            shape[i] = 1u;
        }
        else
        {
            shape[i] = tensorInfo.GetShape()[i - paddedDimensions];
        }
    }

    boost::const_multi_array_ref<T, n> arrayRef(&flat[0], shape);
    return boost::multi_array<T, n>(arrayRef);
}

template <typename T, std::size_t n>
boost::multi_array<T, n> MakeRandomTensor(const armnn::TensorInfo& tensorInfo,
                                          unsigned int seed,
                                          float        min = -10.0f,
                                          float        max = 10.0f)
{
    boost::random::mt19937                          gen(seed);
    boost::random::uniform_real_distribution<float> dist(min, max);

    std::vector<float> init(tensorInfo.GetNumElements());
    for (unsigned int i = 0; i < init.size(); i++)
    {
        init[i] = dist(gen);
    }

    const float   qScale  = tensorInfo.GetQuantizationScale();
    const int32_t qOffset = tensorInfo.GetQuantizationOffset();

    return MakeTensor<T, n>(tensorInfo, armnnUtils::QuantizedVector<T>(init, qScale, qOffset));
}


#pragma once

#include <iomanip>
#include <iostream>
#include <set>

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>

#include "permutations.hpp"

namespace tu
{

  /**
   * A matroid class which maintains the index-to-element relation.
   * It should mostly be associated with a representation matrix.
   */

  template <typename NameType>
  class matroid
  {
  public:
    typedef NameType name_type;
    typedef size_t size_type;
    typedef std::vector <name_type> name_vector_type;
    typedef name_type& reference_type;
    typedef const name_type& const_reference_type;
    typedef matroid <name_type> self_type;

    /**
     * Constructs a matroid by copying the matroid elements from the row/column vectors.
     *
     * @param names1 Row names
     * @param names2 Column names
     */

    matroid(const name_vector_type& names1, const name_vector_type& names2) :
      _names1(names1), _names2(names2)
    {

    }

    /**
     * Constructs a matroid with given height and width. The names are set in default manner.
     *
     * @param size1 Size of a base
     * @param size2 Size of a cobase
     */

    matroid(size_t size1 = 0, size_t size2 = 0)
    {
      resize(size1, size2);
    }

    /**
     * Resizes a matroid.
     *
     * @param size1 New height, i.e. size of each base
     * @param size2 New width, i.e. size of each cobase
     */

    void resize(size_t size1, size_t size2)
    {
      _names1.resize(size1);
      for (size_t i = 0; i < size1; ++i)
        _names1[i] = -(i + 1);
      _names2.resize(size2);
      for (size_t i = 0; i < size2; ++i)
        _names2[i] = (i + 1);
    }

    /**
     * @return Height, i.e. size of each base
     */

    inline size_t size1() const
    {
      return _names1.size();
    }

    /**
     * @return Width, i.e. size of each cobase
     */

    inline size_t size2() const
    {
      return _names2.size();
    }

    /**
     * @param index A row index
     * @return The corresponding matroid element
     */

    inline name_type& name1(size_t index)
    {
      return _names1[index];
    }

    /**
     * @param index A row index
     * @return The corresponding matroid element
     */

    inline const name_type& name1(size_t index) const
    {
      return _names1[index];
    }

    /**
     * @param index A column  index
     * @return The corresponding matroid element
     */

    inline name_type& name2(size_t index)
    {
      return _names2[index];
    }

    /**
     * @param index A column index
     * @return The corresponding matroid element
     */

    inline const name_type& name2(size_t index) const
    {
      return _names2[index];
    }

    /**
     * @return A set of all matroid elements
     */

    inline std::set <NameType> get_elements() const
    {
      std::set <NameType> result;

      std::copy(_names1.begin(), _names1.end(), std::inserter(result, result.end()));
      std::copy(_names2.begin(), _names2.end(), std::inserter(result, result.end()));

      return result;
    }

  private:
    name_vector_type _names1;
    name_vector_type _names2;
  };

  /// A matroid with integer names
  typedef matroid <int> integer_matroid;

  /**
   * Free function to permute two rows.
   *
   * @param matroid The given matroid
   * @param index1 First row index
   * @param index2 Second row index
   */

  template <typename NameType>
  inline void matroid_permute1(matroid <NameType>& matroid, size_t index1, size_t index2)
  {
    std::swap(matroid.name1(index1), matroid.name1(index2));
  }

  /**
   * Free function to permute two rows of a matroid and its representation matrix.
   *
   * @param matroid The given matroid
   * @param matrix Representation matrix of the given matroid
   * @param index1 First row index
   * @param index2 Second row index
   */

  template <typename MatroidType, typename MatrixType>
  inline void matroid_permute1(MatroidType& matroid, MatrixType& matrix, size_t index1, size_t index2)
  {
    matroid_permute1(matroid, index1, index2);
    matrix_permute1(matrix, index1, index2);
  }

  /**
   * Free function to permute two columns.
   *
   * @param matroid The given matroid
   * @param index1 First column index
   * @param index2 Second column index
   */

  template <typename NameType>
  inline void matroid_permute2(matroid <NameType>& matroid, size_t index1, size_t index2)
  {
    std::swap(matroid.name2(index1), matroid.name2(index2));
  }

  /**
   * Free function to permute two columns of a matroid and its representation matrix.
   *
   * @param matroid The given matroid
   * @param matrix Representation matrix of the given matroid
   * @param index1 First column index
   * @param index2 Second column index
   */

  template <typename MatroidType, typename MatrixType>
  inline void matroid_permute2(MatroidType& matroid, MatrixType& matrix, size_t index1, size_t index2)
  {
    matroid_permute2(matroid, index1, index2);
    matrix_permute2(matrix, index1, index2);
  }

  /**
   * Free function to perform a pivot on a matroid.
   *
   * @param matroid The given matroid
   * @param i Row index
   * @param j Column index
   */

  template <typename NameType>
  void matroid_binary_pivot(matroid <NameType>& matroid, size_t i, size_t j)
  {
    std::swap(matroid.name1(i), matroid.name2(j));
  }

  /**
   * Free function to perform a pivot on a matroid and its representation matrix.
   *
   * @param matroid The given matroid
   * @param matrix Representation matrix of the given matroid
   * @param i Row index
   * @param j Column index
   */

  template <typename MatroidType, typename MatrixType>
  void matroid_binary_pivot(MatroidType& matroid, MatrixType& matrix, size_t i, size_t j)
  {
    matroid_binary_pivot(matroid, i, j);
    matrix_binary_pivot(matrix, i, j);
  }

  /**
   * Prints a matroid with its representation matrix.
   *
   * @param matroid The given matrix
   * @param matrix Representation matrix of the given matroid
   */

  template <typename MatroidType, typename MatrixType>
  void matroid_print(const MatroidType& matroid, const MatrixType& matrix)
  {
    assert (matroid.size1() == matrix.size1());
    assert (matroid.size2() == matrix.size2());

    std::cout << "     ";
    for (size_t column = 0; column < matroid.size2(); ++column)
    {
      std::cout << std::setw(3) << matroid.name2(column);
    }
    std::cout << "\n    ";
    for (size_t column = 0; column < matroid.size2(); ++column)
    {
      std::cout << "--";
    }
    for (size_t row = 0; row < matroid.size1(); ++row)
    {
      std::cout << "\n" << std::setw(3) << matroid.name1(row) << " |";
      for (size_t column = 0; column < matroid.size2(); ++column)
      {
        std::cout << std::setw(3) << matrix(row, column);
      }
    }
    std::cout << std::endl;
  }

  /**
   * Prints a matroid minor with its representation matrix.
   *
   * @param matroid The given matrix
   * @param matrix Representation matrix of the given matroid
   * @param height Number of rows of the minor
   * @param width Number of columns of the minor
   */

  template <typename MatroidType, typename MatrixType>
  void matroid_print_minor(const MatroidType& matroid, const MatrixType& matrix, size_t height, size_t width)
  {
    assert (matroid.size1() == matrix.size1());
    assert (matroid.size2() == matrix.size2());

    std::cout << "     ";
    for (size_t column = 0; column < width; ++column)
    {
      std::cout << std::setw(3) << matroid.name2(column);
    }
    std::cout << "\n    ";
    for (size_t column = 0; column < width; ++column)
    {
      std::cout << "--";
    }
    for (size_t row = 0; row < height; ++row)
    {
      std::cout << "\n" << std::setw(3) << matroid.name1(row) << " |";
      for (size_t column = 0; column < width; ++column)
      {
        std::cout << std::setw(3) << matrix(row, column);
      }
    }
    std::cout << std::endl;
  }

  /**
   * Returns all matroid elements.
   *
   * @param matroid The given matroid
   * @return A set of matroid elements
   */

  template <typename MatroidType>
  std::set <int> matroid_elements(const MatroidType& matroid)
  {
    std::set <int> elements;
    for (size_t row = 0; row < matroid.size1(); ++row)
      elements.insert(matroid.name1(row));
    for (size_t column = 0; column < matroid.size2(); ++column)
      elements.insert(matroid.name2(column));

    return elements;
  }

} /* namespace tu */


// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2008 Steven Watanabe
//
// 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

\brief conversion.cpp

\detailed
Test explicit and implicit unit conversion.

Output:
@verbatim

//[conversion_output_1
L1 = 2 m
L2 = 2 m
L3 = 2 m
L4 = 200 cm
L5 = 5 m
L6 = 4 m
L7 = 200 cm
//]

//[conversion_output_2
volume (m^3)  = 1 m^3
volume (cm^3) = 1e+06 cm^3
volume (m^3)  = 1 m^3

energy (joules) = 1 J
energy (ergs)   = 1e+07 erg
energy (joules) = 1 J

velocity (2 m/s)  = 2 m s^-1
velocity (2 cm/s) = 0.02 m s^-1
//]

@endverbatim
**/

#include <iostream>

#include <boost/units/io.hpp>
#include <boost/units/pow.hpp>
#include <boost/units/systems/cgs.hpp>
#include <boost/units/systems/cgs/io.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/io.hpp>

using namespace boost::units;

int main()
{
    // test quantity_cast
    {
    // implicit value_type conversions
    //[conversion_snippet_1
    quantity<si::length>     L1 = quantity<si::length,int>(int(2.5)*si::meters);
    quantity<si::length,int> L2(quantity<si::length,double>(2.5*si::meters));
    //]

    //[conversion_snippet_3
    quantity<si::length,int> L3 = static_cast<quantity<si::length,int> >(L1);
    //]

    //[conversion_snippet_4
    quantity<cgs::length>    L4 = static_cast<quantity<cgs::length> >(L1);
    //]

    quantity<si::length,int> L5(4*si::meters),
                             L6(5*si::meters);
    quantity<cgs::length>    L7(L1);

    swap(L5,L6);

    std::cout << "L1 = " << L1 << std::endl
              << "L2 = " << L2 << std::endl
              << "L3 = " << L3 << std::endl
              << "L4 = " << L4 << std::endl
              << "L5 = " << L5 << std::endl
              << "L6 = " << L6 << std::endl
              << "L7 = " << L7 << std::endl
              << std::endl;
    }

    // test explicit unit system conversion
    {
    //[conversion_snippet_5
    quantity<si::volume>    vs(1.0*pow<3>(si::meter));
    quantity<cgs::volume>   vc(vs);
    quantity<si::volume>    vs2(vc);

    quantity<si::energy>    es(1.0*si::joule);
    quantity<cgs::energy>   ec(es);
    quantity<si::energy>    es2(ec);

    quantity<si::velocity>  v1 = 2.0*si::meters/si::second,
                            v2(2.0*cgs::centimeters/cgs::second);
    //]

    std::cout << "volume (m^3)  = " << vs << std::endl
              << "volume (cm^3) = " << vc << std::endl
              << "volume (m^3)  = " << vs2 << std::endl
              << std::endl;

    std::cout << "energy (joules) = " << es << std::endl
              << "energy (ergs)   = " << ec << std::endl
              << "energy (joules) = " << es2 << std::endl
              << std::endl;

    std::cout << "velocity (2 m/s)  = " << v1 << std::endl
              << "velocity (2 cm/s) = " << v2 << std::endl
              << std::endl;
    }

    return 0;
}


/*=============================================================================
    Copyright (c) 2017 Paul Fultz II
    if.cpp
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#include <boost/hof/if.hpp>
#include "test.hpp"

#include <boost/hof/first_of.hpp>
#include <boost/hof/placeholders.hpp>

struct is_5
{
    template<class T>
    constexpr bool operator()(T i) const
    {
        return i == 5;
    }
};

struct is_not_5
{
    template<class T>
    constexpr bool operator()(T i) const
    {
        return i != 5;
    }
};

template<class F>
struct test_int
{
    template<class T>
    constexpr bool operator()(T x) const
    {
        return boost::hof::first_of(
            boost::hof::if_(std::is_integral<T>())(F()),
            boost::hof::always(true)
        )(x);
    }
};

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(test_int<is_5>()(5));
    BOOST_HOF_TEST_CHECK(test_int<is_5>()(5L));
    BOOST_HOF_TEST_CHECK(test_int<is_5>()(5.0));
    BOOST_HOF_TEST_CHECK(test_int<is_5>()(6.0));

    BOOST_HOF_TEST_CHECK(test_int<is_not_5>()(6));
    BOOST_HOF_TEST_CHECK(test_int<is_not_5>()(6L));
    BOOST_HOF_TEST_CHECK(test_int<is_not_5>()(5.0));
    BOOST_HOF_TEST_CHECK(test_int<is_not_5>()(6.0));

    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_5>()(5));
    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_5>()(5L));
    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_5>()(5.0));
    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_5>()(6.0));

    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_not_5>()(6));
    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_not_5>()(6L));
    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_not_5>()(5.0));
    BOOST_HOF_STATIC_TEST_CHECK(test_int<is_not_5>()(6.0));
}

template<class F>
struct test_int_c
{
    template<class T>
    constexpr bool operator()(T x) const
    {
        return boost::hof::first_of(
            boost::hof::if_c<std::is_integral<T>::value>(F()),
            boost::hof::always(true)
        )(x);
    }
};

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(test_int_c<is_5>()(5));
    BOOST_HOF_TEST_CHECK(test_int_c<is_5>()(5L));
    BOOST_HOF_TEST_CHECK(test_int_c<is_5>()(5.0));
    BOOST_HOF_TEST_CHECK(test_int_c<is_5>()(6.0));

    BOOST_HOF_TEST_CHECK(test_int_c<is_not_5>()(6));
    BOOST_HOF_TEST_CHECK(test_int_c<is_not_5>()(6L));
    BOOST_HOF_TEST_CHECK(test_int_c<is_not_5>()(5.0));
    BOOST_HOF_TEST_CHECK(test_int_c<is_not_5>()(6.0));

    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_5>()(5));
    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_5>()(5L));
    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_5>()(5.0));
    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_5>()(6.0));

    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_not_5>()(6));
    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_not_5>()(6L));
    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_not_5>()(5.0));
    BOOST_HOF_STATIC_TEST_CHECK(test_int_c<is_not_5>()(6.0));
}

struct sum_f
{
    template<class T>
    constexpr int operator()(T x, T y) const
    {
        return boost::hof::first_of(
            boost::hof::if_(std::is_integral<T>())(boost::hof::_ + boost::hof::_),
            boost::hof::always(0)
        )(x, y);
    }
};

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(sum_f()(1, 2) == 3);
    BOOST_HOF_TEST_CHECK(sum_f()(1.0, 2.0) == 0);
    BOOST_HOF_TEST_CHECK(sum_f()("", "") == 0);

    BOOST_HOF_STATIC_TEST_CHECK(sum_f()(1, 2) == 3);
    BOOST_HOF_STATIC_TEST_CHECK(sum_f()("", "") == 0);
}

struct sum_f_c
{
    template<class T>
    constexpr int operator()(T x, T y) const
    {
        return boost::hof::first_of(
            boost::hof::if_c<std::is_integral<T>::value>(boost::hof::_ + boost::hof::_),
            boost::hof::always(0)
        )(x, y);
    }
};

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(sum_f_c()(1, 2) == 3);
    BOOST_HOF_TEST_CHECK(sum_f_c()(1.0, 2.0) == 0);
    BOOST_HOF_TEST_CHECK(sum_f_c()("", "") == 0);

    BOOST_HOF_STATIC_TEST_CHECK(sum_f_c()(1, 2) == 3);
    BOOST_HOF_STATIC_TEST_CHECK(sum_f_c()("", "") == 0);
}

#if BOOST_HOF_HAS_NOEXCEPT_DEDUCTION
BOOST_HOF_TEST_CASE()
{
    static_assert(noexcept(boost::hof::if_(std::is_integral<int>())(boost::hof::identity)(1)), "noexcept if");
}
#endif


/*
 * Copyright 2009 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.
 *
 */

// Third party includes
#include <boost/program_options.hpp>

// VOTCA includes
#include <votca/tools/histogramnew.h>
#include <votca/tools/tokenizer.h>

// Local VOTCA includes
#include <votca/csg/cgengine.h>
#include <votca/csg/csgapplication.h>

using namespace std;
using namespace votca::csg;

class CsgFluctuations : public CsgApplication {
  string ProgramName() override { return "fluctuations"; }
  void HelpText(ostream &out) override {
    out << "calculate density fluctuations in subvolumes of the simulation "
           "box.";
    out << "Subolumes can be either cubic slabs in dimensions (x|y|z) or "
           "spherical";
    out << "slabs with respect to either the center of box or a reference "
           "molecule";
  }

  // some program options are added here

  void Initialize() override {
    CsgApplication::Initialize();
    // add program option to pick molecule
    AddProgramOptions("Fluctuation options")(
        "filter",
        boost::program_options::value<string>(&filter_)->default_value("*"),
        "filter molecule names")("rmax",
                                 boost::program_options::value<double>(),
                                 "maximal distance to be considered")(
        "rmin",
        boost::program_options::value<double>(&rmin_)->default_value(0.0),
        "minimal distance to be considered")(
        "refmol",
        boost::program_options::value<string>(&refmol_)->default_value(""),
        "Reference molecule")(
        "nbin",
        boost::program_options::value<votca::Index>(&nbins_)->default_value(
            100),
        "Number of bins")(
        "geometry", boost::program_options::value<string>(),
        "(sphere|x|y|z) Take radial or x, y, z slabs from rmin to rmax")(
        "outfile",
        boost::program_options::value<string>(&outfilename_)
            ->default_value("fluctuations.dat"),
        "Output file");
  }
  bool EvaluateOptions() override {
    CsgApplication::EvaluateOptions();
    CheckRequired("rmax");
    CheckRequired("geometry");
    return true;
  }

  // we want to process a trajectory
  bool DoTrajectory() override { return true; }
  bool DoMapping() override { return true; }

  void BeginEvaluate(Topology *top, Topology *) override {
    filter_ = OptionsMap()["filter"].as<string>();
    refmol_ = OptionsMap()["refmol"].as<string>();
    rmin_ = OptionsMap()["rmin"].as<double>();
    rmax_ = OptionsMap()["rmax"].as<double>();
    nbins_ = OptionsMap()["nbin"].as<votca::Index>();
    outfilename_ = OptionsMap()["outfile"].as<string>();
    geometryinput_ = OptionsMap()["geometry"].as<string>();
    nframes_ = 0;

    do_spherical_ = false;

    if (geometryinput_ == "sphere") {
      cout << "Doing spherical slabs" << endl;
      do_spherical_ = true;
    } else if (geometryinput_ == "x") {
      cout << "Doing slabs along x-axis" << endl;
      dim_ = 0;
    } else if (geometryinput_ == "y") {
      cout << "Doing slabs along  y-axis" << endl;
      dim_ = 1;
    } else if (geometryinput_ == "z") {
      cout << "Doing slabs along  z-axis" << endl;
      dim_ = 2;
    } else {
      throw std::runtime_error("Unrecognized geometry option. (sphere|x|y|z)");
    }

    N_avg_ = Eigen::VectorXd::Zero(nbins_);
    N_sq_avg_ = Eigen::VectorXd::Zero(nbins_);

    if (do_spherical_) {
      cout << "Calculating fluctions for " << rmin_ << "<r<" << rmax_;
      cout << "using " << nbins_ << " bins" << endl;
    } else {
      cout << "Calculating fluctions for " << rmin_ << "<" << geometryinput_
           << "<" << rmax_;
      cout << "using " << nbins_ << " bins" << endl;
    }

    if (refmol_ == "" && do_spherical_) {
      Eigen::Matrix3d box = top->getBox();
      ref_ = box.rowwise().sum() / 2;

      cout << "Reference is center of box " << ref_ << endl;
    }

    outfile_.open(outfilename_);
    if (!outfile_) {
      throw runtime_error("cannot open" + outfilename_ + " for output");
    }
  }

  // write out results in EndEvaluate
  void EndEvaluate() override;
  // do calculation in this function
  void EvalConfiguration(Topology *conf, Topology *top_ref) override;

 protected:
  // number of particles in dV
  votca::Index nbins_;
  Eigen::VectorXd N_avg_;
  // sqare
  Eigen::VectorXd N_sq_avg_;
  string filter_;
  string refmol_;
  double rmax_;
  double rmin_;
  Eigen::Vector3d ref_;
  votca::Index nframes_;
  string outfilename_;
  ofstream outfile_;
  string geometryinput_;
  bool do_spherical_;
  votca::Index dim_;
};

int main(int argc, char **argv) {
  CsgFluctuations app;

  return app.Exec(argc, argv);
}

void CsgFluctuations::EvalConfiguration(Topology *conf, Topology *) {

  if (refmol_ != "") {
    for (const auto &bead : conf->Beads()) {
      if (votca::tools::wildcmp(refmol_, bead.getName())) {
        ref_ = bead.getPos();
        cout << " Solute pos " << ref_ << endl;
      }
    }
  }

  votca::tools::HistogramNew hist;
  hist.Initialize(rmin_, rmax_, nbins_);

  /* check how many molecules are in each bin*/
  for (const auto &bead : conf->Beads()) {
    if (!votca::tools::wildcmp(filter_, bead.getName())) {
      continue;
    }
    double r = 0;
    if (do_spherical_) {
      Eigen::Vector3d eR = bead.getPos() - ref_;
      r = eR.norm();
    } else {
      Eigen::Vector3d eR = bead.getPos();
      if (dim_ == 0) {
        r = eR.x();
      } else if (dim_ == 1) {
        r = eR.y();
      } else if (dim_ == 2) {
        r = eR.z();
      }
    }
    hist.Process(r);
  }

  /* update averages*/
  N_avg_ += hist.data().y();
  N_sq_avg_ += hist.data().y().cwiseAbs2();

  nframes_++;
}

// output everything when processing frames is done
void CsgFluctuations::EndEvaluate() {
  cout << "Writing results to " << outfilename_ << endl;
  outfile_ << "# radius number_fluct avg_number" << endl;

  for (votca::Index i = 0; i < nbins_; i++) {
    N_avg_[i] /= (double)nframes_;
    N_sq_avg_[i] /= (double)nframes_;
  }
  for (votca::Index i = 0; i < nbins_; i++) {
    outfile_ << rmin_ + (double)i * (rmax_ - rmin_) / (double)nbins_ << " ";
    outfile_ << (N_sq_avg_[i] - N_avg_[i] * N_avg_[i]) / N_avg_[i]
             << " ";  // fluctuation
    outfile_ << N_avg_[i] << endl;
  }
}

// add our user program options


/*
 * disjoint_set.hpp
 * Author: Aven Bross
 *
 * Produces an augmented embedding structure from a planar embedding
 */

#ifndef __AUGMENTED_EMBEDDING_HPP
#define __AUGMENTED_EMBEDDING_HPP

// STL headers
#include <vector>

// Basic graph headers
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_traits.hpp>

// Local project headers
#include "incidence_list_helpers.hpp"

template<
        typename graph_t, typename planar_embedding_t,
        typename augmented_embedding_t
    >
void augment_embedding(
        const graph_t & graph, const planar_embedding_t & planar_embedding,
        augmented_embedding_t & augmented_embedding
    )
{
    // Type definitions
    typedef typename boost::property_traits<augmented_embedding_t>::value_type
        ::value_type adjacency_node_t;
    typedef typename boost::property_traits<augmented_embedding_t>::value_type
        ::iterator adjacency_node_iterator_t;
    typedef typename boost::graph_traits<graph_t>::vertex_iterator
        vertex_iterator_t;
    typedef typename boost::graph_traits<graph_t>::vertex_descriptor vertex_t;

    // Iterators for walking through the vertex set of the graph
    vertex_iterator_t v_begin, v_iter, v_end;

    // Create the embedding ordered adjacency list with uninitialized iterators
    for(boost::tie(v_iter, v_end) = boost::vertices(graph); v_iter != v_end;
            v_iter++
        )
    {
        vertex_t v = *v_iter;

        // Clear the augmented adjacency list, we will be constructing our own
        augmented_embedding[v].clear();

        // Construct v's augmented adjacency list, iterators uninitialized
        for(auto edge_iter = planar_embedding[v].begin();
                edge_iter != planar_embedding[v].end(); ++edge_iter
            )
        {
            vertex_t u = get_incident_vertex(v, *edge_iter, graph);
            adjacency_node_t node;
            node.vertex = u;
            augmented_embedding[v].push_back(node);
        }
    }

    // Construct worklist data structure
    std::vector<std::vector<adjacency_node_t>>
        work_list_storage(boost::num_vertices(graph));
    boost::iterator_property_map<
            typename std::vector<std::vector<adjacency_node_t>>
                ::iterator,
            typename boost::property_map<graph_t, boost::vertex_index_t>
                ::const_type
        > work_list_map(
                work_list_storage.begin(),
                boost::get(boost::vertex_index, graph)
            );

    // Reserve deg(v) space for each v in G
    for(boost::tie(v_iter, v_end) = boost::vertices(graph); v_iter != v_end;
            v_iter++
        )
    {
        vertex_t v = *v_iter;
        work_list_map[v].reserve(out_degree(v, graph));
    }

    // Construct the worklist for each vertex
    for(boost::tie(v_iter, v_end) = boost::vertices(graph); v_iter != v_end;
            v_iter++
        )
    {
        vertex_t v = *v_iter;

        for(auto adjacency_node_iter = augmented_embedding[v].begin();
                adjacency_node_iter != augmented_embedding[v].end();
                ++adjacency_node_iter
            )
        {
            vertex_t u = adjacency_node_iter -> vertex;

            adjacency_node_t node;
            node.vertex = v;
            node.iterator = adjacency_node_iter;
            work_list_map[u].push_back(node);
        }
    }

    // Find iterators using worklists
    boost::tie(v_begin, v_iter) = boost::vertices(graph);
    while(v_iter != v_begin) {
        --v_iter;

        vertex_t v = *v_iter;

        for(auto work_list_iter = work_list_map[v].begin();
                work_list_iter != work_list_map[v].end();
                ++work_list_iter
            )
        {
            // Grab the vertex and iterator for this worklist node
            vertex_t u = work_list_iter -> vertex;
            adjacency_node_iterator_t u_v_iterator
                = work_list_iter -> iterator;

            // The node for v must be the last node in u's worklist, so grab it
            adjacency_node_iterator_t v_u_iterator
                = work_list_map[u].back().iterator;

            // Assign u's iterator to v's node and vice versa
            u_v_iterator -> iterator = v_u_iterator;
            v_u_iterator -> iterator = u_v_iterator;

            // Remove the node for v from u's worklist
            work_list_map[u].pop_back();
        }
    }
}

#endif


/* ---------------------------------------------------------------------
 *
 * Copyright (C) 1999 - 2020 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, redistribute
 * it, and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * The full text of the license can be found in the file LICENSE.md at
 * the top level directory of deal.II.
 *
 * ---------------------------------------------------------------------
 *
 * Authors: Wolfgang Bangerth, 1999,
 *          Guido Kanschat, 2011
 *          Luca Heltai, 2021
 */
#include "base_block_problem.h"

#include <deal.II/dofs/dof_renumbering.h>

using namespace dealii;

template <int dim>
BaseBlockProblem<dim>::BaseBlockProblem(
  const std::vector<std::string> component_names,
  const std::string &            problem_name)
  : BaseProblem<dim>(component_names.size(), problem_name)
  , component_names(component_names)
{}

template <int dim>
void
BaseBlockProblem<dim>::setup_system()
{
  TimerOutput::Scope timer_section(this->timer, "setup_system");
  if (!this->fe) // this 其作用就是指向成员函数所作用的对象
    {
      this->fe = FETools::get_fe_by_name<dim>(this->fe_name);
      this->mapping =
        std::make_unique<MappingQGeneric<dim>>(this->mapping_degree);
      const auto vars = dim == 1 ? "x" : dim == 2 ? "x,y" : "x,y,z";
      this->forcing_term.initialize(vars,
                                    this->forcing_term_expression,
                                    this->constants);
      this->exact_solution.initialize(vars,
                                      this->exact_solution_expression,
                                      this->constants);

      this->dirichlet_boundary_condition.initialize(
        vars, this->dirichlet_boundary_conditions_expression, this->constants);

      this->neumann_boundary_condition.initialize(
        vars, this->neumann_boundary_conditions_expression, this->constants);
    }

  this->dof_handler.distribute_dofs(*this->fe);

  // 以顺时针的方式重新编号Dofs。
  std::vector<unsigned int> blocks(this->n_components);
  unsigned int              i = 0;
  Assert(component_names.size() > 0, ExcInternalError());
  AssertDimension(this->n_components, component_names.size());
  blocks[0] = i;
  for (unsigned int j = 1; j < this->n_components; ++j)
    {
      if (component_names[j] == component_names[j - 1])
        blocks[j] = i;
      else
        blocks[j] = ++i;
    }
  DoFRenumbering::component_wise(this->dof_handler, blocks);

  dofs_per_block = DoFTools::count_dofs_per_fe_block(this->dof_handler, blocks);

  locally_owned_dofs =
    this->dof_handler.locally_owned_dofs().split_by_block(dofs_per_block);

  IndexSet non_blocked_locally_relevant_dofs;
  DoFTools::extract_locally_relevant_dofs(this->dof_handler,
                                          non_blocked_locally_relevant_dofs);
  locally_relevant_dofs =
    non_blocked_locally_relevant_dofs.split_by_block(dofs_per_block);

  this->pcout << "Number of degrees of freedom: " << this->dof_handler.n_dofs()
              << " (" << Patterns::Tools::to_string(dofs_per_block) << ")"
              << std::endl;

  this->constraints.clear();
  this->constraints.reinit(non_blocked_locally_relevant_dofs);
  DoFTools::make_hanging_node_constraints(this->dof_handler, this->constraints);

  for (const auto &id : this->dirichlet_ids)
    VectorTools::interpolate_boundary_values(*this->mapping,
                                             this->dof_handler,
                                             id,
                                             this->dirichlet_boundary_condition,
                                             this->constraints);
  this->constraints.close();

  TrilinosWrappers::BlockSparsityPattern dsp(locally_owned_dofs,
                                             locally_owned_dofs,
                                             locally_relevant_dofs,
                                             this->mpi_communicator);

  DoFTools::make_sparsity_pattern(this->dof_handler,
                                  dsp,
                                  this->constraints,
                                  false);
  // SparsityTools::distribute_sparsity_pattern(dsp,
  //                                            locally_owned_dofs,
  //                                            mpi_communicator,
  //                                            locally_relevant_dofs);

  dsp.compress();
  system_block_matrix.reinit(dsp);

  block_solution.reinit(locally_owned_dofs, this->mpi_communicator);
  system_block_rhs.reinit(locally_owned_dofs, this->mpi_communicator);

  locally_relevant_block_solution.reinit(locally_owned_dofs,
                                         locally_relevant_dofs,
                                         this->mpi_communicator);

  this->error_per_cell.reinit(this->triangulation.n_active_cells());

  // 现在调用任何可能需要的东西
  this->setup_system_call_back();
}

template <int dim>
void
BaseBlockProblem<dim>::assemble_system_one_cell(
  const typename DoFHandler<dim>::active_cell_iterator &,
  ScratchData &,
  CopyData &)
{
  Assert(false, ExcPureFunctionCalled());
}

template <int dim>
void
BaseBlockProblem<dim>::copy_one_cell(const CopyData &copy)
{
  this->constraints.distribute_local_to_global(copy.matrices[0],
                                               copy.vectors[0],
                                               copy.local_dof_indices[0],
                                               system_block_matrix,
                                               system_block_rhs);
}

template <int dim>
void
BaseBlockProblem<dim>::assemble_system()
{
  TimerOutput::Scope timer_section(this->timer, "assemble_system");
  QGauss<dim>        quadrature_formula(this->fe->degree + 1);
  QGauss<dim - 1>    face_quadrature_formula(this->fe->degree + 1);

  ScratchData scratch(*this->mapping,
                      *this->fe,
                      quadrature_formula,
                      update_values | update_gradients |
                        update_quadrature_points | update_JxW_values,
                      face_quadrature_formula,
                      update_values | update_quadrature_points |
                        update_JxW_values);

  CopyData copy(this->fe->n_dofs_per_cell());

  auto worker = [&](const auto &cell, auto &scratch, auto &copy) {
    assemble_system_one_cell(cell, scratch, copy);
  };

  auto copier = [&](const auto &copy) { copy_one_cell(copy); };

  using CellFilter =
    FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>;

  WorkStream::run(CellFilter(IteratorFilters::LocallyOwnedCell(),
                             this->dof_handler.begin_active()),
                  CellFilter(IteratorFilters::LocallyOwnedCell(),
                             this->dof_handler.end()),
                  worker,
                  copier,
                  scratch,
                  copy);

  system_block_matrix.compress(VectorOperation::add);
  system_block_rhs.compress(VectorOperation::add);
}

template <int dim>
void
BaseBlockProblem<dim>::solve()
{
  TimerOutput::Scope timer_section(this->timer, "solve");
  // SolverCG<LA::MPI::BlockVector> solver(solver_control);
  // LA::MPI::PreconditionAMG  amg;
  // amg.initialize(system_matrix);
  // solver.solve(system_matrix, solution, system_rhs, amg);
  // constraints.distribute(solution);
  // locally_relevant_solution = solution;
}

template class BaseBlockProblem<1>;
template class BaseBlockProblem<2>;
template class BaseBlockProblem<3>;


<% render(instance) %>
<%= includes((0..x).size) %>

#include <boost/hana/list/list.hpp>
using boost::hana::partition;

<%= render('list/partition/main.cpp') %>


/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

/*************************************************************************************************/

#ifndef ADOBE_EXPRESSION_PARSER_HPP
#define ADOBE_EXPRESSION_PARSER_HPP

#include <adobe/config.hpp>

#include <adobe/array_fwd.hpp>
#include <adobe/istream.hpp>
#include <adobe/dictionary_fwd.hpp>
#include <adobe/implementation/lex_stream_fwd.hpp>

#include <boost/noncopyable.hpp>

/*************************************************************************************************/

namespace adobe {

/*************************************************************************************************/

/*! \page expression_language Expression Language

Underlying the language for Adam and Eve is a common, simple, expression language. The language
supports

\code

expression                  = or_expression ["?" expression ":" expression].

or_expression               = and_expression { "||" and_expression }.
and_expression              = equality_expression { "&&" equality_expression }.
equality_expression         = relational_expression { ("==" | "!=") relational_expression }.
relational_expression       = additive_expression { ("<" | ">" | "<=" | ">=") additive_expression }.
additive_expression         = multiplicative_expression { ("+" | "-") multiplicative_expression }.
multiplicative_expression   = unary_expression { ("*" | "/" | "%") unary_expression }.

unary_expression            = postfix_expression | (unary_operator unary_expression).
unary_operator              = "+" | "-" | "!".

postfix_expression          = primary_expression { ("[" expression "]") | ("." identifier) }.

primary_expression          = name | number | boolean | string | "empty" | array | dictionary
                                | variable_or_fuction | ( "(" expression ")" ).

variable_or_function        = identifier ["(" [argument_expression_list] ")"].

array                       = "[" [argument_list] "]".
dictionary                  = "{" named_argument_list "}".

argument_expression_list    = named_argument_list | argument_list.

argument_list               = expression { "," expression }.
named_argument_list         = named_argument { "," named_argument }.
named_argument              = identifier ":" expression.

name                        = "@" (identifier | keyword).
boolean                     = "true" | "false".

\endcode

*/

/*************************************************************************************************/

class expression_parser : public boost::noncopyable
{
 public:

    expression_parser(std::istream& in, const line_position_t& position);

    ~expression_parser();

    const line_position_t& next_position();

    void set_keyword_extension_lookup(const keyword_extension_lookup_proc_t& proc);

//  expression = or_expression ["?" expression ":" expression].
    bool is_expression(array_t&);
    void require_expression(array_t&);

//  or_expression = and_expression { "||" and_expression }.
    bool is_or_expression(array_t&);

//  and_expression = equality_expression { "&&" equality_expression }.
    bool is_and_expression(array_t&);

//  equality_expression = relational_expression { ("==" | "!=") relational_expression }.
    bool is_equality_expression(array_t&);

//  relational_expression = additive_expression { relational_operator additive_expression }.
    bool is_relational_expression(array_t&);

//  additive_expression = multiplicative_expression { ("+" | "-") multiplicative_expression }.
    bool is_additive_expression(array_t&);

    bool is_additive_operator(name_t&);

//  multiplicative_expression = unary_expression { ("*" | "/" | "%" | "div") unary_expression }.
    bool is_multiplicative_expression(array_t&);

    bool is_multiplicative_operator(name_t&);

//  unary_expression = postfix_expression | (unary_operator unary_expression).
    bool is_unary_expression(array_t&);

//  unary_operator = "+" | "-" | "!".
    bool is_unary_operator(name_t&);

//  postfix_expression = primary_expression { ("[" expression "]") | ("." identifier) }.
    bool is_postfix_expression(array_t&);

//  primary_expression = name | number | boolean | string | "empty" | array | dictionary
//      | variable_or_fuction | ( "(" expression ")" ).
    bool is_primary_expression(array_t&);

//  variable_or_fuctiontion = identifier ["(" [argument_expression_list] ")"].
    bool is_variable_or_function(array_t&);

//  argument_expression_list = named_argument_list | argument_list.
    bool is_argument_expression_list(array_t&);

//  array = "[" [argument_list] "]".
    bool is_array(array_t&);

//  dictionary = "{" named_argument_list "}".
    bool is_dictionary(array_t&);

//  argument_list = expression { "," expression }.
    bool is_argument_list(array_t&);

//  named_argument_list = named_argument { "," named_argument }.
    bool is_named_argument_list(array_t&);

//  named_argument = ident ":" expression.
    bool is_named_argument(array_t&);

//  name = "@" (identifier | keyword).
    bool is_name(any_regular_t&);

//  boolean = "true" | "false".
    bool is_boolean(any_regular_t&);

//  relational_operator = "<" | ">" | "<=" | ">=".
    bool is_relational_operator(name_t&);

//  lexical tokens:

    bool is_identifier(name_t&);
    bool is_lead_comment(string_t&);
    bool is_trail_comment(string_t&);

/*
    REVISIT (sparent) : We should provide a protected call to get the token stream and allow
    subclasses to access it directly - but for now we'll stick with the law of Demiter.
*/

 protected:
    const stream_lex_token_t& get_token();
    void putback();

    bool is_token (name_t tokenName, any_regular_t& tokenValue);
    bool is_token (name_t tokenName);
    void require_token (name_t tokenName, any_regular_t& tokenValue);
    void require_token (name_t tokenName);
    bool is_keyword (name_t keywordName);
    void require_keyword (name_t keywordName);

    void throw_exception (const char* errorString);
    void throw_exception (const name_t& found, const name_t& expected);

private:
    class implementation;
    implementation*     object;
};

/*************************************************************************************************/

} // namespace adobe

/*************************************************************************************************/

#endif

/*************************************************************************************************/


/**************************************************************************
 * Copyright (c) 2017-2019 by the mfmg authors                            *
 * All rights reserved.                                                   *
 *                                                                        *
 * This file is part of the mfmg library. mfmg is distributed under a BSD *
 * 3-clause license. For the licensing terms see the LICENSE file in the  *
 * top-level directory                                                    *
 *                                                                        *
 * SPDX-License-Identifier: BSD-3-Clause                                  *
 *************************************************************************/

#define BOOST_TEST_MODULE laplace

#include <deal.II/lac/trilinos_precondition.h>

#include <cstdio>

#include "laplace.hpp"
#include "main.cc"

namespace tt = boost::test_tools;

template <int dim>
class ExactSolution : public dealii::Function<dim>
{
public:
  ExactSolution() = default;

  virtual ~ExactSolution() override = default;

  double value(dealii::Point<dim> const &p,
               unsigned int const component = 0) const override;
};

template <int dim>
double ExactSolution<dim>::value(dealii::Point<dim> const &p,
                                 unsigned int const) const
{
  double val = 1.;
  for (unsigned int d = 0; d < dim; ++d)
    val *= (p[d] - 1.) * p[d];

  return val;
}

template <int dim>
class Source : public dealii::Function<dim>
{
public:
  Source() = default;

  virtual ~Source() override = default;

  double value(dealii::Point<dim> const &p,
               unsigned int const component = 0) const override;
};

template <int dim>
double Source<dim>::value(dealii::Point<dim> const &p, unsigned int const) const
{
  double val = 0.;
  for (unsigned int d = 0; d < dim; ++d)
  {
    double tmp = 1.;
    for (unsigned int i = 0; i < dim; ++i)
      if (i != d)
        tmp *= (p[i] - 1.) * p[i];

    val += -2. * tmp;
  }

  return val;
}

template <int dim>
class MaterialProperty : public dealii::Function<dim>
{
public:
  MaterialProperty() = default;

  virtual ~MaterialProperty() override = default;

  double value(dealii::Point<dim> const &p,
               unsigned int const component = 0) const override;
};

template <int dim>
double MaterialProperty<dim>::value(dealii::Point<dim> const &,
                                    unsigned int const) const
{
  return 1.0;
}

BOOST_AUTO_TEST_CASE(laplace_2d)
{
  MaterialProperty<2> material_property;
  Source<2> source;

  Laplace<2, dealii::TrilinosWrappers::MPI::Vector> laplace(MPI_COMM_WORLD, 2);
  laplace.setup_system(boost::property_tree::ptree());
  laplace.assemble_system(source, material_property);
  dealii::TrilinosWrappers::PreconditionSSOR preconditioner;
  dealii::TrilinosWrappers::MPI::Vector solution =
      laplace.solve(preconditioner);

  // The exact solution is quadratic so the error should be zero.
  ExactSolution<2> exact_solution;
  BOOST_TEST(laplace.compute_error(exact_solution) == 0., tt::tolerance(1e-14));

  laplace.output_results();
  // Remove output file
  unsigned int rank = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
  unsigned int world_size =
      dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
  if (rank == 0)
  {
    BOOST_TEST(
        std::remove(
            ("solution-" + std::to_string(world_size) + ".pvtu").c_str()) == 0);
    for (unsigned int i = 0; i < world_size; ++i)
      BOOST_TEST(std::remove(("solution-" + std::to_string(i) + "-" +
                              std::to_string(world_size) + ".vtu")
                                 .c_str()) == 0);
  }
}

BOOST_AUTO_TEST_CASE(laplace_3d)
{
  MaterialProperty<3> material_property;
  Source<3> source;

  Laplace<3, dealii::TrilinosWrappers::MPI::Vector> laplace(MPI_COMM_WORLD, 2);
  laplace.setup_system(boost::property_tree::ptree());
  laplace.assemble_system(source, material_property);
  dealii::TrilinosWrappers::PreconditionSSOR preconditioner;
  dealii::TrilinosWrappers::MPI::Vector solution =
      laplace.solve(preconditioner);

  // The exact solution is quadratic so the error should be zero.
  ExactSolution<3> exact_solution;
  BOOST_TEST(laplace.compute_error(exact_solution) == 0., tt::tolerance(1e-14));
}


/*
* Copyright (c) by CryptoLab inc.
* This program is licensed under a
* Creative Commons Attribution-NonCommercial 3.0 Unported License.
* You should have received a copy of the license along with this
* work.  If not, see <http://creativecommons.org/licenses/by-nc/3.0/>.
*/
#include "Ring.h"

#include <NTL/BasicThreadPool.h>
#include <NTL/lip.h>
#include <NTL/sp_arith.h>
#include <NTL/tools.h>
#include <NTL/vector.h>
#include <NTL/ZZVec.h>
#include <NTL/lip.h>

#include "EvaluatorUtils.h"
#include "BootContext.h"

Ring::Ring() {

	qpows = new ZZ[logQQ + 1];
	qpows[0] = ZZ(1);
	for (long i = 1; i < logQQ + 1; ++i) {
		qpows[i] = qpows[i - 1] << 1;
	}

	rotGroup = new long[Nh];
	long fivePows = 1;
	for (long i = 0; i < Nh; ++i) {
		rotGroup[i] = fivePows;
		fivePows *= 5;
		fivePows %= M;
	}

	ksiPows = new complex<double>[M + 1];
	for (long j = 0; j < M; ++j) {
		double angle = 2.0 * M_PI * j / M;
		ksiPows[j].real(cos(angle));
		ksiPows[j].imag(sin(angle));
	}
	ksiPows[M] = ksiPows[0];

}

void Ring::arrayBitReverse(complex<double>* vals, long n) {
	for (long i = 1, j = 0; i < n; ++i) {
		long bit = n >> 1;
		for (; j >= bit; bit >>= 1) {
			j -= bit;
		}
		j += bit;
		if (i < j) {
			swap(vals[i], vals[j]);
		}
	}
}

void Ring::EMB(complex<double>* vals, long n) {
	arrayBitReverse(vals, n);
	for (long len = 2; len <= n; len <<= 1) {
		for (long i = 0; i < n; i += len) {
			long lenh = len >> 1;
			long lenq = len << 2;
			long gap = M / lenq;
			for (long j = 0; j < lenh; ++j) {
				long idx = ((rotGroup[j] % lenq)) * gap;
				complex<double> u = vals[i + j];
				complex<double> v = vals[i + j + lenh];
				v *= ksiPows[idx];
				vals[i + j] = u + v;
				vals[i + j + lenh] = u - v;
			}
		}
	}
}

void Ring::EMBInvLazy(complex<double>* vals, long n) {
	for (long len = n; len >= 1; len >>= 1) {
		for (long i = 0; i < n; i += len) {
			long lenh = len >> 1;
			long lenq = len << 2;
			long gap = M / lenq;
			for (long j = 0; j < lenh; ++j) {
				long idx = (lenq - (rotGroup[j] % lenq)) * gap;
				complex<double> u = vals[i + j] + vals[i + j + lenh];
				complex<double> v = vals[i + j] - vals[i + j + lenh];
				v *= ksiPows[idx];
				vals[i + j] = u;
				vals[i + j + lenh] = v;
			}
		}
	}
	arrayBitReverse(vals, n);
}

void Ring::EMBInv(complex<double>* vals, long n) {
	EMBInvLazy(vals, n);
	for (long i = 0; i < n; ++i) {
		vals[i] /= n;
	}
}

void Ring::encode(ZZ* mx, double* vals, long slots, long logp) {
	complex<double>* uvals = new complex<double>[slots];
	long i, jdx, idx;
	for (i = 0; i < slots; ++i) {
		uvals[i].real(vals[i]);
	}

	long gap = Nh / slots;

	EMBInv(uvals, slots);

	for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
		mx[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);
		mx[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);
	}
	delete[] uvals;
}

void Ring::encode(ZZ* mx, complex<double>* vals, long slots, long logp) {
	complex<double>* uvals = new complex<double> [slots];
	long i, jdx, idx;
	copy(vals, vals + slots, uvals);
	long gap = Nh / slots;
	EMBInv(uvals, slots);
	for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
		mx[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);
		mx[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);
	}
	delete[] uvals;
}

void Ring::decode(ZZ* mx, complex<double>* vals, long slots, long logp, long logq) {
	ZZ q = qpows[logq];
	long gap = Nh / slots;
	ZZ tmp;
	for (long i = 0, idx = 0; i < slots; ++i, idx += gap) {
		rem(tmp, mx[idx], q);
		if (NumBits(tmp) == logq) tmp -= q;
		vals[i].real(EvaluatorUtils::scaleDownToReal(tmp, logp));

		rem(tmp, mx[idx + Nh], q);
		if (NumBits(tmp) == logq) tmp -= q;
		vals[i].imag(EvaluatorUtils::scaleDownToReal(tmp, logp));
	}
	EMB(vals, slots);
}

void Ring::addBootContext(long logSlots, long logp) {
	if (bootContextMap.find(logSlots) == bootContextMap.end()) {
		long slots = 1 << logSlots;
		long dslots = slots << 1;
		long logk = logSlots >> 1;

		long k = 1 << logk;
		long i, pos, ki, jdx, idx, deg;
		long gap = Nh >> logSlots;

		long np;

		uint64_t** rpvec = new uint64_t*[slots];
		uint64_t** rpvecInv = new uint64_t*[slots];
		uint64_t* rp1;
		uint64_t* rp2;

		long* bndvec = new long[slots];
		long* bndvecInv = new long[slots];
		long bnd1;
		long bnd2;

		ZZ* pvec = new ZZ[N];
		complex<double>* pvals = new complex<double> [dslots];

		double c = 0.25 / M_PI;

		if (logSlots < logNh) {
			long dgap = gap >> 1;
			for (ki = 0; ki < slots; ki += k) {
				for (pos = ki; pos < ki + k; ++pos) {
					for (i = 0; i < slots - pos; ++i) {
						deg = ((M - rotGroup[i + pos]) * i * gap) % M;
						pvals[i] = ksiPows[deg];
						pvals[i + slots].real(-pvals[i].imag());
						pvals[i + slots].imag(pvals[i].real());
					}
					for (i = slots - pos; i < slots; ++i) {
						deg = ((M - rotGroup[i + pos - slots]) * i * gap) % M;
						pvals[i] = ksiPows[deg];
						pvals[i + slots].real(-pvals[i].imag());
						pvals[i + slots].imag(pvals[i].real());
					}
					EvaluatorUtils::rightRotateAndEqual(pvals, dslots, ki);
					EMBInv(pvals, dslots);
					for (i = 0, jdx = Nh, idx = 0; i < dslots; ++i, jdx += dgap, idx += dgap) {
						pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);
						pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);
					}
					bndvec[pos] = maxBits(pvec, N);
					np = ceil((bndvec[pos] + logQ + 2 * logN + 2)/(double)pbnd);
					rpvec[pos] = new uint64_t[np << logN];
					CRT(rpvec[pos], pvec, np);
					for (i = 0; i < N; ++i) {
						pvec[i] = ZZ::zero();
					}
				}
			}

			for (i = 0; i < slots; ++i) {
				pvals[i] = 0.0;
				pvals[i + slots].real(0);
				pvals[i + slots].imag(-c);
			}
			EMBInv(pvals, dslots);
			for (i = 0, jdx = Nh, idx = 0; i < dslots; ++i, jdx += dgap, idx += dgap) {
				pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);
				pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);
			}
			bnd1 = maxBits(pvec, N);
			np = ceil((bnd1 + logQ + 2 * logN + 2)/(double)pbnd);
			rp1 = new uint64_t[np << logN];
			CRT(rp1, pvec, np);
			for (i = 0; i < N; ++i) {
				pvec[i] = ZZ::zero();
			}

			for (i = 0; i < slots; ++i) {
				pvals[i] = c;
				pvals[i + slots] = 0;
			}

			EMBInv(pvals, dslots);
			for (i = 0, jdx = Nh, idx = 0; i < dslots; ++i, jdx += dgap, idx += dgap) {
				pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);
				pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);
			}
			bnd2 = maxBits(pvec, N);
			np = ceil((bnd2 + logQ + 2 * logN + 2)/(double)pbnd);
			rp2 = new uint64_t[np << logN];
			CRT(rp2, pvec, np);
			for (i = 0; i < N; ++i) {
				pvec[i] = ZZ::zero();
			}

		} else {
			for (ki = 0; ki < slots; ki += k) {
				for (pos = ki; pos < ki + k; ++pos) {
					for (i = 0; i < slots - pos; ++i) {
						deg = ((M - rotGroup[i + pos]) * i * gap) % M;
						pvals[i] = ksiPows[deg];
					}
					for (i = slots - pos; i < slots; ++i) {
						deg = ((M - rotGroup[i + pos - slots]) * i * gap) % M;
						pvals[i] = ksiPows[deg];
					}
					EvaluatorUtils::rightRotateAndEqual(pvals, slots, ki);
					EMBInv(pvals, slots);
					for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
						pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);
						pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);
					}
					bndvec[pos] = maxBits(pvec, N);
					np = ceil((bndvec[pos] + logQ + 2 * logN + 2)/(double)pbnd);
					rpvec[pos] = new uint64_t[np << logN];
					CRT(rpvec[pos], pvec, np);
					for (i = 0; i < N; ++i) {
						pvec[i] = ZZ::zero();
					}
				}
			}
		}

		for (ki = 0; ki < slots; ki += k) {
			for (pos = ki; pos < ki + k; ++pos) {

				for (i = 0; i < slots - pos; ++i) {
					deg = (rotGroup[i] * (i + pos) * gap) % M;
					pvals[i] = ksiPows[deg];
				}
				for (i = slots - pos; i < slots; ++i) {
					deg = (rotGroup[i] * (i + pos - slots) * gap) % M;
					pvals[i] = ksiPows[deg];
				}
				EvaluatorUtils::rightRotateAndEqual(pvals, slots, ki);
				EMBInv(pvals, slots);
				for (i = 0, jdx = Nh, idx = 0; i < slots;++i, jdx += gap, idx += gap) {
					pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);
					pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);
				}
				bndvecInv[pos] = maxBits(pvec, N);
				np = ceil((bndvecInv[pos] + logQ + 2 * logN + 2)/(double)pbnd);
				rpvecInv[pos] = new uint64_t[np << logN];
				CRT(rpvecInv[pos], pvec, np);
				for (i = 0; i < N; ++i) {
					pvec[i] = ZZ::zero();
				}
			}
		}
		delete[] pvals;
		delete[] pvec;

		bootContextMap.insert(pair<long, BootContext*>(logSlots, new BootContext(rpvec, rpvecInv, rp1, rp2, bndvec, bndvecInv, bnd1, bnd2, logp)));
	}
}

//----------------------------------------------------------------------------------
//   MULTIPLICATION
//----------------------------------------------------------------------------------

long Ring::maxBits(const ZZ* f, long n) {
   long i, m;
   m = 0;

   for (i = 0; i < n; i++) {
      m = max(m, NumBits(f[i]));
   }
   return m;
}

void Ring::CRT(uint64_t* rx, ZZ* x, const long np) {
	multiplier.CRT(rx, x, np);
}

void Ring::addNTTAndEqual(uint64_t* ra, uint64_t* rb, const long np) {
	multiplier.addNTTAndEqual(ra, rb, np);
}

void Ring::mult(ZZ* x, ZZ* a, ZZ* b, long np, const ZZ& q) {
	multiplier.mult(x, a, b, np, q);
}

void Ring::multNTT(ZZ* x, ZZ* a, uint64_t* rb, long np, const ZZ& q) {
	multiplier.multNTT(x, a, rb, np, q);
}

void Ring::multDNTT(ZZ* x, uint64_t* ra, uint64_t* rb, long np, const ZZ& q) {
	multiplier.multDNTT(x, ra, rb, np, q);
}

void Ring::multAndEqual(ZZ* a, ZZ* b, long np, const ZZ& q) {
	multiplier.multAndEqual(a, b, np, q);
}

void Ring::multNTTAndEqual(ZZ* a, uint64_t* rb, long np, const ZZ& q) {
	multiplier.multNTTAndEqual(a, rb, np, q);
}

void Ring::square(ZZ* x, ZZ* a, long np, const ZZ& q) {
	multiplier.square(x, a, np, q);
}

void Ring::squareNTT(ZZ* x, uint64_t* ra, long np, const ZZ& q) {
	multiplier.squareNTT(x, ra, np, q);
}

void Ring::squareAndEqual(ZZ* a, long np, const ZZ& q) {
	multiplier.squareAndEqual(a, np, q);
}

//----------------------------------------------------------------------------------
//   OTHER
//----------------------------------------------------------------------------------

void Ring::mod(ZZ* res, ZZ* p, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		res[i] = p[i] % mod;
	}
}

void Ring::modAndEqual(ZZ* p, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		p[i] %= mod;
	}
}

void Ring::negate(ZZ* res, ZZ* p) {
	for (long i = 0; i < N; ++i) {
		res[i] = -p[i];
	}
}

void Ring::negateAndEqual(ZZ* p) {
	for (long i = 0; i < N; ++i) {
		p[i] = -p[i];
	}
}

void Ring::add(ZZ* res, ZZ* p1, ZZ* p2, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		AddMod(res[i], p1[i], p2[i], mod);
	}
}

void Ring::addAndEqual(ZZ* p1, ZZ* p2, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		AddMod(p1[i], p1[i], p2[i], mod);
	}
}

void Ring::sub(ZZ* res, ZZ* p1, ZZ* p2, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		AddMod(res[i], p1[i], -p2[i], mod);
	}
}

void Ring::subAndEqual(ZZ* p1, ZZ* p2, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		AddMod(p1[i], p1[i], -p2[i], mod);
	}
}

void Ring::subAndEqual2(ZZ* p1, ZZ* p2, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		AddMod(p2[i], p1[i], -p2[i], mod);
	}
}

void Ring::multByMonomial(ZZ* res, ZZ* p, long monomialDeg) {
	long shift = monomialDeg % M;
	if (shift == 0) {
		for (long i = 0; i < N; ++i) {
			res[i] = p[i];
		}
	} else {
		ZZ* tmpx = new ZZ[N];
		if (shift < N) {
			for (long i = 0; i < N; ++i) {
				tmpx[i] = p[i];
			}
		} else {
			for (long i = 0; i < N; ++i) {
				tmpx[i] = -p[i];
			}
		}

		shift %= N;

		for (long i = 0; i < shift; ++i) {
			res[i] = -tmpx[N - shift + i];
		}

		for (long i = shift; i < N; ++i) {
			res[i] = tmpx[i - shift];
		}
		delete[] tmpx;
	}
}

void Ring::multByMonomialAndEqual(ZZ* p, long monomialDeg) {
	long shift = monomialDeg % M;
	if (shift == 0) {
		return;
	}
	ZZ* tmpx = new ZZ[N];
	if (shift < N) {
		for (long i = 0; i < N; ++i) {
			tmpx[i] = p[i];
		}
	} else {
		for (long i = 0; i < N; ++i) {
			tmpx[i] = -p[i];
		}
	}

	shift %= N;

	for (long i = 0; i < shift; ++i) {
		p[i] = -tmpx[N - shift + i];
	}

	for (long i = shift; i < N; ++i) {
		p[i] = tmpx[i - shift];
	}

	delete[] tmpx;
}

void Ring::multByConst(ZZ* res, ZZ* p, ZZ& cnst, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		MulMod(res[i], p[i], cnst, mod);
	}
}

void Ring::multByConstAndEqual(ZZ* p, ZZ& cnst, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		MulMod(p[i], p[i], cnst, mod);
	}
}

void Ring::leftShift(ZZ* res, ZZ* p, const long bits, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		res[i] = p[i] << bits;
		res[i] %= mod;
	}
}

void Ring::leftShiftAndEqual(ZZ* p, const long bits, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		p[i] <<= bits;
		p[i] %= mod;
	}
}

void Ring::doubleAndEqual(ZZ* p, const ZZ& mod) {
	for (long i = 0; i < N; ++i) {
		p[i] <<= 1;
		p[i] %= mod;
	}
}

void Ring::rightShift(ZZ* res, ZZ* p, long bits) {
	ZZ tmp = to_ZZ(1) << (bits - 1);
	for (long i = 0; i < N; ++i) {
		res[i] = (p[i] + tmp) >> bits;
		//res[i] = p[i] >> bits;
	}
}

void Ring::rightShiftAndEqual(ZZ* p, long bits) {
	ZZ tmp = to_ZZ(1) << (bits - 1);
	for (long i = 0; i < N; ++i) {
		p[i] += tmp;
		p[i] >>= bits;
	}
}

//----------------------------------------------------------------------------------
//   ROTATION & CONJUGATION
//----------------------------------------------------------------------------------

void Ring::leftRotate(ZZ* res, ZZ* p, long r) {
	long pow = rotGroup[r];
	for (long i = 0; i < N; ++i) {
		long ipow = i * pow;
		long shift = ipow % M;
		if (shift < N) {
			res[shift] = p[i];
		} else {
			res[shift - N] = -p[i];
		}
	}
}

void Ring::conjugate(ZZ* res, ZZ* p) {
	res[0] = p[0];
	for (long i = 1; i < N; ++i) {
		res[i] = -p[N - i];
	}
}

//----------------------------------------------------------------------------------
//   SAMPLING
//----------------------------------------------------------------------------------

void Ring::subFromGaussAndEqual(ZZ* res, const ZZ& q) {
	static double Pi = 4.0 * atan(1.0);
	static long bignum = 0xfffffff;

	for (long i = 0; i < N; i+=2) {
		double r1 = (1 + RandomBnd(bignum)) / ((double)bignum + 1);
		double r2 = (1 + RandomBnd(bignum)) / ((double)bignum + 1);
		double theta=2 * Pi * r1;
		double rr= sqrt(-2.0 * log(r2)) * sigma;

		AddMod(res[i], -res[i], (long) floor(rr * cos(theta) + 0.5), q);
		AddMod(res[i + 1], -res[i + 1], (long) floor(rr * sin(theta) + 0.5), q);
	}
}

void Ring::addGaussAndEqual(ZZ* res, const ZZ& q) {
	static double Pi = 4.0 * atan(1.0);
	static long bignum = 0xfffffff;

	for (long i = 0; i < N; i+=2) {
		double r1 = (1 + RandomBnd(bignum)) / ((double)bignum + 1);
		double r2 = (1 + RandomBnd(bignum)) / ((double)bignum + 1);
		double theta=2 * Pi * r1;
		double rr= sqrt(-2.0 * log(r2)) * sigma;

		AddMod(res[i], res[i], (long) floor(rr * cos(theta) + 0.5), q);
		AddMod(res[i + 1], res[i + 1], (long) floor(rr * sin(theta) + 0.5), q);
	}
}

void Ring::sampleHWT(ZZ* res) {
	long idx = 0;
	ZZ tmp = RandomBits_ZZ(h);
	while(idx < h) {
		long i = RandomBits_long(logN);
		if(res[i] == 0) {
			res[i] = (bit(tmp, idx) == 0) ? ZZ(1) : ZZ(-1);
			idx++;
		}
	}
}

void Ring::sampleZO(ZZ* res) {
	ZZ tmp = RandomBits_ZZ(M);
	for (long i = 0; i < N; ++i) {
		res[i] = (bit(tmp, 2 * i) == 0) ? ZZ(0) : (bit(tmp, 2 * i + 1) == 0) ? ZZ(1) : ZZ(-1);
	}
}

void Ring::sampleUniform2(ZZ* res, long bits) {
	for (long i = 0; i < N; i++) {
		res[i] = RandomBits_ZZ(bits);
	}
}


#include "game/vsr/vsr.h"
#include <game/vsr/cga_op.h>
#include <game/vsr/generic_op.h>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>

#include <Eigen/Dense>
#include <Eigen/Eigenvalues>

#include <iostream>

using vsr::cga::Gen;
using vsr::cga::Vec;
using vsr::cga::Biv;
using vsr::cga::Pnt;
using vsr::cga::Rot;
using vsr::cga::Mot;
using vsr::cga::Trs;
using vsr::cga::Lin;

using namespace vsr::cga;
namespace py = pybind11;

namespace {
template <typename ScalarType, int Rows, int Cols>
py::array_t<ScalarType> Matrix() {
  return py::array(py::buffer_info(
      nullptr, /* Pointer to data (nullptr -> ask NumPy to allocate!) */
      sizeof(ScalarType),                         /* Size of one item */
      py::format_descriptor<ScalarType>::format(), /* Buffer format */
      2,                                          /* How many dimensions? */
      {Rows, Cols}, /* Number of elements for each dimension */
      {sizeof(ScalarType) * Rows, sizeof(ScalarType)}
      /* Strides for each dimension */
      ));
}
}

template <typename MultivectorT>
py::array_t<double> VDMatrix(const MultivectorT &p, const MultivectorT &q) {

  using MotRec = vsr::Multivector<vsr::algebra<vsr::metric<4, 1, true>, double>,
                                  vsr::Basis<0, 3, 5, 6, 9, 10, 12, 15>>;
  std::vector<MotRec> rs;
  rs.reserve(8);

  for (int i = 0; i < 8; ++i) {
    Mot ei;
    ei[i] = 1.0;
    rs[i] = MotRec(~q * ei * p);
  }

  auto matrix = ::Matrix<double, 8, 8>();
  auto buf = matrix.request();
  Eigen::Map<Eigen::Matrix<double, 8, 8>> L(
      reinterpret_cast<double *>(buf.ptr));
  L = Eigen::Matrix<double, 8, 8>::Zero();

  for (int i = 0; i < 8; ++i) {
    for (int j = 0; j < 8; ++j) {
      Mot ei;
      ei[i] = 1.0;
      L(i, j) = (~ei * rs[j])[0];
    }
  }

  return matrix;
}

PYBIND11_PLUGIN(motor_estimation_valkenburg_dorst) {
  py::module m("motor_estimation_valkenburg_dorst",
               "motor_estimation_valkenburg_dorst");
  m.def("point_matrix", &VDMatrix<Pnt>);
  m.def("dual_line_matrix", &VDMatrix<Dll>);
  m.def("dual_plane_matrix", &VDMatrix<Dlp>);
  return m.ptr();
}


#ifndef STAN_MATH_PRIM_ARR_FUNCTOR_integrate_1d_HPP
#define STAN_MATH_PRIM_ARR_FUNCTOR_integrate_1d_HPP

#include <stan/math/prim/scal/err/check_less_or_equal.hpp>
#include <stan/math/prim/scal/err/domain_error.hpp>
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp>
#include <boost/math/quadrature/exp_sinh.hpp>
#include <boost/math/quadrature/sinh_sinh.hpp>
#include <boost/math/quadrature/tanh_sinh.hpp>
#include <functional>
#include <limits>
#include <ostream>
#include <vector>

namespace stan {
namespace math {
/**
 * Integrate a single variable function f from a to b to within a specified
 * relative tolerance. This function assumes a is less than b.
 *
 * The signature for f should be:
 *   double f(double x, double xc)
 *
 * It should return the value of the function evaluated at x.
 *
 * Depending on whether or not a is finite or negative infinity and b is finite
 * or positive infinity, a different version of the 1d quadrature algorithm from
 * the Boost quadrature library is chosen.
 *
 * Integrals that cross zero are broken into two, and the separate integrals are
 * each integrated to the given relative tolerance.
 *
 * For integrals with finite limits, the xc argument is the distance to the
 * nearest boundary. So for a > 0, b > 0, it will be a - x for x closer to a,
 * and b - x for x closer to b. xc is computed in a way that avoids the
 * precision loss of computing a - x or b - x manually. For integrals that cross
 * zero, xc can take values a - x, -x, or b - x depending on which integration
 * limit it is nearest.
 *
 * If either limit is infinite, xc is set to NaN
 *
 * @tparam T Type of f
 * @param f the function to be integrated
 * @param a lower limit of integration
 * @param b upper limit of integration
 * @param relative_tolerance target relative tolerance passed to Boost
 * quadrature
 * @return numeric integral of function f
 */
template <typename F>
inline double integrate(const F& f, double a, double b,
                        double relative_tolerance) {
  double error1 = 0.0;
  double error2 = 0.0;
  double L1 = 0.0;
  double L2 = 0.0;
  bool used_two_integrals = false;
  size_t levels;
  double Q = 0.0;
  if (std::isinf(a) && std::isinf(b)) {
    auto f_wrap = [&](double x) {
      return f(x, std::numeric_limits<double>::quiet_NaN());
    };
    boost::math::quadrature::sinh_sinh<double> integrator;
    Q = integrator.integrate(f_wrap, relative_tolerance, &error1, &L1, &levels);
  } else if (std::isinf(a)) {
    boost::math::quadrature::exp_sinh<double> integrator;
    /**
     * If the integral crosses zero, break it into two (advice from the Boost
     * implementation:
     * https://www.boost.org/doc/libs/1_66_0/libs/math/doc/html/math_toolkit/double_exponential/de_caveats.html)
     */
    if (b <= 0.0) {
      auto f_wrap = [&](double x) {
        return f(-(x + b), std::numeric_limits<double>::quiet_NaN());
      };
      Q = integrator.integrate(f_wrap, relative_tolerance, &error1, &L1,
                               &levels);
    } else {
      boost::math::quadrature::tanh_sinh<double> integrator_right;
      auto f_wrap = [&](double x) {
        return f(-x, std::numeric_limits<double>::quiet_NaN());
      };
      Q = integrator.integrate(f_wrap, relative_tolerance, &error1, &L1,
                               &levels)
          + integrator_right.integrate(f_wrap, -b, 0, relative_tolerance,
                                       &error2, &L2, &levels);
      used_two_integrals = true;
    }
  } else if (std::isinf(b)) {
    boost::math::quadrature::exp_sinh<double> integrator;
    if (a >= 0.0) {
      auto f_wrap = [&](double x) {
        return f(x + a, std::numeric_limits<double>::quiet_NaN());
      };
      Q = integrator.integrate(f_wrap, relative_tolerance, &error1, &L1,
                               &levels);
    } else {
      boost::math::quadrature::tanh_sinh<double> integrator_right;
      auto f_wrap = [&](double x) {
        return f(x, std::numeric_limits<double>::quiet_NaN());
      };
      Q = integrator.integrate(f_wrap, relative_tolerance, &error1, &L1,
                               &levels)
          + integrator_right.integrate(f_wrap, a, 0, relative_tolerance,
                                       &error2, &L2, &levels);
      used_two_integrals = true;
    }
  } else {
    auto f_wrap = [&](double x, double xc) { return f(x, xc); };
    boost::math::quadrature::tanh_sinh<double> integrator;
    if (a < 0.0 && b > 0.0) {
      Q = integrator.integrate(f_wrap, a, 0.0, relative_tolerance, &error1, &L1,
                               &levels)
          + integrator.integrate(f_wrap, 0.0, b, relative_tolerance, &error2,
                                 &L2, &levels);
      used_two_integrals = true;
    } else {
      Q = integrator.integrate(f_wrap, a, b, relative_tolerance, &error1, &L1,
                               &levels);
    }
  }

  static const char* function = "integrate";
  if (used_two_integrals) {
    if (error1 > relative_tolerance * L1) {
      domain_error(function, "error estimate of integral below zero", error1,
                   "",
                   " exceeds the given relative tolerance times norm of "
                   "integral below zero");
    }
    if (error2 > relative_tolerance * L2) {
      domain_error(function, "error estimate of integral above zero", error2,
                   "",
                   " exceeds the given relative tolerance times norm of "
                   "integral above zero");
    }
  } else {
    if (error1 > relative_tolerance * L1) {
      domain_error(
          function, "error estimate of integral", error1, "",
          " exceeds the given relative tolerance times norm of integral");
    }
  }
  return Q;
}

/**
 * Compute the integral of the single variable function f from a to b to within
 * a specified relative tolerance. a and b can be finite or infinite.
 *
 * The signature for f should be:
 *   double f(double x, double xc, const std::vector<double>& theta,
 *     const std::vector<double>& x_r, const std::vector<int>& x_i,
 * std::ostream* msgs)
 *
 * It should return the value of the function evaluated at x. Any errors
 * should be printed to the msgs stream.
 *
 * Integrals that cross zero are broken into two, and the separate integrals are
 * each integrated to the given relative tolerance.
 *
 * For integrals with finite limits, the xc argument is the distance to the
 * nearest boundary. So for a > 0, b > 0, it will be a - x for x closer to a,
 * and b - x for x closer to b. xc is computed in a way that avoids the
 * precision loss of computing a - x or b - x manually. For integrals that cross
 * zero, xc can take values a - x, -x, or b - x depending on which integration
 * limit it is nearest.
 *
 * If either limit is infinite, xc is set to NaN
 *
 * The integration algorithm terminates when
 *   \f[
 *     \frac{{|I_{n + 1} - I_n|}}{{|I|_{n + 1}}} < \text{relative tolerance}
 *   \f]
 * where \f$I_{n}\f$ is the nth estimate of the integral and \f$|I|_{n}\f$ is
 * the nth estimate of the norm of the integral.
 *
 * Integrals that cross zero are
 * split into two. In this case, each integral is separately integrated to the
 * given relative_tolerance.
 *
 * @tparam T Type of f
 * @param f the function to be integrated
 * @param a lower limit of integration
 * @param b upper limit of integration
 * @param theta additional parameters to be passed to f
 * @param x_r additional data to be passed to f
 * @param x_i additional integer data to be passed to f
 * @param[in, out] msgs the print stream for warning messages
 * @param relative_tolerance tolerance passed to Boost quadrature
 * @return numeric integral of function f
 */
template <typename F>
inline double integrate_1d(
    const F& f, const double a, const double b,
    const std::vector<double>& theta, const std::vector<double>& x_r,
    const std::vector<int>& x_i, std::ostream& msgs,
    const double relative_tolerance
    = std::sqrt(std::numeric_limits<double>::epsilon())) {
  static const char* function = "integrate_1d";
  check_less_or_equal(function, "lower limit", a, b);

  if (a == b) {
    if (std::isinf(a))
      domain_error(function, "Integration endpoints are both", a, "", "");
    return 0.0;
  } else {
    return integrate(
        std::bind<double>(f, std::placeholders::_1, std::placeholders::_2,
                          theta, x_r, x_i, &msgs),
        a, b, relative_tolerance);
  }
}

}  // namespace math
}  // namespace stan

#endif


#include <cfloat>
#include <tgmath.h>
#include <iomanip>
#include <boost/lexical_cast.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <tuw_geometry/world_scoped_maps.h>
#include <tuw_geometry/utils.h>

using namespace tuw;

WorldScopedMaps::WorldScopedMaps () :
  width_pixel_ (-1),
  height_pixel_(-1),
  min_x_(0), max_x_(0), min_y_(0), max_y_(0) {

}

bool WorldScopedMaps::initialized() {
  return ((width_pixel_ != -1) && (height_pixel_ != -1));
}

void WorldScopedMaps::init () {

    dx_ = max_x_ - min_x_;
    dy_ = max_y_ - min_y_;
    sx_ = width_pixel_  / dx_;
    sy_ = height_pixel_ / dy_;
    ox_ = width_pixel_  / 2.0;
    oy_ = height_pixel_ / 2.0;
    double ca = cos ( rotation_ ), sa = sin ( rotation_ );
    mx_ = min_x_ + dx_/2.;
    my_ = min_y_ + dy_/2.;
    cv::Matx<double, 3, 3 > Tw ( 1, 0, -mx_, 0, 1, -my_, 0, 0, 1 ); // translation
    cv::Matx<double, 3, 3 > Sc ( sx_, 0, 0, 0, sy_, 0, 0, 0, 1 );   // scaling
    cv::Matx<double, 3, 3 > Sp ( -1, 0, 0, 0, 1, 0, 0, 0, 1 );      // mirroring
    cv::Matx<double, 3, 3 > R ( ca, -sa, 0, sa, ca, 0, 0, 0, 1 );   // rotation
    cv::Matx<double, 3, 3 > Tm ( 1, 0, ox_, 0, 1, oy_, 0, 0, 1 );   // translation
    Mw2m_ = Tm * R * Sp * Sc * Tw;

    Mm2w_ = Mw2m_.inv();
}
void WorldScopedMaps::init ( int width_pixel, int height_pixel, double min_x, double max_x, double min_y, double max_y, double rotation ) {
    width_pixel_ = width_pixel,   height_pixel_ = height_pixel;
    min_y_ = std::min ( min_y, max_y );
    max_y_ = std::max ( min_y, max_y );
    min_x_ = std::min ( min_x, max_x );
    max_x_ = std::max ( min_x, max_x );
    rotation_ = rotation;

    init();
}

const cv::Matx33d  &WorldScopedMaps::Mw2m () const {
    return Mw2m_;
}
const cv::Matx33d  &WorldScopedMaps::Mm2w () const {
    return Mm2w_;
}
Point2D WorldScopedMaps::w2m ( const Point2D &src ) const {
    return Mw2m_ * src;
}
Point2D WorldScopedMaps::w2m ( double x, double y ) const {
    return w2m(Point2D(x,y));
}
Point2D &WorldScopedMaps::w2m ( const Point2D &src, Point2D &des ) const {
    des = Mw2m_ * src;
    return des;
}
Point2D WorldScopedMaps::m2w ( const Point2D &src ) const {
    return Mm2w_ * src;
}
Point2D WorldScopedMaps::m2w ( double x, double y ) const {
    return m2w(Point2D(x,y));
}
Point2D &WorldScopedMaps::m2w ( const Point2D &src, Point2D &des ) const {
    des = Mm2w_ * src;
    return des;
}
double WorldScopedMaps::max_x () const {
    return max_x_;
}
double WorldScopedMaps::min_x () const  {
    return min_x_;
}
double WorldScopedMaps::scale_x () const  {
    return sx_;
}
double WorldScopedMaps::max_y () const  {
    return max_y_;
}
double WorldScopedMaps::min_y () const  {
    return min_y_;
}
double WorldScopedMaps::scale_y () const  {
    return sy_;
}
int WorldScopedMaps::width () const {
    return width_pixel_;
}
int WorldScopedMaps::height () const {
    return height_pixel_;
}

double WorldScopedMaps::scale_w2m (double v) const {
    return v * sx_;
}
std::string WorldScopedMaps::infoHeader() const{
    char buffer[0x1FF];
    Point2D p0 = m2w(0, 0);
    Point2D p1 = m2w(width_pixel_/2, height_pixel_/2);
    sprintf(buffer, "%4i,%4i [px];  %6.2f, %6.2f [m] => %6.2f, %6.2f [px/m]; 0, 0 [px] = %6.2f, %6.2f [m] @ %3.2f [rad]; %4i, %4i [px] = %6.2f, %6.2f [m] @ %3.2f [rad]",
            width_pixel_, height_pixel_, dx_, dy_, sx_, sy_, p0.x(), p0.y(), rotation_, width_pixel_/2, height_pixel_/2, p1.x(), p1.y(), rotation_);
    return std::string(buffer);
}


#ifndef MOCHIMOCHI_MPA_HPP_
#define MOCHIMOCHI_MPA_HPP_

#include <algorithm>
#include <unordered_map>
#include <boost/range/irange.hpp>
#include "../binary/pa.hpp"

class MPA {
private:
  const std::size_t kClass;

private:
  std::unordered_map<std::size_t, PA> _pas;

public:
  MPA(const std::size_t dim, const std::size_t n_class, const double C, const int select = 2)
    : kClass(n_class) {
    static_assert(std::numeric_limits<decltype(n_class)>::max() > 2, "Class range Error. (n_class > 2)");

    for (const auto i : boost::irange<std::size_t>(1, kClass + 1)) {
      _pas.insert(std::pair<std::size_t, PA>(i, PA(dim, C, select)) );
    }
  }

  virtual ~MPA() { }

public:
  void update(const Eigen::VectorXd& feature, const std::size_t label) {
    for(auto& pa : _pas) {
      const auto t = (pa.first == label) ? 1 : -1;
      pa.second.update(feature, t);
    }
  }

  std::size_t predict(const Eigen::VectorXd& feature) const {
    return std::max_element(_pas.begin(), _pas.end(),
                            [&](const auto& p1, const auto& p2) {
                              return p1.second.get_weight().dot(feature) < p2.second.get_weight().dot(feature);
                            })->first;
  }

};

#endif //MOCHIMOCHI_MPA_HPP_