#ifndef PYTHONIC_TYPES_NUMPY_GEXPR_HPP
#define PYTHONIC_TYPES_NUMPY_GEXPR_HPP

#include "pythonic/utils/meta.hpp"
#ifdef USE_BOOST_SIMD
#include <boost/simd/sdk/simd/native.hpp>
#include <boost/simd/include/functions/store.hpp>
#endif

namespace pythonic {

    namespace types {

        /* helper to count new axis
         */
        template <class... T> struct count_new_axis;

        template <> struct count_new_axis<types::none_type> {
          static constexpr size_t value = 1;
        };
        template <class T> struct count_new_axis<T> {
          static constexpr size_t value = 0;
        };
        template <class T0, class... T> struct count_new_axis<T0, T...> {
          static constexpr size_t value =
              count_new_axis<T0>::value + count_new_axis<T...>::value;
        };

        /* helper to turn a new axis into a slice
         */
        template<class T>
          struct to_slice {
            typedef T type;
            static constexpr bool is_new_axis = false;
            T operator()(T value) { return value; }
          };
        template<>
          struct to_slice<none_type> {
            typedef contiguous_slice type;
            static constexpr bool is_new_axis = true;
            contiguous_slice operator()(none_type) { return contiguous_slice{none_type{}, none_type{}}; }
          };

        /* helper to build a new shape out of a shape and a slice with new axis
         */
        template<size_t N, size_t M, size_t C>
          array<long, N> make_reshape(array<long, M> const& shape, array<bool, C> const& is_new_axis) {
            array<long, N> new_shape;
            size_t j = 0;
            for(size_t i = 0; i < C; ++i)
              if(is_new_axis[i])
                new_shape[i] = 1;
              else
                new_shape[i] = shape [j++];
            for(size_t i = C; i < N; ++i)
              new_shape[i] = shape [i + j - C];
            return new_shape;
          };

        /* helper to build an extended slice aka numpy_gexpr out of a subscript
         */
        template<size_t C>
          struct extended_slice {
            template<class T, size_t N, class... S>
              numpy_gexpr<ndarray<T, N + C>, typename to_slice<S>::type...> operator()(ndarray<T,N>&& a, S const&... s)
              {
                return numpy_gexpr<ndarray<T, N + C>, typename to_slice<S>::type...>{
                  std::move(a).reshape(
                      make_reshape<N + C>(a.shape,
                                          array<bool, sizeof...(S)>{to_slice<S>::is_new_axis...})
                      ),
                  to_slice<S>{}(s)...
                };
              }
            template<class T, size_t N, class... S>
              numpy_gexpr<ndarray<T, N + C>, typename to_slice<S>::type...> operator()(ndarray<T,N> const& a, S const&... s)
              {
                return numpy_gexpr<ndarray<T, N + C>, typename to_slice<S>::type...>{
                  a.reshape(
                      make_reshape<N + C>(a.shape,
                                          array<bool, sizeof...(S)>{{to_slice<S>::is_new_axis...}})
                      ),
                  to_slice<S>{}(s)...
                };
              }
          };
        template<>
          struct extended_slice<0> {
            template<class T, size_t N, class... S>
              auto operator()(ndarray<T,N>&& a, long s0, S const&... s)
              -> decltype(std::declval<numpy_iexpr<ndarray<T,N>>>()(s...))
              {
                return std::move(a)[s0](s...);
              }
            template<class T, size_t N, class... S>
              auto operator()(ndarray<T,N> const& a, long s0, S const&... s)
              -> decltype(a[s0](s...))
              {
                return a[s0](s...);
              }
            template<class T, size_t N, class ...S>
                numpy_gexpr<ndarray<T,N> const &, slice, S...> operator()(ndarray<T,N> const& a, slice const& s0, S const&... s)
                {
                    return numpy_gexpr<ndarray<T,N> const &, slice, S...>(a, s0, s...);
                }
            template<class T, size_t N, class ...S>
                numpy_gexpr<ndarray<T,N> const &, contiguous_slice, S...> operator()(ndarray<T,N> const& a, contiguous_slice const& s0, S const&... s)
                {
                    return make_gexpr(a, s0, s...);
                }
          };

        template<size_t L>
            struct nget;
        /* manually unrolled copy function
         */
        template <size_t I> struct flat_copy;
        template<> struct flat_copy<0> { void operator()(long*, long const*){}};
        template<size_t I> struct flat_copy { void operator()(long* to, long const* from){ to[I-1] = from[I-1] ; flat_copy<I-1>()(to, from); }};

        /* Meta-Function to count the number of slices in a type list
         */
        template<class... Types>
            struct count_long;
        template<>
            struct count_long<long> {
                static constexpr size_t value = 1;
            };
        template<>
            struct count_long<slice> {
                static constexpr size_t value = 0;
            };
        template<>
            struct count_long<contiguous_slice> {
                static constexpr size_t value = 0;
            };

        template<class T, class... Types>
            struct count_long<T, Types...> {
                static constexpr size_t value = count_long<T>::value + count_long<Types...>::value;
            };
        template<>
            struct count_long<> {
                static constexpr size_t value = 0;
            };

        /* helper to get the type of the nth element of an array
         */
        template<class T, size_t N>
            struct nth_value_type {
                typedef typename nth_value_type<typename T::value_type, N-1>::type type;
            };

        template<class T>
            struct nth_value_type<T, 0> {
                typedef T type;
            };
        /* helper that yields true if the first slice of a pack is a contiguous slice
         */
        template<class... S>
            struct is_contiguous {
                static const bool value = false;
            };
        template<class... S>
            struct is_contiguous<contiguous_slice, S...> {
                static const bool value = true;
            };

        /* numpy_gexpr factory
         *
         * replaces the constructor, in order to properly merge gexpr composition into a single gexpr
         */
        namespace details {

          // this struct is specialized for every type combination and takes care of the slice merge
          template<class T, class Tp>
            struct merge_gexpr;

          template<>
          struct merge_gexpr<std::tuple<>, std::tuple<>> {
              std::tuple<> const& operator()(std::tuple<> const &t0, std::tuple<> const&)
              {
                return t0;
              }
            };

          template <class... T0>
          struct merge_gexpr<std::tuple<T0...>, std::tuple<>> {
              std::tuple<T0...> const &operator()(std::tuple<T0...> const &t0, std::tuple<>) {
                return t0;
              }
          };

          template <class... T1>
          struct merge_gexpr<std::tuple<>, std::tuple<T1...>> {
            std::tuple<T1...> const & operator()(std::tuple<>, std::tuple<T1...> const &t1) {
              return t1;
            }
          };

          template <class S0, class... T0, class S1, class... T1>
          struct merge_gexpr<std::tuple<S0, T0...>, std::tuple<S1, T1...>> {
            auto operator()(std::tuple<S0, T0...> const &t0,
                             std::tuple<S1, T1...> const &t1)
                -> decltype(std::tuple_cat(std::make_tuple(std::get<0>(t0) *
                                                           std::get<0>(t1)),
                                           merge_gexpr<std::tuple<T0...>, std::tuple<T1...>>{}(tuple_tail(t0), tuple_tail(t1))))
            {
              return std::tuple_cat(std::make_tuple(std::get<0>(t0) * std::get<0>(t1)),
                                    merge_gexpr<std::tuple<T0...>, std::tuple<T1...>>{}(tuple_tail(t0), tuple_tail(t1)));
            }
          };

          template <class... T0, class S1, class... T1>
          struct merge_gexpr<std::tuple<long, T0...>, std::tuple<S1, T1...>> {
            auto operator()(std::tuple<long, T0...> const &t0, std::tuple<S1, T1...> const &t1)
            -> decltype(std::tuple_cat(std::make_tuple(std::get<0>(t0)),
                                           merge_gexpr<std::tuple<T0...>, std::tuple< S1, T1...>>{}(tuple_tail(t0), t1)))
            {
              return std::tuple_cat(std::make_tuple(std::get<0>(t0)),
                                    merge_gexpr<std::tuple<T0...>, std::tuple<S1, T1...>>{}(tuple_tail(t0), t1));
            }
          };

          template <class S0, class... T0, class... T1>
            struct merge_gexpr<std::tuple<S0, T0...>, std::tuple<long, T1...>>
            {
              auto operator()(std::tuple<S0, T0...> const &t0, std::tuple<long, T1...> const &t1)
              -> decltype(std::tuple_cat(
                      std::make_tuple(std::get<0>(t1) * std::get<0>(t0).step + std::get<0>(t0).lower),
                      merge_gexpr<std::tuple<T0...>, std::tuple<T1...>>{}(tuple_tail(t0), tuple_tail(t1))))
              {
                return std::tuple_cat(std::make_tuple(std::get<0>(t1) * std::get<0>(t0).step + std::get<0>(t0).lower),
                                      merge_gexpr<std::tuple<T0...>, std::tuple<T1...>>{}(tuple_tail(t0), tuple_tail(t1)));
              }
            };

          template <class... T0, class... T1>
            struct merge_gexpr<std::tuple<long, T0...>, std::tuple<long, T1...>> {
              auto operator()(std::tuple<long, T0...> const &t0,
                              std::tuple<long, T1...> const &t1)
              -> decltype(std::tuple_cat(std::make_tuple(std::get<0>(t0)),
                                         merge_gexpr<std::tuple<T0...>, std::tuple<long, T1...>>{}(tuple_tail(t0), t1)))
              {
                return std::tuple_cat(std::make_tuple(std::get<0>(t0)),
                                      merge_gexpr<std::tuple<T0...>, std::tuple<long, T1...>>{}(tuple_tail(t0), t1));
              }
            };

          template <class Arg, class... Sp>
          numpy_gexpr<Arg, Sp...> _make_gexpr(Arg arg, std::tuple<Sp...> const &t) {
            return {arg, t};
          }

          template<class Arg, class... S>
            struct make_gexpr {
              numpy_gexpr<Arg, S...> operator()(Arg arg, S const&...s) {
                return {arg, s...};
              }
            };
          // this specialization is in charge of merging gexpr
          template<class Arg, class...S, class... Sp>
            struct make_gexpr<numpy_gexpr<Arg,S...> const&, Sp...> {
              auto operator()(numpy_gexpr<Arg,S...> const& arg, Sp const&...s)
              -> decltype(_make_gexpr(std::declval<Arg>(), merge_gexpr<std::tuple<S...>, std::tuple<Sp...>>{}(std::tuple<S...>(),  std::tuple<Sp...>())))
              { return {arg.arg, merge_gexpr<std::tuple<S...>, std::tuple<Sp...>>{}(arg.slices, std::make_tuple(s...))}; }
            };

        }

