#ifndef BOOST_QVM_GEN_MAT_OPERATIONS3_HPP_INCLUDED
#define BOOST_QVM_GEN_MAT_OPERATIONS3_HPP_INCLUDED

/// Copyright (c) 2008-2021 Emil Dotchevski and Reverge Studios, Inc.

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

/// This file was generated by a program. Do not edit manually.

#include <boost/qvm/assert.hpp>
#include <boost/qvm/deduce_mat.hpp>
#include <boost/qvm/deduce_vec.hpp>
#include <boost/qvm/error.hpp>
#include <boost/qvm/gen/mat_assign3.hpp>
#include <boost/qvm/quat_traits.hpp>
#include <boost/qvm/scalar_traits.hpp>
#include <boost/qvm/throw_exception.hpp>

namespace boost { namespace qvm {

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,3,3> >::type
operator+( A const & a, B const & b )
    {
    typedef typename deduce_mat2<A,B,3,3>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==3);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==3);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)+mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)+mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)+mat_traits<B>::template read_element<0,2>(b);
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)+mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<1,1>(r)=mat_traits<A>::template read_element<1,1>(a)+mat_traits<B>::template read_element<1,1>(b);
    mat_traits<R>::template write_element<1,2>(r)=mat_traits<A>::template read_element<1,2>(a)+mat_traits<B>::template read_element<1,2>(b);
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)+mat_traits<B>::template read_element<2,0>(b);
    mat_traits<R>::template write_element<2,1>(r)=mat_traits<A>::template read_element<2,1>(a)+mat_traits<B>::template read_element<2,1>(b);
    mat_traits<R>::template write_element<2,2>(r)=mat_traits<A>::template read_element<2,2>(a)+mat_traits<B>::template read_element<2,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator+;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct plus_mm_defined;

    template <>
    struct
    plus_mm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==1 && mat_traits<B>::cols==1,
    deduce_mat2<A,B,3,1> >::type
operator+( A const & a, B const & b )
    {
    typedef typename deduce_mat2<A,B,3,1>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==3);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==1);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)+mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)+mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)+mat_traits<B>::template read_element<2,0>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator+;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct plus_mm_defined;

    template <>
    struct
    plus_mm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==1 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,1,3> >::type
operator+( A const & a, B const & b )
    {
    typedef typename deduce_mat2<A,B,1,3>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==1);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==3);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)+mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)+mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)+mat_traits<B>::template read_element<0,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator+;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct plus_mm_defined;

    template <>
    struct
    plus_mm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,3,3> >::type
operator-( A const & a, B const & b )
    {
    typedef typename deduce_mat2<A,B,3,3>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==3);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==3);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)-mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)-mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)-mat_traits<B>::template read_element<0,2>(b);
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)-mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<1,1>(r)=mat_traits<A>::template read_element<1,1>(a)-mat_traits<B>::template read_element<1,1>(b);
    mat_traits<R>::template write_element<1,2>(r)=mat_traits<A>::template read_element<1,2>(a)-mat_traits<B>::template read_element<1,2>(b);
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)-mat_traits<B>::template read_element<2,0>(b);
    mat_traits<R>::template write_element<2,1>(r)=mat_traits<A>::template read_element<2,1>(a)-mat_traits<B>::template read_element<2,1>(b);
    mat_traits<R>::template write_element<2,2>(r)=mat_traits<A>::template read_element<2,2>(a)-mat_traits<B>::template read_element<2,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_mm_defined;

    template <>
    struct
    minus_mm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==1 && mat_traits<B>::cols==1,
    deduce_mat2<A,B,3,1> >::type
operator-( A const & a, B const & b )
    {
    typedef typename deduce_mat2<A,B,3,1>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==3);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==1);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)-mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)-mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)-mat_traits<B>::template read_element<2,0>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_mm_defined;

    template <>
    struct
    minus_mm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==1 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,1,3> >::type
operator-( A const & a, B const & b )
    {
    typedef typename deduce_mat2<A,B,1,3>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==1);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==3);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)-mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)-mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)-mat_traits<B>::template read_element<0,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_mm_defined;

    template <>
    struct
    minus_mm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    A &>::type
operator+=( A & a, B const & b )
    {
    mat_traits<A>::template write_element<0,0>(a)+=mat_traits<B>::template read_element<0,0>(b);
    mat_traits<A>::template write_element<0,1>(a)+=mat_traits<B>::template read_element<0,1>(b);
    mat_traits<A>::template write_element<0,2>(a)+=mat_traits<B>::template read_element<0,2>(b);
    mat_traits<A>::template write_element<1,0>(a)+=mat_traits<B>::template read_element<1,0>(b);
    mat_traits<A>::template write_element<1,1>(a)+=mat_traits<B>::template read_element<1,1>(b);
    mat_traits<A>::template write_element<1,2>(a)+=mat_traits<B>::template read_element<1,2>(b);
    mat_traits<A>::template write_element<2,0>(a)+=mat_traits<B>::template read_element<2,0>(b);
    mat_traits<A>::template write_element<2,1>(a)+=mat_traits<B>::template read_element<2,1>(b);
    mat_traits<A>::template write_element<2,2>(a)+=mat_traits<B>::template read_element<2,2>(b);
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator+=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct plus_eq_mm_defined;

    template <>
    struct
    plus_eq_mm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==1 && mat_traits<B>::cols==1,
    A &>::type
operator+=( A & a, B const & b )
    {
    mat_traits<A>::template write_element<0,0>(a)+=mat_traits<B>::template read_element<0,0>(b);
    mat_traits<A>::template write_element<1,0>(a)+=mat_traits<B>::template read_element<1,0>(b);
    mat_traits<A>::template write_element<2,0>(a)+=mat_traits<B>::template read_element<2,0>(b);
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator+=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct plus_eq_mm_defined;

    template <>
    struct
    plus_eq_mm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==1 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    A &>::type
operator+=( A & a, B const & b )
    {
    mat_traits<A>::template write_element<0,0>(a)+=mat_traits<B>::template read_element<0,0>(b);
    mat_traits<A>::template write_element<0,1>(a)+=mat_traits<B>::template read_element<0,1>(b);
    mat_traits<A>::template write_element<0,2>(a)+=mat_traits<B>::template read_element<0,2>(b);
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator+=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct plus_eq_mm_defined;

    template <>
    struct
    plus_eq_mm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    A &>::type
operator-=( A & a, B const & b )
    {
    mat_traits<A>::template write_element<0,0>(a)-=mat_traits<B>::template read_element<0,0>(b);
    mat_traits<A>::template write_element<0,1>(a)-=mat_traits<B>::template read_element<0,1>(b);
    mat_traits<A>::template write_element<0,2>(a)-=mat_traits<B>::template read_element<0,2>(b);
    mat_traits<A>::template write_element<1,0>(a)-=mat_traits<B>::template read_element<1,0>(b);
    mat_traits<A>::template write_element<1,1>(a)-=mat_traits<B>::template read_element<1,1>(b);
    mat_traits<A>::template write_element<1,2>(a)-=mat_traits<B>::template read_element<1,2>(b);
    mat_traits<A>::template write_element<2,0>(a)-=mat_traits<B>::template read_element<2,0>(b);
    mat_traits<A>::template write_element<2,1>(a)-=mat_traits<B>::template read_element<2,1>(b);
    mat_traits<A>::template write_element<2,2>(a)-=mat_traits<B>::template read_element<2,2>(b);
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_eq_mm_defined;

    template <>
    struct
    minus_eq_mm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==1 && mat_traits<B>::cols==1,
    A &>::type
operator-=( A & a, B const & b )
    {
    mat_traits<A>::template write_element<0,0>(a)-=mat_traits<B>::template read_element<0,0>(b);
    mat_traits<A>::template write_element<1,0>(a)-=mat_traits<B>::template read_element<1,0>(b);
    mat_traits<A>::template write_element<2,0>(a)-=mat_traits<B>::template read_element<2,0>(b);
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_eq_mm_defined;

    template <>
    struct
    minus_eq_mm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==1 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    A &>::type
operator-=( A & a, B const & b )
    {
    mat_traits<A>::template write_element<0,0>(a)-=mat_traits<B>::template read_element<0,0>(b);
    mat_traits<A>::template write_element<0,1>(a)-=mat_traits<B>::template read_element<0,1>(b);
    mat_traits<A>::template write_element<0,2>(a)-=mat_traits<B>::template read_element<0,2>(b);
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_eq_mm_defined;

    template <>
    struct
    minus_eq_mm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
operator*( A const & a, B b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)*b;
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)*b;
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)*b;
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)*b;
    mat_traits<R>::template write_element<1,1>(r)=mat_traits<A>::template read_element<1,1>(a)*b;
    mat_traits<R>::template write_element<1,2>(r)=mat_traits<A>::template read_element<1,2>(a)*b;
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)*b;
    mat_traits<R>::template write_element<2,1>(r)=mat_traits<A>::template read_element<2,1>(a)*b;
    mat_traits<R>::template write_element<2,2>(r)=mat_traits<A>::template read_element<2,2>(a)*b;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_ms_defined;

    template <>
    struct
    mul_ms_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    is_scalar<A>::value && mat_traits<B>::rows==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols> >::type
operator*( A a, B const & b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a*mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=a*mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=a*mat_traits<B>::template read_element<0,2>(b);
    mat_traits<R>::template write_element<1,0>(r)=a*mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<1,1>(r)=a*mat_traits<B>::template read_element<1,1>(b);
    mat_traits<R>::template write_element<1,2>(r)=a*mat_traits<B>::template read_element<1,2>(b);
    mat_traits<R>::template write_element<2,0>(r)=a*mat_traits<B>::template read_element<2,0>(b);
    mat_traits<R>::template write_element<2,1>(r)=a*mat_traits<B>::template read_element<2,1>(b);
    mat_traits<R>::template write_element<2,2>(r)=a*mat_traits<B>::template read_element<2,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_sm_defined;

    template <>
    struct
    mul_sm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==1 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
operator*( A const & a, B b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)*b;
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)*b;
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)*b;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_ms_defined;

    template <>
    struct
    mul_ms_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    is_scalar<A>::value && mat_traits<B>::rows==3 && mat_traits<B>::cols==1,
    deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols> >::type
operator*( A a, B const & b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a*mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<1,0>(r)=a*mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<2,0>(r)=a*mat_traits<B>::template read_element<2,0>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_sm_defined;

    template <>
    struct
    mul_sm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
operator*( A const & a, B b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)*b;
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)*b;
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)*b;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_ms_defined;

    template <>
    struct
    mul_ms_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    is_scalar<A>::value && mat_traits<B>::rows==1 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols> >::type