        template<class Arg, class... S>
          auto make_gexpr(Arg && arg, S const&...s)
          -> decltype(details::make_gexpr<Arg, S...>{}(std::forward<Arg>(arg), s...))
          { return details::make_gexpr<Arg, S...>{}(std::forward<Arg>(arg), s...); }

        /* type-based compile time overlapping detection: detect if a type may overlap with another
         * the goal is to detect whether the following operation
         *
         * a[...] = b
         *
         * requires a copy.
         *
         * It requires a copy if b = a[...], as in
         *
         * a[1:] = a[:-1]
         *
         * because this is *not* equivalent to for i in range(0, n-1): a[i+1] = a[i]
         *
         * to avoid the copy, we rely on the lhs type
         */

        template<class E>
          struct may_overlap_gexpr : std::integral_constant<bool, not std::is_scalar<E>::value and not is_complex<E>::value> {};
        template<class E>
          struct may_overlap_gexpr<E&> : may_overlap_gexpr<E> {};
        template<class E>
          struct may_overlap_gexpr<E const &> : may_overlap_gexpr<E> {};
        template<class T, size_t N>
          struct may_overlap_gexpr<ndarray<T,N>> : std::false_type {};
        template<class E>
          struct may_overlap_gexpr<numpy_iexpr<E>> : may_overlap_gexpr<E> {};
        template<class E>
          struct may_overlap_gexpr<numpy_texpr<E>> : may_overlap_gexpr<E> {};
        template<class E>
          struct may_overlap_gexpr<list<E>> : may_overlap_gexpr<E> {};
        template<class E, size_t N>
          struct may_overlap_gexpr<array<E, N>> : may_overlap_gexpr<E> {};
        template<class Op, class... Args>
          struct may_overlap_gexpr<numpy_expr<Op, Args...>> : utils::any_of<may_overlap_gexpr<Args>::value...> {};

        template <class Arg, class... S>
            struct numpy_gexpr_helper;

        /* Expression template for numpy expressions - extended slicing operators
         */
        template<class Arg, class... S>
            struct numpy_gexpr {
                // numpy_gexpr is a wrapper for extended sliced array around a numpy expression.
                // It contains compacted sorted slices value in lower, step and upper is the same as shape.
                // indices for long index are store in the indices array.
                // position for slice and long value in the extended slice can be found through the S... template
                // and compacted values as we know that first S is a slice.

                typedef typename std::remove_reference<Arg>::type::dtype dtype;
                static constexpr size_t value = std::remove_reference<Arg>::type::value - count_long<S...>::value;

                // It is not possible to vectorize everything. We only vectorize if the last dimension is contiguous, which happens if
                // 1. Arg is an ndarray (this is too strict)
                // 2. the size of the gexpr is lower than the dim of arg, or it's the same, but the last slice is contiguous
                static const bool is_vectorizable =
                  std::is_same<ndarray<typename std::remove_reference<Arg>::type::dtype, std::remove_reference<Arg>::type::value>,
                               typename std::remove_cv<typename std::remove_reference<Arg>::type>::type
                              >::value and
                  (
                    sizeof...(S) < std::remove_reference<Arg>::type::value or
                    std::is_same<contiguous_slice, typename std::tuple_element<sizeof...(S) - 1, std::tuple<S...>>::type>::value
                  );
                static const bool is_strided =
                    std::remove_reference<Arg>::type::is_strided or
                    (((sizeof...(S) - count_long<S...>::value) == value)
                    and  not std::is_same<contiguous_slice, typename std::tuple_element<sizeof...(S) - 1, std::tuple<S...>>::type>::value);

                typedef typename std::remove_reference<decltype(numpy_gexpr_helper<Arg, S...>::get(std::declval<numpy_gexpr>(), 0L))>::type value_type;

                typedef typename std::conditional<
                  is_strided or value != 1,
                  nditerator<numpy_gexpr>,
                  dtype*
                >::type iterator;
                typedef typename std::conditional<
                  is_strided or value != 1,
                  const_nditerator<numpy_gexpr>,
                  dtype const*
                >::type const_iterator;

                Arg arg;
                std::tuple<S...> slices;
                dtype* buffer;
                array<long, value> shape;
                array<long, value> lower;
                array<long, value> step;
                array<long, std::remove_reference<Arg>::type::value - value> indices;

                numpy_gexpr() {}
                numpy_gexpr(numpy_gexpr const & ) = default;
                numpy_gexpr(numpy_gexpr && ) = default;

                template<class Argp> // not using the default one, to make it possible to accept reference and non reference version of Argp
                numpy_gexpr(numpy_gexpr<Argp, S...> const& other) :
                    arg(other.arg),
                    slices(other.slices),
                    buffer(other.buffer),
                    shape(other.shape),
                    lower(other.lower),
                    step(other.step),
                    indices(other.indices)
                {
                  static_assert(std::is_same<typename returnable<Arg>::type, typename returnable<Argp>::type>::value,
                     "this constructor is only here to adapt reference / non reference type, nothing else");
                }

                template<size_t J, class Slice>
                typename std::enable_if<std::is_same<Slice, slice>::value
                                          or std::is_same<Slice, contiguous_slice>::value,
                                        void>::type
                init_shape(std::tuple<S const &...> const& values, Slice const& s, utils::int_<1>, utils::int_<J>) {
                    auto ns = s.normalize(arg.shape[sizeof...(S) - 1]);
                    lower[J] = ns.lower;
                    step[J] = ns.step;
                    shape[J] = ns.size();
                }

                template<size_t I, size_t J, class Slice>
                    typename std::enable_if<std::is_same<Slice, slice>::value
                                              or std::is_same<Slice, contiguous_slice>::value,
                                            void>::type
                    init_shape(std::tuple<S const&...> const & values, Slice const& s, utils::int_<I>, utils::int_<J>) {
                        auto ns = s.normalize(arg.shape[sizeof...(S) - I]);
                        lower[J] = ns.lower;
                        step[J] = ns.step;
                        shape[J] = ns.size();
                        init_shape(values, std::get<sizeof...(S) - I + 1>(values), utils::int_<I - 1>(), utils::int_<J + 1>());
                    }

                template<size_t J>
                void init_shape(std::tuple<S const &...> const& values, long cs, utils::int_<1>, utils::int_<J>) {
                    if(cs < 0) cs += arg.shape[sizeof...(S) - 1];
                    indices[sizeof...(S) - 1 - J] = cs;
                }

                template<size_t I, size_t J>
                    void init_shape(std::tuple<S const&...> const & values, long cs, utils::int_<I>, utils::int_<J>) {
                        if(cs < 0) cs += arg.shape[sizeof...(S) - I];
                        indices[sizeof...(S) - I - J] = cs;
                        init_shape(values, std::get<sizeof...(S) - I + 1>(values), utils::int_<I - 1>(), utils::int_<J>());
                    }

              // private because we must use the make_gexpr factory to create a gexpr
              private:
                template<class _Arg, class... _S>
                friend struct details::make_gexpr;

                template<class E>
                friend struct ::pythonic::python_to_pythran;

                template<size_t C>
                friend struct extended_slice;

                // When we create a new numpy_gexpr, we deduce step, lower and shape from slices
                // and indices from long value.
                // Also, last shape information are set from origin array like in :
                // >>> a = numpy.arange(2*3*4).reshape(2,3,4)
                // >>> a[:, 1]
                // the last dimension (4) is missing from slice information
                // Finally, if origin expression was already sliced, lower bound and step have to
                // be increased
                numpy_gexpr(Arg const &arg, std::tuple<S const &...> const& values) : arg(arg), slices(values), buffer(arg.buffer) {
                    init_shape(values, std::get<0>(values), utils::int_<sizeof...(S)>(), utils::int_<0>());
                    for(size_t i = sizeof...(S) - count_long<S...>::value; i < value; ++i)
                        shape[i] = arg.shape[i + count_long<S...>::value];
                }
                numpy_gexpr(Arg const &arg, S const &...s) : numpy_gexpr(arg, std::tuple<S const&...>(s...)) {
                }

              public:

                template<class Argp, class... Sp>
                numpy_gexpr(numpy_gexpr<Argp, Sp...> const &expr, Arg arg) : arg(arg), slices(tuple_pop(expr.slices)), buffer(arg.buffer) {
                  flat_copy<value>()(&shape[0], &expr.shape[1]);
                  flat_copy<value>()(&lower[0], &expr.lower[1]);
                  flat_copy<value>()(&step[0], &expr.step[1]);
                  flat_copy<Arg::value - value>()(&indices[0], &expr.indices[0]);
                }

                template<class G>
                numpy_gexpr(G const &expr, Arg &&arg) : arg(std::forward<Arg>(arg)), slices(tuple_pop(expr.slices)), buffer(arg.buffer) {
                  flat_copy<value>()(&shape[0], &expr.shape[1]);
                  flat_copy<value>()(&lower[0], &expr.lower[1]);
                  flat_copy<value>()(&step[0], &expr.step[1]);
                }

                template<class E>
                  typename std::enable_if<may_overlap_gexpr<E>::value, numpy_gexpr&>::type
                  _copy(E const& expr) {
                    return utils::broadcast_copy<numpy_gexpr&, ndarray<typename E::dtype, E::value>, value, value - utils::dim_of<E>::value,
                                                 is_vectorizable>(*this, ndarray<typename E::dtype, E::value>{expr});
                  }
                template<class E>
                  typename std::enable_if<not may_overlap_gexpr<E>::value, numpy_gexpr&>::type
                  _copy(E const& expr) {
                    return utils::broadcast_copy<numpy_gexpr&, E, value, value - utils::dim_of<E>::value,
                                                 is_vectorizable and is_vectorizable_array<E>::value>(*this, expr);
                  }

                template<class E>
                numpy_gexpr& operator=(E const& expr) {
                  return _copy(expr);
                }
                numpy_gexpr& operator=(numpy_gexpr const& expr) {
                  return _copy(expr);
                }
                template<class E>
                numpy_gexpr& operator+=(E const& expr) {
                    return (*this) = (*this) + expr;
                }
                numpy_gexpr& operator+=(numpy_gexpr const& expr) {
                    return (*this) = (*this) + expr;
                }
                template<class E>
                numpy_gexpr& operator-=(E const& expr) {
                    return (*this) = (*this) - expr;
                }
                numpy_gexpr& operator-=(numpy_gexpr const& expr) {
                    return (*this) = (*this) - expr;
                }
                template<class E>
                numpy_gexpr& operator*=(E const& expr) {
                    return (*this) = (*this) * expr;
                }
                numpy_gexpr& operator*=(numpy_gexpr const& expr) {
                    return (*this) = (*this) * expr;
                }
                template<class E>
                numpy_gexpr& operator/=(E const& expr) {
                    return (*this) = (*this) / expr;
                }
                numpy_gexpr& operator/=(numpy_gexpr const& expr) {
                    return (*this) = (*this) / expr;
                }

                const_iterator begin() const {
                  return make_const_nditerator<is_strided or value != 1>()(*this, (is_strided or value != 1) ?0 : lower[0]); }
                const_iterator end() const { return make_const_nditerator<is_strided or value != 1>()(*this, ((is_strided or value != 1) ?0 : lower[0]) + shape[0]); }

                iterator begin() { return make_nditerator<is_strided or value != 1>()(*this, (is_strided or value != 1) ?0 : lower[0]); }
                iterator end() { return make_nditerator<is_strided or value != 1>()(*this, ((is_strided or value != 1) ?0 : lower[0]) + shape[0]); }

                auto fast(long i) const -> decltype(numpy_gexpr_helper<Arg, S...>::get(*this, i)) {
                    return numpy_gexpr_helper<Arg, S...>::get(*this, lower[0] + (is_contiguous<S...>::value ? i : step[0] * i));
                }
                auto fast(long i) -> decltype(numpy_gexpr_helper<Arg, S...>::get(*this, i)) {
                    return numpy_gexpr_helper<Arg, S...>::get(*this, lower[0] + (is_contiguous<S...>::value ? i : step[0] * i));
                }

#ifdef USE_BOOST_SIMD
                template<class I>
                auto load(I i) const
                -> decltype(boost::simd::load<boost::simd::native<dtype, BOOST_SIMD_DEFAULT_EXTENSION>>(this->buffer, i))
                {
                  typedef dtype T;
                  typedef typename boost::simd::native<T, BOOST_SIMD_DEFAULT_EXTENSION> vT;
                  return boost::simd::load<vT>(buffer, lower[0] + i);
                }
                template<class V>
                void store(V &&v, long i) {
                  boost::simd::store(v, buffer, lower[0] + i);
                }

#endif

                auto operator[](long i) const -> decltype(this->fast(i)) {
                    if(i<0) i += shape[0];
                    return fast(i);
                }
                auto operator[](long i) -> decltype(this->fast(i)) {
                    if(i<0) i += shape[0];
                    return fast(i);
                }
                auto operator()(long i) const -> decltype((*this)[i]) {
                    return (*this)[i];
                }
                auto operator()(long i) -> decltype((*this)[i]) {
                    return (*this)[i];
                }

                template<class... Sp>
                auto operator()(contiguous_slice const& s0, Sp const&... s) const
                -> decltype(make_gexpr(*this, s0, s...))
                {
                  return make_gexpr(*this, s0, s...);
                }
                auto operator[](contiguous_slice const& s0) const
                -> decltype(make_gexpr(*this, s0))
                {
                  return make_gexpr(*this, s0);
                }

                template<class... Sp>
                auto operator()(slice const& s0, Sp const&... s) const
                -> decltype(make_gexpr(*this, s0, s...))
                {
                  return make_gexpr(*this, s0, s...);
                }
                auto operator[](slice const& s0) const
                -> decltype(make_gexpr(*this, s0))
                {
                  return make_gexpr(*this, s0);
                }
                template<class... Sp>
                auto operator()(long i, Sp const&... s) const
                -> decltype(std::declval<value_type>()(s...))
                {
                  return (*this)[i](s...);
                }

                template<size_t M>
                    auto operator[](array<long, M> const& indices) const &
                    -> decltype(nget<M-1>()(*this, indices))
                    {
                        return nget<M-1>()(*this, indices);
                    }
                template<size_t M>
                    auto operator[](array<long, M> const& indices) &&
                    -> decltype(nget<M-1>()(std::move(*this), indices))
                    {
                        return nget<M-1>()(std::move(*this), indices);
                    }
                template<class F>
                    typename std::enable_if<is_numexpr_arg<F>::value, numpy_fexpr<numpy_gexpr, F>>::type
                    fast(F const& filter) const {
                        return numpy_fexpr<numpy_gexpr, F>(*this, filter);
                    }
                template<class F>
                    typename std::enable_if<is_numexpr_arg<F>::value, numpy_fexpr<numpy_gexpr, F>>::type
                    operator[](F const& filter) const {
                        return fast(filter);
                    }

                long flat_size() const {
                    return std::accumulate(shape.begin() + 1, shape.end(), *shape.begin(), std::multiplies<long>());
                }
            };

        // As gexpr has to begin with a slice. When we access it, we need to forward the firsts accessed information
        // to an iexpr until the value in S... is a slice again.
        template <class Arg, class S0, class S1, class...S>
            struct numpy_gexpr_helper<Arg, S0, S1, S...> {
                typedef numpy_gexpr<numpy_iexpr<Arg>, S1, S...> type;
                static type get(numpy_gexpr<Arg, S0, S1, S...> const& e, long i) {
                    return type(e, numpy_iexpr<Arg>(e.arg, i));
                }
                static type get(numpy_gexpr<Arg, S0, S1, S...> & e, long i) {
                    return type(e, numpy_iexpr<Arg>(e.arg, i));
                }
            };

        //Compute forwarding of "long" index to iexpr until we reach a new slice in S... parameters
        namespace {

            template <size_t N, class Arg, class...S>
                struct finalize_numpy_gexpr_helper;

            // We reach a new slice so we have a new gexpr
            template <size_t N, class Arg, class... S>
                struct finalize_numpy_gexpr_helper<N, Arg, contiguous_slice, S...> {

                    typedef numpy_gexpr<Arg, contiguous_slice, S...> type;
                    template<class E, class F>
                        static type get(E const& e, F && f) {
                            return type(e, std::forward<F>(f));
                        }
                };

            // We reach a new slice so we have a new gexpr
            template <size_t N, class Arg, class... S>
                struct finalize_numpy_gexpr_helper<N, Arg, slice, S...> {

                    typedef numpy_gexpr<Arg, slice, S...> type;
                    template<class E, class F>
                        static type get(E const& e, F && f) {
                            return type(e, std::forward<F>(f));
                        }
                };

            // We have a long index so it is not a gexpr but a iexpr.
            // We declare a new iexpr and we continue looking for a new slice.
            template <size_t N, class Arg, class... S>
                struct finalize_numpy_gexpr_helper<N, Arg, long, S...> {
                    template<class E, class F>
                        static auto get(E const& e, F && f)
                        -> decltype(finalize_numpy_gexpr_helper<N + 1, numpy_iexpr<Arg>, S...>::get(e, std::declval<numpy_iexpr<Arg>>()))
                        {
                            return finalize_numpy_gexpr_helper<N + 1, numpy_iexpr<Arg>, S...>::get(e, numpy_iexpr<Arg>(std::forward<F>(f), e.indices[N]));
                        }
                    template<class E, class F>
                        static auto get(E & e, F && f)
                        -> decltype(finalize_numpy_gexpr_helper<N + 1, numpy_iexpr<Arg>, S...>::get(e, std::declval<numpy_iexpr<Arg>&>()))
                        {
                            numpy_iexpr<Arg> iexpr(std::forward<F>(f), e.indices[N]);
                            return finalize_numpy_gexpr_helper<N + 1, numpy_iexpr<Arg>, S...>::get(e, iexpr);
                        }
                };

            //If it was a single sliced array, we can return the matching iexpr.
            template <size_t N, class Arg>
                struct finalize_numpy_gexpr_helper<N, Arg, long> {
                    template<class E, class F>
                        static auto get(E const& e, F const & f)
                        -> decltype(numpy_iexpr_helper<F, Arg::value>::get(f, 0))
                        {
                            return numpy_iexpr_helper<F, Arg::value>::get(f, e.indices[N]);
                        }
                    template<class E, class F>
                        static auto get(E const& e, F & f)
                        -> decltype(numpy_iexpr_helper<F, Arg::value>::get(f, 0))
                        {
                            return numpy_iexpr_helper<F, Arg::value>::get(f, e.indices[N]);
                        }
                };
        }

        // forward new combination of gexpr/iexpr computation to finalize_numpy_gexpr_helper
        template <class Arg, class S0, class... S>
            struct numpy_gexpr_helper<Arg, S0, long, S...> {
                static auto get(numpy_gexpr<Arg, S0, long, S...> const& e, long i)
                    ->decltype(finalize_numpy_gexpr_helper<0, numpy_iexpr<Arg>, long, S...>::get(e, std::declval<numpy_iexpr<Arg>>()))
                {
                    return finalize_numpy_gexpr_helper<0, numpy_iexpr<Arg>, long, S...>::get(e, numpy_iexpr<Arg>(e.arg, i));
                }
                static auto get(numpy_gexpr<Arg, S0, long, S...> & e, long i)
                    ->decltype(finalize_numpy_gexpr_helper<0, numpy_iexpr<Arg>, long, S...>::get(e, std::declval<numpy_iexpr<Arg>&>()))
                {
                    return finalize_numpy_gexpr_helper<0, numpy_iexpr<Arg>, long, S...>::get(e, numpy_iexpr<Arg>(e.arg, i));
                }
            };