operator*( A a, B const & b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a*mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=a*mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=a*mat_traits<B>::template read_element<0,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_sm_defined;

    template <>
    struct
    mul_sm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    A &>::type
operator*=( A & a, B b )
    {
    mat_traits<A>::template write_element<0,0>(a)*=b;
    mat_traits<A>::template write_element<0,1>(a)*=b;
    mat_traits<A>::template write_element<0,2>(a)*=b;
    mat_traits<A>::template write_element<1,0>(a)*=b;
    mat_traits<A>::template write_element<1,1>(a)*=b;
    mat_traits<A>::template write_element<1,2>(a)*=b;
    mat_traits<A>::template write_element<2,0>(a)*=b;
    mat_traits<A>::template write_element<2,1>(a)*=b;
    mat_traits<A>::template write_element<2,2>(a)*=b;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_eq_ms_defined;

    template <>
    struct
    mul_eq_ms_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==1 && is_scalar<B>::value,
    A &>::type
operator*=( A & a, B b )
    {
    mat_traits<A>::template write_element<0,0>(a)*=b;
    mat_traits<A>::template write_element<1,0>(a)*=b;
    mat_traits<A>::template write_element<2,0>(a)*=b;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_eq_ms_defined;

    template <>
    struct
    mul_eq_ms_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    A &>::type
operator*=( A & a, B b )
    {
    mat_traits<A>::template write_element<0,0>(a)*=b;
    mat_traits<A>::template write_element<0,1>(a)*=b;
    mat_traits<A>::template write_element<0,2>(a)*=b;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct mul_eq_ms_defined;

    template <>
    struct
    mul_eq_ms_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
operator/( A const & a, B b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)/b;
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)/b;
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)/b;
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)/b;
    mat_traits<R>::template write_element<1,1>(r)=mat_traits<A>::template read_element<1,1>(a)/b;
    mat_traits<R>::template write_element<1,2>(r)=mat_traits<A>::template read_element<1,2>(a)/b;
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)/b;
    mat_traits<R>::template write_element<2,1>(r)=mat_traits<A>::template read_element<2,1>(a)/b;
    mat_traits<R>::template write_element<2,2>(r)=mat_traits<A>::template read_element<2,2>(a)/b;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_ms_defined;

    template <>
    struct
    div_ms_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    is_scalar<A>::value && mat_traits<B>::rows==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols> >::type