        //If we have no more slice later, we can say it is an iexpr (We look only for one last long? Not many last long?)
        template <class Arg, class S>
            struct numpy_gexpr_helper<Arg, S, long> {
                static auto get(numpy_gexpr<Arg, S, long> const& e, long i)
                    -> decltype(numpy_iexpr_helper<numpy_iexpr<Arg>, numpy_iexpr<Arg>::value>::get(std::declval<numpy_iexpr<Arg>>(), 0))
                {
                    return numpy_iexpr_helper<numpy_iexpr<Arg>, numpy_iexpr<Arg>::value>::get(numpy_iexpr<Arg>(e.arg, i), e.indices[0]);
                }
                static auto get(numpy_gexpr<Arg, S, long> & e, long i)
                    -> decltype(numpy_iexpr_helper<numpy_iexpr<Arg>, numpy_iexpr<Arg>::value>::get(std::declval<numpy_iexpr<Arg>&>(), 0))
                {
                    numpy_iexpr<Arg> iexpr(e.arg, i);
                    return numpy_iexpr_helper<numpy_iexpr<Arg>, numpy_iexpr<Arg>::value>::get(iexpr, e.indices[0]);
                }
            };

        template <class Arg, class S>
            struct numpy_gexpr_helper<Arg, S> : numpy_iexpr_helper<numpy_gexpr<Arg, S>, numpy_gexpr<Arg, S>::value> {
            };

    }
    template<class Arg, class...S>
        struct returnable<types::numpy_gexpr<Arg, S...>>
        {
            typedef types::numpy_gexpr<typename returnable<Arg>::type, S...> type;
        };

    template<class T, size_t N, class...S>
        struct assignable<types::numpy_gexpr<types::ndarray<T,N> const &, S...>>
        {
            typedef types::numpy_gexpr<types::ndarray<T,N> const &, S...> type;
        };
    template<class T, size_t N, class...S>
        struct assignable<types::numpy_gexpr<types::ndarray<T,N> &, S...>>
        {
            typedef types::numpy_gexpr<types::ndarray<T,N> &, S...> type;
        };

    template<class Arg, class...S>
        struct assignable<types::numpy_gexpr<Arg, S...>>
        {
            typedef types::numpy_gexpr<typename assignable<Arg>::type, S...> type;
        };

    template<class Arg, class... S>
        struct lazy<types::numpy_gexpr<Arg, S...>>
        {
            typedef types::numpy_gexpr<typename lazy<Arg>::type, typename lazy<S>::type...> type;
        };
    template<class Arg, class... S>
        struct lazy<types::numpy_gexpr<Arg const &, S...>>
        {
            typedef types::numpy_gexpr<typename lazy<Arg>::type const &, typename lazy<S>::type...> type;
        };

}
/* type inference stuff  {*/
#include "pythonic/types/combined.hpp"

template<class Arg, class... S>
struct __combined<pythonic::types::numpy_gexpr<Arg,S...>, pythonic::types::numpy_gexpr<Arg,S...>> {
  using type = pythonic::types::numpy_gexpr<Arg,S...>;
};

template<class Arg, class... S, class Argp, class... Sp>
struct __combined<pythonic::types::numpy_gexpr<Arg,S...>, pythonic::types::numpy_gexpr<Argp,Sp...>> {
  using type = pythonic::types::numpy_gexpr<Arg,S...>;
};

template<class Arg, class... S, class O>
struct __combined<pythonic::types::numpy_gexpr<Arg,S...>, O> {
  using type = pythonic::types::numpy_gexpr<Arg,S...>;
};
template<class Arg, class... S, class O>
struct __combined<O, pythonic::types::numpy_gexpr<Arg,S...>> {
  using type = pythonic::types::numpy_gexpr<Arg,S...>;
};

/* combined are sorted such that the assigned type comes first */
template<class Arg, class... S, class T, size_t N>
struct __combined<pythonic::types::numpy_gexpr<Arg,S...>, pythonic::types::ndarray<T,N>> {
  using type = pythonic::types::numpy_gexpr<Arg,S...>;
};
template<class Arg, class... S, class T, size_t N>
struct __combined<pythonic::types::ndarray<T,N>, pythonic::types::numpy_gexpr<Arg,S...>> {
  using type = pythonic::types::ndarray<T,N>;
};

#endif


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

// Copyright (c) 2012-2014 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_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP

#include <algorithm>
#include <cstddef>
#include <set>
#include <boost/range.hpp>

#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>

#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/envelope.hpp>

#include <boost/geometry/strategies/buffer.hpp>

#include <boost/geometry/geometries/ring.hpp>

#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
#include <boost/geometry/algorithms/detail/buffer/turn_in_input.hpp>

#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/occupation_info.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>

#include <boost/geometry/util/range.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{

enum segment_relation_code
{
    segment_relation_on_left,
    segment_relation_on_right,
    segment_relation_within,
    segment_relation_disjoint
};

template <typename Ring, typename RobustPolicy>
struct buffered_piece_collection
{
    typedef buffered_piece_collection<Ring, RobustPolicy> this_type;

    typedef typename geometry::point_type<Ring>::type point_type;
    typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
    typedef typename geometry::robust_point_type
    <
        point_type,
        RobustPolicy
    >::type robust_point_type;

    typedef typename strategy::side::services::default_strategy
        <
            typename cs_tag<point_type>::type
        >::type side_strategy;

    typedef typename geometry::rescale_policy_type
        <
            typename geometry::point_type<Ring>::type
        >::type rescale_policy_type;

    typedef typename geometry::segment_ratio_type
    <
        point_type,
        RobustPolicy
    >::type segment_ratio_type;

    typedef buffer_turn_info
    <
        point_type,
        robust_point_type,
        segment_ratio_type
    > buffer_turn_info_type;

    typedef buffer_turn_operation
    <
        point_type,
        segment_ratio_type
    > buffer_turn_operation_type;

    typedef std::vector<buffer_turn_info_type> turn_vector_type;

    struct robust_turn
    {
        int turn_index;
        int operation_index;
        robust_point_type point;
        segment_identifier seg_id;
        segment_ratio_type fraction;
    };

    struct piece
    {
        strategy::buffer::piece_type type;
        int index;

        int left_index; // points to previous piece
        int right_index; // points to next piece

        // The next two members form together a complete clockwise ring
        // for each piece (with one dupped point)

        // 1: half, part of offsetted_rings
        segment_identifier first_seg_id;
        int last_segment_index; // no segment-identifier - it is the same as first_seg_id
        int offsetted_count;

        // 2: half, not part (future: might be indexed in one vector too)
        std::vector<point_type> helper_segments; // 3 points for segment, 2 points for join - 0 points for flat-end

        // Robust representations
        std::vector<robust_turn> robust_turns; // Used only in rescale_pieces - we might use a map instead
        geometry::model::ring<robust_point_type> robust_ring;
        geometry::model::box<robust_point_type> robust_envelope;
    };

    typedef std::vector<piece> piece_vector_type;

    piece_vector_type m_pieces;
    turn_vector_type m_turns;
    int m_first_piece_index;

    buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
    std::vector< std::vector < robust_point_type > > robust_offsetted_rings;
    buffered_ring_collection<Ring> traversed_rings;
    segment_identifier current_segment_id;

    RobustPolicy const& m_robust_policy;

    struct redundant_turn
    {
        inline bool operator()(buffer_turn_info_type const& turn) const
        {
            // Erase discarded turns (location not OK) and the turns
            // only used to detect oppositeness.
            return turn.location != location_ok
                || turn.opposite();
        }
    };

    buffered_piece_collection(RobustPolicy const& robust_policy)
        : m_first_piece_index(-1)
        , m_robust_policy(robust_policy)
    {}

#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
    // Will (most probably) be removed later
    template <typename OccupationMap>
    inline void adapt_mapped_robust_point(OccupationMap const& map,
            buffer_turn_info_type& turn, int distance) const
    {
        for (int x = -distance; x <= distance; x++)
        {
            for (int y = -distance; y <= distance; y++)
            {
                robust_point_type rp = turn.robust_point;
                geometry::set<0>(rp, geometry::get<0>(rp) + x);
                geometry::set<1>(rp, geometry::get<1>(rp) + y);
                if (map.find(rp) != map.end())
                {
                    turn.mapped_robust_point = rp;
                    return;
                }
            }
        }
    }
#endif

    inline void get_occupation(
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
        int distance = 0
#endif
    )
    {
        typedef occupation_info<angle_info<robust_point_type, coordinate_type> >
                buffer_occupation_info;

        typedef std::map
        <
            robust_point_type,
            buffer_occupation_info,
            geometry::less<robust_point_type>
        > occupation_map_type;

        occupation_map_type occupation_map;

        // 1: Add all intersection points to occupation map
        typedef typename boost::range_iterator<turn_vector_type>::type
            iterator_type;

        for (iterator_type it = boost::begin(m_turns);
            it != boost::end(m_turns);
            ++it)
        {
            if (it->count_on_offsetted >= 1)
            {
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
                if (distance > 0 && ! occupation_map.empty())
                {
                    adapt_mapped_robust_point(occupation_map, *it, distance);
                }
#endif
                occupation_map[it->get_robust_point()].count++;
            }
        }

        // 2: Remove all points from map which has only one
        typename occupation_map_type::iterator it = occupation_map.begin();
        while (it != occupation_map.end())
        {
            if (it->second.count <= 1)
            {
                typename occupation_map_type::iterator to_erase = it;
                ++it;
                occupation_map.erase(to_erase);
            }
            else
            {
                ++it;
            }
        }

        if (occupation_map.empty())
        {
            return;
        }

        // 3: Add vectors (incoming->intersection-point,
        //                 intersection-point -> outgoing)
        //    for all (co-located) points still present in the map

        int index = 0;
        for (iterator_type it = boost::begin(m_turns);
            it != boost::end(m_turns);
            ++it, ++index)
        {
            typename occupation_map_type::iterator mit =
                        occupation_map.find(it->get_robust_point());

            if (mit != occupation_map.end())
            {
                buffer_occupation_info& info = mit->second;
                for (int i = 0; i < 2; i++)
                {
                    add_incoming_and_outgoing_angles(it->get_robust_point(), *it,
                                m_pieces,
                                index, i, it->operations[i].seg_id,
                                info);
                }

                it->count_on_multi++;
            }
        }

#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
        // X: Check rounding issues
        if (distance == 0)
        {
            for (typename occupation_map_type::const_iterator it = occupation_map.begin();
                it != occupation_map.end(); ++it)
            {
                if (it->second.has_rounding_issues(it->first))
                {
                    if(distance == 0)
                    {
                        get_occupation(distance + 1);
                        return;
                    }
                }
            }
        }
#endif

        // If, in a cluster, one turn is blocked, block them all
        for (typename occupation_map_type::const_iterator it = occupation_map.begin();
            it != occupation_map.end(); ++it)
        {
            typename buffer_occupation_info::turn_vector_type const& turns = it->second.turns;
            bool blocked = false;
            for (std::size_t i = 0; i < turns.size(); i++)
            {
                if (m_turns[turns[i].turn_index].blocked())
                {
                    blocked = true;
                    break;
                }
            }
            if (blocked)
            {
                for (std::size_t i = 0; i < turns.size(); i++)
                {
                    m_turns[turns[i].turn_index].count_on_occupied++;
                }
            }
        }

        // 4: Mark all turns as not selectable as a starting point for traversing
        //    rings. They still can be used to continue already started rings.
        for (typename occupation_map_type::iterator it = occupation_map.begin();
            it != occupation_map.end(); ++it)
        {
            typename buffer_occupation_info::turn_vector_type const& turns = it->second.turns;
            for (std::size_t i = 0; i < turns.size(); i++)
            {
                m_turns[turns[i].turn_index].selectable_start = false;
            }
        }
    }

    inline void classify_turns()
    {
        for (typename boost::range_iterator<turn_vector_type>::type it =
            boost::begin(m_turns); it != boost::end(m_turns); ++it)
        {
            if ( it->count_within > 0
              || it->count_on_occupied > 0 )
            {
                it->location = inside_buffer;
            }
        }
    }

    template <typename Geometry, typename DistanceStrategy>
    inline void check_remaining_points(Geometry const& input_geometry, DistanceStrategy const& distance_strategy)
    {
        int const factor = distance_strategy.factor();

        // This might use partition too (for multi-polygons)

        for (typename boost::range_iterator<turn_vector_type>::type it =
            boost::begin(m_turns); it != boost::end(m_turns); ++it)
        {
            if (it->location == location_ok)
            {
                int code = turn_in_input
                        <
                            typename geometry::tag<Geometry>::type
                        >::apply(it->point, input_geometry);
                if (code * factor == 1)
                {
                    it->location = inside_original;
                }
            }
        }
    }

    inline bool assert_indices_in_robust_rings() const
    {
        geometry::equal_to<robust_point_type> comparator;
        for (typename boost::range_iterator<turn_vector_type const>::type it =
            boost::begin(m_turns); it != boost::end(m_turns); ++it)
        {
            for (int i = 0; i < 2; i++)
            {
                robust_point_type const &p1
                    = m_pieces[it->operations[i].piece_index].robust_ring
                              [it->operations[i].index_in_robust_ring];
                robust_point_type const &p2 = it->robust_point;
                if (! comparator(p1, p2))
                {
                    return false;
                }
            }
        }
        return true;
    }

    inline void rescale_piece_rings()
    {
        for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
            it != boost::end(m_pieces);
            ++it)
        {
            piece& pc = *it;

            pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
            BOOST_ASSERT(pc.offsetted_count >= 0);

            pc.robust_ring.reserve(pc.offsetted_count + pc.helper_segments.size());

            // Add rescaled offsetted segments
            {
                buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];

                typedef typename boost::range_iterator<const buffered_ring<Ring> >::type it_type;
                for (it_type it = boost::begin(ring) + pc.first_seg_id.segment_index;
                    it != boost::begin(ring) + pc.last_segment_index;
                    ++it)
                {
                    robust_point_type point;
                    geometry::recalculate(point, *it, m_robust_policy);
                    pc.robust_ring.push_back(point);
                }
            }

            // Add rescaled helper-segments
            {
                typedef typename std::vector<point_type>::const_iterator it_type;
                for (it_type it = boost::begin(pc.helper_segments);
                    it != boost::end(pc.helper_segments);
                    ++it)
                {
                    robust_point_type point;
                    geometry::recalculate(point, *it, m_robust_policy);
                    pc.robust_ring.push_back(point);
                }
            }

            // Calculate the envelope
            geometry::detail::envelope::envelope_range::apply(pc.robust_ring,
                    pc.robust_envelope);
        }
    }

    inline void insert_rescaled_piece_turns()
    {
        // Add rescaled turn points to corresponding pieces
        // (after this, each turn occurs twice)
        int index = 0;
        for (typename boost::range_iterator<turn_vector_type>::type it =
            boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
        {
            geometry::recalculate(it->robust_point, it->point, m_robust_policy);
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
            it->mapped_robust_point = it->robust_point;
#endif

            robust_turn turn;
            it->turn_index = index;
            turn.turn_index = index;
            turn.point = it->robust_point;
            for (int i = 0; i < 2; i++)
            {
                turn.operation_index = i;
                turn.seg_id = it->operations[i].seg_id;
                turn.fraction = it->operations[i].fraction;

                piece& pc = m_pieces[it->operations[i].piece_index];
                pc.robust_turns.push_back(turn);

                // Take into account for the box (intersection points should fall inside,
                // but in theory they can be one off because of rounding
                geometry::expand(pc.robust_envelope, it->robust_point);
            }
        }

        // Insert all rescaled turn-points into these rings, to form a
        // reliable integer-based ring. All turns can be compared (inside) to this
        // rings to see if they are inside.

        for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
            it != boost::end(m_pieces);
            ++it)
        {
            piece& pc = *it;
            int piece_segment_index = pc.first_seg_id.segment_index;
            if (! pc.robust_turns.empty())
            {
                if (pc.robust_turns.size() > 1u)
                {
                    std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
                }
                // Walk through them, in reverse to insert at right index
                int index_offset = pc.robust_turns.size() - 1;
                for (typename std::vector<robust_turn>::const_reverse_iterator
                        rit = pc.robust_turns.rbegin();
                    rit != pc.robust_turns.rend();
                    ++rit, --index_offset)
                {
                    int const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
                    BOOST_ASSERT
                        (
                            index_in_vector > 0 && index_in_vector < pc.offsetted_count
                        );

                    pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
                    pc.offsetted_count++;

                    m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
                }
            }
        }

        BOOST_ASSERT(assert_indices_in_robust_rings());
    }

    template <typename Geometry, typename DistanceStrategy>
    inline void get_turns(Geometry const& input_geometry, DistanceStrategy const& distance_strategy)
    {
        rescale_piece_rings();

        {
            // Calculate the turns
            piece_turn_visitor
                <
                    buffered_ring_collection<buffered_ring<Ring> >,
                    turn_vector_type,
                    RobustPolicy
                > visitor(offsetted_rings, m_turns, m_robust_policy, m_pieces.size());

            geometry::partition
                <
                    model::box<robust_point_type>, piece_get_box, piece_ovelaps_box
                >::apply(m_pieces, visitor);
        }

        insert_rescaled_piece_turns();

        {
            // Check if it is inside any of the pieces
            turn_in_piece_visitor
                <
                    turn_vector_type, piece_vector_type
                > visitor(m_turns, m_pieces);

            geometry::partition
                <
                    model::box<robust_point_type>,
                    turn_get_box, turn_ovelaps_box,
                    piece_get_box, piece_ovelaps_box
                >::apply(m_turns, m_pieces, visitor);

        }

        get_occupation();

        classify_turns();

        check_remaining_points(input_geometry, distance_strategy);
    }

    inline void start_new_ring()
    {
        int const n = offsetted_rings.size();
        current_segment_id.source_index = 0;
        current_segment_id.multi_index = n;
        current_segment_id.ring_index = -1;
        current_segment_id.segment_index = 0;

        offsetted_rings.resize(n + 1);

        m_first_piece_index = boost::size(m_pieces);
    }

    inline void finish_ring()
    {
        BOOST_ASSERT(m_first_piece_index != -1);
        if (m_first_piece_index < static_cast<int>(boost::size(m_pieces)))
        {
            // If piece was added
            // Reassign left-of-first and right-of-last
            geometry::range::at(m_pieces, m_first_piece_index).left_index
                                                    = boost::size(m_pieces) - 1;
            geometry::range::back(m_pieces).right_index = m_first_piece_index;
        }
        m_first_piece_index = -1;
    }

    inline int add_point(point_type const& p)
    {
        BOOST_ASSERT
            (
                boost::size(offsetted_rings) > 0
            );

        current_segment_id.segment_index++;
        offsetted_rings.back().push_back(p);
        return offsetted_rings.back().size();
    }

    //-------------------------------------------------------------------------

    inline piece& add_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one)
    {
        piece pc;
        pc.type = type;
        pc.index = boost::size(m_pieces);
        pc.first_seg_id = current_segment_id;

        // Assign left/right (for first/last piece per ring they will be re-assigned later)
        pc.left_index = pc.index - 1;
        pc.right_index = pc.index + 1;

        std::size_t const n = boost::size(offsetted_rings.back());
        pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;

        m_pieces.push_back(pc);
        return m_pieces.back();
    }

    template <typename Range>
    inline void add_piece(strategy::buffer::piece_type type, point_type const& p1, point_type const& p2,
            Range const& range, bool first)
    {
        piece& pc = add_piece(type, ! first);

        // If it follows a non-join (so basically the same piece-type) point b1 should be added.
        // There should be two intersections later and it should be discarded.
        // But for now we need it to calculate intersections
        if (first)
        {
            add_point(range.front());
        }
        pc.last_segment_index = add_point(range.back());

        pc.helper_segments.push_back(range.back());
        pc.helper_segments.push_back(p2);
        pc.helper_segments.push_back(p1);
        pc.helper_segments.push_back(range.front());
    }

    inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
            point_type const& b1, point_type const& b2)
    {
        piece& pc = add_piece(type, false);
        add_point(b1);
        pc.last_segment_index = add_point(b2);
        pc.helper_segments.push_back(b2);
        pc.helper_segments.push_back(p);
        pc.helper_segments.push_back(b1);
    }

    template <typename Range>
    inline piece& add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one)
    {
        piece& pc = add_piece(type, decrease_segment_index_by_one);

        bool first = true;
        int last = offsetted_rings.back().size() + 1;
        for (typename Range::const_iterator it = boost::begin(range);
            it != boost::end(range);
            ++it)
        {
            bool add = true;
            if (first)
            {
                // Only for very first one, add first. In all other cases it is shared with previous.
                add = offsetted_rings.back().empty();
                first = false;
            }
            if (add)
            {
                last = add_point(*it);
            }

        }

        pc.last_segment_index = last;

        return pc;
    }

    template <typename Range>
    inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range)
    {
        piece& pc = add_piece(type, range, true);

        if (boost::size(range) > 0)
        {
            pc.helper_segments.push_back(range.back());
            pc.helper_segments.push_back(p);
            pc.helper_segments.push_back(range.front());
        }
    }

    template <typename EndcapStrategy, typename Range>
    inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point)
    {
        if (range.empty())
        {
            return;
        }
        strategy::buffer::piece_type pt = strategy.get_piece_type();
        if (pt == strategy::buffer::buffered_flat_end)
        {
            // It is flat, should just be added, without helper segments
            add_piece(pt, range, true);
        }
        else
        {
            // Normal case, it has an "inside", helper segments should be added
            add_piece(pt, end_point, range);
        }
    }

    //-------------------------------------------------------------------------

    inline void enrich()
    {
        typedef typename strategy::side::services::default_strategy
        <
            typename cs_tag<Ring>::type
        >::type side_strategy_type;

        enrich_intersection_points<false, false>(m_turns,
                    detail::overlay::operation_union,
                    offsetted_rings, offsetted_rings,
                    m_robust_policy, side_strategy_type());
    }

    // Discards all rings which do have not-OK intersection points only.
    // Those can never be traversed and should not be part of the output.
    inline void discard_rings()
    {
        for (typename boost::range_iterator<turn_vector_type const>::type it =
            boost::begin(m_turns); it != boost::end(m_turns); ++it)
        {
            if (it->location != location_ok)
            {
                offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true;
                offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true;
            }
            else if (! it->both(detail::overlay::operation_union))
            {
                offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true;
                offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true;
            }
        }
    }

    inline void discard_turns()
    {
        m_turns.erase
            (
                std::remove_if(boost::begin(m_turns), boost::end(m_turns),
                                redundant_turn()),
                boost::end(m_turns)
            );

    }

    inline void traverse()
    {
        typedef detail::overlay::traverse
            <
                false, false,
                buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >,
                backtrack_for_buffer
            > traverser;

        traversed_rings.clear();
        traverser::apply(offsetted_rings, offsetted_rings,
                        detail::overlay::operation_union,
                        m_robust_policy, m_turns, traversed_rings);
    }

    inline void reverse()
    {
        for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings);
            it != boost::end(offsetted_rings);
            ++it)
        {
            if (! it->has_intersections())
            {
                std::reverse(it->begin(), it->end());
            }
        }
        for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type
                it = boost::begin(traversed_rings);
                it != boost::end(traversed_rings);
                ++it)
        {
            std::reverse(it->begin(), it->end());
        }

    }

    template <typename GeometryOutput, typename OutputIterator>
    inline OutputIterator assign(OutputIterator out) const
    {
        typedef detail::overlay::ring_properties<point_type> properties;

        std::map<ring_identifier, properties> selected;

        // Select all rings which do not have any self-intersection (other ones should be traversed)
        int index = 0;
        for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
            it != boost::end(offsetted_rings);
            ++it, ++index)
        {
            if (! it->has_intersections())
            {
                ring_identifier id(0, index, -1);
                selected[id] = properties(*it, true);
            }
        }

        // Select all created rings
        index = 0;
        for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type
                it = boost::begin(traversed_rings);
                it != boost::end(traversed_rings);
                ++it, ++index)
        {
            ring_identifier id(2, index, -1);
            selected[id] = properties(*it, true);
        }

        detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, false);
        return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
    }

};

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

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP


//==================================================================================================
/**
  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_ARCH_COMMON_SIMD_FUNCTION_GENMASK_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_GENMASK_HPP_INCLUDED

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/meta/as_arithmetic.hpp>
#include <boost/simd/function/if_else.hpp>
#include <boost/simd/constant/allbits.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  namespace bs = boost::simd;

  // -----------------------------------------------------------------------------------------------
  // genmask from logical
  BOOST_DISPATCH_OVERLOAD_IF( genmask_
                            , (typename A0, typename X)
                            , (detail::is_native<X>)
                            , bd::cpu_
                            , bs::pack_< bs::logical_<A0>, X >
                            )
  {
    using result_t = as_arithmetic_t<A0>;

    BOOST_FORCEINLINE result_t operator()( A0 const& a0 ) const BOOST_NOEXCEPT
    {
      return do_(a0, typename is_bitwise_logical<A0>::type{});
    }

    BOOST_FORCEINLINE result_t do_( A0 const& a0, std::true_type const& ) const BOOST_NOEXCEPT
    {
      return bitwise_cast<result_t>(a0);
    }

    BOOST_FORCEINLINE result_t do_( A0 const& a0, std::false_type const& ) const BOOST_NOEXCEPT
    {
      return if_else(a0, Allbits<result_t>(), result_t(0));
    }
  };

  BOOST_DISPATCH_OVERLOAD_IF( genmask_
                            , (typename A0,typename X)
                            , (detail::is_native<X>)
                            , bd::cpu_
                            , bs::pack_<bd::arithmetic_<A0>,X>
                            )
  {
    BOOST_FORCEINLINE A0 operator()( const A0& a0) const BOOST_NOEXCEPT
    {
       return if_else(a0,  Allbits<A0>(), A0(0));
    }
  };
} } }

#endif


/*
    This file is part of Nori, a simple educational ray tracer

    Copyright (c) 2012 by Wenzel Jakob and Steve Marschner.

    Nori is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License Version 3
    as published by the Free Software Foundation.

    Nori is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <nori/mesh.h>
#include <nori/obj.h>
#include <boost/unordered_map.hpp>
#include <QTextStream>
#include <QStringList>
#include <QFileInfo>
#include <QtCore/qfileinfo.h>

NORI_NAMESPACE_BEGIN

/**
 * \brief Loader for Wavefront OBJ triangle meshes
 */
class WavefrontOBJ : public Mesh {
public:
	WavefrontOBJ(const PropertyList &propList) : Mesh(propList) {
		typedef boost::unordered_map<OBJVertex, uint32_t, OBJVertexHash> VertexMap;

		/* Process the OBJ-file line by line */
		QString filename = propList.getString("filename");
		QFile input(QFile::exists(filename) ? filename : absFileName(filename));
		if (!input.open(QIODevice::ReadOnly | QIODevice::Text))
			throw NoriException(QString("Cannot open \"%1\"").arg(filename));

		Transform trafo = propList.getTransform("toWorld", Transform());

		cout << "Loading \"" << qPrintable(filename) << "\" .." << endl;
		m_name = QFileInfo(filename).fileName();

		QTextStream stream(&input);
		QTextStream line;
		QString temp, prefix;

		std::vector<Point3f>   positions;
		std::vector<Point2f>   texcoords;
		std::vector<Normal3f>  normals;
		std::vector<uint32_t>  indices;
		std::vector<OBJVertex> vertices;
		VertexMap vertexMap;

		while (!(temp = stream.readLine()).isNull()) {
			line.setString(&temp);

			line >> prefix;
			if (prefix == "v") {
				Point3f p;
				line >> p.x() >> p.y() >> p.z();
				p = trafo * p;
				positions.push_back(p);
			} else if (prefix == "vt") {
				Point2f tc;
				line >> tc.x() >> tc.y();
				texcoords.push_back(tc);
			} else if (prefix == "vn") {
				Normal3f n;
				line >> n.x() >> n.y() >> n.z();
				n = (trafo * n).normalized();
				normals.push_back(n);
			} else if (prefix == "f") {
				QString v1, v2, v3, v4;
				line >> v1 >> v2 >> v3 >> v4;
				OBJVertex tri[6];
				int nVertices = 3;

				tri[0] = OBJVertex(v1);
				tri[1] = OBJVertex(v2);
				tri[2] = OBJVertex(v3);

				if (!v4.isNull()) {
					/* This is a quad, split into two triangles */
					tri[3] = OBJVertex(v4);
					tri[4] = tri[0];
					tri[5] = tri[2];
					nVertices = 6;
				}

				/* Now convert from the Wavefront OBJ indexing scheme to a good
				   old indexed vertex list (i.e. just one index per vertex) */
				for (int i=0; i<nVertices; ++i) {
					const OBJVertex &v = tri[i];
					VertexMap::const_iterator it = vertexMap.find(v);
					if (it == vertexMap.end()) {
						vertexMap[v] = (uint32_t) vertices.size();
						indices.push_back((uint32_t) vertices.size());
						vertices.push_back(v);
					} else {
						indices.push_back(it->second);
					}
				}
			}
		}

		m_triangleCount = (uint32_t) (indices.size() / 3);
		m_vertexCount = (uint32_t) vertices.size();

		cout << "Read " << m_triangleCount << " triangles and "
			 << m_vertexCount << " vertices." << endl;

		/* Create the compact in-memory representation (i.e. without
		   unused buffer space). This involves some copying and following
		   of indirections. */

		m_indices = new uint32_t[indices.size()];
		for (size_t i=0; i<indices.size(); ++i)
			m_indices[i] = indices[i];

		m_vertexPositions = new Point3f[m_vertexCount];
		for (size_t i=0; i<m_vertexCount; ++i)
			m_vertexPositions[i] = positions.at(vertices[i].p);

		if (!normals.empty()) {
			m_vertexNormals = new Normal3f[m_vertexCount];
			for (size_t i=0; i<m_vertexCount; ++i)
				m_vertexNormals[i] = normals.at(vertices[i].n);
		}

		if (!texcoords.empty()) {
			m_vertexTexCoords = new Point2f[m_vertexCount];
			for (size_t i=0; i<m_vertexCount; ++i)
				m_vertexTexCoords[i] = texcoords.at(vertices[i].uv);
		}
	}

protected:
	/// Vertex indices used by the OBJ format
	struct OBJVertex {
		uint32_t p, n, uv;

		inline OBJVertex() { }