operator/( A a, B const & b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a/mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<0,1>(r)=a/mat_traits<B>::template read_element<0,1>(b);
    mat_traits<R>::template write_element<0,2>(r)=a/mat_traits<B>::template read_element<0,2>(b);
    mat_traits<R>::template write_element<1,0>(r)=a/mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<1,1>(r)=a/mat_traits<B>::template read_element<1,1>(b);
    mat_traits<R>::template write_element<1,2>(r)=a/mat_traits<B>::template read_element<1,2>(b);
    mat_traits<R>::template write_element<2,0>(r)=a/mat_traits<B>::template read_element<2,0>(b);
    mat_traits<R>::template write_element<2,1>(r)=a/mat_traits<B>::template read_element<2,1>(b);
    mat_traits<R>::template write_element<2,2>(r)=a/mat_traits<B>::template read_element<2,2>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_sm_defined;

    template <>
    struct
    div_sm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==1 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
operator/( A const & a, B b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)/b;
    mat_traits<R>::template write_element<1,0>(r)=mat_traits<A>::template read_element<1,0>(a)/b;
    mat_traits<R>::template write_element<2,0>(r)=mat_traits<A>::template read_element<2,0>(a)/b;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_ms_defined;

    template <>
    struct
    div_ms_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    is_scalar<A>::value && mat_traits<B>::rows==3 && mat_traits<B>::cols==1,
    deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols> >::type
operator/( A a, B const & b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<B>::rows,mat_traits<B>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a/mat_traits<B>::template read_element<0,0>(b);
    mat_traits<R>::template write_element<1,0>(r)=a/mat_traits<B>::template read_element<1,0>(b);
    mat_traits<R>::template write_element<2,0>(r)=a/mat_traits<B>::template read_element<2,0>(b);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_sm_defined;

    template <>
    struct
    div_sm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
operator/( A const & a, B b )
    {
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=mat_traits<A>::template read_element<0,0>(a)/b;
    mat_traits<R>::template write_element<0,1>(r)=mat_traits<A>::template read_element<0,1>(a)/b;
    mat_traits<R>::template write_element<0,2>(r)=mat_traits<A>::template read_element<0,2>(a)/b;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_ms_defined;

    template <>
    struct
    div_ms_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    A &>::type
operator/=( A & a, B b )
    {
    mat_traits<A>::template write_element<0,0>(a)/=b;
    mat_traits<A>::template write_element<0,1>(a)/=b;
    mat_traits<A>::template write_element<0,2>(a)/=b;
    mat_traits<A>::template write_element<1,0>(a)/=b;
    mat_traits<A>::template write_element<1,1>(a)/=b;
    mat_traits<A>::template write_element<1,2>(a)/=b;
    mat_traits<A>::template write_element<2,0>(a)/=b;
    mat_traits<A>::template write_element<2,1>(a)/=b;
    mat_traits<A>::template write_element<2,2>(a)/=b;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_eq_ms_defined;

    template <>
    struct
    div_eq_ms_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==1 && is_scalar<B>::value,
    A &>::type
operator/=( A & a, B b )
    {
    mat_traits<A>::template write_element<0,0>(a)/=b;
    mat_traits<A>::template write_element<1,0>(a)/=b;
    mat_traits<A>::template write_element<2,0>(a)/=b;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_eq_ms_defined;

    template <>
    struct
    div_eq_ms_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    A &>::type
operator/=( A & a, B b )
    {
    mat_traits<A>::template write_element<0,0>(a)/=b;
    mat_traits<A>::template write_element<0,1>(a)/=b;
    mat_traits<A>::template write_element<0,2>(a)/=b;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator/=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct div_eq_ms_defined;

    template <>
    struct
    div_eq_ms_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class R,class A>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<R>::rows==3 && mat_traits<A>::rows==3 &&
    mat_traits<R>::cols==3 && mat_traits<A>::cols==3,
    R>::type
convert_to( A const & a )
    {
    R r;
    mat_traits<R>::template write_element<0,0>(r) = mat_traits<A>::template read_element<0,0>(a);
    mat_traits<R>::template write_element<0,1>(r) = mat_traits<A>::template read_element<0,1>(a);
    mat_traits<R>::template write_element<0,2>(r) = mat_traits<A>::template read_element<0,2>(a);
    mat_traits<R>::template write_element<1,0>(r) = mat_traits<A>::template read_element<1,0>(a);
    mat_traits<R>::template write_element<1,1>(r) = mat_traits<A>::template read_element<1,1>(a);
    mat_traits<R>::template write_element<1,2>(r) = mat_traits<A>::template read_element<1,2>(a);
    mat_traits<R>::template write_element<2,0>(r) = mat_traits<A>::template read_element<2,0>(a);
    mat_traits<R>::template write_element<2,1>(r) = mat_traits<A>::template read_element<2,1>(a);
    mat_traits<R>::template write_element<2,2>(r) = mat_traits<A>::template read_element<2,2>(a);
    return r;
    }

template <class R,class A>
BOOST_QVM_INLINE
typename enable_if_c<
    is_mat<R>::value && is_quat<A>::value &&
    mat_traits<R>::rows==3 && mat_traits<R>::cols==3,
    R>::type
convert_to( A const & q )
    {
    typedef typename mat_traits<R>::scalar_type T;
    T const a=quat_traits<A>::template read_element<0>(q);
    T const b=quat_traits<A>::template read_element<1>(q);
    T const c=quat_traits<A>::template read_element<2>(q);
    T const d=quat_traits<A>::template read_element<3>(q);
    T const bb = b*b;
    T const cc = c*c;
    T const dd = d*d;
    T const bc = b*c;
    T const bd = b*d;
    T const cd = c*d;
    T const ab = a*b;
    T const ac = a*c;
    T const ad = a*d;
    T const one = scalar_traits<T>::value(1);
    T const two = one+one;
    R r;
    mat_traits<R>::template write_element<0,0>(r) = one - two*(cc+dd);
    mat_traits<R>::template write_element<0,1>(r) = two*(bc-ad);
    mat_traits<R>::template write_element<0,2>(r) = two*(bd+ac);
    mat_traits<R>::template write_element<1,0>(r) = two*(bc+ad);
    mat_traits<R>::template write_element<1,1>(r) = one - two*(bb+dd);
    mat_traits<R>::template write_element<1,2>(r) = two*(cd-ab);
    mat_traits<R>::template write_element<2,0>(r) = two*(bd-ac);
    mat_traits<R>::template write_element<2,1>(r) = two*(cd+ab);
    mat_traits<R>::template write_element<2,2>(r) = one - two*(bb+cc);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::convert_to;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct convert_to_m_defined;

    template <>
    struct
    convert_to_m_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class R,class A>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<R>::rows==3 && mat_traits<A>::rows==3 &&
    mat_traits<R>::cols==1 && mat_traits<A>::cols==1,
    R>::type
convert_to( A const & a )
    {
    R r;
    mat_traits<R>::template write_element<0,0>(r) = mat_traits<A>::template read_element<0,0>(a);
    mat_traits<R>::template write_element<1,0>(r) = mat_traits<A>::template read_element<1,0>(a);
    mat_traits<R>::template write_element<2,0>(r) = mat_traits<A>::template read_element<2,0>(a);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::convert_to;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct convert_to_m_defined;

    template <>
    struct
    convert_to_m_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class R,class A>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<R>::rows==1 && mat_traits<A>::rows==1 &&
    mat_traits<R>::cols==3 && mat_traits<A>::cols==3,
    R>::type
convert_to( A const & a )
    {
    R r;
    mat_traits<R>::template write_element<0,0>(r) = mat_traits<A>::template read_element<0,0>(a);
    mat_traits<R>::template write_element<0,1>(r) = mat_traits<A>::template read_element<0,1>(a);
    mat_traits<R>::template write_element<0,2>(r) = mat_traits<A>::template read_element<0,2>(a);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::convert_to;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct convert_to_m_defined;

    template <>
    struct
    convert_to_m_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    bool>::type
operator==( A const & a, B const & b )
    {
    return
        mat_traits<A>::template read_element<0,0>(a)==mat_traits<B>::template read_element<0,0>(b) &&
        mat_traits<A>::template read_element<0,1>(a)==mat_traits<B>::template read_element<0,1>(b) &&
        mat_traits<A>::template read_element<0,2>(a)==mat_traits<B>::template read_element<0,2>(b) &&
        mat_traits<A>::template read_element<1,0>(a)==mat_traits<B>::template read_element<1,0>(b) &&
        mat_traits<A>::template read_element<1,1>(a)==mat_traits<B>::template read_element<1,1>(b) &&
        mat_traits<A>::template read_element<1,2>(a)==mat_traits<B>::template read_element<1,2>(b) &&
        mat_traits<A>::template read_element<2,0>(a)==mat_traits<B>::template read_element<2,0>(b) &&
        mat_traits<A>::template read_element<2,1>(a)==mat_traits<B>::template read_element<2,1>(b) &&
        mat_traits<A>::template read_element<2,2>(a)==mat_traits<B>::template read_element<2,2>(b);
    }

namespace
sfinae
    {
    using ::boost::qvm::operator==;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct eq_mm_defined;

    template <>
    struct
    eq_mm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==1 && mat_traits<B>::cols==1,
    bool>::type
operator==( A const & a, B const & b )
    {
    return
        mat_traits<A>::template read_element<0,0>(a)==mat_traits<B>::template read_element<0,0>(b) &&
        mat_traits<A>::template read_element<1,0>(a)==mat_traits<B>::template read_element<1,0>(b) &&
        mat_traits<A>::template read_element<2,0>(a)==mat_traits<B>::template read_element<2,0>(b);
    }

namespace
sfinae
    {
    using ::boost::qvm::operator==;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct eq_mm_defined;

    template <>
    struct
    eq_mm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==1 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    bool>::type
operator==( A const & a, B const & b )
    {
    return
        mat_traits<A>::template read_element<0,0>(a)==mat_traits<B>::template read_element<0,0>(b) &&
        mat_traits<A>::template read_element<0,1>(a)==mat_traits<B>::template read_element<0,1>(b) &&
        mat_traits<A>::template read_element<0,2>(a)==mat_traits<B>::template read_element<0,2>(b);
    }

namespace
sfinae
    {
    using ::boost::qvm::operator==;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct eq_mm_defined;

    template <>
    struct
    eq_mm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    bool>::type
operator!=( A const & a, B const & b )
    {
    return
        !(mat_traits<A>::template read_element<0,0>(a)==mat_traits<B>::template read_element<0,0>(b)) ||
        !(mat_traits<A>::template read_element<0,1>(a)==mat_traits<B>::template read_element<0,1>(b)) ||
        !(mat_traits<A>::template read_element<0,2>(a)==mat_traits<B>::template read_element<0,2>(b)) ||
        !(mat_traits<A>::template read_element<1,0>(a)==mat_traits<B>::template read_element<1,0>(b)) ||
        !(mat_traits<A>::template read_element<1,1>(a)==mat_traits<B>::template read_element<1,1>(b)) ||
        !(mat_traits<A>::template read_element<1,2>(a)==mat_traits<B>::template read_element<1,2>(b)) ||
        !(mat_traits<A>::template read_element<2,0>(a)==mat_traits<B>::template read_element<2,0>(b)) ||
        !(mat_traits<A>::template read_element<2,1>(a)==mat_traits<B>::template read_element<2,1>(b)) ||
        !(mat_traits<A>::template read_element<2,2>(a)==mat_traits<B>::template read_element<2,2>(b));
    }

namespace
sfinae
    {
    using ::boost::qvm::operator!=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct neq_mm_defined;

    template <>
    struct
    neq_mm_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==1 && mat_traits<B>::cols==1,
    bool>::type
operator!=( A const & a, B const & b )
    {
    return
        !(mat_traits<A>::template read_element<0,0>(a)==mat_traits<B>::template read_element<0,0>(b)) ||
        !(mat_traits<A>::template read_element<1,0>(a)==mat_traits<B>::template read_element<1,0>(b)) ||
        !(mat_traits<A>::template read_element<2,0>(a)==mat_traits<B>::template read_element<2,0>(b));
    }

namespace
sfinae
    {
    using ::boost::qvm::operator!=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct neq_mm_defined;

    template <>
    struct
    neq_mm_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==1 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    bool>::type
operator!=( A const & a, B const & b )
    {
    return
        !(mat_traits<A>::template read_element<0,0>(a)==mat_traits<B>::template read_element<0,0>(b)) ||
        !(mat_traits<A>::template read_element<0,1>(a)==mat_traits<B>::template read_element<0,1>(b)) ||
        !(mat_traits<A>::template read_element<0,2>(a)==mat_traits<B>::template read_element<0,2>(b));
    }

namespace
sfinae
    {
    using ::boost::qvm::operator!=;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct neq_mm_defined;

    template <>
    struct
    neq_mm_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3,
    deduce_mat<A> >::type
operator-( A const & a )
    {
    typedef typename deduce_mat<A>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=-mat_traits<A>::template read_element<0,0>(a);
    mat_traits<R>::template write_element<0,1>(r)=-mat_traits<A>::template read_element<0,1>(a);
    mat_traits<R>::template write_element<0,2>(r)=-mat_traits<A>::template read_element<0,2>(a);
    mat_traits<R>::template write_element<1,0>(r)=-mat_traits<A>::template read_element<1,0>(a);
    mat_traits<R>::template write_element<1,1>(r)=-mat_traits<A>::template read_element<1,1>(a);
    mat_traits<R>::template write_element<1,2>(r)=-mat_traits<A>::template read_element<1,2>(a);
    mat_traits<R>::template write_element<2,0>(r)=-mat_traits<A>::template read_element<2,0>(a);
    mat_traits<R>::template write_element<2,1>(r)=-mat_traits<A>::template read_element<2,1>(a);
    mat_traits<R>::template write_element<2,2>(r)=-mat_traits<A>::template read_element<2,2>(a);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_m_defined;

    template <>
    struct
    minus_m_defined<3,3>
        {
        static bool const value=true;
        };
    }

template <class A>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==1,
    deduce_mat<A> >::type
operator-( A const & a )
    {
    typedef typename deduce_mat<A>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=-mat_traits<A>::template read_element<0,0>(a);
    mat_traits<R>::template write_element<1,0>(r)=-mat_traits<A>::template read_element<1,0>(a);
    mat_traits<R>::template write_element<2,0>(r)=-mat_traits<A>::template read_element<2,0>(a);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_m_defined;

    template <>
    struct
    minus_m_defined<3,1>
        {
        static bool const value=true;
        };
    }

template <class A>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<A>::cols==3,
    deduce_mat<A> >::type
operator-( A const & a )
    {
    typedef typename deduce_mat<A>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)=-mat_traits<A>::template read_element<0,0>(a);
    mat_traits<R>::template write_element<0,1>(r)=-mat_traits<A>::template read_element<0,1>(a);
    mat_traits<R>::template write_element<0,2>(r)=-mat_traits<A>::template read_element<0,2>(a);
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator-;
    }

namespace
qvm_detail
    {
    template <int R,int C>
    struct minus_m_defined;

    template <>
    struct
    minus_m_defined<1,3>
        {
        static bool const value=true;
        };
    }

template <class A>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3,
    typename mat_traits<A>::scalar_type>::type
determinant( A const & a )
    {
    typedef typename mat_traits<A>::scalar_type T;
    T const a00=mat_traits<A>::template read_element<0,0>(a);
    T const a01=mat_traits<A>::template read_element<0,1>(a);
    T const a02=mat_traits<A>::template read_element<0,2>(a);
    T const a10=mat_traits<A>::template read_element<1,0>(a);
    T const a11=mat_traits<A>::template read_element<1,1>(a);
    T const a12=mat_traits<A>::template read_element<1,2>(a);
    T const a20=mat_traits<A>::template read_element<2,0>(a);
    T const a21=mat_traits<A>::template read_element<2,1>(a);
    T const a22=mat_traits<A>::template read_element<2,2>(a);
    T det=(a00*(a11*a22-a12*a21)-a01*(a10*a22-a12*a20)+a02*(a10*a21-a11*a20));
    return det;
    }

namespace
sfinae
    {
    using ::boost::qvm::determinant;
    }

namespace
qvm_detail
    {
    template <int D>
    struct determinant_defined;

    template <>
    struct
    determinant_defined<3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3 && is_scalar<B>::value,
    deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols> >::type
inverse( A const & a, B det )
    {
    typedef typename mat_traits<A>::scalar_type T;
    BOOST_QVM_ASSERT(det!=scalar_traits<B>::value(0));
    T const a00=mat_traits<A>::template read_element<0,0>(a);
    T const a01=mat_traits<A>::template read_element<0,1>(a);
    T const a02=mat_traits<A>::template read_element<0,2>(a);
    T const a10=mat_traits<A>::template read_element<1,0>(a);
    T const a11=mat_traits<A>::template read_element<1,1>(a);
    T const a12=mat_traits<A>::template read_element<1,2>(a);
    T const a20=mat_traits<A>::template read_element<2,0>(a);
    T const a21=mat_traits<A>::template read_element<2,1>(a);
    T const a22=mat_traits<A>::template read_element<2,2>(a);
    T const f=scalar_traits<T>::value(1)/det;
    typedef typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type R;
    R r;
    mat_traits<R>::template write_element<0,0>(r)= f*(a11*a22-a12*a21);
    mat_traits<R>::template write_element<0,1>(r)=-f*(a01*a22-a02*a21);
    mat_traits<R>::template write_element<0,2>(r)= f*(a01*a12-a02*a11);
    mat_traits<R>::template write_element<1,0>(r)=-f*(a10*a22-a12*a20);
    mat_traits<R>::template write_element<1,1>(r)= f*(a00*a22-a02*a20);
    mat_traits<R>::template write_element<1,2>(r)=-f*(a00*a12-a02*a10);
    mat_traits<R>::template write_element<2,0>(r)= f*(a10*a21-a11*a20);
    mat_traits<R>::template write_element<2,1>(r)=-f*(a00*a21-a01*a20);
    mat_traits<R>::template write_element<2,2>(r)= f*(a00*a11-a01*a10);
    return r;
    }

template <class A>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<A>::cols==3,
    deduce_mat<A> >::type
inverse( A const & a )
    {
    typedef typename mat_traits<A>::scalar_type T;
    T det=determinant(a);
    if( det==scalar_traits<T>::value(0) )
        BOOST_QVM_THROW_EXCEPTION(zero_determinant_error());
    return inverse(a,det);
    }

namespace
sfinae
    {
    using ::boost::qvm::inverse;
    }

namespace
qvm_detail
    {
    template <int D>
    struct inverse_m_defined;

    template <>
    struct
    inverse_m_defined<3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,3,3> >::type
operator*( A const & a, B const & b )
    {
    typedef typename mat_traits<A>::scalar_type Ta;
    typedef typename mat_traits<B>::scalar_type Tb;
    Ta const a00 = mat_traits<A>::template read_element<0,0>(a);
    Ta const a01 = mat_traits<A>::template read_element<0,1>(a);
    Ta const a02 = mat_traits<A>::template read_element<0,2>(a);
    Ta const a10 = mat_traits<A>::template read_element<1,0>(a);
    Ta const a11 = mat_traits<A>::template read_element<1,1>(a);
    Ta const a12 = mat_traits<A>::template read_element<1,2>(a);
    Ta const a20 = mat_traits<A>::template read_element<2,0>(a);
    Ta const a21 = mat_traits<A>::template read_element<2,1>(a);
    Ta const a22 = mat_traits<A>::template read_element<2,2>(a);
    Tb const b00 = mat_traits<B>::template read_element<0,0>(b);
    Tb const b01 = mat_traits<B>::template read_element<0,1>(b);
    Tb const b02 = mat_traits<B>::template read_element<0,2>(b);
    Tb const b10 = mat_traits<B>::template read_element<1,0>(b);
    Tb const b11 = mat_traits<B>::template read_element<1,1>(b);
    Tb const b12 = mat_traits<B>::template read_element<1,2>(b);
    Tb const b20 = mat_traits<B>::template read_element<2,0>(b);
    Tb const b21 = mat_traits<B>::template read_element<2,1>(b);
    Tb const b22 = mat_traits<B>::template read_element<2,2>(b);
    typedef typename deduce_mat2<A,B,3,3>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==3);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==3);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a00*b00+a01*b10+a02*b20;
    mat_traits<R>::template write_element<0,1>(r)=a00*b01+a01*b11+a02*b21;
    mat_traits<R>::template write_element<0,2>(r)=a00*b02+a01*b12+a02*b22;
    mat_traits<R>::template write_element<1,0>(r)=a10*b00+a11*b10+a12*b20;
    mat_traits<R>::template write_element<1,1>(r)=a10*b01+a11*b11+a12*b21;
    mat_traits<R>::template write_element<1,2>(r)=a10*b02+a11*b12+a12*b22;
    mat_traits<R>::template write_element<2,0>(r)=a20*b00+a21*b10+a22*b20;
    mat_traits<R>::template write_element<2,1>(r)=a20*b01+a21*b11+a22*b21;
    mat_traits<R>::template write_element<2,2>(r)=a20*b02+a21*b12+a22*b22;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int /*CR*/,int C>
    struct mul_mm_defined;

    template <>
    struct
    mul_mm_defined<3,3,3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    A &>::type
operator*=( A & a, B const & b )
    {
    typedef typename mat_traits<A>::scalar_type Ta;
    typedef typename mat_traits<B>::scalar_type Tb;
    Ta const a00 = mat_traits<A>::template read_element<0,0>(a);
    Ta const a01 = mat_traits<A>::template read_element<0,1>(a);
    Ta const a02 = mat_traits<A>::template read_element<0,2>(a);
    Ta const a10 = mat_traits<A>::template read_element<1,0>(a);
    Ta const a11 = mat_traits<A>::template read_element<1,1>(a);
    Ta const a12 = mat_traits<A>::template read_element<1,2>(a);
    Ta const a20 = mat_traits<A>::template read_element<2,0>(a);
    Ta const a21 = mat_traits<A>::template read_element<2,1>(a);
    Ta const a22 = mat_traits<A>::template read_element<2,2>(a);
    Tb const b00 = mat_traits<B>::template read_element<0,0>(b);
    Tb const b01 = mat_traits<B>::template read_element<0,1>(b);
    Tb const b02 = mat_traits<B>::template read_element<0,2>(b);
    Tb const b10 = mat_traits<B>::template read_element<1,0>(b);
    Tb const b11 = mat_traits<B>::template read_element<1,1>(b);
    Tb const b12 = mat_traits<B>::template read_element<1,2>(b);
    Tb const b20 = mat_traits<B>::template read_element<2,0>(b);
    Tb const b21 = mat_traits<B>::template read_element<2,1>(b);
    Tb const b22 = mat_traits<B>::template read_element<2,2>(b);
    mat_traits<A>::template write_element<0,0>(a)=a00*b00+a01*b10+a02*b20;
    mat_traits<A>::template write_element<0,1>(a)=a00*b01+a01*b11+a02*b21;
    mat_traits<A>::template write_element<0,2>(a)=a00*b02+a01*b12+a02*b22;
    mat_traits<A>::template write_element<1,0>(a)=a10*b00+a11*b10+a12*b20;
    mat_traits<A>::template write_element<1,1>(a)=a10*b01+a11*b11+a12*b21;
    mat_traits<A>::template write_element<1,2>(a)=a10*b02+a11*b12+a12*b22;
    mat_traits<A>::template write_element<2,0>(a)=a20*b00+a21*b10+a22*b20;
    mat_traits<A>::template write_element<2,1>(a)=a20*b01+a21*b11+a22*b21;
    mat_traits<A>::template write_element<2,2>(a)=a20*b02+a21*b12+a22*b22;
    return a;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*=;
    }

namespace
qvm_detail
    {
    template <int D>
    struct mul_eq_mm_defined;

    template <>
    struct
    mul_eq_mm_defined<3>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==3 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==1,
    deduce_mat2<A,B,3,1> >::type
operator*( A const & a, B const & b )
    {
    typedef typename mat_traits<A>::scalar_type Ta;
    typedef typename mat_traits<B>::scalar_type Tb;
    Ta const a00 = mat_traits<A>::template read_element<0,0>(a);
    Ta const a01 = mat_traits<A>::template read_element<0,1>(a);
    Ta const a02 = mat_traits<A>::template read_element<0,2>(a);
    Ta const a10 = mat_traits<A>::template read_element<1,0>(a);
    Ta const a11 = mat_traits<A>::template read_element<1,1>(a);
    Ta const a12 = mat_traits<A>::template read_element<1,2>(a);
    Ta const a20 = mat_traits<A>::template read_element<2,0>(a);
    Ta const a21 = mat_traits<A>::template read_element<2,1>(a);
    Ta const a22 = mat_traits<A>::template read_element<2,2>(a);
    Tb const b00 = mat_traits<B>::template read_element<0,0>(b);
    Tb const b10 = mat_traits<B>::template read_element<1,0>(b);
    Tb const b20 = mat_traits<B>::template read_element<2,0>(b);
    typedef typename deduce_mat2<A,B,3,1>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==3);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==1);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a00*b00+a01*b10+a02*b20;
    mat_traits<R>::template write_element<1,0>(r)=a10*b00+a11*b10+a12*b20;
    mat_traits<R>::template write_element<2,0>(r)=a20*b00+a21*b10+a22*b20;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int /*CR*/,int C>
    struct mul_mm_defined;

    template <>
    struct
    mul_mm_defined<3,3,1>
        {
        static bool const value=true;
        };
    }

template <class A,class B>
BOOST_QVM_INLINE_OPERATIONS
typename lazy_enable_if_c<
    mat_traits<A>::rows==1 && mat_traits<B>::rows==3 &&
    mat_traits<A>::cols==3 && mat_traits<B>::cols==3,
    deduce_mat2<A,B,1,3> >::type
operator*( A const & a, B const & b )
    {
    typedef typename mat_traits<A>::scalar_type Ta;
    typedef typename mat_traits<B>::scalar_type Tb;
    Ta const a00 = mat_traits<A>::template read_element<0,0>(a);
    Ta const a01 = mat_traits<A>::template read_element<0,1>(a);
    Ta const a02 = mat_traits<A>::template read_element<0,2>(a);
    Tb const b00 = mat_traits<B>::template read_element<0,0>(b);
    Tb const b01 = mat_traits<B>::template read_element<0,1>(b);
    Tb const b02 = mat_traits<B>::template read_element<0,2>(b);
    Tb const b10 = mat_traits<B>::template read_element<1,0>(b);
    Tb const b11 = mat_traits<B>::template read_element<1,1>(b);
    Tb const b12 = mat_traits<B>::template read_element<1,2>(b);
    Tb const b20 = mat_traits<B>::template read_element<2,0>(b);
    Tb const b21 = mat_traits<B>::template read_element<2,1>(b);
    Tb const b22 = mat_traits<B>::template read_element<2,2>(b);
    typedef typename deduce_mat2<A,B,1,3>::type R;
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows==1);
    BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols==3);
    R r;
    mat_traits<R>::template write_element<0,0>(r)=a00*b00+a01*b10+a02*b20;
    mat_traits<R>::template write_element<0,1>(r)=a00*b01+a01*b11+a02*b21;
    mat_traits<R>::template write_element<0,2>(r)=a00*b02+a01*b12+a02*b22;
    return r;
    }

namespace
sfinae
    {
    using ::boost::qvm::operator*;
    }

namespace
qvm_detail
    {
    template <int R,int /*CR*/,int C>
    struct mul_mm_defined;

    template <>
    struct
    mul_mm_defined<1,3,3>
        {
        static bool const value=true;
        };
    }

} }

#endif


#include <boost/integer/integer_mask.hpp>


/**
 *  Image GraphCut 3D Segmentation
 *
 *  Copyright (c) 2016, Zurich University of Applied Sciences, School of Engineering, T. Fitze, Y. Pauchard
 *
 *  Licensed under GNU General Public License 3.0 or later.
 *  Some rights reserved.
 */

 #ifndef __MaxFlowGraphBoost_hxx_
#define __MaxFlowGraphBoost_hxx_

// boost
#include <boost/assign/list_of.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>

/*
* Wraps the boosts graph library for easier use of the boykov_kolmogorov_max_flow algorithm.
*
*/
class MaxFlowGraphBoost {
public:
    typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
            boost::no_property,
            boost::property<boost::edge_index_t, std::size_t> > GraphType;

    typedef boost::graph_traits<GraphType>::edge_descriptor EdgeDescriptor;

    MaxFlowGraphBoost(unsigned int dimension1, unsigned int dimension2, unsigned int dimension3)
            : numberOfVertices(dimension1 * dimension2 * dimension3 + 2)
            , SOURCE(numberOfVertices - 2)
            , SINK(numberOfVertices - 1)
            , currentEdgeIndex(-1)
            , graph(numberOfVertices)
            , reverseEdges()
            , capacity()
            , groups(numberOfVertices)
    {
    }

    // boykov_kolmogorov_max_flow requires all edges to have a reverse edge.
    void addBidirectionalEdge(unsigned int source, unsigned int target, float weight, float reverseWeight){

        // tracking the currentEdgeIndex manually instead of getting it via boost:num_edges(graph) results in a massive
        // speedup: http://stackoverflow.com/questions/7890857/boost-graph-library-edge-insertion-slow-for-large-graph

        // create both edges
        EdgeDescriptor edge = boost::add_edge(source, target, ++currentEdgeIndex, graph).first;
        EdgeDescriptor reverseEdge = boost::add_edge(target, source, ++currentEdgeIndex, graph).first;

        // add them to out property maps
        reverseEdges.push_back(reverseEdge);
        reverseEdges.push_back(edge);
        capacity.push_back(weight);
        capacity.push_back(weight);
    }

    void addTerminalEdges(unsigned int node, float sourceWeight, float sinkWeight){
        addBidirectionalEdge(node, SOURCE, sourceWeight, sinkWeight);
        addBidirectionalEdge(node, SINK, sinkWeight, sinkWeight);
    }

    // start the calculation
    void calculateMaxFlow(){
        std::vector<float> residualCapacity(getNumberOfEdges(), 0);

        // max flow
        boost::boykov_kolmogorov_max_flow(graph
                , boost::make_iterator_property_map(&capacity.front(), boost::get(boost::edge_index, graph))
                , boost::make_iterator_property_map(&residualCapacity.front(), boost::get(boost::edge_index, graph))
                , boost::make_iterator_property_map(&reverseEdges.front(), boost::get(boost::edge_index, graph))
                , boost::make_iterator_property_map(&groups.front(), boost::get(boost::vertex_index, graph))
                , boost::get(boost::vertex_index, graph)
                , SOURCE
                , SINK);
    }

    // query the resulting segmentation group of a vertex.
    int groupOf(unsigned int vertex){
        return groups.at(vertex);
    }

    int groupOfSource(){
        return groupOf(SOURCE);
    }

    int groupOfSink(){
        return groupOf(SINK);
    }

    long getNumberOfVertices(){
        return boost::num_vertices(graph) - 2;
    }

    long getNumberOfEdges(){
        return boost::num_edges(graph);
    }
private:
    long numberOfVertices;
    unsigned int SOURCE;
    unsigned int SINK;
    long currentEdgeIndex;

    GraphType graph;
    std::vector<EdgeDescriptor> reverseEdges;
    std::vector<float> capacity;
    std::vector<int> groups;

};

#endif


#ifndef INCLUDED_objective_hash_XformHashFromNest_HH
#define INCLUDED_objective_hash_XformHashFromNest_HH

#include "scheme/util/SimpleArray.hh"

#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>

namespace scheme { namespace objective { namespace hash {

template< class _Nest >
struct XformHashFromNest {

	template< class _Xform >
	struct apply {

		typedef boost::is_same< typename _Nest::Value, _Xform > XformCheck;
		BOOST_STATIC_ASSERT_MSG( XformCheck::value, "Nest::Value must be same as Xform" );

		typedef _Nest Nest;
		typedef _Xform Xform;
		typedef typename _Nest::Float Float;
		typedef typename _Nest::Index Index;
		typedef util::SimpleArray<3,Float> F3;
		typedef util::SimpleArray<3,int>   I3;

		Nest nest_;

		apply(){}

		apply( Float cart_resl, Float ang_resl_deg, Float cart_bound=512.0 ){
			init( cart_resl, ang_resl_deg, cart_bound );
		}

		void
		init( Float cart_resl, Float ang_resl_deg, Float cart_bound ) {
			F3 lb(-cart_bound), ub(cart_bound);
			I3 bs( std::ceil(2.0*cart_bound/cart_resl) );
			nest_.init( ang_resl_deg, lb, ub, bs );
		}

		Index get_key( Xform const & x, int resl = 0 ) const {
			return nest_.get_index( x, resl );
		}

		bool is_valid( Index key, int resl = 0 ) const {
			return nest_.check_state( key, resl );
		}

		Xform get_center( Index key, int resl = 0 ) const {
			Xform val;
			BOOST_VERIFY( nest_.get_state( key, resl, val ) );
			return val;
		}

		Index approx_size( int resl = 0 ) const {
			return nest_.size( resl );
		}

		static std::string name(){ return "XformHashFromNest< "+_Nest::pmap_name() + " >" ; }

	};

};

}}}

#endif


#ifndef TEST_UNIT_MATH_MIX_MAT_VECTORIZE_EXPECT_MIX_MATRIX_VALUE_HPP
#define TEST_UNIT_MATH_MIX_MAT_VECTORIZE_EXPECT_MIX_MATRIX_VALUE_HPP

#include <math/mix/mat/vectorize/build_mix_matrix.hpp>
#include <math/mix/mat/vectorize/expect_val_deriv_eq.hpp>
#include <Eigen/Dense>
#include <vector>

template <typename F, typename T>
void expect_mix_matrix_value() {
  using std::vector;
  typedef Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> matrix_t;

  size_t num_inputs = F::valid_inputs().size();
  size_t num_cols = 3;
  matrix_t template_m(num_inputs, num_cols);

  for (int i = 0; i < template_m.size(); ++i) {
    matrix_t y = build_mix_matrix<F>(template_m, i);
    matrix_t z = build_mix_matrix<F>(template_m, i);
    matrix_t fz = F::template apply<matrix_t>(z);
    EXPECT_EQ(z.size(), fz.size());
    expect_val_deriv_eq(F::apply_base(y(i)), y(i), fz(i), z(i));
  }

  size_t vector_matrix_size = 2;
  for (size_t i = 0; i < vector_matrix_size; ++i) {
    for (int j = 0; j < template_m.size(); ++j) {
      vector<matrix_t> a;
      vector<matrix_t> b;
      for (size_t k = 0; k < vector_matrix_size; ++k) {
        if (k == i) {
          a.push_back(build_mix_matrix<F>(template_m, j));
          b.push_back(build_mix_matrix<F>(template_m, j));
        } else {
          a.push_back(build_mix_matrix<F>(template_m));
          b.push_back(build_mix_matrix<F>(template_m));
        }
      }
      vector<matrix_t> fb = F::template apply<vector<matrix_t> >(b);
      EXPECT_EQ(b.size(), fb.size());
      EXPECT_EQ(b[i].size(), fb[i].size());
      expect_val_deriv_eq(F::apply_base(a[i](j)), a[i](j), fb[i](j), b[i](j));
    }
  }

  int seed_i = num_inputs + 1;
  matrix_t c = build_mix_matrix<F>(template_m, seed_i);
  matrix_t d = build_mix_matrix<F>(template_m, seed_i);
  matrix_t fab = F::template apply<matrix_t>(d.block(1, 1, 1, 1));
  expect_val_deriv_eq(F::apply_base(c(1, 1)), c(1, 1), fab(0, 0), d(1, 1));
}

#endif


// MIT License
//
// Copyright (c) 2019 Jelle Spijker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#include "../include/fluids/Liquid.h"

#include <boost/units/cmath.hpp>
#include <fluids/Liquid.h>

namespace Fluids {

Liquid::Liquid() :
    m_static_pressure(new quantity<si::pressure>(1.e5 * si::pascals)),
    m_speed(new quantity<si::velocity>(0. * si::meters_per_second)),
    m_height(new quantity<si::length>(0. * si::meter)),
    m_density(new quantity<si::mass_density>(1000. * si::kilogram_per_cubic_meter)),
    m_dynamic_viscosity(new quantity<si::dynamic_viscosity>(1.15e-3 * si::pascals * si::seconds)),
    m_dynamic_pressure(new quantity<si::pressure>(0. * si::pascal)),
    m_potential_pressure(new quantity<si::pressure>(0. * si::pascal)),
    m_bernoulli(new quantity<si::pressure>(0. * si::pascal)) {

}

Liquid::Liquid(const Liquid &other) :
    m_static_pressure(new quantity<si::pressure>(*other.m_static_pressure)),
    m_speed(new quantity<si::velocity>(*other.m_speed)),
    m_height(new quantity<si::length>(*other.m_height)),
    m_density(new quantity<si::mass_density>(*other.m_density)),
    m_dynamic_viscosity(new quantity<si::dynamic_viscosity>(*other.m_dynamic_viscosity)),
    m_dynamic_pressure(new quantity<si::pressure>(*other.m_dynamic_pressure)),
    m_potential_pressure(new quantity<si::pressure>(*other.m_potential_pressure)),
    m_bernoulli(new quantity<si::pressure>(*other.m_bernoulli)) {

}

Liquid &Liquid::operator=(const Liquid &other) {
  if (this == &other)
    return *this;
  m_static_pressure = std::make_shared<quantity<si::pressure>>(*other.m_static_pressure);
  m_speed = std::make_shared<quantity<si::velocity>>(*other.m_speed);
  m_height = std::make_shared<quantity<si::length>>(*other.m_height);
  m_density = std::make_shared<quantity<si::mass_density>>(*other.m_density);
  m_dynamic_viscosity = std::make_shared<quantity<si::dynamic_viscosity>>(*other.m_dynamic_viscosity);
  m_dynamic_pressure = std::make_shared<quantity<si::pressure>>(*other.m_dynamic_pressure);
  m_potential_pressure = std::make_shared<quantity<si::pressure>>(*other.m_potential_pressure);
  m_bernoulli = std::make_shared<quantity<si::pressure>>(*other.m_bernoulli);
  return *this;
}

const std::shared_ptr<quantity<si::mass_density>> &Liquid::Get_Density() const {
  return m_density;
}

void Liquid::Set_Density(const std::shared_ptr<quantity<si::mass_density>> &density) {
  Liquid::m_density = density;
}

const std::shared_ptr<quantity<si::length>> &Liquid::Get_Height() const {
  return m_height;
}

void Liquid::Set_Height(const std::shared_ptr<quantity<si::length>> &height) {
  Liquid::m_height = height;
}

const std::shared_ptr<quantity<si::pressure>> &Liquid::Get_Dynamic_pressure() const {
  *m_dynamic_pressure = 0.5 * *this->Get_Density() * abs(*this->Get_Speed()) * *this->Get_Speed();
  return m_dynamic_pressure;
}

const std::shared_ptr<quantity<si::pressure>> &Liquid::Get_Potential_pressure() const {
  *m_potential_pressure = si::constants::g * *this->Get_Height() * *this->Get_Density();
  return m_potential_pressure;
}

const std::shared_ptr<quantity<si::pressure>> &Liquid::Get_Bernoulli() const {
  *m_bernoulli = *this->Get_Static_pressure() + *this->Get_Dynamic_pressure() + *this->Get_Potential_pressure();
  return m_bernoulli;
}

const std::shared_ptr<quantity<si::dynamic_viscosity>> &Liquid::Get_Dynamic_viscosity() const {
  return m_dynamic_viscosity;
}

void Liquid::Set_Dynamic_viscosity(const std::shared_ptr<quantity<si::dynamic_viscosity>> &dynamic_viscosity) {
  Liquid::m_dynamic_viscosity = dynamic_viscosity;
}

const std::shared_ptr<quantity<si::velocity>> &Liquid::Get_Speed() const {
  return m_speed;
}

void Liquid::Set_Speed(const std::shared_ptr<quantity<si::velocity>> &speed) {
  Liquid::m_speed = speed;
}

const std::shared_ptr<quantity<si::pressure>> &Liquid::Get_Static_pressure() const {
  return m_static_pressure;
}

void Liquid::Set_Static_pressure(const std::shared_ptr<quantity<si::pressure>> &static_pressure) {
  Liquid::m_static_pressure = static_pressure;
}
}


// Copyright (C) 2011 by the BEM++ Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "fiber/geometrical_data.hpp"
#include "fiber/laplace_3d_adjoint_double_layer_potential_kernel_functor.hpp"
#include "fiber/laplace_3d_double_layer_potential_kernel_functor.hpp"
#include "fiber/default_collection_of_kernels.hpp"

#include "../type_template.hpp"
#include "../check_arrays_are_close.hpp"

#include <algorithm>
#include "common/armadillo_fwd.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/version.hpp>
#include <complex>

// Tests

BOOST_AUTO_TEST_SUITE(Laplace3dAdjointDoubleLayerPotentialKernel)

BOOST_AUTO_TEST_CASE_TEMPLATE(addGeometricalDependencies_works,
                              ValueType, kernel_types)
{
    Fiber::Laplace3dAdjointDoubleLayerPotentialKernelFunctor<ValueType> op;
    size_t testGeomDeps = 1024, trialGeomDeps = 16; // random initial values
    op.addGeometricalDependencies(testGeomDeps, trialGeomDeps);

    BOOST_CHECK(testGeomDeps & Fiber::GLOBALS);
    BOOST_CHECK(testGeomDeps & Fiber::NORMALS);
    BOOST_CHECK(trialGeomDeps & Fiber::GLOBALS);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(evaluateOnGrid_agrees_with_double_layer_potential,
                              ValueType, kernel_types)
{
    // Check that DLP(x, y) = ADLP(y, x)

    typedef Fiber::Laplace3dAdjointDoubleLayerPotentialKernelFunctor<ValueType> ADLPFunctor;
    typedef Fiber::DefaultCollectionOfKernels<ADLPFunctor> ADLPKernels;
    ADLPKernels adlpKernels((ADLPFunctor()));

    Fiber::GeometricalData<typename ADLPFunctor::CoordinateType> testGeomData, trialGeomData;
    const int worldDim = 3;
    const int testPointCount = 2, trialPointCount = 3;
    testGeomData.globals.set_size(worldDim, testPointCount);
    testGeomData.globals.fill(0.);
    testGeomData.globals(0, 1) = 1.;

    testGeomData.normals.set_size(worldDim, testPointCount);
    testGeomData.normals.fill(0.);
    testGeomData.normals(0, 0) = 1.;
    testGeomData.normals(0, 1) = 1.;

    trialGeomData.globals.set_size(worldDim, trialPointCount);
    trialGeomData.globals.fill(1.);
    trialGeomData.globals(0, 0) = 2.;
    trialGeomData.globals(0, 1) = 3.;
    trialGeomData.globals(0, 2) = 4.;

    Fiber::CollectionOf4dArrays<ValueType> adlpResults;
    adlpKernels.evaluateOnGrid(testGeomData, trialGeomData, adlpResults);
    Fiber::_4dArray<ValueType>& adlpResult = adlpResults[0];

    typedef Fiber::Laplace3dDoubleLayerPotentialKernelFunctor<ValueType> DLPFunctor;
    typedef Fiber::DefaultCollectionOfKernels<DLPFunctor> DLPKernels;
    DLPKernels dlpKernels((DLPFunctor()));
    std::swap(testGeomData, trialGeomData);

    Fiber::CollectionOf4dArrays<ValueType> dlpResults;
    dlpKernels.evaluateOnGrid(testGeomData, trialGeomData, dlpResults);
    Fiber::_4dArray<ValueType>& dlpResult = dlpResults[0];

    // swap test and trial point indexing
    Fiber::_4dArray<ValueType> reorderedDlpResult(dlpResult.extent(1),
                                                  dlpResult.extent(0),
                                                  dlpResult.extent(3),
                                                  dlpResult.extent(2));
    for (size_t i0 = 0; i0 < dlpResult.extent(0); ++i0)
        for (size_t i1 = 0; i1 < dlpResult.extent(1); ++i1)
            for (size_t i2 = 0; i2 < dlpResult.extent(2); ++i2)
                for (size_t i3 = 0; i3 < dlpResult.extent(3); ++i3)
                    reorderedDlpResult(i1, i0, i3, i2) = dlpResult(i0, i1, i2, i3);

    BOOST_CHECK(check_arrays_are_close<ValueType>(adlpResult, reorderedDlpResult, 1e-6));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(evaluateOnGrid_agrees_with_evaluateAtPointPairs,
                              ValueType, kernel_types)
{
    typedef Fiber::Laplace3dAdjointDoubleLayerPotentialKernelFunctor<ValueType> Functor;
    typedef Fiber::DefaultCollectionOfKernels<Functor> Kernels;
    Kernels kernels((Functor()));

    typedef Fiber::GeometricalData<typename Functor::CoordinateType> GeomData;

    const int worldDim = 3;
    const int testPointCount = 2, trialPointCount = 3;

    // Collect data with evaluateOnGrid
    GeomData testGeomDataOnGrid, trialGeomDataOnGrid;

    testGeomDataOnGrid.globals.set_size(worldDim, testPointCount);
    testGeomDataOnGrid.globals.fill(0.);
    testGeomDataOnGrid.globals(0, 1) = 1.;

    testGeomDataOnGrid.normals.set_size(worldDim, testPointCount);
    testGeomDataOnGrid.normals.fill(0.);
    testGeomDataOnGrid.normals(1, 0) = 1.;
    testGeomDataOnGrid.normals(1, 1) = 1.;

    trialGeomDataOnGrid.globals.set_size(worldDim, trialPointCount);
    trialGeomDataOnGrid.globals.fill(1.);
    trialGeomDataOnGrid.globals(0, 0) = 2.;
    trialGeomDataOnGrid.globals(0, 1) = 3.;
    trialGeomDataOnGrid.globals(0, 2) = 4.;

    Fiber::CollectionOf4dArrays<ValueType> resultOnGrid;
    kernels.evaluateOnGrid(testGeomDataOnGrid, trialGeomDataOnGrid, resultOnGrid);

    arma::Col<ValueType> convertedResultOnGrid(testPointCount * trialPointCount);
    for (int testPoint = 0; testPoint < testPointCount; ++testPoint)
        for (int trialPoint = 0; trialPoint < trialPointCount; ++trialPoint)
            convertedResultOnGrid(testPoint + trialPoint * testPointCount) =
                    resultOnGrid[0](0, 0, testPoint, trialPoint);

    // Collect data with evaluateAtPointPairs
    GeomData testGeomDataAtPointPairs, trialGeomDataAtPointPairs;
    testGeomDataAtPointPairs.globals.set_size(worldDim, testPointCount * trialPointCount);
    testGeomDataAtPointPairs.normals.set_size(worldDim, testPointCount * trialPointCount);
    trialGeomDataAtPointPairs.globals.set_size(worldDim, testPointCount * trialPointCount);
    for (int testPoint = 0; testPoint < testPointCount; ++testPoint)
        for (int trialPoint = 0; trialPoint < trialPointCount; ++trialPoint) {
            testGeomDataAtPointPairs.globals.col(testPoint + trialPoint * testPointCount) =
                    testGeomDataOnGrid.globals.col(testPoint);
            testGeomDataAtPointPairs.normals.col(testPoint + trialPoint * testPointCount) =
                    testGeomDataOnGrid.normals.col(testPoint);
            trialGeomDataAtPointPairs.globals.col(testPoint + trialPoint * testPointCount) =
                    trialGeomDataOnGrid.globals.col(trialPoint);
        }

    Fiber::CollectionOf3dArrays<ValueType> resultAtPointPairs;
    kernels.evaluateAtPointPairs(testGeomDataAtPointPairs, trialGeomDataAtPointPairs,
                                 resultAtPointPairs);
    arma::Col<ValueType> convertedResultAtPointPairs(testPointCount * trialPointCount);
    for (int point = 0; point < testPointCount * trialPointCount; ++point)
        convertedResultAtPointPairs(point) =
                resultAtPointPairs[0](0, 0, point);

    BOOST_CHECK(check_arrays_are_close<ValueType>(
                    convertedResultAtPointPairs, convertedResultOnGrid, 1e-6));
}

BOOST_AUTO_TEST_SUITE_END()


/*
 * $Revision: 477 $ $Date: 2010-08-31 11:49:37 -0700 (Tue, 31 Aug 2010) $
 *
 * Copyright by Astos Solutions GmbH, Germany
 *
 * this file is published under the Astos Solutions Free Public License
 * For details on copyright and terms of use see
 * http://www.astos.de/Astos_Solutions_Free_Public_License.html
 */

#include "PlanetGridLayer.h"
#include "RenderContext.h"
#include "QuadtreeTile.h"
#include "Units.h"
#include "WorldGeometry.h"
#include "TextureFont.h"
#include <Eigen/LU>
#include <algorithm>

using namespace vesta;
using namespace Eigen;
using namespace std;

PlanetGridLayer::PlanetGridLayer() :
    m_gridColor(1.0f, 1.0f, 1.0f),
    m_gridOpacity(0.5f)
{
}

PlanetGridLayer::~PlanetGridLayer()
{
}

static void
drawParallel(float lat, float lon0, float lon1)
{
    float cosLat = cos(lat);
    float sinLat = sin(lat);

    glBegin(GL_LINE_STRIP);
    for (unsigned int i = 0; i <= 32; ++i)
    {
        float t = float(i) / 32.0f;
        float lon = (1.0f - t) * lon0 + t * lon1;
        Vector3f v(cos(lon) * cosLat, sin(lon) * cosLat, sinLat);
        glVertex3fv(v.data());
    }
    glEnd();
}

static void
drawMeridian(float lon, float lat0, float lat1)
{
    float cosLon = cos(lon);
    float sinLon = sin(lon);

    glBegin(GL_LINE_STRIP);
    for (unsigned int i = 0; i <= 32; ++i)
    {
        float t = float(i) / 32.0f;
        float lat = (1.0f - t) * lat0 + t * lat1;
        float cosLat = cos(lat);
        Vector3f v(cosLon * cosLat, sinLon * cosLat, sin(lat));
        glVertex3fv(v.data());
    }
    glEnd();
}

static float
chooseGridSpacing(float idealSpacing)
{
    static const float allowedSpacings[] =
    {
        30.0f,
        15.0f,
        10.0f,
         5.0f,
         3.0f,
         2.0f,
         1.0f,
         1.0f / 2.0f,  // 30 mins
         1.0f / 3.0f,  // 20 mins
         1.0f / 5.0f,  // 12 mins
         1.0f / 10.0f, //  6 mins
         1.0f / 15.0f, //  4 mins
         1.0f / 20.0f, //  3 mins
         1.0f / 30.0f, //  2 mins
         1.0f / 60.0f, //  1 min
    };
    static const unsigned int nSpacings = sizeof(allowedSpacings) / sizeof(allowedSpacings[0]);

    float spacing = allowedSpacings[nSpacings - 1];
    for (unsigned int i = 0; i < nSpacings; ++i)
    {
        if (idealSpacing > allowedSpacings[i])
        {
            spacing = allowedSpacings[i];
            break;
        }
    }

    return spacing;
}

void
PlanetGridLayer::renderTile(RenderContext& rc, const WorldGeometry* world, const QuadtreeTile* tile) const
{
    float radius = world->ellipsoidAxes().minCoeff() * 0.5f;
    Vector3f cameraPosition = (rc.modelview().inverse() * Vector4f::UnitW()).start<3>();
    float distToCenter = rc.modelview().translation().norm();
    float altitude = max(1.0f, distToCenter - radius);
    float apparentSize = radius / altitude;

    // Compute the approximate projected size of the planet in pixels
    float pixelSize = apparentSize / rc.pixelSize();
    float idealLatSpacing = 360.0f / (pixelSize / 30.0f);

    // Fade out grid when grid spacing gets large
    float opacity = m_gridOpacity;
    if (idealLatSpacing > 45.0f)
    {
        opacity *= max(0.0f, (90.0f - idealLatSpacing) / 45.0f);
    }

    if (opacity == 0.0f)
    {
        return;
    }

    rc.setVertexInfo(VertexSpec::Position);

    Material simpleMaterial;
    simpleMaterial.setDiffuse(m_gridColor);
    simpleMaterial.setOpacity(opacity);
    rc.bindMaterial(&simpleMaterial);

    // Reduce meridian spacing when the observer is close to the pole
    float z = abs(cameraPosition.normalized().z());
    float idealLonSpacing = idealLatSpacing / max(0.01f, sqrt(1.0f - z * z));

    // TODO: Reduce spacing further when observer is close to the surface
    // and looking out along the horizon.

    float latSpacing = float(toRadians(chooseGridSpacing(idealLatSpacing)));
    float lonSpacing = float(toRadians(chooseGridSpacing(idealLonSpacing)));

    float tileArc = float(PI) * tile->extent();
    Vector2f southwest = tile->southwest();

    float lonWest = float(PI) * southwest.x();
    float lonEast = lonWest + tileArc;
    float latSouth = float(PI) * southwest.y();
    float latNorth = latSouth + tileArc;

    int firstMeridian = int(ceil(lonWest / lonSpacing));
    int lastMeridian = int(floor(lonEast / lonSpacing));
    int firstParallel = int(ceil(latSouth / latSpacing));
    int lastParallel = int(floor(latNorth / latSpacing));

    for (int i = firstMeridian; i <= lastMeridian; ++i)
    {
        drawMeridian(i * lonSpacing, latSouth, latNorth);
    }

    for (int i = firstParallel; i <= lastParallel; ++i)
    {
        drawParallel(i * latSpacing, lonWest, lonEast);
    }

    // TODO: Draw coordinate labels
    float subLon = atan2(cameraPosition.y(), cameraPosition.z());
    float subLat = acos(cameraPosition.normalized().z());

    float meridian = std::floor(subLon) / idealLonSpacing;
}

/** Set the font used for coordinate labels.
  */
void
PlanetGridLayer::setLabelFont(TextureFont* font)
{
    m_labelFont = font;
}


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

#define BOOST_TEST_MODULE vxc_grid_test

// Standard includes
#include <fstream>

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

// Local VOTCA includes
#include "votca/xtp/orbitals.h"
#include "votca/xtp/vxc_grid.h"

using namespace votca::xtp;
using namespace std;

BOOST_AUTO_TEST_SUITE(vxc_grid_test)

AOBasis CreateBasis(const QMMolecule& mol) {

  BasisSet basis;
  basis.Load(std::string(XTP_TEST_DATA_FOLDER) + "/vxc_grid/3-21G.xml");
  AOBasis aobasis;
  aobasis.Fill(basis, mol);
  return aobasis;
}

BOOST_AUTO_TEST_CASE(vxc_grid_build) {

  QMMolecule mol("none", 0);

  mol.LoadFromFile(std::string(XTP_TEST_DATA_FOLDER) +
                   "/vxc_grid/molecule.xyz");
  AOBasis aobasis = CreateBasis(mol);

  Vxc_Grid grid;
  grid.GridSetup("medium", mol, aobasis);

  BOOST_CHECK_EQUAL(grid.getGridSize(), grid.getGridpoints().size());
  BOOST_CHECK_EQUAL(grid.getGridSize(), 53404);
  BOOST_CHECK_EQUAL(grid.getBoxesSize(), 51);
}

BOOST_AUTO_TEST_SUITE_END()


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

  Defines the as_integer meta-function

  @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_DETAIL_DISPATCH_META_AS_INTEGER_HPP_INCLUDED
#define BOOST_SIMD_DETAIL_DISPATCH_META_AS_INTEGER_HPP_INCLUDED

#include <boost/simd/detail/dispatch/meta/sign_of.hpp>
#include <boost/simd/detail/dispatch/meta/factory_of.hpp>
#include <boost/simd/detail/dispatch/meta/primitive_of.hpp>
#include <boost/simd/detail/dispatch/meta/make_integer.hpp>
#include <type_traits>

namespace boost { namespace dispatch
{
  namespace detail
  {
    template<typename T, typename Sign> struct as_integer
    {
      using type  = boost::dispatch::make_integer_t < sizeof(boost::dispatch::primitive_of_t<T>)
                                                    , Sign
                                                    , boost::dispatch::factory_of<T>
                                                    >;
    };
  }

  /*!
    @ingroup group-generation
    @brief Turn a type into an equivalent integer

    Converts any type which Primitive is Fundamental into a integral type with a compatible size
    and an optional sign (which by default is the origin type's sign).

    @tparam T     Type to convert.
    @tparam Sign  Optional sign of the resulting integer (@ signed or @c unsigned)
  **/
  template<typename T, typename Sign = boost::dispatch::sign_of_t<T>>
  struct as_integer : detail::as_integer<typename std::decay<T>::type,Sign>
  {};

  template<typename T, typename Sign = boost::dispatch::sign_of_t<T>>
  using as_integer_t = typename as_integer<T,Sign>::type;
} }

#endif