		OBJVertex(const QString &string)
			: n((uint32_t) -1), uv((uint32_t) -1) {
			QStringList tokens = string.split("/");

			if (tokens.size() != 1 && tokens.size() != 3)
				goto fail;

			bool ok;
			p  = (uint32_t) tokens[0].toInt(&ok) - 1; if (!ok) goto fail;

			if (tokens.size() == 3) {
				if (tokens[1].length() > 0) {
					uv = (uint32_t) tokens[1].toInt(&ok) - 1; if (!ok) goto fail;
				}
				if (tokens[2].length() > 0) {
					n  = (uint32_t) tokens[2].toInt(&ok) - 1; if (!ok) goto fail;
				}
			}

			return;
		fail:
			throw NoriException(QString("Could not parse vertex data: '%1'!").arg(string));
		}

		inline bool operator==(const OBJVertex &v) const {
			return v.p == p && v.n == n && v.uv == uv;
		}
	};

	/// Hash function for \ref OBJVertex
	struct OBJVertexHash : std::unary_function<OBJVertex, size_t> {
		std::size_t operator()(const OBJVertex &v) const {
			size_t hash = 0;
			boost::hash_combine(hash, v.p);
			boost::hash_combine(hash, v.n);
			boost::hash_combine(hash, v.uv);
			return hash;
		}
	};
};

extern Mesh *loadOBJFile(const QString &filename){
    PropertyList propList;
    propList.setString("filename", filename);
    return new WavefrontOBJ(propList);
}

NORI_REGISTER_CLASS(WavefrontOBJ, "obj");
NORI_NAMESPACE_END


/*
* TS Elements
* Copyright 2015-2018 M. Newhouse
* Released under the MIT license.
*/

#pragma once

#include <boost/optional.hpp>

#include "utility/rect.hpp"
#include "utility/vector2.hpp"
#include "utility/rotation.hpp"

#include <vector>
#include <cstdint>

namespace ts
{
  namespace resources
  {
    class Pattern;

    static const struct dynamic_mask_t{} dynamic_mask;

    // The CollisionMask class turns a pattern map into a collision bitmap. It stores
    // the pixels in a space-efficient manner, using only one bit for each one.
    // Thanks to bitwise operations, this also makes it a time-efficient solution.
    // It has 1 or more levels or frames, which can be accessed individually.
    class CollisionMask
    {
    public:
      // There are two types of constructors: those for static collision masks and those for
      // dynamic ones.
      // Static masks generate a frame for every level, testing each pixel for "wallness" on
      // the particular level, setting the pixels for which wall_test(pattern(x, y), level) returns
      // true.

      template <typename WallTest>
      CollisionMask(const resources::Pattern& pattern, std::uint32_t level_count, WallTest&& wall_test);

      template <typename WallTest>
      CollisionMask(const resources::Pattern& pattern, IntRect rect,
                    std::uint32_t level_count, WallTest&& wall_test);

      // Dynamic masks incrementally rotate the pattern for each frame, setting the pixels for which
      // wall_test(pattern(source_x, source_y)) returns true.
      template <typename WallTest>
      CollisionMask(dynamic_mask_t, const resources::Pattern& pattern,
                    std::uint32_t frame_count, WallTest&& wall_test);

      template <typename WallTest>
      CollisionMask(dynamic_mask_t, const resources::Pattern& pattern, IntRect rect,
                    std::uint32_t frame_count, WallTest&& wall_test);

      using bitmask_type = std::uint32_t;

      // The FrameInterface provides an interface to access one of the collision mask's
      // individual frames.
      struct FrameInterface
      {
      public:
        bool operator()(std::uint32_t x, std::uint32_t y) const;

        const bitmask_type* row_begin(std::uint32_t y) const;
        std::size_t row_width() const;
        std::size_t row_count() const;

      private:
        friend CollisionMask;
        FrameInterface(const bitmask_type* frame_bits, std::size_t row_width, std::size_t row_count);

        const bitmask_type* frame_bits_;
        std::size_t row_width_;
        std::size_t row_count_;
      };

      FrameInterface frame(std::uint32_t frame_id) const;
      FrameInterface rotation_frame(Rotation<double> rotation) const;

      IntRect bounding_box() const;

    private:
      std::uint32_t row_width_;
      std::uint32_t frame_count_;
      Vector2u bitmap_size_;
      IntRect bounding_box_;
      std::vector<bitmask_type> pixel_data_;
      double rotation_multiplier_;
    };

    using CollisionMaskFrame = CollisionMask::FrameInterface;

    struct CollisionPoint
    {
      CollisionPoint() = default;
      explicit CollisionPoint(Vector2i point_)
        : collided(true), point(point_)
      {}

      explicit operator bool() const { return collided; }

      bool collided = false;
      Vector2i point;
    };

    CollisionPoint test_collision(const CollisionMaskFrame& subject, const CollisionMaskFrame& object,
                                  Vector2i subject_position, Vector2i object_position);

    CollisionPoint test_scenery_collision(const CollisionMaskFrame& subject, const CollisionMaskFrame& scenery,
                                          Vector2i subject_position);

  }
}


#include <turtle_input_helper.hpp>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

namespace duraark_rdf {

std::set<uint32_t> parse_index_list_(const std::string& str) {
    using boost::spirit::qi::uint_;
    using boost::spirit::qi::char_;
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::ascii::space;

    auto first = str.begin();
    auto last = str.end();
    uint32_t index_begin = 0, index_end = 0;
    std::set<uint32_t> indices;
    auto match_first = [&] (uint32_t idx) { index_begin = index_end = idx; };
    auto match_second = [&] (uint32_t idx) { index_end = idx; };
    auto match_after = [&] () { for (uint32_t i=index_begin; i<=index_end; ++i) { indices.insert(i); }; };
    bool r = phrase_parse(first, last, *((uint_[match_first] >> -(char_('-') >> uint_[match_second]))[match_after]), space);
    if (!r || first != last) {
        return std::set<uint32_t>();
    }
    return indices;
}

std::pair<std::string, bool>
parse_transformation_string(turtle_input& input, const std::string& guid_0,
                     const std::string& guid_1) {
    auto entity_triples = input.filter_triples(
        turtle_input::filter(),
        turtle_input::filter::equals("rel:globalUniqueId"));
    std::string name_0 = "", name_1 = "";
    for (auto& entity : entity_triples) {
        std::string crt_guid = entity.second["rel:globalUniqueId"];
        if (crt_guid == guid_0) {
            name_0 = fs::path(entity.first).filename().stem().string();
        }
        if (crt_guid == guid_1) {
            name_1 = fs::path(entity.first).filename().stem().string();
        }
    }

    if (name_0 == "") {
        throw std::runtime_error("Unable to find object for GUID \"" + guid_0 +
                                 "\"");
    }
    if (name_1 == "") {
        throw std::runtime_error("Unable to find object for GUID \"" + guid_1 +
                                 "\"");
    }

    bool inverse = false;
    std::string tr_name = "obj:" + name_0 + "_to_" + name_1;
    auto tr_obj = input.filter_triples(
        turtle_input::filter::contains(tr_name),
        turtle_input::filter::equals("rel:transformParam"));
    if (!tr_obj.size()) {
        tr_name = "obj:" + name_1 + "_to_" + name_0;
        tr_obj = input.filter_triples(turtle_input::filter::contains(tr_name),
                                      turtle_input::filter("rel:transformParam"));
        if (!tr_obj.size()) {
            throw std::runtime_error(
                "No transformation found for given objects");
        }
        inverse = true;
    }

    auto& pred = tr_obj[tr_name];

    auto pred_found = pred.find("rel:transformParam");

    if (pred_found == pred.end()) {
        throw std::runtime_error(
            "Transform object has no \"rel:transformParam\" attribute");
    }

    return {pred_found->second, inverse};
}

Eigen::Matrix4f
parse_registration(turtle_input& input, const std::string& guid_0,
                     const std::string& guid_1) {
    std::pair<std::string, bool> t = parse_transformation_string(input, guid_0, guid_1);
    std::istringstream iss(t.first);
    std::vector<std::string> tokens{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
    assert(tokens.size() == 16);

    Eigen::Matrix4f m;
    for (uint32_t i = 0; i < 4; ++i) {
        for (uint32_t j = 0; j < 4; ++j) {
            double value;
            std::stringstream convert_str(tokens[i*4+j]);
            convert_str >> value;
            convert_str.str("");
            m(i, j) = value;
        }
    }

    if (t.second) {
        Eigen::Matrix4f inv = m.inverse();
        m = inv;
    }

    return m;
}

std::vector<subset_association_t> parse_subset_associations(turtle_input& input, std::map<std::string, uint32_t>& possible_hits, std::set<std::string>* const pointcloud_entities) {
    // parse point-cloud entities
    std::map<std::string, std::string> pc_guids;
    if (pointcloud_entities) pointcloud_entities->clear();
    auto entity_triples = input.filter_triples(
        turtle_input::filter::contains("PC_"),
        turtle_input::filter::equals("rel:globalUniqueId"));
    for (const auto& entity : entity_triples) {
        std::string pc_guid = entity.second.at("rel:globalUniqueId");
        pc_guids[entity.first] = pc_guid;
        if (pointcloud_entities) pointcloud_entities->insert(pc_guid);
    }

    std::vector<subset_association_t> assocs;
    entity_triples = input.filter_triples(turtle_input::filter::contains("SBS_"), turtle_input::filter());
    for (const auto& entity : entity_triples) {
        auto& m = entity.second;
        auto sub_it = m.find("rel:pointSubsetOf");
        auto rep_it = m.find("rel:subsetRepOf");
        auto idx_it = m.find("rel:pointSubsetContains");
        auto poss_it = m.find("rel:possibleScanHits");
        if (sub_it != m.end() && rep_it != m.end() && idx_it != m.end()) {
            subset_association_t assoc;
            assoc.ifc_object_guid = rep_it->second;
            assoc.pointcloud_guid = pc_guids[sub_it->second];
            assoc.point_indices = parse_index_list_(idx_it->second);
            uint32_t poss_hits = 0;
            if (poss_it != m.end()) {
                std::stringstream sstr_conv;
                sstr_conv << poss_it->second;
                sstr_conv >> poss_hits;
            }
            possible_hits[rep_it->second] = poss_hits;
            assocs.push_back(assoc);
        }
    }

    return assocs;
}

}  // duraark_rdf


// 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) 2007-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)

#ifndef BOOST_UNITS_DIM_HPP
#define BOOST_UNITS_DIM_HPP

#include <boost/static_assert.hpp>

#include <boost/type_traits/is_same.hpp>

#include <boost/mpl/arithmetic.hpp>

#include <boost/units/config.hpp>
#include <boost/units/static_rational.hpp>
#include <boost/units/detail/dim_impl.hpp>

/// \file dim.hpp
/// \brief Handling of fundamental dimension/exponent pairs.

namespace boost {

namespace units {

namespace detail {

struct dim_tag { };

}

/// \brief Dimension tag/exponent pair for a single fundamental dimension.
///
/// \details
/// The dim class represents a single dimension tag/dimension exponent pair.
/// That is, @c dim<tag_type,value_type> is a pair where @c tag_type represents the
/// fundamental dimension being represented and @c value_type represents the
/// exponent of that fundamental dimension as a @c static_rational. @c tag_type must
/// be a derived from a specialization of @c base_dimension.
/// Specialization of the following Boost.MPL metafunctions are provided
///
///     - @c mpl::plus for two @c dims
///     - @c mpl::minus for two @c dims
///     - @c mpl::negate for a @c dim
///
/// These metafunctions all operate on the exponent, and require
/// that the @c dim operands have the same base dimension tag.
/// In addition, multiplication and division by @c static_rational
/// is supported.
///
///     - @c mpl::times for a @c static_rational and a @c dim in either order
///     - @c mpl::divides for a @c static_rational and a @c dim in either order
///
/// These metafunctions likewise operate on the exponent only.
template<typename T,typename V>
struct dim
{
    typedef dim             type;
    typedef detail::dim_tag tag;
    typedef T               tag_type;
    typedef V               value_type;
};

} // namespace units

} // namespace boost

#if BOOST_UNITS_HAS_BOOST_TYPEOF

#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()

BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::dim, 2)

#endif

#ifndef BOOST_UNITS_DOXYGEN

namespace boost {

namespace mpl {

// define MPL operators acting on dim<T,V>

template<>
struct plus_impl<boost::units::detail::dim_tag,boost::units::detail::dim_tag>
{
    template<class T0, class T1>
    struct apply
    {
        BOOST_STATIC_ASSERT((boost::is_same<typename T0::tag_type,typename T1::tag_type>::value == true));
        typedef boost::units::dim<typename T0::tag_type, typename mpl::plus<typename T0::value_type, typename T1::value_type>::type> type;
    };
};

template<>
struct minus_impl<boost::units::detail::dim_tag,boost::units::detail::dim_tag>
{
    template<class T0, class T1>
    struct apply
    {
        BOOST_STATIC_ASSERT((boost::is_same<typename T0::tag_type,typename T1::tag_type>::value == true));
        typedef boost::units::dim<typename T0::tag_type, typename mpl::minus<typename T0::value_type, typename T1::value_type>::type> type;
    };
};

template<>
struct times_impl<boost::units::detail::dim_tag,boost::units::detail::static_rational_tag>
{
    template<class T0, class T1>
    struct apply
    {
        typedef boost::units::dim<typename T0::tag_type, typename mpl::times<typename T0::value_type, T1>::type> type;
    };
};

template<>
struct times_impl<boost::units::detail::static_rational_tag,boost::units::detail::dim_tag>
{
    template<class T0, class T1>
    struct apply
    {
        typedef boost::units::dim<typename T1::tag_type, typename mpl::times<T0, typename T1::value_type>::type> type;
    };
};

template<>
struct divides_impl<boost::units::detail::dim_tag,boost::units::detail::static_rational_tag>
{
    template<class T0, class T1>
    struct apply
    {
        typedef boost::units::dim<typename T0::tag_type, typename mpl::divides<typename T0::value_type, T1>::type> type;
    };
};

template<>
struct divides_impl<boost::units::detail::static_rational_tag,boost::units::detail::dim_tag>
{
    template<class T0, class T1>
    struct apply
    {
        typedef boost::units::dim<typename T1::tag_type, typename mpl::divides<T0, typename T1::value_type>::type> type;
    };
};

template<>
struct negate_impl<boost::units::detail::dim_tag>
{
    template<class T0>
    struct apply
    {
        typedef boost::units::dim<typename T0::tag_type,typename mpl::negate<typename T0::value_type>::type> type;
    };
};

} // namespace mpl

} // namespace boost

#endif

#endif // BOOST_UNITS_DIM_HPP


#include <boost/mpl/list.hpp>
#include <boost/test/unit_test.hpp>
#include <complex>

#include "fhmdot/include/hmatrix.hpp"
#include "fhmdot/include/qnum.hpp"

using namespace fhmdot::hmatrix;
using namespace fhmdot::qnum;

typedef boost::mpl::list<float, double, typename std::complex<float>,
                         typename std::complex<double>>
    values;
typedef boost::mpl::list<sh_none, sh_u1, sh_su2> Q;

BOOST_AUTO_TEST_CASE_TEMPLATE(unittest_hmatrix, T, values) {
  mps<Q, T> mps_a();
  mps<Q, T> mps_b();
}


// Copyright 2008 by BBN Technologies Corp.
// All Rights Reserved.

#include "Generic/common/leak_detection.h"

#include <math.h>
#include "Generic/common/Symbol.h"
#include "Generic/common/UTF8InputStream.h"
#include "Generic/common/ProbModel.h"
#include "Generic/trainers/ProbModelWriter.h"
#include "Generic/theories/SynNode.h"

#include "English/descriptors/en_DescClassModifiers.h"
#include <boost/scoped_ptr.hpp>

const int EnglishDescClassModifiers::_LOG_OF_ZERO = -10000;
const int EnglishDescClassModifiers::_VOCAB_SIZE = 10000;

EnglishDescClassModifiers::EnglishDescClassModifiers()
	:  _modModel(0), _modBackoffModel(0),
		_modWriter(0), _modBackoffWriter(0)
	{ }

EnglishDescClassModifiers::~EnglishDescClassModifiers(){
	delete _modModel;
	delete _modBackoffModel;
	delete _modWriter;
	delete _modBackoffWriter;
}

void EnglishDescClassModifiers::initialize(const char* model_prefix)
{
	char buffer[501];
	sprintf(buffer,"%s.mnp3", model_prefix);
	boost::scoped_ptr<UTF8InputStream> modModelStream_scoped_ptr(UTF8InputStream::build());
	UTF8InputStream& modModelStream(*modModelStream_scoped_ptr);
	modModelStream.open(buffer);
	// no smoothing of premod model (cause we do it by hand)
	// we need to track lambdas, though
	// front component has a kappa of 3.0
	_modModel = _new ProbModel(3, modModelStream, false, true, 3.0);
	modModelStream.close();

	sprintf(buffer,"%s.mnp4", model_prefix);
	boost::scoped_ptr<UTF8InputStream> modBackoffModelStream_scoped_ptr(UTF8InputStream::build());
	UTF8InputStream& modBackoffModelStream(*modBackoffModelStream_scoped_ptr);
	modBackoffModelStream.open(buffer);
	// no smoothing of premod model (cause we do it by hand)
	// we need to track lambdas, though
	// back component has a kappa of 1.0
	_modBackoffModel = _new ProbModel(2, modBackoffModelStream, false, true, 1.0);
	modBackoffModelStream.close();
}

void EnglishDescClassModifiers::initializeForTraining(const char* model_prefix)
{
	 _modWriter = _new ProbModelWriter(3, 500);
	 _modBackoffWriter = _new ProbModelWriter(2, 500);
	char file[500];
	sprintf(file,"%s.mnp3", model_prefix);
	_modStream.open(file);
	sprintf(file,"%s.mnp4", model_prefix);
	_modBackoffStream.open(file);

}

void EnglishDescClassModifiers::writeModifiers(){
	_modWriter->writeModel(_modStream);
	_modBackoffWriter->writeModel(_modBackoffStream);
}

void EnglishDescClassModifiers::closeFiles(){
	_modStream.close();
	_modBackoffStream.close();
}

//Calculate the PreModifier portion of the Descriptor Classifier Score
double EnglishDescClassModifiers::getModifierScore(const SynNode* node, Symbol proposedType){
	// Modifier  is (type, stemmed_head, mod_head)
	// mod backoff is (type, mod_head)
	Symbol premodVector[3];
	Symbol premodBackoffVector[2];
	Symbol headWord = node->getHeadWord();

	premodVector[0] = proposedType;
	premodBackoffVector[0] = proposedType;

	premodVector[1] = headWord;
	double premod_score = 0;
	int headIndex = node->getHeadIndex();

	for (int j = 0; j < headIndex; j++) {
		premodVector[2] = premodBackoffVector[1] = node->getChild(j)->getHeadWord();
		double frontProb = exp(_modModel->getProbability(premodVector));
		// WARNING: the incorrect lambda is being used for comparison to old system
		double frontLambda = _modModel->getIncorrectLambda(premodVector);
		double backProb = exp(_modBackoffModel->getProbability(premodBackoffVector));

		// WARNING: the incorrect lambda is being used for comparison to old system
		double backLambda = _modBackoffModel->getIncorrectLambda(premodBackoffVector);
		double combined_score = (frontLambda*frontProb)+
			((1.0-frontLambda)*((backLambda*backProb) +
			((1.0-backLambda)* 1.0/_VOCAB_SIZE)));
		premod_score += combined_score == 0 ? _LOG_OF_ZERO : log(combined_score);
	}
	return premod_score;
}

//For Training add the PreModifiers  of the current node
void EnglishDescClassModifiers::addModifers(const SynNode *node, Symbol type){
	Symbol premodArr[3];
	Symbol premodBackArr[2];

	premodArr[0] = premodBackArr[0] = type;

	int headIndex = node->getHeadIndex();
	Symbol termToHead[100];
	int termSize = node->getTerminalSymbols(termToHead, 100);
	premodArr[1] = node->getHeadWord();

	for (int j = 0; j < termSize; j++) {
		if(termToHead[j]==premodArr[1])
			break;
		premodArr[2] = premodBackArr[1] = termToHead[j];
		_modWriter->registerTransition(premodArr);
		_modBackoffWriter->registerTransition(premodBackArr);
	}
}