diff options
Diffstat (limited to 'boost/numeric/ublas')
43 files changed, 12314 insertions, 5640 deletions
diff --git a/boost/numeric/ublas/assignment.hpp b/boost/numeric/ublas/assignment.hpp index d2079e13dc..d14ada02bd 100644 --- a/boost/numeric/ublas/assignment.hpp +++ b/boost/numeric/ublas/assignment.hpp @@ -8,6 +8,7 @@ #ifndef ASSIGNMENT_HPP #define ASSIGNMENT_HPP + #include <boost/numeric/ublas/vector_expression.hpp> #include <boost/numeric/ublas/matrix_expression.hpp> @@ -174,7 +175,11 @@ template <std::ptrdiff_t I> class static_vector_move_manip: public index_manipulator<static_vector_move_manip<I> > { public: template <typename V> - BOOST_UBLAS_INLINE void manip(V &k) const { k+=I; } + BOOST_UBLAS_INLINE void manip(V &k) const { + // With the equivalent expression using '+=' operator, mscv reports waring C4245: + // '+=' : conversion from 'ptrdiff_t' to 'unsigned int', signed/unsigned mismatch + k = k + I; + } }; /** @@ -375,8 +380,10 @@ public: template <typename V, typename K> BOOST_UBLAS_INLINE void manip(V &k, K &l) const { - k+=I; - l+=J; + // With the equivalent expression using '+=' operator, mscv reports waring C4245: + // '+=' : conversion from 'ptrdiff_t' to 'unsigned int', signed/unsigned mismatch + k = k + I; + l = l + J; } }; @@ -926,29 +933,29 @@ public: typedef typename E::expression_type::size_type size_type; BOOST_UBLAS_INLINE - vector_expression_assigner(E &e):ve(e), i(0) { + vector_expression_assigner(E &e):ve(&e), i(0) { } BOOST_UBLAS_INLINE - vector_expression_assigner(size_type k, E &e):ve(e), i(k) { + vector_expression_assigner(size_type k, E &e):ve(&e), i(k) { // Overloaded like that so it can be differentiated from (E, val). // Otherwise there would be an ambiquity when value_type == size_type. } BOOST_UBLAS_INLINE - vector_expression_assigner(E &e, value_type val):ve(e), i(0) { + vector_expression_assigner(E &e, value_type val):ve(&e), i(0) { operator,(val); } template <class AE> BOOST_UBLAS_INLINE - vector_expression_assigner(E &e, const vector_expression<AE> &nve):ve(e), i(0) { + vector_expression_assigner(E &e, const vector_expression<AE> &nve):ve(&e), i(0) { operator,(nve); } template <typename T> BOOST_UBLAS_INLINE - vector_expression_assigner(E &e, const index_manipulator<T> &ta):ve(e), i(0) { + vector_expression_assigner(E &e, const index_manipulator<T> &ta):ve(&e), i(0) { operator,(ta); } @@ -976,18 +983,18 @@ public: template <class T> BOOST_UBLAS_INLINE vector_expression_assigner<E, T> operator, (fill_policy_wrapper<T>) const { - return vector_expression_assigner<E, T>(i, ve); + return vector_expression_assigner<E, T>(i, *ve); } private: BOOST_UBLAS_INLINE vector_expression_assigner &apply(const typename E::expression_type::value_type& val) { - Fill_Policy::apply(ve, i++, val); + Fill_Policy::apply(*ve, i++, val); return *this; } private: - E &ve; + E *ve; size_type i; }; @@ -1101,39 +1108,39 @@ public: typedef typename E::expression_type::size_type size_type; BOOST_UBLAS_INLINE - matrix_expression_assigner(E &e): me(e), i(0), j(0) { + matrix_expression_assigner(E &e): me(&e), i(0), j(0) { } BOOST_UBLAS_INLINE - matrix_expression_assigner(E &e, size_type k, size_type l): me(e), i(k), j(l) { + matrix_expression_assigner(E &e, size_type k, size_type l): me(&e), i(k), j(l) { } BOOST_UBLAS_INLINE - matrix_expression_assigner(E &e, typename E::expression_type::value_type val): me(e), i(0), j(0) { + matrix_expression_assigner(E &e, typename E::expression_type::value_type val): me(&e), i(0), j(0) { operator,(val); } template <class AE> BOOST_UBLAS_INLINE - matrix_expression_assigner(E &e, const vector_expression<AE> &nve):me(e), i(0), j(0) { + matrix_expression_assigner(E &e, const vector_expression<AE> &nve):me(&e), i(0), j(0) { operator,(nve); } template <class AE> BOOST_UBLAS_INLINE - matrix_expression_assigner(E &e, const matrix_expression<AE> &nme):me(e), i(0), j(0) { + matrix_expression_assigner(E &e, const matrix_expression<AE> &nme):me(&e), i(0), j(0) { operator,(nme); } template <typename T> BOOST_UBLAS_INLINE - matrix_expression_assigner(E &e, const index_manipulator<T> &ta):me(e), i(0), j(0) { + matrix_expression_assigner(E &e, const index_manipulator<T> &ta):me(&e), i(0), j(0) { operator,(ta); } BOOST_UBLAS_INLINE matrix_expression_assigner &operator, (const typename E::expression_type::value_type& val) { - Traverse_Policy::apply_wrap(me, i ,j); + Traverse_Policy::apply_wrap(*me, i ,j); return apply(val); } @@ -1162,21 +1169,21 @@ public: template <class T> BOOST_UBLAS_INLINE matrix_expression_assigner<E, T, Traverse_Policy> operator, (fill_policy_wrapper<T>) const { - return matrix_expression_assigner<E, T, Traverse_Policy>(me, i, j); + return matrix_expression_assigner<E, T, Traverse_Policy>(*me, i, j); } template <class T> BOOST_UBLAS_INLINE matrix_expression_assigner<E, Fill_Policy, T> operator, (traverse_policy_wrapper<T>) { - Traverse_Policy::apply_wrap(me, i ,j); - return matrix_expression_assigner<E, Fill_Policy, T>(me, i, j); + Traverse_Policy::apply_wrap(*me, i ,j); + return matrix_expression_assigner<E, Fill_Policy, T>(*me, i, j); } private: BOOST_UBLAS_INLINE matrix_expression_assigner &apply(const typename E::expression_type::value_type& val) { - Fill_Policy::apply(me, i, j, val); + Fill_Policy::apply(*me, i, j, val); Traverse_Policy::advance(i,j); return *this; } @@ -1187,14 +1194,14 @@ private: size_type bi = i; size_type bj = j; typename AE::size_type k=0, l=0; - Fill_Policy::apply(me, i, j, nme()(k, l)); - while (Traverse_Policy::next(nme, me, i, j, bi, bj, k, l)) - Fill_Policy::apply(me, i, j, nme()(k, l)); + Fill_Policy::apply(*me, i, j, nme()(k, l)); + while (Traverse_Policy::next(nme, *me, i, j, bi, bj, k, l)) + Fill_Policy::apply(*me, i, j, nme()(k, l)); return *this; } private: - E &me; + E *me; size_type i, j; }; diff --git a/boost/numeric/ublas/detail/concepts.hpp b/boost/numeric/ublas/detail/concepts.hpp index 674c610ed5..21d5501456 100644 --- a/boost/numeric/ublas/detail/concepts.hpp +++ b/boost/numeric/ublas/detail/concepts.hpp @@ -644,7 +644,7 @@ namespace boost { namespace numeric { namespace ublas { template<class T> T ZeroElement (T) { - return T(0.0); + return static_cast<T> (0); } template<class T> @@ -662,13 +662,7 @@ namespace boost { namespace numeric { namespace ublas { template<class T> T OneElement (T) { - return T(0.0); - } - - template<class T> - vector<T> - OneElement (vector<T>) { - return zero_vector<T> (); + return static_cast<T> (1); } template<class T> @@ -677,110 +671,6 @@ namespace boost { namespace numeric { namespace ublas { return identity_matrix<T> (); } -// template<> -// float -// ZeroElement (float) { -// return 0.f; -// } -// template<> -// double -// ZeroElement (double) { -// return 0.; -// } -// template<> -// vector<float> -// ZeroElement (vector<float>) { -// return zero_vector<float> (); -// } -// template<> -// vector<double> -// ZeroElement (vector<double>) { -// return zero_vector<double> (); -// } -// template<> -// matrix<float> -// ZeroElement (matrix<float>) { -// return zero_matrix<float> (); -// } -// template<> -// matrix<double> -// ZeroElement (matrix<double>) { -// return zero_matrix<double> (); -// } -// template<> -// std::complex<float> -// ZeroElement (std::complex<float>) { -// return std::complex<float> (0.f); -// } -// template<> -// std::complex<double> -// ZeroElement (std::complex<double>) { -// return std::complex<double> (0.); -// } -// template<> -// vector<std::complex<float> > -// ZeroElement (vector<std::complex<float> >) { -// return zero_vector<std::complex<float> > (); -// } -// template<> -// vector<std::complex<double> > -// ZeroElement (vector<std::complex<double> >) { -// return zero_vector<std::complex<double> > (); -// } -// template<> -// matrix<std::complex<float> > -// ZeroElement (matrix<std::complex<float> >) { -// return zero_matrix<std::complex<float> > (); -// } -// template<> -// matrix<std::complex<double> > -// ZeroElement (matrix<std::complex<double> >) { -// return zero_matrix<std::complex<double> > (); -// } - -// template<class T> -// T -// OneElement (T); -// template<> -// float -// OneElement (float) { -// return 1.f; -// } -// template<> -// double -// OneElement (double) { -// return 1.; -// } -// template<> -// matrix<float> -// OneElement (matrix<float>) { -// return identity_matrix<float> (); -// } -// template<> -// matrix<double> -// OneElement (matrix<double>) { -// return identity_matrix<double> (); -// } -// template<> -// std::complex<float> -// OneElement (std::complex<float>) { -// return std::complex<float> (1.f); -// } -// template<> -// std::complex<double> -// OneElement (std::complex<double>) { -// return std::complex<double> (1.); -// } -// template<> -// matrix<std::complex<float> > -// OneElement (matrix<std::complex<float> >) { -// return identity_matrix<std::complex<float> > (); -// } -// template<> -// matrix<std::complex<double> > -// OneElement (matrix<std::complex<double> >) { -// return identity_matrix<std::complex<double> > (); -// } template<class E1, class E2> bool diff --git a/boost/numeric/ublas/detail/matrix_assign.hpp b/boost/numeric/ublas/detail/matrix_assign.hpp index be172dd63d..b6de2586fa 100644 --- a/boost/numeric/ublas/detail/matrix_assign.hpp +++ b/boost/numeric/ublas/detail/matrix_assign.hpp @@ -30,7 +30,7 @@ namespace detail { template<class E1, class E2, class S> BOOST_UBLAS_INLINE bool equals (const matrix_expression<E1> &e1, const matrix_expression<E2> &e2, S epsilon, S min_norm) { - return norm_inf (e1 - e2) < epsilon * + return norm_inf (e1 - e2) <= epsilon * std::max<S> (std::max<S> (norm_inf (e1), norm_inf (e2)), min_norm); } @@ -74,7 +74,7 @@ namespace detail { #endif if (it2 != it2_end && it2e != it2e_end) { size_type it2_index = it2.index2 (), it2e_index = it2e.index2 (); - while (true) { + for (;;) { difference_type compare2 = it2_index - it2e_index; if (compare2 == 0) { ++ it2, ++ it2e; @@ -177,7 +177,7 @@ namespace detail { #endif if (it1 != it1_end && it1e != it1e_end) { size_type it1_index = it1.index1 (), it1e_index = it1e.index1 (); - while (true) { + for (;;) { difference_type compare2 = it1_index - it1e_index; if (compare2 == 0) { ++ it1, ++ it1e; @@ -670,7 +670,15 @@ namespace detail { size1 = (std::min) (- diff1, it1_size); if (size1 > 0) { it1_size -= size1; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size1 >= 0) { // zeroing #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator2 it2 (it1.begin ()); @@ -719,7 +727,15 @@ namespace detail { size2 = (std::min) (- diff2, it2_size); if (size2 > 0) { it2_size -= size2; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size2 >= 0) // zeroing functor_type::apply (*it2, expr_value_type/*zero*/()), ++ it2; } else { @@ -734,7 +750,15 @@ namespace detail { while (-- size2 >= 0) functor_type::apply (*it2, *it2e), ++ it2, ++ it2e; size2 = it2_size; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size2 >= 0) // zeroing functor_type::apply (*it2, expr_value_type/*zero*/()), ++ it2; } else { @@ -743,7 +767,15 @@ namespace detail { ++ it1, ++ it1e; } size1 = it1_size; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size1 >= 0) { // zeroing #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator2 it2 (it1.begin ()); @@ -802,7 +834,15 @@ namespace detail { size2 = (std::min) (- diff2, it2_size); if (size2 > 0) { it2_size -= size2; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size2 >= 0) { // zeroing #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator1 it1 (it2.begin ()); @@ -851,7 +891,15 @@ namespace detail { size1 = (std::min) (- diff1, it1_size); if (size1 > 0) { it1_size -= size1; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size1 >= 0) // zeroing functor_type::apply (*it1, expr_value_type/*zero*/()), ++ it1; } else { @@ -866,7 +914,16 @@ namespace detail { while (-- size1 >= 0) functor_type::apply (*it1, *it1e), ++ it1, ++ it1e; size1 = it1_size; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { + +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size1 >= 0) // zeroing functor_type::apply (*it1, expr_value_type/*zero*/()), ++ it1; } else { @@ -875,7 +932,15 @@ namespace detail { ++ it2, ++ it2e; } size2 = it2_size; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size2 >= 0) { // zeroing #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator1 it1 (it2.begin ()); @@ -903,7 +968,16 @@ namespace detail { void matrix_assign (M &m, const matrix_expression<E> &e, sparse_tag, row_major_tag) { typedef F<typename M::iterator2::reference, typename E::value_type> functor_type; // R unnecessary, make_conformant not required + +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif BOOST_STATIC_ASSERT ((!functor_type::computed)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif BOOST_UBLAS_CHECK (m.size1 () == e ().size1 (), bad_size ()); BOOST_UBLAS_CHECK (m.size2 () == e ().size2 (), bad_size ()); typedef typename M::value_type value_type; @@ -935,7 +1009,16 @@ namespace detail { void matrix_assign (M &m, const matrix_expression<E> &e, sparse_tag, column_major_tag) { typedef F<typename M::iterator1::reference, typename E::value_type> functor_type; // R unnecessary, make_conformant not required + +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif BOOST_STATIC_ASSERT ((!functor_type::computed)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif BOOST_UBLAS_CHECK (m.size1 () == e ().size1 (), bad_size ()); BOOST_UBLAS_CHECK (m.size2 () == e ().size2 (), bad_size ()); typedef typename M::value_type value_type; @@ -1002,7 +1085,7 @@ namespace detail { #endif if (it2 != it2_end && it2e != it2e_end) { size_type it2_index = it2.index2 (), it2e_index = it2e.index2 (); - while (true) { + for (;;) { difference_type compare2 = it2_index - it2e_index; if (compare2 == 0) { functor_type::apply (*it2, *it2e); @@ -1013,7 +1096,15 @@ namespace detail { } else break; } else if (compare2 < 0) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif functor_type::apply (*it2, expr_value_type/*zero*/()); ++ it2; } else @@ -1031,7 +1122,15 @@ namespace detail { } } } +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (it2 != it2_end) { // zeroing functor_type::apply (*it2, expr_value_type/*zero*/()); ++ it2; @@ -1041,7 +1140,15 @@ namespace detail { } ++ it1, ++ it1e; } else if (compare < 0) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator2 it2 (it1.begin ()); typename M::iterator2 it2_end (it1.end ()); @@ -1061,7 +1168,15 @@ namespace detail { increment (it1e, it1e_end, compare); } } +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (it1 != it1_end) { #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator2 it2 (it1.begin ()); @@ -1125,7 +1240,7 @@ namespace detail { #endif if (it1 != it1_end && it1e != it1e_end) { size_type it1_index = it1.index1 (), it1e_index = it1e.index1 (); - while (true) { + for (;;) { difference_type compare2 = it1_index - it1e_index; if (compare2 == 0) { functor_type::apply (*it1, *it1e); @@ -1136,7 +1251,15 @@ namespace detail { } else break; } else if (compare2 < 0) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif functor_type::apply (*it1, expr_value_type/*zero*/()); // zeroing ++ it1; } else @@ -1154,7 +1277,15 @@ namespace detail { } } } +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (it1 != it1_end) { // zeroing functor_type::apply (*it1, expr_value_type/*zero*/()); ++ it1; @@ -1164,7 +1295,15 @@ namespace detail { } ++ it2, ++ it2e; } else if (compare < 0) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator1 it1 (it2.begin ()); typename M::iterator1 it1_end (it2.end ()); @@ -1184,7 +1323,15 @@ namespace detail { increment (it2e, it2e_end, compare); } } +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (it2 != it2_end) { #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION typename M::iterator1 it1 (it2.begin ()); @@ -1390,7 +1537,7 @@ namespace detail { #endif if (it2 != it2_end && it2e != it2e_end) { size_type it2_index = it2.index2 (), it2e_index = it2e.index2 (); - while (true) { + for (;;) { difference_type compare2 = it2_index - it2e_index; if (compare2 == 0) { functor_type::apply (*it2, *it2e); @@ -1515,7 +1662,7 @@ namespace detail { #endif if (it1 != it1_end && it1e != it1e_end) { size_type it1_index = it1.index1 (), it1e_index = it1e.index1 (); - while (true) { + for (;;) { difference_type compare2 = it1_index - it1e_index; if (compare2 == 0) { functor_type::apply (*it1, *it1e); diff --git a/boost/numeric/ublas/detail/returntype_deduction.hpp b/boost/numeric/ublas/detail/returntype_deduction.hpp index 030d1f6b24..6ef1f0be08 100644 --- a/boost/numeric/ublas/detail/returntype_deduction.hpp +++ b/boost/numeric/ublas/detail/returntype_deduction.hpp @@ -126,13 +126,13 @@ struct error_cant_deduce_type {}; test(unsigned long const&); template <typename X, typename Y> - typename disable_if< + typename boost::disable_if< is_basic<X>, x_value_type >::type test(X const&); template <typename X, typename Y> - typename disable_if< + typename boost::disable_if< mpl::or_< is_basic<Y> , is_same<Y, asymmetric> diff --git a/boost/numeric/ublas/detail/vector_assign.hpp b/boost/numeric/ublas/detail/vector_assign.hpp index e612876df5..b0ffacfb62 100644 --- a/boost/numeric/ublas/detail/vector_assign.hpp +++ b/boost/numeric/ublas/detail/vector_assign.hpp @@ -59,7 +59,7 @@ namespace detail { typename E::const_iterator ite_end (e ().end ()); if (it != it_end && ite != ite_end) { size_type it_index = it.index (), ite_index = ite.index (); - while (true) { + for (;;) { difference_type compare = it_index - ite_index; if (compare == 0) { ++ it, ++ ite; @@ -316,7 +316,15 @@ namespace detail { difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size)); if (size > 0) { it_size -= size; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size >= 0) // zeroing functor_type::apply (*it, value_type/*zero*/()), ++ it; } else { @@ -330,7 +338,15 @@ namespace detail { while (-- size >= 0) functor_type::apply (*it, *ite), ++ it, ++ ite; size = it_size; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (-- size >= 0) // zeroing functor_type::apply (*it, value_type/*zero*/()), ++ it; } else { @@ -348,7 +364,15 @@ namespace detail { void vector_assign (V &v, const vector_expression<E> &e, sparse_tag) { BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ()); typedef F<typename V::iterator::reference, typename E::value_type> functor_type; +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif BOOST_STATIC_ASSERT ((!functor_type::computed)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif typedef typename V::value_type value_type; #if BOOST_UBLAS_TYPE_CHECK vector<value_type> cv (v.size ()); @@ -393,7 +417,7 @@ namespace detail { typename E::const_iterator ite_end (e ().end ()); if (it != it_end && ite != ite_end) { size_type it_index = it.index (), ite_index = ite.index (); - while (true) { + for (;;) { difference_type compare = it_index - ite_index; if (compare == 0) { functor_type::apply (*it, *ite); @@ -404,7 +428,15 @@ namespace detail { } else break; } else if (compare < 0) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif functor_type::apply (*it, value_type/*zero*/()); ++ it; } else @@ -422,8 +454,15 @@ namespace detail { } } } - +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (!functor_type::computed) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif while (it != it_end) { // zeroing functor_type::apply (*it, value_type/*zero*/()); ++ it; @@ -524,7 +563,7 @@ namespace detail { typename E::iterator ite_end (e ().end ()); if (it != it_end && ite != ite_end) { size_type it_index = it.index (), ite_index = ite.index (); - while (true) { + for (;;) { difference_type compare = it_index - ite_index; if (compare == 0) { functor_type::apply (*it, *ite); diff --git a/boost/numeric/ublas/functional.hpp b/boost/numeric/ublas/functional.hpp index c7c92614c0..571f510faa 100644 --- a/boost/numeric/ublas/functional.hpp +++ b/boost/numeric/ublas/functional.hpp @@ -433,20 +433,19 @@ namespace boost { namespace numeric { namespace ublas { template<class E> static BOOST_UBLAS_INLINE result_type apply (const vector_expression<E> &e) { -#ifndef BOOST_UBLAS_SCALED_NORM - real_type t = real_type (); typedef typename E::size_type vector_size_type; vector_size_type size (e ().size ()); +#ifndef BOOST_UBLAS_SCALED_NORM + real_type t = real_type (); for (vector_size_type i = 0; i < size; ++ i) { real_type u (type_traits<value_type>::norm_2 (e () (i))); t += u * u; } - return type_traits<real_type>::type_sqrt (t); + return static_cast<result_type>(type_traits<real_type>::type_sqrt (t)); #else real_type scale = real_type (); real_type sum_squares (1); - size_type size (e ().size ()); - for (size_type i = 0; i < size; ++ i) { + for (vector_size_type i = 0; i < size; ++ i) { real_type u (type_traits<value_type>::norm_2 (e () (i))); if ( real_type () /* zero */ == u ) continue; if (scale < u) { @@ -458,7 +457,7 @@ namespace boost { namespace numeric { namespace ublas { sum_squares += v * v; } } - return scale * type_traits<real_type>::type_sqrt (sum_squares); + return static_cast<result_type>(scale * type_traits<real_type>::type_sqrt (sum_squares)); #endif } // Dense case @@ -472,7 +471,7 @@ namespace boost { namespace numeric { namespace ublas { t += u * u; ++ it; } - return type_traits<real_type>::type_sqrt (t); + return static_cast<result_type>(type_traits<real_type>::type_sqrt (t)); #else real_type scale = real_type (); real_type sum_squares (1); @@ -488,7 +487,7 @@ namespace boost { namespace numeric { namespace ublas { } ++ it; } - return scale * type_traits<real_type>::type_sqrt (sum_squares); + return static_cast<result_type>(scale * type_traits<real_type>::type_sqrt (sum_squares)); #endif } // Sparse case @@ -502,7 +501,7 @@ namespace boost { namespace numeric { namespace ublas { t += u * u; ++ it; } - return type_traits<real_type>::type_sqrt (t); + return static_cast<result_type>(type_traits<real_type>::type_sqrt (t)); #else real_type scale = real_type (); real_type sum_squares (1); @@ -518,10 +517,56 @@ namespace boost { namespace numeric { namespace ublas { } ++ it; } - return scale * type_traits<real_type>::type_sqrt (sum_squares); + return static_cast<result_type>(scale * type_traits<real_type>::type_sqrt (sum_squares)); #endif } }; + + template<class V> + struct vector_norm_2_square : + public vector_scalar_real_unary_functor<V> { + typedef typename vector_scalar_real_unary_functor<V>::value_type value_type; + typedef typename vector_scalar_real_unary_functor<V>::real_type real_type; + typedef typename vector_scalar_real_unary_functor<V>::result_type result_type; + + template<class E> + static BOOST_UBLAS_INLINE + result_type apply (const vector_expression<E> &e) { + real_type t = real_type (); + typedef typename E::size_type vector_size_type; + vector_size_type size (e ().size ()); + for (vector_size_type i = 0; i < size; ++ i) { + real_type u (type_traits<value_type>::norm_2 (e () (i))); + t += u * u; + } + return t; + } + // Dense case + template<class D, class I> + static BOOST_UBLAS_INLINE + result_type apply (D size, I it) { + real_type t = real_type (); + while (-- size >= 0) { + real_type u (type_traits<value_type>::norm_2 (*it)); + t += u * u; + ++ it; + } + return t; + } + // Sparse case + template<class I> + static BOOST_UBLAS_INLINE + result_type apply (I it, const I &it_end) { + real_type t = real_type (); + while (it != it_end) { + real_type u (type_traits<value_type>::norm_2 (*it)); + t += u * u; + ++ it; + } + return t; + } + }; + template<class V> struct vector_norm_inf: public vector_scalar_real_unary_functor<V> { @@ -749,7 +794,7 @@ namespace boost { namespace numeric { namespace ublas { result_type apply (I1 it1, const I1 &it1_end, I2 it2, const I2 &it2_end, sparse_bidirectional_iterator_tag) { result_type t = result_type (0); if (it1 != it1_end && it2 != it2_end) { - while (true) { + for (;;) { if (it1.index () == it2.index ()) { t += *it1 * *it2, ++ it1, ++ it2; if (it1 == it1_end || it2 == it2_end) @@ -887,7 +932,7 @@ namespace boost { namespace numeric { namespace ublas { result_type t = result_type (0); if (it1 != it1_end && it2 != it2_end) { size_type it1_index = it1.index2 (), it2_index = it2.index (); - while (true) { + for (;;) { difference_type compare = it1_index - it2_index; if (compare == 0) { t += *it1 * *it2, ++ it1, ++ it2; @@ -1055,7 +1100,7 @@ namespace boost { namespace numeric { namespace ublas { result_type t = result_type (0); if (it1 != it1_end && it2 != it2_end) { size_type it1_index = it1.index (), it2_index = it2.index1 (); - while (true) { + for (;;) { difference_type compare = it1_index - it2_index; if (compare == 0) { t += *it1 * *it2, ++ it1, ++ it2; @@ -1232,7 +1277,7 @@ namespace boost { namespace numeric { namespace ublas { result_type t = result_type (0); if (it1 != it1_end && it2 != it2_end) { size_type it1_index = it1.index2 (), it2_index = it2.index1 (); - while (true) { + for (;;) { difference_type compare = difference_type (it1_index - it2_index); if (compare == 0) { t += *it1 * *it2, ++ it1, ++ it2; @@ -1674,6 +1719,7 @@ namespace boost { namespace numeric { namespace ublas { BOOST_UBLAS_CHECK (i < size_i, bad_index ()); BOOST_UBLAS_CHECK (j < size_j, bad_index ()); BOOST_UBLAS_CHECK (i <= j, bad_index ()); + boost::ignore_unused(size_i, size_j); // FIXME size_type overflow // sigma_j (j + 1) = (j + 1) * j / 2 // j = 0 1 2 3, sigma = 0 1 3 6 diff --git a/boost/numeric/ublas/matrix.hpp b/boost/numeric/ublas/matrix.hpp index d06391077a..6e405d8494 100644 --- a/boost/numeric/ublas/matrix.hpp +++ b/boost/numeric/ublas/matrix.hpp @@ -258,6 +258,30 @@ namespace boost { namespace numeric { return at_element (i, j); } + /** Access a matrix element. Here we return a reference + * \param i the first coordinate of the element. By default it's the row + * \param j the second coordinate of the element. By default it's the column + * \return a reference to the element + */ + BOOST_UBLAS_INLINE + reference operator () (size_type i) { + return data()[i]; + } + + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return data()[i]; + } + +// /** Access a matrix element. Here we return a reference +// * \param i the first coordinate of the element. By default it's the row +// * \param j the second coordinate of the element. By default it's the column +// * \return a reference to the element +// */ +// BOOST_UBLAS_INLINE +// const_reference operator () const (size_type i) { +// return data()[i]; +// } // Element assignment /** Change the value of a matrix element. Return back a reference to it @@ -1234,14 +1258,6 @@ namespace boost { namespace numeric { matrix_container<self_type> (), data_ () {} - /// \brief Construct a fixed_matrix from a list of values - /// The list may be included in curly braces. Typical syntax is choices are : - /// fixed_matrix<double, 2,2> v = { 1, 2, 3, 4 } or fixed_matrix<double,4> v( {1, 2, 3, 4} ) or fixed_matrix<double,2,2> v( 1, 2, 3, 4 ) - template <typename... Types> - fixed_matrix(value_type v0, Types... vrest) : - matrix_container<self_type> (), - data_{ { v0, vrest... } } {} - /** Dense fixed_matrix constructor with defined initial value for all the matrix elements * \param init initial value assigned to all elements */ @@ -1278,6 +1294,15 @@ namespace boost { namespace numeric { matrix_assign<scalar_assign> (*this, ae); } + /// \brief Construct a fixed_matrix from a list of values + /// The list may be included in curly braces. Typical syntax is choices are : + /// fixed_matrix<double, 2,2> v = { 1, 2, 3, 4 } or fixed_matrix<double,4> v( {1, 2, 3, 4} ) or fixed_matrix<double,2,2> v( 1, 2, 3, 4 ) + template <typename... Types> + BOOST_UBLAS_INLINE + fixed_matrix(value_type v0, Types... vrest) : + matrix_container<self_type> (), + data_( array_type{ v0, vrest... } ) {} + // Accessors /** Return the number of rows of the fixed_matrix * You can also use the free size<>() function in operation/size.hpp as size<1>(m) where m is a fixed_matrix @@ -1384,7 +1409,7 @@ namespace boost { namespace numeric { /*! @note "pass by value" the key idea to enable move semantics */ BOOST_UBLAS_INLINE - fixed_matrix &operator = (matrix m) { + fixed_matrix &operator = (fixed_matrix m) { assign_temporary(m); return *this; } diff --git a/boost/numeric/ublas/matrix_expression.hpp b/boost/numeric/ublas/matrix_expression.hpp index a36313096e..b09ad7fa90 100644 --- a/boost/numeric/ublas/matrix_expression.hpp +++ b/boost/numeric/ublas/matrix_expression.hpp @@ -22,5611 +22,5671 @@ namespace boost { namespace numeric { namespace ublas { - template<class E> - class matrix_reference: - public matrix_expression<matrix_reference<E> > { +template<class E> +class matrix_reference: + public matrix_expression<matrix_reference<E> > { - typedef matrix_reference<E> self_type; - public: + typedef matrix_reference<E> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef typename E::size_type size_type; - typedef typename E::difference_type difference_type; - typedef typename E::value_type value_type; - typedef typename E::const_reference const_reference; - typedef typename boost::mpl::if_<boost::is_const<E>, - typename E::const_reference, - typename E::reference>::type reference; - typedef E referred_type; - typedef const self_type const_closure_type; - typedef self_type closure_type; - typedef typename E::orientation_category orientation_category; - typedef typename E::storage_category storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - explicit matrix_reference (referred_type &e): - e_ (e) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e_.size1 (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e_.size2 (); - } - - public: - // Expression accessors - const correct - BOOST_UBLAS_INLINE - const referred_type &expression () const { - return e_; - } - BOOST_UBLAS_INLINE - referred_type &expression () { - return e_; - } - - public: - // Element access + using matrix_expression<self_type>::operator (); +#endif + typedef typename E::size_type size_type; + typedef typename E::difference_type difference_type; + typedef typename E::value_type value_type; + typedef typename E::const_reference const_reference; + typedef typename boost::mpl::if_<boost::is_const<E>, + typename E::const_reference, + typename E::reference>::type reference; + typedef E referred_type; + typedef const self_type const_closure_type; + typedef self_type closure_type; + typedef typename E::orientation_category orientation_category; + typedef typename E::storage_category storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + explicit matrix_reference (referred_type &e): + e_ (e) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e_.size1 (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e_.size2 (); + } + +public: + // Expression accessors - const correct + BOOST_UBLAS_INLINE + const referred_type &expression () const { + return e_; + } + BOOST_UBLAS_INLINE + referred_type &expression () { + return e_; + } + +public: + // Element access #ifndef BOOST_UBLAS_REFERENCE_CONST_MEMBER - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return expression () (i, j); - } - BOOST_UBLAS_INLINE - reference operator () (size_type i, size_type j) { - return expression () (i, j); - } + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return expression () (i, j); + } + BOOST_UBLAS_INLINE + reference operator () (size_type i, size_type j) { + return expression () (i, j); + } #else - BOOST_UBLAS_INLINE - reference operator () (size_type i, size_type j) const { - return expression () (i, j); - } -#endif - - // Assignment - BOOST_UBLAS_INLINE - matrix_reference &operator = (const matrix_reference &m) { - expression ().operator = (m); - return *this; - } - template<class AE> - BOOST_UBLAS_INLINE - matrix_reference &operator = (const matrix_expression<AE> &ae) { - expression ().operator = (ae); - return *this; - } - template<class AE> - BOOST_UBLAS_INLINE - matrix_reference &assign (const matrix_expression<AE> &ae) { - expression ().assign (ae); - return *this; - } - template<class AE> - BOOST_UBLAS_INLINE - matrix_reference &operator += (const matrix_expression<AE> &ae) { - expression ().operator += (ae); - return *this; - } - template<class AE> - BOOST_UBLAS_INLINE - matrix_reference &plus_assign (const matrix_expression<AE> &ae) { - expression ().plus_assign (ae); - return *this; - } - template<class AE> - BOOST_UBLAS_INLINE - matrix_reference &operator -= (const matrix_expression<AE> &ae) { - expression ().operator -= (ae); - return *this; - } - template<class AE> - BOOST_UBLAS_INLINE - matrix_reference &minus_assign (const matrix_expression<AE> &ae) { - expression ().minus_assign (ae); - return *this; - } - template<class AT> - BOOST_UBLAS_INLINE - matrix_reference &operator *= (const AT &at) { - expression ().operator *= (at); - return *this; - } - template<class AT> - BOOST_UBLAS_INLINE - matrix_reference &operator /= (const AT &at) { - expression ().operator /= (at); - return *this; - } - - // Swapping - BOOST_UBLAS_INLINE - void swap (matrix_reference &m) { - expression ().swap (m.expression ()); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_reference &mr) const { - return &(*this).e_ == &mr.e_; - } - - // Iterator types - typedef typename E::const_iterator1 const_iterator1; - typedef typename boost::mpl::if_<boost::is_const<E>, - typename E::const_iterator1, - typename E::iterator1>::type iterator1; - typedef typename E::const_iterator2 const_iterator2; - typedef typename boost::mpl::if_<boost::is_const<E>, - typename E::const_iterator2, - typename E::iterator2>::type iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - return expression ().find1 (rank, i, j); - } - BOOST_UBLAS_INLINE - iterator1 find1 (int rank, size_type i, size_type j) { - return expression ().find1 (rank, i, j); - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - return expression ().find2 (rank, i, j); - } - BOOST_UBLAS_INLINE - iterator2 find2 (int rank, size_type i, size_type j) { - return expression ().find2 (rank, i, j); - } - - // Iterators are the iterators of the referenced expression. - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return expression ().begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return expression ().end1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } - - BOOST_UBLAS_INLINE - iterator1 begin1 () { - return expression ().begin1 (); - } - BOOST_UBLAS_INLINE - iterator1 end1 () { - return expression ().end1 (); - } - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return expression ().begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return expression ().end2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - BOOST_UBLAS_INLINE - iterator2 begin2 () { - return expression ().begin2 (); - } - BOOST_UBLAS_INLINE - iterator2 end2 () { - return expression ().end2 (); - } - - // Reverse iterators - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base1<iterator1> reverse_iterator1; - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - reverse_iterator1 rbegin1 () { - return reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - reverse_iterator1 rend1 () { - return reverse_iterator1 (begin1 ()); - } - - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - typedef reverse_iterator_base2<iterator2> reverse_iterator2; - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - BOOST_UBLAS_INLINE - reverse_iterator2 rbegin2 () { - return reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - reverse_iterator2 rend2 () { - return reverse_iterator2 (begin2 ()); - } - - private: - referred_type &e_; - }; - - - template<class E1, class E2, class F> - class vector_matrix_binary: - public matrix_expression<vector_matrix_binary<E1, E2, F> > { - - typedef E1 expression1_type; - typedef E2 expression2_type; - public: - typedef typename E1::const_closure_type expression1_closure_type; - typedef typename E2::const_closure_type expression2_closure_type; - private: - typedef vector_matrix_binary<E1, E2, F> self_type; - public: + BOOST_UBLAS_INLINE + reference operator () (size_type i, size_type j) const { + return expression () (i, j); + } +#endif + +#ifndef BOOST_UBLAS_REFERENCE_CONST_MEMBER + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return expression () (i); + } + BOOST_UBLAS_INLINE + reference operator () (size_type i) { + return expression () (i); + } +#else + BOOST_UBLAS_INLINE + reference operator () (size_type i) const { + return expression () (i); + } +#endif + + + // Assignment + BOOST_UBLAS_INLINE + matrix_reference &operator = (const matrix_reference &m) { + expression ().operator = (m); + return *this; + } + template<class AE> + BOOST_UBLAS_INLINE + matrix_reference &operator = (const matrix_expression<AE> &ae) { + expression ().operator = (ae); + return *this; + } + template<class AE> + BOOST_UBLAS_INLINE + matrix_reference &assign (const matrix_expression<AE> &ae) { + expression ().assign (ae); + return *this; + } + template<class AE> + BOOST_UBLAS_INLINE + matrix_reference &operator += (const matrix_expression<AE> &ae) { + expression ().operator += (ae); + return *this; + } + template<class AE> + BOOST_UBLAS_INLINE + matrix_reference &plus_assign (const matrix_expression<AE> &ae) { + expression ().plus_assign (ae); + return *this; + } + template<class AE> + BOOST_UBLAS_INLINE + matrix_reference &operator -= (const matrix_expression<AE> &ae) { + expression ().operator -= (ae); + return *this; + } + template<class AE> + BOOST_UBLAS_INLINE + matrix_reference &minus_assign (const matrix_expression<AE> &ae) { + expression ().minus_assign (ae); + return *this; + } + template<class AT> + BOOST_UBLAS_INLINE + matrix_reference &operator *= (const AT &at) { + expression ().operator *= (at); + return *this; + } + template<class AT> + BOOST_UBLAS_INLINE + matrix_reference &operator /= (const AT &at) { + expression ().operator /= (at); + return *this; + } + + // Swapping + BOOST_UBLAS_INLINE + void swap (matrix_reference &m) { + expression ().swap (m.expression ()); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_reference &mr) const { + return &(*this).e_ == &mr.e_; + } + + // Iterator types + typedef typename E::const_iterator1 const_iterator1; + typedef typename boost::mpl::if_<boost::is_const<E>, + typename E::const_iterator1, + typename E::iterator1>::type iterator1; + typedef typename E::const_iterator2 const_iterator2; + typedef typename boost::mpl::if_<boost::is_const<E>, + typename E::const_iterator2, + typename E::iterator2>::type iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + return expression ().find1 (rank, i, j); + } + BOOST_UBLAS_INLINE + iterator1 find1 (int rank, size_type i, size_type j) { + return expression ().find1 (rank, i, j); + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + return expression ().find2 (rank, i, j); + } + BOOST_UBLAS_INLINE + iterator2 find2 (int rank, size_type i, size_type j) { + return expression ().find2 (rank, i, j); + } + + // Iterators are the iterators of the referenced expression. + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return expression ().begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return expression ().end1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } + + BOOST_UBLAS_INLINE + iterator1 begin1 () { + return expression ().begin1 (); + } + BOOST_UBLAS_INLINE + iterator1 end1 () { + return expression ().end1 (); + } + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return expression ().begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return expression ().end2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + BOOST_UBLAS_INLINE + iterator2 begin2 () { + return expression ().begin2 (); + } + BOOST_UBLAS_INLINE + iterator2 end2 () { + return expression ().end2 (); + } + + // Reverse iterators + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base1<iterator1> reverse_iterator1; + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + reverse_iterator1 rbegin1 () { + return reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + reverse_iterator1 rend1 () { + return reverse_iterator1 (begin1 ()); + } + + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + typedef reverse_iterator_base2<iterator2> reverse_iterator2; + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + + BOOST_UBLAS_INLINE + reverse_iterator2 rbegin2 () { + return reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + reverse_iterator2 rend2 () { + return reverse_iterator2 (begin2 ()); + } + +private: + referred_type &e_; +}; + + +template<class E1, class E2, class F> +class vector_matrix_binary: + public matrix_expression<vector_matrix_binary<E1, E2, F> > { + + typedef E1 expression1_type; + typedef E2 expression2_type; +public: + typedef typename E1::const_closure_type expression1_closure_type; + typedef typename E2::const_closure_type expression2_closure_type; +private: + typedef vector_matrix_binary<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef F functor_type; - typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; - typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef unknown_orientation_tag orientation_category; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - vector_matrix_binary (const expression1_type &e1, const expression2_type &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e1_.size (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e2_.size (); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression1_closure_type &expression1 () const { - return e1_; - } - BOOST_UBLAS_INLINE - const expression2_closure_type &expression2 () const { - return e2_; - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (e1_ (i), e2_ (j)); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const vector_matrix_binary &vmb) const { - return (*this).expression1 ().same_closure (vmb.expression1 ()) && - (*this).expression2 ().same_closure (vmb.expression2 ()); - } - - // Iterator types - private: - typedef typename E1::const_iterator const_subiterator1_type; - typedef typename E2::const_iterator const_subiterator2_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + typedef F functor_type; + typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; + typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef unknown_orientation_tag orientation_category; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + vector_matrix_binary (const expression1_type &e1, const expression2_type &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e1_.size (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e2_.size (); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression1_closure_type &expression1 () const { + return e1_; + } + BOOST_UBLAS_INLINE + const expression2_closure_type &expression2 () const { + return e2_; + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (e1_ (i), e2_ (j)); + } + + + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const vector_matrix_binary &vmb) const { + return (*this).expression1 ().same_closure (vmb.expression1 ()) && + (*this).expression2 ().same_closure (vmb.expression2 ()); + } + + // Iterator types +private: + typedef typename E1::const_iterator const_subiterator1_type; + typedef typename E2::const_iterator const_subiterator2_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef typename iterator_restrict_traits<typename const_subiterator1_type::iterator_category, - typename const_subiterator2_type::iterator_category>::iterator_category iterator_category; - typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1; - typedef const_iterator1 iterator1; - typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2; - typedef const_iterator2 iterator2; + typedef typename iterator_restrict_traits<typename const_subiterator1_type::iterator_category, + typename const_subiterator2_type::iterator_category>::iterator_category iterator_category; + typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1; + typedef const_iterator1 iterator1; + typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - const_subiterator1_type it1 (e1_.find (i)); - const_subiterator1_type it1_end (e1_.find (size1 ())); - const_subiterator2_type it2 (e2_.find (j)); - const_subiterator2_type it2_end (e2_.find (size2 ())); - if (it2 == it2_end || (rank == 1 && (it2.index () != j || *it2 == value_type/*zero*/()))) { - it1 = it1_end; - it2 = it2_end; - } + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + const_subiterator1_type it1 (e1_.find (i)); + const_subiterator1_type it1_end (e1_.find (size1 ())); + const_subiterator2_type it2 (e2_.find (j)); + const_subiterator2_type it2_end (e2_.find (size2 ())); + if (it2 == it2_end || (rank == 1 && (it2.index () != j || *it2 == typename E2::value_type/*zero*/()))) { + it1 = it1_end; + it2 = it2_end; + } #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, it1.index (), it2.index ()); + return const_iterator1 (*this, it1.index (), it2.index ()); #else #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return const_iterator1 (*this, it1, it2, it2 != it2_end ? *it2 : value_type/*zero*/()); + return const_iterator1 (*this, it1, it2, it2 != it2_end ? *it2 : typename E2::value_type/*zero*/()); #else - return const_iterator1 (*this, it1, it2); -#endif -#endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - const_subiterator2_type it2 (e2_.find (j)); - const_subiterator2_type it2_end (e2_.find (size2 ())); - const_subiterator1_type it1 (e1_.find (i)); - const_subiterator1_type it1_end (e1_.find (size1 ())); - if (it1 == it1_end || (rank == 1 && (it1.index () != i || *it1 == value_type/*zero*/()))) { - it2 = it2_end; - it1 = it1_end; - } + return const_iterator1 (*this, it1, it2); +#endif +#endif + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + const_subiterator2_type it2 (e2_.find (j)); + const_subiterator2_type it2_end (e2_.find (size2 ())); + const_subiterator1_type it1 (e1_.find (i)); + const_subiterator1_type it1_end (e1_.find (size1 ())); + if (it1 == it1_end || (rank == 1 && (it1.index () != i || *it1 == typename E1::value_type/*zero*/()))) { + it2 = it2_end; + it1 = it1_end; + } #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, it1.index (), it2.index ()); + return const_iterator2 (*this, it1.index (), it2.index ()); #else #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return const_iterator2 (*this, it1, it2, it1 != it1_end ? *it1 : value_type/*zero*/()); + return const_iterator2 (*this, it1, it2, it1 != it1_end ? *it1 : typename E1::value_type/*zero*/()); #else - return const_iterator2 (*this, it1, it2); + return const_iterator2 (*this, it1, it2); #endif #endif - } + } - // Iterators enhance the iterators of the referenced expressions - // with the binary functor. + // Iterators enhance the iterators of the referenced expressions + // with the binary functor. #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<vector_matrix_binary>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, - typename E2::const_iterator::iterator_category>::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, - typename E2::const_iterator::iterator_category>::iterator_category iterator_category; - typedef typename vector_matrix_binary::difference_type difference_type; - typedef typename vector_matrix_binary::value_type value_type; - typedef typename vector_matrix_binary::const_reference reference; - typedef typename vector_matrix_binary::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction + class const_iterator1: + public container_const_reference<vector_matrix_binary>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, + typename E2::const_iterator::iterator_category>::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, + typename E2::const_iterator::iterator_category>::iterator_category iterator_category; + typedef typename vector_matrix_binary::difference_type difference_type; + typedef typename vector_matrix_binary::value_type value_type; + typedef typename vector_matrix_binary::const_reference reference; + typedef typename vector_matrix_binary::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it1_ (), it2_ (), t2_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t2): - container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t2_ (t2) {} + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it1_ (), it2_ (), t2_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t2): + container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t2_ (t2) {} #else - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2): - container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {} -#endif - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - ++ it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - -- it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - it1_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - it1_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ - it.it1_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2): + container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {} +#endif + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + ++ it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + -- it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + it1_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + it1_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ - it.it1_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (*it1_, t2_); + return functor_type::apply (*it1_, t2_); #else - return functor_type::apply (*it1_, *it2_); + return functor_type::apply (*it1_, *it2_); #endif - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it1_.index (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it2_.index (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it1_.index (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it2_.index (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - t2_ = it.t2_; -#endif - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ == it.it1_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ < it.it1_; - } - - private: + t2_ = it.t2_; +#endif + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ == it.it1_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ < it.it1_; + } + + private: #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - const_subiterator1_type it1_; - // Mutable due to assignment - /* const */ const_subiterator2_type it2_; - value_type t2_; + const_subiterator1_type it1_; + // Mutable due to assignment + /* const */ const_subiterator2_type it2_; + value_type t2_; #else - const_subiterator1_type it1_; - const_subiterator2_type it2_; -#endif - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + const_subiterator1_type it1_; + const_subiterator2_type it2_; +#endif + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<vector_matrix_binary>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, - typename E2::const_iterator::iterator_category>::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, - typename E2::const_iterator::iterator_category>::iterator_category iterator_category; - typedef typename vector_matrix_binary::difference_type difference_type; - typedef typename vector_matrix_binary::value_type value_type; - typedef typename vector_matrix_binary::const_reference reference; - typedef typename vector_matrix_binary::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction + class const_iterator2: + public container_const_reference<vector_matrix_binary>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, + typename E2::const_iterator::iterator_category>::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, + typename E2::const_iterator::iterator_category>::iterator_category iterator_category; + typedef typename vector_matrix_binary::difference_type difference_type; + typedef typename vector_matrix_binary::value_type value_type; + typedef typename vector_matrix_binary::const_reference reference; + typedef typename vector_matrix_binary::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it1_ (), it2_ (), t1_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t1): - container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t1_ (t1) {} + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it1_ (), it2_ (), t1_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t1): + container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t1_ (t1) {} #else - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2): - container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {} -#endif - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - ++ it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - -- it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - it2_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - it2_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure(it ()), external_logic ()); - BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ - it.it2_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2): + container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {} +#endif + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + ++ it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + -- it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + it2_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + it2_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure(it ()), external_logic ()); + BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ - it.it2_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (t1_, *it2_); + return functor_type::apply (t1_, *it2_); #else - return functor_type::apply (*it1_, *it2_); + return functor_type::apply (*it1_, *it2_); #endif - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it1_.index (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it2_.index (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it1_.index (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it2_.index (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - t1_ = it.t1_; -#endif - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure( it ()), external_logic ()); - BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ == it.it2_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ < it.it2_; - } - - private: + t1_ = it.t1_; +#endif + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure( it ()), external_logic ()); + BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ == it.it2_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ < it.it2_; + } + + private: #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - // Mutable due to assignment - /* const */ const_subiterator1_type it1_; - const_subiterator2_type it2_; - value_type t1_; + // Mutable due to assignment + /* const */ const_subiterator1_type it1_; + const_subiterator2_type it2_; + value_type t1_; #else - const_subiterator1_type it1_; - const_subiterator2_type it2_; -#endif - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class E1, class E2, class F> - struct vector_matrix_binary_traits { - typedef vector_matrix_binary<E1, E2, F> expression_type; + const_subiterator1_type it1_; + const_subiterator2_type it2_; +#endif + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class E1, class E2, class F> +struct vector_matrix_binary_traits { + typedef vector_matrix_binary<E1, E2, F> expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - // ISSUE matrix is arbitary temporary type - typedef matrix<typename F::value_type> result_type; -#endif - }; - - // (outer_prod (v1, v2)) [i] [j] = v1 [i] * v2 [j] - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::result_type - outer_prod (const vector_expression<E1> &e1, - const vector_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0); - typedef typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - template<class E, class F> - class matrix_unary1: - public matrix_expression<matrix_unary1<E, F> > { - - typedef E expression_type; - typedef F functor_type; - public: - typedef typename E::const_closure_type expression_closure_type; - private: - typedef matrix_unary1<E, F> self_type; - public: + // ISSUE matrix is arbitary temporary type + typedef matrix<typename F::value_type> result_type; +#endif +}; + +// (outer_prod (v1, v2)) [i] [j] = v1 [i] * v2 [j] +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::result_type +outer_prod (const vector_expression<E1> &e1, + const vector_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0); + typedef typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +template<class E, class F> +class matrix_unary1: + public matrix_expression<matrix_unary1<E, F> > { + + typedef E expression_type; + typedef F functor_type; +public: + typedef typename E::const_closure_type expression_closure_type; +private: + typedef matrix_unary1<E, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef typename E::size_type size_type; - typedef typename E::difference_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef typename E::orientation_category orientation_category; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - explicit matrix_unary1 (const expression_type &e): - e_ (e) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e_.size1 (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e_.size2 (); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression_closure_type &expression () const { - return e_; - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (e_ (i, j)); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_unary1 &mu1) const { - return (*this).expression ().same_closure (mu1.expression ()); - } - - // Iterator types - private: - typedef typename E::const_iterator1 const_subiterator1_type; - typedef typename E::const_iterator2 const_subiterator2_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + typedef typename E::size_type size_type; + typedef typename E::difference_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef typename E::orientation_category orientation_category; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + explicit matrix_unary1 (const expression_type &e): + e_ (e) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e_.size1 (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e_.size2 (); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression_closure_type &expression () const { + return e_; + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (e_ (i, j)); + } + + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (e_ (i)); + } + + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_unary1 &mu1) const { + return (*this).expression ().same_closure (mu1.expression ()); + } + + // Iterator types +private: + typedef typename E::const_iterator1 const_subiterator1_type; + typedef typename E::const_iterator2 const_subiterator2_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1; - typedef const_iterator1 iterator1; - typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2; - typedef const_iterator2 iterator2; + typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1; + typedef const_iterator1 iterator1; + typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - const_subiterator1_type it1 (e_.find1 (rank, i, j)); + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + const_subiterator1_type it1 (e_.find1 (rank, i, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, it1.index1 (), it1.index2 ()); + return const_iterator1 (*this, it1.index1 (), it1.index2 ()); #else - return const_iterator1 (*this, it1); + return const_iterator1 (*this, it1); #endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - const_subiterator2_type it2 (e_.find2 (rank, i, j)); + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + const_subiterator2_type it2 (e_.find2 (rank, i, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, it2.index1 (), it2.index2 ()); + return const_iterator2 (*this, it2.index1 (), it2.index2 ()); #else - return const_iterator2 (*this, it2); + return const_iterator2 (*this, it2); #endif - } + } - // Iterators enhance the iterators of the referenced expression - // with the unary functor. + // Iterators enhance the iterators of the referenced expression + // with the unary functor. #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<matrix_unary1>, - public iterator_base_traits<typename E::const_iterator1::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename E::const_iterator1::iterator_category iterator_category; - typedef typename matrix_unary1::difference_type difference_type; - typedef typename matrix_unary1::value_type value_type; - typedef typename matrix_unary1::const_reference reference; - typedef typename matrix_unary1::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mu, const const_subiterator1_type &it): - container_const_reference<self_type> (mu), it_ (it) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - ++ it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - -- it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - it_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - it_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ - it.it_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (*it_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator1: + public container_const_reference<matrix_unary1>, + public iterator_base_traits<typename E::const_iterator1::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename E::const_iterator1::iterator_category iterator_category; + typedef typename matrix_unary1::difference_type difference_type; + typedef typename matrix_unary1::value_type value_type; + typedef typename matrix_unary1::const_reference reference; + typedef typename matrix_unary1::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mu, const const_subiterator1_type &it): + container_const_reference<self_type> (mu), it_ (it) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + ++ it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + -- it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + it_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + it_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ - it.it_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (*it_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - it_ = it.it_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ == it.it_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ < it.it_; - } - - private: - const_subiterator1_type it_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + it_ = it.it_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ == it.it_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ < it.it_; + } + + private: + const_subiterator1_type it_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<matrix_unary1>, - public iterator_base_traits<typename E::const_iterator2::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename E::const_iterator2::iterator_category iterator_category; - typedef typename matrix_unary1::difference_type difference_type; - typedef typename matrix_unary1::value_type value_type; - typedef typename matrix_unary1::const_reference reference; - typedef typename matrix_unary1::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mu, const const_subiterator2_type &it): - container_const_reference<self_type> (mu), it_ (it) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - ++ it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - -- it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - it_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - it_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ - it.it_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (*it_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator2: + public container_const_reference<matrix_unary1>, + public iterator_base_traits<typename E::const_iterator2::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename E::const_iterator2::iterator_category iterator_category; + typedef typename matrix_unary1::difference_type difference_type; + typedef typename matrix_unary1::value_type value_type; + typedef typename matrix_unary1::const_reference reference; + typedef typename matrix_unary1::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mu, const const_subiterator2_type &it): + container_const_reference<self_type> (mu), it_ (it) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + ++ it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + -- it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + it_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + it_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ - it.it_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (*it_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - it_ = it.it_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ == it.it_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ < it.it_; - } - - private: - const_subiterator2_type it_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression_closure_type e_; - }; - - template<class E, class F> - struct matrix_unary1_traits { - typedef matrix_unary1<E, F> expression_type; + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + it_ = it.it_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ == it.it_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ < it.it_; + } + + private: + const_subiterator2_type it_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression_closure_type e_; +}; + +template<class E, class F> +struct matrix_unary1_traits { + typedef matrix_unary1<E, F> expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E::matrix_temporary_type result_type; -#endif - }; - - // (- m) [i] [j] = - m [i] [j] - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::result_type - operator - (const matrix_expression<E> &e) { - typedef typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - - // (conj m) [i] [j] = conj (m [i] [j]) - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::result_type - conj (const matrix_expression<E> &e) { - typedef typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - - // (real m) [i] [j] = real (m [i] [j]) - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::result_type - real (const matrix_expression<E> &e) { - typedef typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - - // (imag m) [i] [j] = imag (m [i] [j]) - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::result_type - imag (const matrix_expression<E> &e) { - typedef typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - - template<class E, class F> - class matrix_unary2: - public matrix_expression<matrix_unary2<E, F> > { - - typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<typename E::value_type> >, - E, - const E>::type expression_type; - typedef F functor_type; - public: - typedef typename boost::mpl::if_<boost::is_const<expression_type>, - typename E::const_closure_type, - typename E::closure_type>::type expression_closure_type; - private: - typedef matrix_unary2<E, F> self_type; - public: + typedef typename E::matrix_temporary_type result_type; +#endif +}; + +// (- m) [i] [j] = - m [i] [j] +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::result_type +operator - (const matrix_expression<E> &e) { + typedef typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} + +// (conj m) [i] [j] = conj (m [i] [j]) +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::result_type +conj (const matrix_expression<E> &e) { + typedef typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} + +// (real m) [i] [j] = real (m [i] [j]) +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::result_type +real (const matrix_expression<E> &e) { + typedef typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} + +// (imag m) [i] [j] = imag (m [i] [j]) +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::result_type +imag (const matrix_expression<E> &e) { + typedef typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} + +template<class E, class F> +class matrix_unary2: + public matrix_expression<matrix_unary2<E, F> > { + + typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<typename E::value_type> >, + E, + const E>::type expression_type; + typedef F functor_type; +public: + typedef typename boost::mpl::if_<boost::is_const<expression_type>, + typename E::const_closure_type, + typename E::closure_type>::type expression_closure_type; +private: + typedef matrix_unary2<E, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef typename E::size_type size_type; - typedef typename E::difference_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<value_type> >, - typename E::reference, - value_type>::type reference; - - typedef const self_type const_closure_type; - typedef self_type closure_type; - typedef typename boost::mpl::if_<boost::is_same<typename E::orientation_category, - row_major_tag>, - column_major_tag, - typename boost::mpl::if_<boost::is_same<typename E::orientation_category, - column_major_tag>, - row_major_tag, - typename E::orientation_category>::type>::type orientation_category; - typedef typename E::storage_category storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - // matrix_unary2 may be used as mutable expression - - // this is the only non const expression constructor - explicit matrix_unary2 (expression_type &e): - e_ (e) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e_.size2 (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e_.size1 (); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression_closure_type &expression () const { - return e_; - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (e_ (j, i)); - } - BOOST_UBLAS_INLINE - reference operator () (size_type i, size_type j) { - BOOST_STATIC_ASSERT ((boost::is_same<functor_type, scalar_identity<value_type > >::value)); - return e_ (j, i); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_unary2 &mu2) const { - return (*this).expression ().same_closure (mu2.expression ()); - } - - // Iterator types - private: - typedef typename E::const_iterator1 const_subiterator2_type; - typedef typename E::const_iterator2 const_subiterator1_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + typedef typename E::size_type size_type; + typedef typename E::difference_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<value_type> >, + typename E::reference, + value_type>::type reference; + + typedef const self_type const_closure_type; + typedef self_type closure_type; + typedef typename boost::mpl::if_<boost::is_same<typename E::orientation_category, + row_major_tag>, + column_major_tag, + typename boost::mpl::if_<boost::is_same<typename E::orientation_category, + column_major_tag>, + row_major_tag, + typename E::orientation_category>::type>::type orientation_category; + typedef typename E::storage_category storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + // matrix_unary2 may be used as mutable expression - + // this is the only non const expression constructor + explicit matrix_unary2 (expression_type &e): + e_ (e) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e_.size2 (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e_.size1 (); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression_closure_type &expression () const { + return e_; + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (e_ (j, i)); + } + BOOST_UBLAS_INLINE + reference operator () (size_type i, size_type j) { + BOOST_STATIC_ASSERT ((boost::is_same<functor_type, scalar_identity<value_type > >::value)); + return e_ (j, i); + } + + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (e_ (i)); + } + BOOST_UBLAS_INLINE + reference operator () (size_type i) { + BOOST_STATIC_ASSERT ((boost::is_same<functor_type, scalar_identity<value_type > >::value)); + return e_ (i); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_unary2 &mu2) const { + return (*this).expression ().same_closure (mu2.expression ()); + } + + // Iterator types +private: + typedef typename E::const_iterator1 const_subiterator2_type; + typedef typename E::const_iterator2 const_subiterator1_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1; - typedef const_iterator1 iterator1; - typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2; - typedef const_iterator2 iterator2; + typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1; + typedef const_iterator1 iterator1; + typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - const_subiterator1_type it1 (e_.find2 (rank, j, i)); + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + const_subiterator1_type it1 (e_.find2 (rank, j, i)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, it1.index2 (), it1.index1 ()); + return const_iterator1 (*this, it1.index2 (), it1.index1 ()); #else - return const_iterator1 (*this, it1); + return const_iterator1 (*this, it1); #endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - const_subiterator2_type it2 (e_.find1 (rank, j, i)); + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + const_subiterator2_type it2 (e_.find1 (rank, j, i)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, it2.index2 (), it2.index1 ()); + return const_iterator2 (*this, it2.index2 (), it2.index1 ()); #else - return const_iterator2 (*this, it2); + return const_iterator2 (*this, it2); #endif - } + } - // Iterators enhance the iterators of the referenced expression - // with the unary functor. + // Iterators enhance the iterators of the referenced expression + // with the unary functor. #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<matrix_unary2>, - public iterator_base_traits<typename E::const_iterator2::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename E::const_iterator2::iterator_category iterator_category; - typedef typename matrix_unary2::difference_type difference_type; - typedef typename matrix_unary2::value_type value_type; - typedef typename matrix_unary2::const_reference reference; - typedef typename matrix_unary2::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mu, const const_subiterator1_type &it): - container_const_reference<self_type> (mu), it_ (it) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - ++ it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - -- it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - it_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - it_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ - it.it_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (*it_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator1: + public container_const_reference<matrix_unary2>, + public iterator_base_traits<typename E::const_iterator2::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename E::const_iterator2::iterator_category iterator_category; + typedef typename matrix_unary2::difference_type difference_type; + typedef typename matrix_unary2::value_type value_type; + typedef typename matrix_unary2::const_reference reference; + typedef typename matrix_unary2::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mu, const const_subiterator1_type &it): + container_const_reference<self_type> (mu), it_ (it) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + ++ it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + -- it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + it_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + it_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ - it.it_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (*it_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it_.index2 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it_.index1 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - it_ = it.it_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ == it.it_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ < it.it_; - } - - private: - const_subiterator1_type it_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it_.index2 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it_.index1 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + it_ = it.it_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ == it.it_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ < it.it_; + } + + private: + const_subiterator1_type it_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<matrix_unary2>, - public iterator_base_traits<typename E::const_iterator1::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename E::const_iterator1::iterator_category iterator_category; - typedef typename matrix_unary2::difference_type difference_type; - typedef typename matrix_unary2::value_type value_type; - typedef typename matrix_unary2::const_reference reference; - typedef typename matrix_unary2::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mu, const const_subiterator2_type &it): - container_const_reference<self_type> (mu), it_ (it) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - ++ it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - -- it_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - it_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - it_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ - it.it_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (*it_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator2: + public container_const_reference<matrix_unary2>, + public iterator_base_traits<typename E::const_iterator1::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename E::const_iterator1::iterator_category iterator_category; + typedef typename matrix_unary2::difference_type difference_type; + typedef typename matrix_unary2::value_type value_type; + typedef typename matrix_unary2::const_reference reference; + typedef typename matrix_unary2::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mu, const const_subiterator2_type &it): + container_const_reference<self_type> (mu), it_ (it) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + ++ it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + -- it_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + it_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + it_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ - it.it_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (*it_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it_.index2 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it_.index1 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - it_ = it.it_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ == it.it_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it_ < it.it_; - } - - private: - const_subiterator2_type it_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression_closure_type e_; - }; - - template<class E, class F> - struct matrix_unary2_traits { - typedef matrix_unary2<E, F> expression_type; + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it_.index2 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it_.index1 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + it_ = it.it_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ == it.it_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it_ < it.it_; + } + + private: + const_subiterator2_type it_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression_closure_type e_; +}; + +template<class E, class F> +struct matrix_unary2_traits { + typedef matrix_unary2<E, F> expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E::matrix_temporary_type result_type; -#endif - }; - - // (trans m) [i] [j] = m [j] [i] - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::result_type - trans (const matrix_expression<E> &e) { - typedef typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::result_type - trans (matrix_expression<E> &e) { - typedef typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - - // (herm m) [i] [j] = conj (m [j] [i]) - template<class E> - BOOST_UBLAS_INLINE - typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::result_type - herm (const matrix_expression<E> &e) { - typedef typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type; - return expression_type (e ()); - } - - template<class E1, class E2, class F> - class matrix_binary: - public matrix_expression<matrix_binary<E1, E2, F> > { - - typedef E1 expression1_type; - typedef E2 expression2_type; - typedef F functor_type; - public: - typedef typename E1::const_closure_type expression1_closure_type; - typedef typename E2::const_closure_type expression2_closure_type; - private: - typedef matrix_binary<E1, E2, F> self_type; - public: + typedef typename E::matrix_temporary_type result_type; +#endif +}; + +// (trans m) [i] [j] = m [j] [i] +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::result_type +trans (const matrix_expression<E> &e) { + typedef typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::result_type +trans (matrix_expression<E> &e) { + typedef typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} + +// (herm m) [i] [j] = conj (m [j] [i]) +template<class E> +BOOST_UBLAS_INLINE +typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::result_type +herm (const matrix_expression<E> &e) { + typedef typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type; + return expression_type (e ()); +} + +template<class E1, class E2, class F> +class matrix_binary: + public matrix_expression<matrix_binary<E1, E2, F> > { + + typedef E1 expression1_type; + typedef E2 expression2_type; + typedef F functor_type; +public: + typedef typename E1::const_closure_type expression1_closure_type; + typedef typename E2::const_closure_type expression2_closure_type; +private: + typedef matrix_binary<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; - typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef unknown_orientation_tag orientation_category; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - matrix_binary (const E1 &e1, const E2 &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return BOOST_UBLAS_SAME (e1_.size1 (), e2_.size1 ()); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return BOOST_UBLAS_SAME (e1_.size2 (), e2_.size2 ()); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression1_closure_type &expression1 () const { - return e1_; - } - BOOST_UBLAS_INLINE - const expression2_closure_type &expression2 () const { - return e2_; - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (e1_ (i, j), e2_ (i, j)); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_binary &mb) const { - return (*this).expression1 ().same_closure (mb.expression1 ()) && - (*this).expression2 ().same_closure (mb.expression2 ()); - } - - // Iterator types - private: - typedef typename E1::const_iterator1 const_iterator11_type; - typedef typename E1::const_iterator2 const_iterator12_type; - typedef typename E2::const_iterator1 const_iterator21_type; - typedef typename E2::const_iterator2 const_iterator22_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; + typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef unknown_orientation_tag orientation_category; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + matrix_binary (const E1 &e1, const E2 &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return BOOST_UBLAS_SAME (e1_.size1 (), e2_.size1 ()); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return BOOST_UBLAS_SAME (e1_.size2 (), e2_.size2 ()); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression1_closure_type &expression1 () const { + return e1_; + } + BOOST_UBLAS_INLINE + const expression2_closure_type &expression2 () const { + return e2_; + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (e1_ (i, j), e2_ (i, j)); + } + + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (e1_ (i), e2_ (i)); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_binary &mb) const { + return (*this).expression1 ().same_closure (mb.expression1 ()) && + (*this).expression2 ().same_closure (mb.expression2 ()); + } + + // Iterator types +private: + typedef typename E1::const_iterator1 const_iterator11_type; + typedef typename E1::const_iterator2 const_iterator12_type; + typedef typename E2::const_iterator1 const_iterator21_type; + typedef typename E2::const_iterator2 const_iterator22_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category, - typename const_iterator21_type::iterator_category>::iterator_category iterator_category1; - typedef indexed_const_iterator1<const_closure_type, iterator_category1> const_iterator1; - typedef const_iterator1 iterator1; - typedef typename iterator_restrict_traits<typename const_iterator12_type::iterator_category, - typename const_iterator22_type::iterator_category>::iterator_category iterator_category2; - typedef indexed_const_iterator2<const_closure_type, iterator_category2> const_iterator2; - typedef const_iterator2 iterator2; + typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category, + typename const_iterator21_type::iterator_category>::iterator_category iterator_category1; + typedef indexed_const_iterator1<const_closure_type, iterator_category1> const_iterator1; + typedef const_iterator1 iterator1; + typedef typename iterator_restrict_traits<typename const_iterator12_type::iterator_category, + typename const_iterator22_type::iterator_category>::iterator_category iterator_category2; + typedef indexed_const_iterator2<const_closure_type, iterator_category2> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - const_iterator11_type it11 (e1_.find1 (rank, i, j)); - const_iterator11_type it11_end (e1_.find1 (rank, size1 (), j)); - const_iterator21_type it21 (e2_.find1 (rank, i, j)); - const_iterator21_type it21_end (e2_.find1 (rank, size1 (), j)); - BOOST_UBLAS_CHECK (rank == 0 || it11 == it11_end || it11.index2 () == j, internal_logic ()) - BOOST_UBLAS_CHECK (rank == 0 || it21 == it21_end || it21.index2 () == j, internal_logic ()) - i = (std::min) (it11 != it11_end ? it11.index1 () : size1 (), - it21 != it21_end ? it21.index1 () : size1 ()); + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + const_iterator11_type it11 (e1_.find1 (rank, i, j)); + const_iterator11_type it11_end (e1_.find1 (rank, size1 (), j)); + const_iterator21_type it21 (e2_.find1 (rank, i, j)); + const_iterator21_type it21_end (e2_.find1 (rank, size1 (), j)); + BOOST_UBLAS_CHECK (rank == 0 || it11 == it11_end || it11.index2 () == j, internal_logic ()) + BOOST_UBLAS_CHECK (rank == 0 || it21 == it21_end || it21.index2 () == j, internal_logic ()) + i = (std::min) (it11 != it11_end ? it11.index1 () : size1 (), + it21 != it21_end ? it21.index1 () : size1 ()); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, i, j); + return const_iterator1 (*this, i, j); #else - return const_iterator1 (*this, i, j, it11, it11_end, it21, it21_end); -#endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - const_iterator12_type it12 (e1_.find2 (rank, i, j)); - const_iterator12_type it12_end (e1_.find2 (rank, i, size2 ())); - const_iterator22_type it22 (e2_.find2 (rank, i, j)); - const_iterator22_type it22_end (e2_.find2 (rank, i, size2 ())); - BOOST_UBLAS_CHECK (rank == 0 || it12 == it12_end || it12.index1 () == i, internal_logic ()) - BOOST_UBLAS_CHECK (rank == 0 || it22 == it22_end || it22.index1 () == i, internal_logic ()) - j = (std::min) (it12 != it12_end ? it12.index2 () : size2 (), - it22 != it22_end ? it22.index2 () : size2 ()); + return const_iterator1 (*this, i, j, it11, it11_end, it21, it21_end); +#endif + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + const_iterator12_type it12 (e1_.find2 (rank, i, j)); + const_iterator12_type it12_end (e1_.find2 (rank, i, size2 ())); + const_iterator22_type it22 (e2_.find2 (rank, i, j)); + const_iterator22_type it22_end (e2_.find2 (rank, i, size2 ())); + BOOST_UBLAS_CHECK (rank == 0 || it12 == it12_end || it12.index1 () == i, internal_logic ()) + BOOST_UBLAS_CHECK (rank == 0 || it22 == it22_end || it22.index1 () == i, internal_logic ()) + j = (std::min) (it12 != it12_end ? it12.index2 () : size2 (), + it22 != it22_end ? it22.index2 () : size2 ()); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, i, j); + return const_iterator2 (*this, i, j); #else - return const_iterator2 (*this, i, j, it12, it12_end, it22, it22_end); + return const_iterator2 (*this, i, j, it12, it12_end, it22, it22_end); #endif - } + } - // Iterators enhance the iterators of the referenced expression - // with the binary functor. + // Iterators enhance the iterators of the referenced expression + // with the binary functor. #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<matrix_binary>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator1::iterator_category>::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator1::iterator_category>::iterator_category iterator_category; - typedef typename matrix_binary::difference_type difference_type; - typedef typename matrix_binary::value_type value_type; - typedef typename matrix_binary::const_reference reference; - typedef typename matrix_binary::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mb, size_type i, size_type j, - const const_iterator11_type &it1, const const_iterator11_type &it1_end, - const const_iterator21_type &it2, const const_iterator21_type &it2_end): - container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {} - - private: - // Dense specializations - BOOST_UBLAS_INLINE - void increment (dense_random_access_iterator_tag) { - ++ i_; ++ it1_; ++ it2_; - } - BOOST_UBLAS_INLINE - void decrement (dense_random_access_iterator_tag) { - -- i_; -- it1_; -- it2_; - } - BOOST_UBLAS_INLINE - void increment (dense_random_access_iterator_tag, difference_type n) { - i_ += n; it1_ += n; it2_ += n; - } - BOOST_UBLAS_INLINE - void decrement (dense_random_access_iterator_tag, difference_type n) { - i_ -= n; it1_ -= n; it2_ -= n; - } - BOOST_UBLAS_INLINE - value_type dereference (dense_random_access_iterator_tag) const { - return functor_type::apply (*it1_, *it2_); - } - - // Packed specializations - BOOST_UBLAS_INLINE - void increment (packed_random_access_iterator_tag) { - if (it1_ != it1_end_) - if (it1_.index1 () <= i_) - ++ it1_; - if (it2_ != it2_end_) - if (it2_.index1 () <= i_) - ++ it2_; - ++ i_; - } - BOOST_UBLAS_INLINE - void decrement (packed_random_access_iterator_tag) { - if (it1_ != it1_end_) - if (i_ <= it1_.index1 ()) - -- it1_; - if (it2_ != it2_end_) - if (i_ <= it2_.index1 ()) - -- it2_; - -- i_; - } - BOOST_UBLAS_INLINE - void increment (packed_random_access_iterator_tag, difference_type n) { - while (n > 0) { - increment (packed_random_access_iterator_tag ()); - --n; - } - while (n < 0) { - decrement (packed_random_access_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - void decrement (packed_random_access_iterator_tag, difference_type n) { - while (n > 0) { - decrement (packed_random_access_iterator_tag ()); - --n; - } - while (n < 0) { - increment (packed_random_access_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - value_type dereference (packed_random_access_iterator_tag) const { - value_type t1 = value_type/*zero*/(); - if (it1_ != it1_end_) { - BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ()); - if (it1_.index1 () == i_) - t1 = *it1_; - } - value_type t2 = value_type/*zero*/(); - if (it2_ != it2_end_) { - BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ()); - if (it2_.index1 () == i_) - t2 = *it2_; - } - return functor_type::apply (t1, t2); - } - - // Sparse specializations - BOOST_UBLAS_INLINE - void increment (sparse_bidirectional_iterator_tag) { - size_type index1 = (*this) ().size1 (); - if (it1_ != it1_end_) { - if (it1_.index1 () <= i_) - ++ it1_; - if (it1_ != it1_end_) - index1 = it1_.index1 (); - } - size_type index2 = (*this) ().size1 (); - if (it2_ != it2_end_) - if (it2_.index1 () <= i_) - ++ it2_; - if (it2_ != it2_end_) { - index2 = it2_.index1 (); - } - i_ = (std::min) (index1, index2); - } - BOOST_UBLAS_INLINE - void decrement (sparse_bidirectional_iterator_tag) { - size_type index1 = (*this) ().size1 (); - if (it1_ != it1_end_) { - if (i_ <= it1_.index1 ()) - -- it1_; - if (it1_ != it1_end_) - index1 = it1_.index1 (); - } - size_type index2 = (*this) ().size1 (); - if (it2_ != it2_end_) { - if (i_ <= it2_.index1 ()) - -- it2_; - if (it2_ != it2_end_) - index2 = it2_.index1 (); - } - i_ = (std::max) (index1, index2); - } - BOOST_UBLAS_INLINE - void increment (sparse_bidirectional_iterator_tag, difference_type n) { - while (n > 0) { - increment (sparse_bidirectional_iterator_tag ()); - --n; - } - while (n < 0) { - decrement (sparse_bidirectional_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - void decrement (sparse_bidirectional_iterator_tag, difference_type n) { - while (n > 0) { - decrement (sparse_bidirectional_iterator_tag ()); - --n; - } - while (n < 0) { - increment (sparse_bidirectional_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - value_type dereference (sparse_bidirectional_iterator_tag) const { - value_type t1 = value_type/*zero*/(); - if (it1_ != it1_end_) { - BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ()); - if (it1_.index1 () == i_) - t1 = *it1_; - } - value_type t2 = value_type/*zero*/(); - if (it2_ != it2_end_) { - BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ()); - if (it2_.index1 () == i_) - t2 = *it2_; - } - return functor_type::apply (t1, t2); - } - - public: - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - increment (iterator_category ()); - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - decrement (iterator_category ()); - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - increment (iterator_category (), n); - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - decrement (iterator_category (), n); - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ()); - return index1 () - it.index1 (); - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return dereference (iterator_category ()); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator1: + public container_const_reference<matrix_binary>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator1::iterator_category>::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator1::iterator_category>::iterator_category iterator_category; + typedef typename matrix_binary::difference_type difference_type; + typedef typename matrix_binary::value_type value_type; + typedef typename matrix_binary::const_reference reference; + typedef typename matrix_binary::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mb, size_type i, size_type j, + const const_iterator11_type &it1, const const_iterator11_type &it1_end, + const const_iterator21_type &it2, const const_iterator21_type &it2_end): + container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {} + + private: + // Dense specializations + BOOST_UBLAS_INLINE + void increment (dense_random_access_iterator_tag) { + ++ i_; ++ it1_; ++ it2_; + } + BOOST_UBLAS_INLINE + void decrement (dense_random_access_iterator_tag) { + -- i_; -- it1_; -- it2_; + } + BOOST_UBLAS_INLINE + void increment (dense_random_access_iterator_tag, difference_type n) { + i_ += n; it1_ += n; it2_ += n; + } + BOOST_UBLAS_INLINE + void decrement (dense_random_access_iterator_tag, difference_type n) { + i_ -= n; it1_ -= n; it2_ -= n; + } + BOOST_UBLAS_INLINE + value_type dereference (dense_random_access_iterator_tag) const { + return functor_type::apply (*it1_, *it2_); + } + + // Packed specializations + BOOST_UBLAS_INLINE + void increment (packed_random_access_iterator_tag) { + if (it1_ != it1_end_) + if (it1_.index1 () <= i_) + ++ it1_; + if (it2_ != it2_end_) + if (it2_.index1 () <= i_) + ++ it2_; + ++ i_; + } + BOOST_UBLAS_INLINE + void decrement (packed_random_access_iterator_tag) { + if (it1_ != it1_end_) + if (i_ <= it1_.index1 ()) + -- it1_; + if (it2_ != it2_end_) + if (i_ <= it2_.index1 ()) + -- it2_; + -- i_; + } + BOOST_UBLAS_INLINE + void increment (packed_random_access_iterator_tag, difference_type n) { + while (n > 0) { + increment (packed_random_access_iterator_tag ()); + --n; + } + while (n < 0) { + decrement (packed_random_access_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + void decrement (packed_random_access_iterator_tag, difference_type n) { + while (n > 0) { + decrement (packed_random_access_iterator_tag ()); + --n; + } + while (n < 0) { + increment (packed_random_access_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + value_type dereference (packed_random_access_iterator_tag) const { + typename E1::value_type t1 = typename E1::value_type/*zero*/(); + if (it1_ != it1_end_) { + BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ()); + if (it1_.index1 () == i_) + t1 = *it1_; + } + typename E2::value_type t2 = typename E2::value_type/*zero*/(); + if (it2_ != it2_end_) { + BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ()); + if (it2_.index1 () == i_) + t2 = *it2_; + } + return functor_type::apply (t1, t2); + } + + // Sparse specializations + BOOST_UBLAS_INLINE + void increment (sparse_bidirectional_iterator_tag) { + size_type index1 = (*this) ().size1 (); + if (it1_ != it1_end_) { + if (it1_.index1 () <= i_) + ++ it1_; + if (it1_ != it1_end_) + index1 = it1_.index1 (); + } + size_type index2 = (*this) ().size1 (); + if (it2_ != it2_end_) + if (it2_.index1 () <= i_) + ++ it2_; + if (it2_ != it2_end_) { + index2 = it2_.index1 (); + } + i_ = (std::min) (index1, index2); + } + BOOST_UBLAS_INLINE + void decrement (sparse_bidirectional_iterator_tag) { + size_type index1 = (*this) ().size1 (); + if (it1_ != it1_end_) { + if (i_ <= it1_.index1 ()) + -- it1_; + if (it1_ != it1_end_) + index1 = it1_.index1 (); + } + size_type index2 = (*this) ().size1 (); + if (it2_ != it2_end_) { + if (i_ <= it2_.index1 ()) + -- it2_; + if (it2_ != it2_end_) + index2 = it2_.index1 (); + } + i_ = (std::max) (index1, index2); + } + BOOST_UBLAS_INLINE + void increment (sparse_bidirectional_iterator_tag, difference_type n) { + while (n > 0) { + increment (sparse_bidirectional_iterator_tag ()); + --n; + } + while (n < 0) { + decrement (sparse_bidirectional_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + void decrement (sparse_bidirectional_iterator_tag, difference_type n) { + while (n > 0) { + decrement (sparse_bidirectional_iterator_tag ()); + --n; + } + while (n < 0) { + increment (sparse_bidirectional_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + value_type dereference (sparse_bidirectional_iterator_tag) const { + typename E1::value_type t1 = typename E1::value_type/*zero*/(); + if (it1_ != it1_end_) { + BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ()); + if (it1_.index1 () == i_) + t1 = *it1_; + } + typename E2::value_type t2 = typename E2::value_type/*zero*/(); + if (it2_ != it2_end_) { + BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ()); + if (it2_.index1 () == i_) + t2 = *it2_; + } + return functor_type::apply (t1, t2); + } + + public: + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + increment (iterator_category ()); + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + decrement (iterator_category ()); + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + increment (iterator_category (), n); + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + decrement (iterator_category (), n); + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ()); + return index1 () - it.index1 (); + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return dereference (iterator_category ()); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return i_; - } - BOOST_UBLAS_INLINE - size_type index2 () const { - // if (it1_ != it1_end_ && it2_ != it2_end_) - // return BOOST_UBLAS_SAME (it1_.index2 (), it2_.index2 ()); - // else - return j_; - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - i_ = it.i_; - j_ = it.j_; - it1_ = it.it1_; - it1_end_ = it.it1_end_; - it2_ = it.it2_; - it2_end_ = it.it2_end_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ()); - return index1 () == it.index1 (); - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ()); - return index1 () < it.index1 (); - } - - private: - size_type i_; - size_type j_; - const_iterator11_type it1_; - const_iterator11_type it1_end_; - const_iterator21_type it2_; - const_iterator21_type it2_end_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return i_; + } + BOOST_UBLAS_INLINE + size_type index2 () const { + // if (it1_ != it1_end_ && it2_ != it2_end_) + // return BOOST_UBLAS_SAME (it1_.index2 (), it2_.index2 ()); + // else + return j_; + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + i_ = it.i_; + j_ = it.j_; + it1_ = it.it1_; + it1_end_ = it.it1_end_; + it2_ = it.it2_; + it2_end_ = it.it2_end_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ()); + return index1 () == it.index1 (); + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ()); + return index1 () < it.index1 (); + } + + private: + size_type i_; + size_type j_; + const_iterator11_type it1_; + const_iterator11_type it1_end_; + const_iterator21_type it2_; + const_iterator21_type it2_end_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<matrix_binary>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; - typedef typename matrix_binary::difference_type difference_type; - typedef typename matrix_binary::value_type value_type; - typedef typename matrix_binary::const_reference reference; - typedef typename matrix_binary::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mb, size_type i, size_type j, - const const_iterator12_type &it1, const const_iterator12_type &it1_end, - const const_iterator22_type &it2, const const_iterator22_type &it2_end): - container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {} - - private: - // Dense access specializations - BOOST_UBLAS_INLINE - void increment (dense_random_access_iterator_tag) { - ++ j_; ++ it1_; ++ it2_; - } - BOOST_UBLAS_INLINE - void decrement (dense_random_access_iterator_tag) { - -- j_; -- it1_; -- it2_; - } - BOOST_UBLAS_INLINE - void increment (dense_random_access_iterator_tag, difference_type n) { - j_ += n; it1_ += n; it2_ += n; - } - BOOST_UBLAS_INLINE - void decrement (dense_random_access_iterator_tag, difference_type n) { - j_ -= n; it1_ -= n; it2_ -= n; - } - BOOST_UBLAS_INLINE - value_type dereference (dense_random_access_iterator_tag) const { - return functor_type::apply (*it1_, *it2_); - } - - // Packed specializations - BOOST_UBLAS_INLINE - void increment (packed_random_access_iterator_tag) { - if (it1_ != it1_end_) - if (it1_.index2 () <= j_) - ++ it1_; - if (it2_ != it2_end_) - if (it2_.index2 () <= j_) - ++ it2_; - ++ j_; - } - BOOST_UBLAS_INLINE - void decrement (packed_random_access_iterator_tag) { - if (it1_ != it1_end_) - if (j_ <= it1_.index2 ()) - -- it1_; - if (it2_ != it2_end_) - if (j_ <= it2_.index2 ()) - -- it2_; - -- j_; - } - BOOST_UBLAS_INLINE - void increment (packed_random_access_iterator_tag, difference_type n) { - while (n > 0) { - increment (packed_random_access_iterator_tag ()); - --n; - } - while (n < 0) { - decrement (packed_random_access_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - void decrement (packed_random_access_iterator_tag, difference_type n) { - while (n > 0) { - decrement (packed_random_access_iterator_tag ()); - --n; - } - while (n < 0) { - increment (packed_random_access_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - value_type dereference (packed_random_access_iterator_tag) const { - value_type t1 = value_type/*zero*/(); - if (it1_ != it1_end_) { - BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ()); - if (it1_.index2 () == j_) - t1 = *it1_; - } - value_type t2 = value_type/*zero*/(); - if (it2_ != it2_end_) { - BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ()); - if (it2_.index2 () == j_) - t2 = *it2_; - } - return functor_type::apply (t1, t2); - } - - // Sparse specializations - BOOST_UBLAS_INLINE - void increment (sparse_bidirectional_iterator_tag) { - size_type index1 = (*this) ().size2 (); - if (it1_ != it1_end_) { - if (it1_.index2 () <= j_) - ++ it1_; - if (it1_ != it1_end_) - index1 = it1_.index2 (); - } - size_type index2 = (*this) ().size2 (); - if (it2_ != it2_end_) { - if (it2_.index2 () <= j_) - ++ it2_; - if (it2_ != it2_end_) - index2 = it2_.index2 (); - } - j_ = (std::min) (index1, index2); - } - BOOST_UBLAS_INLINE - void decrement (sparse_bidirectional_iterator_tag) { - size_type index1 = (*this) ().size2 (); - if (it1_ != it1_end_) { - if (j_ <= it1_.index2 ()) - -- it1_; - if (it1_ != it1_end_) - index1 = it1_.index2 (); - } - size_type index2 = (*this) ().size2 (); - if (it2_ != it2_end_) { - if (j_ <= it2_.index2 ()) - -- it2_; - if (it2_ != it2_end_) - index2 = it2_.index2 (); - } - j_ = (std::max) (index1, index2); - } - BOOST_UBLAS_INLINE - void increment (sparse_bidirectional_iterator_tag, difference_type n) { - while (n > 0) { - increment (sparse_bidirectional_iterator_tag ()); - --n; - } - while (n < 0) { - decrement (sparse_bidirectional_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - void decrement (sparse_bidirectional_iterator_tag, difference_type n) { - while (n > 0) { - decrement (sparse_bidirectional_iterator_tag ()); - --n; - } - while (n < 0) { - increment (sparse_bidirectional_iterator_tag ()); - ++n; - } - } - BOOST_UBLAS_INLINE - value_type dereference (sparse_bidirectional_iterator_tag) const { - value_type t1 = value_type/*zero*/(); - if (it1_ != it1_end_) { - BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ()); - if (it1_.index2 () == j_) - t1 = *it1_; - } - value_type t2 = value_type/*zero*/(); - if (it2_ != it2_end_) { - BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ()); - if (it2_.index2 () == j_) - t2 = *it2_; - } - return functor_type::apply (t1, t2); - } - - public: - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - increment (iterator_category ()); - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - decrement (iterator_category ()); - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - increment (iterator_category (), n); - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - decrement (iterator_category (), n); - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ()); - return index2 () - it.index2 (); - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return dereference (iterator_category ()); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator2: + public container_const_reference<matrix_binary>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; + typedef typename matrix_binary::difference_type difference_type; + typedef typename matrix_binary::value_type value_type; + typedef typename matrix_binary::const_reference reference; + typedef typename matrix_binary::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mb, size_type i, size_type j, + const const_iterator12_type &it1, const const_iterator12_type &it1_end, + const const_iterator22_type &it2, const const_iterator22_type &it2_end): + container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {} + + private: + // Dense access specializations + BOOST_UBLAS_INLINE + void increment (dense_random_access_iterator_tag) { + ++ j_; ++ it1_; ++ it2_; + } + BOOST_UBLAS_INLINE + void decrement (dense_random_access_iterator_tag) { + -- j_; -- it1_; -- it2_; + } + BOOST_UBLAS_INLINE + void increment (dense_random_access_iterator_tag, difference_type n) { + j_ += n; it1_ += n; it2_ += n; + } + BOOST_UBLAS_INLINE + void decrement (dense_random_access_iterator_tag, difference_type n) { + j_ -= n; it1_ -= n; it2_ -= n; + } + BOOST_UBLAS_INLINE + value_type dereference (dense_random_access_iterator_tag) const { + return functor_type::apply (*it1_, *it2_); + } + + // Packed specializations + BOOST_UBLAS_INLINE + void increment (packed_random_access_iterator_tag) { + if (it1_ != it1_end_) + if (it1_.index2 () <= j_) + ++ it1_; + if (it2_ != it2_end_) + if (it2_.index2 () <= j_) + ++ it2_; + ++ j_; + } + BOOST_UBLAS_INLINE + void decrement (packed_random_access_iterator_tag) { + if (it1_ != it1_end_) + if (j_ <= it1_.index2 ()) + -- it1_; + if (it2_ != it2_end_) + if (j_ <= it2_.index2 ()) + -- it2_; + -- j_; + } + BOOST_UBLAS_INLINE + void increment (packed_random_access_iterator_tag, difference_type n) { + while (n > 0) { + increment (packed_random_access_iterator_tag ()); + --n; + } + while (n < 0) { + decrement (packed_random_access_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + void decrement (packed_random_access_iterator_tag, difference_type n) { + while (n > 0) { + decrement (packed_random_access_iterator_tag ()); + --n; + } + while (n < 0) { + increment (packed_random_access_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + value_type dereference (packed_random_access_iterator_tag) const { + typename E1::value_type t1 = typename E1::value_type/*zero*/(); + if (it1_ != it1_end_) { + BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ()); + if (it1_.index2 () == j_) + t1 = *it1_; + } + typename E2::value_type t2 = typename E2::value_type/*zero*/(); + if (it2_ != it2_end_) { + BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ()); + if (it2_.index2 () == j_) + t2 = *it2_; + } + return functor_type::apply (t1, t2); + } + + // Sparse specializations + BOOST_UBLAS_INLINE + void increment (sparse_bidirectional_iterator_tag) { + size_type index1 = (*this) ().size2 (); + if (it1_ != it1_end_) { + if (it1_.index2 () <= j_) + ++ it1_; + if (it1_ != it1_end_) + index1 = it1_.index2 (); + } + size_type index2 = (*this) ().size2 (); + if (it2_ != it2_end_) { + if (it2_.index2 () <= j_) + ++ it2_; + if (it2_ != it2_end_) + index2 = it2_.index2 (); + } + j_ = (std::min) (index1, index2); + } + BOOST_UBLAS_INLINE + void decrement (sparse_bidirectional_iterator_tag) { + size_type index1 = (*this) ().size2 (); + if (it1_ != it1_end_) { + if (j_ <= it1_.index2 ()) + -- it1_; + if (it1_ != it1_end_) + index1 = it1_.index2 (); + } + size_type index2 = (*this) ().size2 (); + if (it2_ != it2_end_) { + if (j_ <= it2_.index2 ()) + -- it2_; + if (it2_ != it2_end_) + index2 = it2_.index2 (); + } + j_ = (std::max) (index1, index2); + } + BOOST_UBLAS_INLINE + void increment (sparse_bidirectional_iterator_tag, difference_type n) { + while (n > 0) { + increment (sparse_bidirectional_iterator_tag ()); + --n; + } + while (n < 0) { + decrement (sparse_bidirectional_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + void decrement (sparse_bidirectional_iterator_tag, difference_type n) { + while (n > 0) { + decrement (sparse_bidirectional_iterator_tag ()); + --n; + } + while (n < 0) { + increment (sparse_bidirectional_iterator_tag ()); + ++n; + } + } + BOOST_UBLAS_INLINE + value_type dereference (sparse_bidirectional_iterator_tag) const { + typename E1::value_type t1 = typename E1::value_type/*zero*/(); + if (it1_ != it1_end_) { + BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ()); + if (it1_.index2 () == j_) + t1 = *it1_; + } + typename E2::value_type t2 = typename E2::value_type/*zero*/(); + if (it2_ != it2_end_) { + BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ()); + if (it2_.index2 () == j_) + t2 = *it2_; + } + return functor_type::apply (t1, t2); + } + + public: + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + increment (iterator_category ()); + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + decrement (iterator_category ()); + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + increment (iterator_category (), n); + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + decrement (iterator_category (), n); + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ()); + return index2 () - it.index2 (); + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return dereference (iterator_category ()); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - // if (it1_ != it1_end_ && it2_ != it2_end_) - // return BOOST_UBLAS_SAME (it1_.index1 (), it2_.index1 ()); - // else - return i_; - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return j_; - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - i_ = it.i_; - j_ = it.j_; - it1_ = it.it1_; - it1_end_ = it.it1_end_; - it2_ = it.it2_; - it2_end_ = it.it2_end_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ()); - return index2 () == it.index2 (); - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ()); - return index2 () < it.index2 (); - } - - private: - size_type i_; - size_type j_; - const_iterator12_type it1_; - const_iterator12_type it1_end_; - const_iterator22_type it2_; - const_iterator22_type it2_end_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class E1, class E2, class F> - struct matrix_binary_traits { - typedef matrix_binary<E1, E2, F> expression_type; + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + // if (it1_ != it1_end_ && it2_ != it2_end_) + // return BOOST_UBLAS_SAME (it1_.index1 (), it2_.index1 ()); + // else + return i_; + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return j_; + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + i_ = it.i_; + j_ = it.j_; + it1_ = it.it1_; + it1_end_ = it.it1_end_; + it2_ = it.it2_; + it2_end_ = it.it2_end_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ()); + return index2 () == it.index2 (); + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ()); + return index2 () < it.index2 (); + } + + private: + size_type i_; + size_type j_; + const_iterator12_type it1_; + const_iterator12_type it1_end_; + const_iterator22_type it2_; + const_iterator22_type it2_end_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class E1, class E2, class F> +struct matrix_binary_traits { + typedef matrix_binary<E1, E2, F> expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E1::matrix_temporary_type result_type; -#endif - }; - - // (m1 + m2) [i] [j] = m1 [i] [j] + m2 [i] [j] - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type, - typename E2::value_type> >::result_type - operator + (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - typedef typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type, - typename E2::value_type> >::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // (m1 - m2) [i] [j] = m1 [i] [j] - m2 [i] [j] - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type, - typename E2::value_type> >::result_type - operator - (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - typedef typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type, - typename E2::value_type> >::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // (m1 * m2) [i] [j] = m1 [i] [j] * m2 [i] [j] - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, - typename E2::value_type> >::result_type - element_prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - typedef typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, - typename E2::value_type> >::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // (m1 / m2) [i] [j] = m1 [i] [j] / m2 [i] [j] - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type, - typename E2::value_type> >::result_type - element_div (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - typedef typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type, - typename E2::value_type> >::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - template<class E1, class E2, class F> - class matrix_binary_scalar1: - public matrix_expression<matrix_binary_scalar1<E1, E2, F> > { - - typedef E1 expression1_type; - typedef E2 expression2_type; - typedef F functor_type; - typedef const E1& expression1_closure_type; - typedef typename E2::const_closure_type expression2_closure_type; - typedef matrix_binary_scalar1<E1, E2, F> self_type; - public: + typedef typename E1::matrix_temporary_type result_type; +#endif +}; + +// (m1 + m2) [i] [j] = m1 [i] [j] + m2 [i] [j] +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type, +typename E2::value_type> >::result_type +operator + (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + typedef typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type, + typename E2::value_type> >::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// (m1 - m2) [i] [j] = m1 [i] [j] - m2 [i] [j] +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type, +typename E2::value_type> >::result_type +operator - (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + typedef typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type, + typename E2::value_type> >::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// (m1 * m2) [i] [j] = m1 [i] [j] * m2 [i] [j] +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, +typename E2::value_type> >::result_type +element_prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + typedef typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, + typename E2::value_type> >::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// (m1 / m2) [i] [j] = m1 [i] [j] / m2 [i] [j] +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type, +typename E2::value_type> >::result_type +element_div (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + typedef typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type, + typename E2::value_type> >::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +template<class E1, class E2, class F> +class matrix_binary_scalar1: + public matrix_expression<matrix_binary_scalar1<E1, E2, F> > { + + typedef E1 expression1_type; + typedef E2 expression2_type; + typedef F functor_type; + typedef const E1& expression1_closure_type; + typedef typename E2::const_closure_type expression2_closure_type; + typedef matrix_binary_scalar1<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef typename E2::size_type size_type; - typedef typename E2::difference_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef typename E2::orientation_category orientation_category; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - matrix_binary_scalar1 (const expression1_type &e1, const expression2_type &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e2_.size1 (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e2_.size2 (); - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (expression1_type (e1_), e2_ (i, j)); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_binary_scalar1 &mbs1) const { - return &e1_ == &(mbs1.e1_) && - (*this).e2_.same_closure (mbs1.e2_); - } - - // Iterator types - private: - typedef expression1_type const_subiterator1_type; - typedef typename E2::const_iterator1 const_iterator21_type; - typedef typename E2::const_iterator2 const_iterator22_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + typedef typename E2::size_type size_type; + typedef typename E2::difference_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef typename E2::orientation_category orientation_category; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + matrix_binary_scalar1 (const expression1_type &e1, const expression2_type &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e2_.size1 (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e2_.size2 (); + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (expression1_type (e1_), e2_ (i, j)); + } + + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (expression1_type (e1_), e2_ (i)); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_binary_scalar1 &mbs1) const { + return &e1_ == &(mbs1.e1_) && + (*this).e2_.same_closure (mbs1.e2_); + } + + // Iterator types +private: + typedef expression1_type const_subiterator1_type; + typedef typename E2::const_iterator1 const_iterator21_type; + typedef typename E2::const_iterator2 const_iterator22_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef indexed_const_iterator1<const_closure_type, typename const_iterator21_type::iterator_category> const_iterator1; - typedef const_iterator1 iterator1; - typedef indexed_const_iterator2<const_closure_type, typename const_iterator22_type::iterator_category> const_iterator2; - typedef const_iterator2 iterator2; + typedef indexed_const_iterator1<const_closure_type, typename const_iterator21_type::iterator_category> const_iterator1; + typedef const_iterator1 iterator1; + typedef indexed_const_iterator2<const_closure_type, typename const_iterator22_type::iterator_category> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - const_iterator21_type it21 (e2_.find1 (rank, i, j)); + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + const_iterator21_type it21 (e2_.find1 (rank, i, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, it21.index1 (), it21.index2 ()); + return const_iterator1 (*this, it21.index1 (), it21.index2 ()); #else - return const_iterator1 (*this, const_subiterator1_type (e1_), it21); + return const_iterator1 (*this, const_subiterator1_type (e1_), it21); #endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - const_iterator22_type it22 (e2_.find2 (rank, i, j)); + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + const_iterator22_type it22 (e2_.find2 (rank, i, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, it22.index1 (), it22.index2 ()); + return const_iterator2 (*this, it22.index1 (), it22.index2 ()); #else - return const_iterator2 (*this, const_subiterator1_type (e1_), it22); + return const_iterator2 (*this, const_subiterator1_type (e1_), it22); #endif - } + } - // Iterators enhance the iterators of the referenced expression - // with the binary functor. + // Iterators enhance the iterators of the referenced expression + // with the binary functor. #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<matrix_binary_scalar1>, - public iterator_base_traits<typename E2::const_iterator1::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename E2::const_iterator1::iterator_category iterator_category; - typedef typename matrix_binary_scalar1::difference_type difference_type; - typedef typename matrix_binary_scalar1::value_type value_type; - typedef typename matrix_binary_scalar1::const_reference reference; - typedef typename matrix_binary_scalar1::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator21_type &it2): - container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - ++ it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - -- it2_ ; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - it2_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - it2_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ - it.it2_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (it1_, *it2_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator1: + public container_const_reference<matrix_binary_scalar1>, + public iterator_base_traits<typename E2::const_iterator1::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename E2::const_iterator1::iterator_category iterator_category; + typedef typename matrix_binary_scalar1::difference_type difference_type; + typedef typename matrix_binary_scalar1::value_type value_type; + typedef typename matrix_binary_scalar1::const_reference reference; + typedef typename matrix_binary_scalar1::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator21_type &it2): + container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + ++ it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + -- it2_ ; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + it2_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + it2_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ - it.it2_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (it1_, *it2_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it2_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it2_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ == it.it2_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ < it.it2_; - } - - private: - const_subiterator1_type it1_; - const_iterator21_type it2_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it2_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it2_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ == it.it2_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ < it.it2_; + } + + private: + const_subiterator1_type it1_; + const_iterator21_type it2_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<matrix_binary_scalar1>, - public iterator_base_traits<typename E2::const_iterator2::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename E2::const_iterator2::iterator_category iterator_category; - typedef typename matrix_binary_scalar1::difference_type difference_type; - typedef typename matrix_binary_scalar1::value_type value_type; - typedef typename matrix_binary_scalar1::const_reference reference; - typedef typename matrix_binary_scalar1::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator22_type &it2): - container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - ++ it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - -- it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - it2_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - it2_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ - it.it2_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (it1_, *it2_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator2: + public container_const_reference<matrix_binary_scalar1>, + public iterator_base_traits<typename E2::const_iterator2::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename E2::const_iterator2::iterator_category iterator_category; + typedef typename matrix_binary_scalar1::difference_type difference_type; + typedef typename matrix_binary_scalar1::value_type value_type; + typedef typename matrix_binary_scalar1::const_reference reference; + typedef typename matrix_binary_scalar1::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator22_type &it2): + container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + ++ it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + -- it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + it2_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + it2_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ - it.it2_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (it1_, *it2_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it2_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it2_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ == it.it2_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ < it.it2_; - } - - private: - const_subiterator1_type it1_; - const_iterator22_type it2_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class E1, class E2, class F> - struct matrix_binary_scalar1_traits { - typedef matrix_binary_scalar1<E1, E2, F> expression_type; // allow E1 to be builtin type + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it2_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it2_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ == it.it2_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ < it.it2_; + } + + private: + const_subiterator1_type it1_; + const_iterator22_type it2_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class E1, class E2, class F> +struct matrix_binary_scalar1_traits { + typedef matrix_binary_scalar1<E1, E2, F> expression_type; // allow E1 to be builtin type #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E2::matrix_temporary_type result_type; -#endif - }; - - // (t * m) [i] [j] = t * m [i] [j] - template<class T1, class E2> - BOOST_UBLAS_INLINE - typename enable_if< is_convertible<T1, typename E2::value_type >, - typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type - >::type - operator * (const T1 &e1, - const matrix_expression<E2> &e2) { - typedef typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::expression_type expression_type; - return expression_type (e1, e2 ()); - } - - - template<class E1, class E2, class F> - class matrix_binary_scalar2: - public matrix_expression<matrix_binary_scalar2<E1, E2, F> > { - - typedef E1 expression1_type; - typedef E2 expression2_type; - typedef F functor_type; - public: - typedef typename E1::const_closure_type expression1_closure_type; - typedef const E2& expression2_closure_type; - private: - typedef matrix_binary_scalar2<E1, E2, F> self_type; - public: + typedef typename E2::matrix_temporary_type result_type; +#endif +}; + +// (t * m) [i] [j] = t * m [i] [j] +template<class T1, class E2> +BOOST_UBLAS_INLINE +typename boost::enable_if< is_convertible<T1, typename E2::value_type >, +typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type +>::type +operator * (const T1 &e1, + const matrix_expression<E2> &e2) { + typedef typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::expression_type expression_type; + return expression_type (e1, e2 ()); +} + + +template<class E1, class E2, class F> +class matrix_binary_scalar2: + public matrix_expression<matrix_binary_scalar2<E1, E2, F> > { + + typedef E1 expression1_type; + typedef E2 expression2_type; + typedef F functor_type; +public: + typedef typename E1::const_closure_type expression1_closure_type; + typedef const E2& expression2_closure_type; +private: + typedef matrix_binary_scalar2<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - typedef typename E1::size_type size_type; - typedef typename E1::difference_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef typename E1::orientation_category orientation_category; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - matrix_binary_scalar2 (const expression1_type &e1, const expression2_type &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e1_.size1 (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e1_.size2 (); - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (e1_ (i, j), expression2_type (e2_)); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_binary_scalar2 &mbs2) const { - return (*this).e1_.same_closure (mbs2.e1_) && - &e2_ == &(mbs2.e2_); - } - - // Iterator types - private: - typedef typename E1::const_iterator1 const_iterator11_type; - typedef typename E1::const_iterator2 const_iterator12_type; - typedef expression2_type const_subiterator2_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + typedef typename E1::size_type size_type; + typedef typename E1::difference_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef typename E1::orientation_category orientation_category; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + matrix_binary_scalar2 (const expression1_type &e1, const expression2_type &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e1_.size1 (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e1_.size2 (); + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (e1_ (i, j), expression2_type (e2_)); + } + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (e1_ (i), expression2_type (e2_)); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_binary_scalar2 &mbs2) const { + return (*this).e1_.same_closure (mbs2.e1_) && + &e2_ == &(mbs2.e2_); + } + + // Iterator types +private: + typedef typename E1::const_iterator1 const_iterator11_type; + typedef typename E1::const_iterator2 const_iterator12_type; + typedef expression2_type const_subiterator2_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef indexed_const_iterator1<const_closure_type, typename const_iterator11_type::iterator_category> const_iterator1; - typedef const_iterator1 iterator1; - typedef indexed_const_iterator2<const_closure_type, typename const_iterator12_type::iterator_category> const_iterator2; - typedef const_iterator2 iterator2; + typedef indexed_const_iterator1<const_closure_type, typename const_iterator11_type::iterator_category> const_iterator1; + typedef const_iterator1 iterator1; + typedef indexed_const_iterator2<const_closure_type, typename const_iterator12_type::iterator_category> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int rank, size_type i, size_type j) const { - const_iterator11_type it11 (e1_.find1 (rank, i, j)); + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int rank, size_type i, size_type j) const { + const_iterator11_type it11 (e1_.find1 (rank, i, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, it11.index1 (), it11.index2 ()); + return const_iterator1 (*this, it11.index1 (), it11.index2 ()); #else - return const_iterator1 (*this, it11, const_subiterator2_type (e2_)); + return const_iterator1 (*this, it11, const_subiterator2_type (e2_)); #endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int rank, size_type i, size_type j) const { - const_iterator12_type it12 (e1_.find2 (rank, i, j)); + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int rank, size_type i, size_type j) const { + const_iterator12_type it12 (e1_.find2 (rank, i, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, it12.index1 (), it12.index2 ()); + return const_iterator2 (*this, it12.index1 (), it12.index2 ()); #else - return const_iterator2 (*this, it12, const_subiterator2_type (e2_)); + return const_iterator2 (*this, it12, const_subiterator2_type (e2_)); #endif - } + } - // Iterators enhance the iterators of the referenced expression - // with the binary functor. + // Iterators enhance the iterators of the referenced expression + // with the binary functor. #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<matrix_binary_scalar2>, - public iterator_base_traits<typename E1::const_iterator1::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename E1::const_iterator1::iterator_category iterator_category; - typedef typename matrix_binary_scalar2::difference_type difference_type; - typedef typename matrix_binary_scalar2::value_type value_type; - typedef typename matrix_binary_scalar2::const_reference reference; - typedef typename matrix_binary_scalar2::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mbs, const const_iterator11_type &it1, const const_subiterator2_type &it2): - container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - ++ it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - -- it1_ ; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - it1_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - it1_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ - it.it1_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (*it1_, it2_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator1: + public container_const_reference<matrix_binary_scalar2>, + public iterator_base_traits<typename E1::const_iterator1::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename E1::const_iterator1::iterator_category iterator_category; + typedef typename matrix_binary_scalar2::difference_type difference_type; + typedef typename matrix_binary_scalar2::value_type value_type; + typedef typename matrix_binary_scalar2::const_reference reference; + typedef typename matrix_binary_scalar2::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mbs, const const_iterator11_type &it1, const const_subiterator2_type &it2): + container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + ++ it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + -- it1_ ; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + it1_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + it1_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ - it.it1_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (*it1_, it2_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it1_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it1_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ == it.it1_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ < it.it1_; - } - - private: - const_iterator11_type it1_; - const_subiterator2_type it2_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it1_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it1_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ == it.it1_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ < it.it1_; + } + + private: + const_iterator11_type it1_; + const_subiterator2_type it2_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<matrix_binary_scalar2>, - public iterator_base_traits<typename E1::const_iterator2::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename E1::const_iterator2::iterator_category iterator_category; - typedef typename matrix_binary_scalar2::difference_type difference_type; - typedef typename matrix_binary_scalar2::value_type value_type; - typedef typename matrix_binary_scalar2::const_reference reference; - typedef typename matrix_binary_scalar2::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mbs, const const_iterator12_type &it1, const const_subiterator2_type &it2): - container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} - - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - ++ it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - -- it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - it1_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - it1_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ - it.it1_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return functor_type::apply (*it1_, it2_); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + class const_iterator2: + public container_const_reference<matrix_binary_scalar2>, + public iterator_base_traits<typename E1::const_iterator2::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename E1::const_iterator2::iterator_category iterator_category; + typedef typename matrix_binary_scalar2::difference_type difference_type; + typedef typename matrix_binary_scalar2::value_type value_type; + typedef typename matrix_binary_scalar2::const_reference reference; + typedef typename matrix_binary_scalar2::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mbs, const const_iterator12_type &it1, const const_subiterator2_type &it2): + container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {} + + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + ++ it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + -- it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + it1_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + it1_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ - it.it1_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return functor_type::apply (*it1_, it2_); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it1_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it1_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ == it.it1_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - // FIXME we shouldn't compare floats - // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ < it.it1_; - } - - private: - const_iterator12_type it1_; - const_subiterator2_type it2_; - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class E1, class E2, class F> - struct matrix_binary_scalar2_traits { - typedef matrix_binary_scalar2<E1, E2, F> expression_type; // allow E2 to be builtin type + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it1_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it1_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ == it.it1_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + // FIXME we shouldn't compare floats + // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ < it.it1_; + } + + private: + const_iterator12_type it1_; + const_subiterator2_type it2_; + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class E1, class E2, class F> +struct matrix_binary_scalar2_traits { + typedef matrix_binary_scalar2<E1, E2, F> expression_type; // allow E2 to be builtin type #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E1::matrix_temporary_type result_type; -#endif - }; - - // (m * t) [i] [j] = m [i] [j] * t - template<class E1, class T2> - BOOST_UBLAS_INLINE - typename enable_if< is_convertible<T2, typename E1::value_type>, - typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::result_type - >::type - operator * (const matrix_expression<E1> &e1, - const T2 &e2) { - typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::expression_type expression_type; - return expression_type (e1 (), e2); - } - - // (m / t) [i] [j] = m [i] [j] / t - template<class E1, class T2> - BOOST_UBLAS_INLINE - typename enable_if< is_convertible<T2, typename E1::value_type>, - typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::result_type - >::type - operator / (const matrix_expression<E1> &e1, - const T2 &e2) { - typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::expression_type expression_type; - return expression_type (e1 (), e2); - } - - - template<class E1, class E2, class F> - class matrix_vector_binary1: - public vector_expression<matrix_vector_binary1<E1, E2, F> > { - - public: - typedef E1 expression1_type; - typedef E2 expression2_type; - private: - typedef F functor_type; - public: - typedef typename E1::const_closure_type expression1_closure_type; - typedef typename E2::const_closure_type expression2_closure_type; - private: - typedef matrix_vector_binary1<E1, E2, F> self_type; - public: + typedef typename E1::matrix_temporary_type result_type; +#endif +}; + +// (m * t) [i] [j] = m [i] [j] * t +template<class E1, class T2> +BOOST_UBLAS_INLINE +typename boost::enable_if< is_convertible<T2, typename E1::value_type>, +typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::result_type +>::type +operator * (const matrix_expression<E1> &e1, + const T2 &e2) { + typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::expression_type expression_type; + return expression_type (e1 (), e2); +} + +// (m / t) [i] [j] = m [i] [j] / t +template<class E1, class T2> +BOOST_UBLAS_INLINE +typename boost::enable_if< is_convertible<T2, typename E1::value_type>, +typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::result_type +>::type +operator / (const matrix_expression<E1> &e1, + const T2 &e2) { + typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::expression_type expression_type; + return expression_type (e1 (), e2); +} + + +template<class E1, class E2, class F> +class matrix_vector_binary1: + public vector_expression<matrix_vector_binary1<E1, E2, F> > { + +public: + typedef E1 expression1_type; + typedef E2 expression2_type; +private: + typedef F functor_type; +public: + typedef typename E1::const_closure_type expression1_closure_type; + typedef typename E2::const_closure_type expression2_closure_type; +private: + typedef matrix_vector_binary1<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using vector_expression<self_type>::operator (); -#endif - static const unsigned complexity = 1; - typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; - typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - matrix_vector_binary1 (const expression1_type &e1, const expression2_type &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size () const { - return e1_.size1 (); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression1_closure_type &expression1 () const { - return e1_; - } - BOOST_UBLAS_INLINE - const expression2_closure_type &expression2 () const { - return e2_; - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i) const { - return functor_type::apply (e1_, e2_, i); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_vector_binary1 &mvb1) const { - return (*this).expression1 ().same_closure (mvb1.expression1 ()) && - (*this).expression2 ().same_closure (mvb1.expression2 ()); - } - - // Iterator types - private: - typedef typename E1::const_iterator1 const_subiterator1_type; - typedef typename E2::const_iterator const_subiterator2_type; - typedef const value_type *const_pointer; - - public: + using vector_expression<self_type>::operator (); +#endif + static const unsigned complexity = 1; + typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; + typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + matrix_vector_binary1 (const expression1_type &e1, const expression2_type &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size () const { + return e1_.size1 (); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression1_closure_type &expression1 () const { + return e1_; + } + BOOST_UBLAS_INLINE + const expression2_closure_type &expression2 () const { + return e2_; + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (e1_, e2_, i); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_vector_binary1 &mvb1) const { + return (*this).expression1 ().same_closure (mvb1.expression1 ()) && + (*this).expression2 ().same_closure (mvb1.expression2 ()); + } + + // Iterator types +private: + typedef typename E1::const_iterator1 const_subiterator1_type; + typedef typename E2::const_iterator const_subiterator2_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef indexed_const_iterator<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator; - typedef const_iterator iterator; + typedef indexed_const_iterator<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator; + typedef const_iterator iterator; #else - class const_iterator; - typedef const_iterator iterator; + class const_iterator; + typedef const_iterator iterator; #endif - // Element lookup - BOOST_UBLAS_INLINE - const_iterator find (size_type i) const { + // Element lookup + BOOST_UBLAS_INLINE + const_iterator find (size_type i) const { #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - const_subiterator1_type it1 (e1_.find1 (0, i, 0)); - return const_iterator (*this, it1.index1 ()); + const_subiterator1_type it1 (e1_.find1 (0, i, 0)); + return const_iterator (*this, it1.index1 ()); #else - return const_iterator (*this, e1_.find1 (0, i, 0)); + return const_iterator (*this, e1_.find1 (0, i, 0)); #endif - } + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator: - public container_const_reference<matrix_vector_binary1>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator::iterator_category>::iterator_category>::template - iterator_base<const_iterator, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator::iterator_category>::iterator_category iterator_category; - typedef typename matrix_vector_binary1::difference_type difference_type; - typedef typename matrix_vector_binary1::value_type value_type; - typedef typename matrix_vector_binary1::const_reference reference; - typedef typename matrix_vector_binary1::const_pointer pointer; - - // Construction and destruction + class const_iterator: + public container_const_reference<matrix_vector_binary1>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator::iterator_category>::iterator_category>::template + iterator_base<const_iterator, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator::iterator_category>::iterator_category iterator_category; + typedef typename matrix_vector_binary1::difference_type difference_type; + typedef typename matrix_vector_binary1::value_type value_type; + typedef typename matrix_vector_binary1::const_reference reference; + typedef typename matrix_vector_binary1::const_pointer pointer; + + // Construction and destruction #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - BOOST_UBLAS_INLINE - const_iterator (): - container_const_reference<self_type> (), it1_ (), e2_begin_ (), e2_end_ () {} - BOOST_UBLAS_INLINE - const_iterator (const self_type &mvb, const const_subiterator1_type &it1): - container_const_reference<self_type> (mvb), it1_ (it1), e2_begin_ (mvb.expression2 ().begin ()), e2_end_ (mvb.expression2 ().end ()) {} + BOOST_UBLAS_INLINE + const_iterator (): + container_const_reference<self_type> (), it1_ (), e2_begin_ (), e2_end_ () {} + BOOST_UBLAS_INLINE + const_iterator (const self_type &mvb, const const_subiterator1_type &it1): + container_const_reference<self_type> (mvb), it1_ (it1), e2_begin_ (mvb.expression2 ().begin ()), e2_end_ (mvb.expression2 ().end ()) {} #else - BOOST_UBLAS_INLINE - const_iterator (): - container_const_reference<self_type> (), it1_ () {} - BOOST_UBLAS_INLINE - const_iterator (const self_type &mvb, const const_subiterator1_type &it1): - container_const_reference<self_type> (mvb), it1_ (it1) {} -#endif - - private: - // Dense random access specialization - BOOST_UBLAS_INLINE - value_type dereference (dense_random_access_iterator_tag) const { - const self_type &mvb = (*this) (); + BOOST_UBLAS_INLINE + const_iterator (): + container_const_reference<self_type> (), it1_ () {} + BOOST_UBLAS_INLINE + const_iterator (const self_type &mvb, const const_subiterator1_type &it1): + container_const_reference<self_type> (mvb), it1_ (it1) {} +#endif + + private: + // Dense random access specialization + BOOST_UBLAS_INLINE + value_type dereference (dense_random_access_iterator_tag) const { + const self_type &mvb = (*this) (); #ifdef BOOST_UBLAS_USE_INDEXING - return mvb (index ()); + return mvb (index ()); #elif BOOST_UBLAS_USE_ITERATING - difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ()); + difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ()); #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, it1_.begin (), e2_begin_); + return functor_type::apply (size, it1_.begin (), e2_begin_); #else - return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ()); + return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ()); #endif #else - difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ()); - if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) + difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ()); + if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, it1_.begin (), e2_begin_); + return functor_type::apply (size, it1_.begin (), e2_begin_); #else - return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ()); + return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ()); #endif - else - return mvb (index ()); + else + return mvb (index ()); #endif - } + } - // Packed bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (packed_random_access_iterator_tag) const { + // Packed bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (packed_random_access_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_); + return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_); #else - const self_type &mvb = (*this) (); + const self_type &mvb = (*this) (); #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (it1_.begin (), it1_.end (), - mvb.expression2 ().begin (), mvb.expression2 ().end ()); + return functor_type::apply (it1_.begin (), it1_.end (), + mvb.expression2 ().begin (), mvb.expression2 ().end ()); #else - return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), - boost::numeric::ublas::end (it1_, iterator1_tag ()), - mvb.expression2 ().begin (), mvb.expression2 ().end ()); + return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), + boost::numeric::ublas::end (it1_, iterator1_tag ()), + mvb.expression2 ().begin (), mvb.expression2 ().end ()); #endif #endif - } + } - // Sparse bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (sparse_bidirectional_iterator_tag) const { + // Sparse bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (sparse_bidirectional_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_, sparse_bidirectional_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_, sparse_bidirectional_iterator_tag ()); #else - const self_type &mvb = (*this) (); + const self_type &mvb = (*this) (); #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (it1_.begin (), it1_.end (), - mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ()); #else - return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), - boost::numeric::ublas::end (it1_, iterator1_tag ()), - mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ()); -#endif -#endif - } - - public: - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator &operator ++ () { - ++ it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator &operator -- () { - -- it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator &operator += (difference_type n) { - it1_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator &operator -= (difference_type n) { - it1_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it1_ - it.it1_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return dereference (iterator_category ()); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } - - // Index - BOOST_UBLAS_INLINE - size_type index () const { - return it1_.index1 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator &operator = (const const_iterator &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; + return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), + boost::numeric::ublas::end (it1_, iterator1_tag ()), + mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ()); +#endif +#endif + } + + public: + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator &operator ++ () { + ++ it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator &operator -- () { + -- it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator &operator += (difference_type n) { + it1_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator &operator -= (difference_type n) { + it1_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it1_ - it.it1_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return dereference (iterator_category ()); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } + + // Index + BOOST_UBLAS_INLINE + size_type index () const { + return it1_.index1 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator &operator = (const const_iterator &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - e2_begin_ = it.e2_begin_; - e2_end_ = it.e2_end_; -#endif - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it1_ == it.it1_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it1_ < it.it1_; - } - - private: - const_subiterator1_type it1_; + e2_begin_ = it.e2_begin_; + e2_end_ = it.e2_end_; +#endif + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it1_ == it.it1_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it1_ < it.it1_; + } + + private: + const_subiterator1_type it1_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - // Mutable due to assignment - /* const */ const_subiterator2_type e2_begin_; - /* const */ const_subiterator2_type e2_end_; -#endif - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator begin () const { - return find (0); - } - BOOST_UBLAS_INLINE - const_iterator cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE - const_iterator end () const { - return find (size ()); - } - BOOST_UBLAS_INLINE - const_iterator cend () const { - return end (); - } - - // Reverse iterator - typedef reverse_iterator_base<const_iterator> const_reverse_iterator; - - BOOST_UBLAS_INLINE - const_reverse_iterator rbegin () const { - return const_reverse_iterator (end ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator rend () const { - return const_reverse_iterator (begin ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator crend () const { - return rend (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class T1, class E1, class T2, class E2> - struct matrix_vector_binary1_traits { - typedef unknown_storage_tag storage_category; - typedef row_major_tag orientation_category; - typedef typename promote_traits<T1, T2>::promote_type promote_type; - typedef matrix_vector_binary1<E1, E2, matrix_vector_prod1<E1, E2, promote_type> > expression_type; + // Mutable due to assignment + /* const */ const_subiterator2_type e2_begin_; + /* const */ const_subiterator2_type e2_end_; +#endif + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator begin () const { + return find (0); + } + BOOST_UBLAS_INLINE + const_iterator cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE + const_iterator end () const { + return find (size ()); + } + BOOST_UBLAS_INLINE + const_iterator cend () const { + return end (); + } + + // Reverse iterator + typedef reverse_iterator_base<const_iterator> const_reverse_iterator; + + BOOST_UBLAS_INLINE + const_reverse_iterator rbegin () const { + return const_reverse_iterator (end ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator rend () const { + return const_reverse_iterator (begin ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator crend () const { + return rend (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class T1, class E1, class T2, class E2> +struct matrix_vector_binary1_traits { + typedef unknown_storage_tag storage_category; + typedef row_major_tag orientation_category; + typedef typename promote_traits<T1, T2>::promote_type promote_type; + typedef matrix_vector_binary1<E1, E2, matrix_vector_prod1<E1, E2, promote_type> > expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E1::vector_temporary_type result_type; -#endif - }; - - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary1_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::result_type - prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2, - unknown_storage_tag, - row_major_tag) { - typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // Dispatcher - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary1_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::result_type - prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E2::complexity == 0); - typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::storage_category storage_category; - typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::orientation_category orientation_category; - return prod (e1, e2, storage_category (), orientation_category ()); - } - - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::result_type - prec_prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2, - unknown_storage_tag, - row_major_tag) { - typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // Dispatcher - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::result_type - prec_prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E2::complexity == 0); - typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category; - typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category; - return prec_prod (e1, e2, storage_category (), orientation_category ()); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V & - prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2, - V &v) { - return v.assign (prod (e1, e2)); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V & - prec_prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2, - V &v) { - return v.assign (prec_prod (e1, e2)); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V - prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2) { - return V (prod (e1, e2)); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V - prec_prod (const matrix_expression<E1> &e1, - const vector_expression<E2> &e2) { - return V (prec_prod (e1, e2)); - } - - template<class E1, class E2, class F> - class matrix_vector_binary2: - public vector_expression<matrix_vector_binary2<E1, E2, F> > { - - typedef E1 expression1_type; - typedef E2 expression2_type; - typedef F functor_type; - public: - typedef typename E1::const_closure_type expression1_closure_type; - typedef typename E2::const_closure_type expression2_closure_type; - private: - typedef matrix_vector_binary2<E1, E2, F> self_type; - public: + typedef typename E1::vector_temporary_type result_type; +#endif +}; + +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary1_traits<typename E1::value_type, E1, +typename E2::value_type, E2>::result_type +prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2, + unknown_storage_tag, + row_major_tag) { + typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// Dispatcher +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary1_traits<typename E1::value_type, E1, +typename E2::value_type, E2>::result_type +prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E2::complexity == 0); + typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::storage_category storage_category; + typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::orientation_category orientation_category; + return prod (e1, e2, storage_category (), orientation_category ()); +} + +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, +typename type_traits<typename E2::value_type>::precision_type, E2>::result_type +prec_prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2, + unknown_storage_tag, + row_major_tag) { + typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// Dispatcher +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, +typename type_traits<typename E2::value_type>::precision_type, E2>::result_type +prec_prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E2::complexity == 0); + typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category; + typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category; + return prec_prod (e1, e2, storage_category (), orientation_category ()); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V & +prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2, + V &v) { + return v.assign (prod (e1, e2)); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V & +prec_prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2, + V &v) { + return v.assign (prec_prod (e1, e2)); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V +prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2) { + return V (prod (e1, e2)); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V +prec_prod (const matrix_expression<E1> &e1, + const vector_expression<E2> &e2) { + return V (prec_prod (e1, e2)); +} + +template<class E1, class E2, class F> +class matrix_vector_binary2: + public vector_expression<matrix_vector_binary2<E1, E2, F> > { + + typedef E1 expression1_type; + typedef E2 expression2_type; + typedef F functor_type; +public: + typedef typename E1::const_closure_type expression1_closure_type; + typedef typename E2::const_closure_type expression2_closure_type; +private: + typedef matrix_vector_binary2<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using vector_expression<self_type>::operator (); -#endif - static const unsigned complexity = 1; - typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; - typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - matrix_vector_binary2 (const expression1_type &e1, const expression2_type &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size () const { - return e2_.size2 (); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression1_closure_type &expression1 () const { - return e1_; - } - BOOST_UBLAS_INLINE - const expression2_closure_type &expression2 () const { - return e2_; - } - public: - - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type j) const { - return functor_type::apply (e1_, e2_, j); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_vector_binary2 &mvb2) const { - return (*this).expression1 ().same_closure (mvb2.expression1 ()) && - (*this).expression2 ().same_closure (mvb2.expression2 ()); - } - - // Iterator types - private: - typedef typename E1::const_iterator const_subiterator1_type; - typedef typename E2::const_iterator2 const_subiterator2_type; - typedef const value_type *const_pointer; - - public: + using vector_expression<self_type>::operator (); +#endif + static const unsigned complexity = 1; + typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; + typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + matrix_vector_binary2 (const expression1_type &e1, const expression2_type &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size () const { + return e2_.size2 (); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression1_closure_type &expression1 () const { + return e1_; + } + BOOST_UBLAS_INLINE + const expression2_closure_type &expression2 () const { + return e2_; + } +public: + + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type j) const { + return functor_type::apply (e1_, e2_, j); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_vector_binary2 &mvb2) const { + return (*this).expression1 ().same_closure (mvb2.expression1 ()) && + (*this).expression2 ().same_closure (mvb2.expression2 ()); + } + + // Iterator types +private: + typedef typename E1::const_iterator const_subiterator1_type; + typedef typename E2::const_iterator2 const_subiterator2_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef indexed_const_iterator<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator; - typedef const_iterator iterator; + typedef indexed_const_iterator<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator; + typedef const_iterator iterator; #else - class const_iterator; - typedef const_iterator iterator; + class const_iterator; + typedef const_iterator iterator; #endif - // Element lookup - BOOST_UBLAS_INLINE - const_iterator find (size_type j) const { + // Element lookup + BOOST_UBLAS_INLINE + const_iterator find (size_type j) const { #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - const_subiterator2_type it2 (e2_.find2 (0, 0, j)); - return const_iterator (*this, it2.index2 ()); + const_subiterator2_type it2 (e2_.find2 (0, 0, j)); + return const_iterator (*this, it2.index2 ()); #else - return const_iterator (*this, e2_.find2 (0, 0, j)); + return const_iterator (*this, e2_.find2 (0, 0, j)); #endif - } + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator: - public container_const_reference<matrix_vector_binary2>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category>::template - iterator_base<const_iterator, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; - typedef typename matrix_vector_binary2::difference_type difference_type; - typedef typename matrix_vector_binary2::value_type value_type; - typedef typename matrix_vector_binary2::const_reference reference; - typedef typename matrix_vector_binary2::const_pointer pointer; - - // Construction and destruction + class const_iterator: + public container_const_reference<matrix_vector_binary2>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category>::template + iterator_base<const_iterator, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; + typedef typename matrix_vector_binary2::difference_type difference_type; + typedef typename matrix_vector_binary2::value_type value_type; + typedef typename matrix_vector_binary2::const_reference reference; + typedef typename matrix_vector_binary2::const_pointer pointer; + + // Construction and destruction #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - BOOST_UBLAS_INLINE - const_iterator (): - container_const_reference<self_type> (), it2_ (), e1_begin_ (), e1_end_ () {} - BOOST_UBLAS_INLINE - const_iterator (const self_type &mvb, const const_subiterator2_type &it2): - container_const_reference<self_type> (mvb), it2_ (it2), e1_begin_ (mvb.expression1 ().begin ()), e1_end_ (mvb.expression1 ().end ()) {} + BOOST_UBLAS_INLINE + const_iterator (): + container_const_reference<self_type> (), it2_ (), e1_begin_ (), e1_end_ () {} + BOOST_UBLAS_INLINE + const_iterator (const self_type &mvb, const const_subiterator2_type &it2): + container_const_reference<self_type> (mvb), it2_ (it2), e1_begin_ (mvb.expression1 ().begin ()), e1_end_ (mvb.expression1 ().end ()) {} #else - BOOST_UBLAS_INLINE - const_iterator (): - container_const_reference<self_type> (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator (const self_type &mvb, const const_subiterator2_type &it2): - container_const_reference<self_type> (mvb), it2_ (it2) {} -#endif - - private: - // Dense random access specialization - BOOST_UBLAS_INLINE - value_type dereference (dense_random_access_iterator_tag) const { - const self_type &mvb = (*this) (); + BOOST_UBLAS_INLINE + const_iterator (): + container_const_reference<self_type> (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator (const self_type &mvb, const const_subiterator2_type &it2): + container_const_reference<self_type> (mvb), it2_ (it2) {} +#endif + + private: + // Dense random access specialization + BOOST_UBLAS_INLINE + value_type dereference (dense_random_access_iterator_tag) const { + const self_type &mvb = (*this) (); #ifdef BOOST_UBLAS_USE_INDEXING - return mvb (index ()); + return mvb (index ()); #elif BOOST_UBLAS_USE_ITERATING - difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ()); + difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ()); #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, e1_begin_, it2_.begin ()); + return functor_type::apply (size, e1_begin_, it2_.begin ()); #else - return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ()); + return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ()); #endif #else - difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ()); - if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) + difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ()); + if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, e1_begin_, it2_.begin ()); + return functor_type::apply (size, e1_begin_, it2_.begin ()); #else - return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ()); + return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ()); #endif - else - return mvb (index ()); + else + return mvb (index ()); #endif - } + } - // Packed bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (packed_random_access_iterator_tag) const { + // Packed bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (packed_random_access_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end ()); + return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end ()); #else - const self_type &mvb = (*this) (); + const self_type &mvb = (*this) (); #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), - it2_.begin (), it2_.end ()); + return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), + it2_.begin (), it2_.end ()); #else - return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), - boost::numeric::ublas::begin (it2_, iterator2_tag ()), - boost::numeric::ublas::end (it2_, iterator2_tag ())); + return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), + boost::numeric::ublas::begin (it2_, iterator2_tag ()), + boost::numeric::ublas::end (it2_, iterator2_tag ())); #endif #endif - } + } - // Sparse bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (sparse_bidirectional_iterator_tag) const { + // Sparse bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (sparse_bidirectional_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); + return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); #else - const self_type &mvb = (*this) (); + const self_type &mvb = (*this) (); #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), - it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); + return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), + it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); #else - return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), - boost::numeric::ublas::begin (it2_, iterator2_tag ()), - boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ()); -#endif -#endif - } - - public: - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator &operator ++ () { - ++ it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator &operator -- () { - -- it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator &operator += (difference_type n) { - it2_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator &operator -= (difference_type n) { - it2_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it2_ - it.it2_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return dereference (iterator_category ()); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } - - // Index - BOOST_UBLAS_INLINE - size_type index () const { - return it2_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator &operator = (const const_iterator &it) { - container_const_reference<self_type>::assign (&it ()); - it2_ = it.it2_; + return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (), + boost::numeric::ublas::begin (it2_, iterator2_tag ()), + boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ()); +#endif +#endif + } + + public: + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator &operator ++ () { + ++ it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator &operator -- () { + -- it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator &operator += (difference_type n) { + it2_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator &operator -= (difference_type n) { + it2_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it2_ - it.it2_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return dereference (iterator_category ()); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } + + // Index + BOOST_UBLAS_INLINE + size_type index () const { + return it2_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator &operator = (const const_iterator &it) { + container_const_reference<self_type>::assign (&it ()); + it2_ = it.it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - e1_begin_ = it.e1_begin_; - e1_end_ = it.e1_end_; -#endif - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it2_ == it.it2_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - return it2_ < it.it2_; - } - - private: - const_subiterator2_type it2_; + e1_begin_ = it.e1_begin_; + e1_end_ = it.e1_end_; +#endif + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it2_ == it.it2_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + return it2_ < it.it2_; + } + + private: + const_subiterator2_type it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - // Mutable due to assignment - /* const */ const_subiterator1_type e1_begin_; - /* const */ const_subiterator1_type e1_end_; -#endif - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator begin () const { - return find (0); - } - BOOST_UBLAS_INLINE - const_iterator cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE - const_iterator end () const { - return find (size ()); - } - BOOST_UBLAS_INLINE - const_iterator cend () const { - return end (); - } - - // Reverse iterator - typedef reverse_iterator_base<const_iterator> const_reverse_iterator; - - BOOST_UBLAS_INLINE - const_reverse_iterator rbegin () const { - return const_reverse_iterator (end ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator rend () const { - return const_reverse_iterator (begin ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator crend () const { - return rend (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class T1, class E1, class T2, class E2> - struct matrix_vector_binary2_traits { - typedef unknown_storage_tag storage_category; - typedef column_major_tag orientation_category; - typedef typename promote_traits<T1, T2>::promote_type promote_type; - typedef matrix_vector_binary2<E1, E2, matrix_vector_prod2<E1, E2, promote_type> > expression_type; + // Mutable due to assignment + /* const */ const_subiterator1_type e1_begin_; + /* const */ const_subiterator1_type e1_end_; +#endif + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator begin () const { + return find (0); + } + BOOST_UBLAS_INLINE + const_iterator cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE + const_iterator end () const { + return find (size ()); + } + BOOST_UBLAS_INLINE + const_iterator cend () const { + return end (); + } + + // Reverse iterator + typedef reverse_iterator_base<const_iterator> const_reverse_iterator; + + BOOST_UBLAS_INLINE + const_reverse_iterator rbegin () const { + return const_reverse_iterator (end ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator rend () const { + return const_reverse_iterator (begin ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator crend () const { + return rend (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class T1, class E1, class T2, class E2> +struct matrix_vector_binary2_traits { + typedef unknown_storage_tag storage_category; + typedef column_major_tag orientation_category; + typedef typename promote_traits<T1, T2>::promote_type promote_type; + typedef matrix_vector_binary2<E1, E2, matrix_vector_prod2<E1, E2, promote_type> > expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E2::vector_temporary_type result_type; -#endif - }; - - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary2_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::result_type - prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2, - unknown_storage_tag, - column_major_tag) { - typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // Dispatcher - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary2_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::result_type - prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E1::complexity == 0); - typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::storage_category storage_category; - typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::orientation_category orientation_category; - return prod (e1, e2, storage_category (), orientation_category ()); - } - - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::result_type - prec_prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2, - unknown_storage_tag, - column_major_tag) { - typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // Dispatcher - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::result_type - prec_prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E1::complexity == 0); - typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category; - typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category; - return prec_prod (e1, e2, storage_category (), orientation_category ()); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V & - prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2, - V &v) { - return v.assign (prod (e1, e2)); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V & - prec_prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2, - V &v) { - return v.assign (prec_prod (e1, e2)); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V - prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2) { - return V (prod (e1, e2)); - } - - template<class V, class E1, class E2> - BOOST_UBLAS_INLINE - V - prec_prod (const vector_expression<E1> &e1, - const matrix_expression<E2> &e2) { - return V (prec_prod (e1, e2)); - } - - template<class E1, class E2, class F> - class matrix_matrix_binary: - public matrix_expression<matrix_matrix_binary<E1, E2, F> > { - - public: - typedef E1 expression1_type; - typedef E2 expression2_type; - private: - typedef F functor_type; - public: - typedef typename E1::const_closure_type expression1_closure_type; - typedef typename E2::const_closure_type expression2_closure_type; - private: - typedef matrix_matrix_binary<E1, E2, F> self_type; - public: + typedef typename E2::vector_temporary_type result_type; +#endif +}; + +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary2_traits<typename E1::value_type, E1, +typename E2::value_type, E2>::result_type +prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2, + unknown_storage_tag, + column_major_tag) { + typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// Dispatcher +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary2_traits<typename E1::value_type, E1, +typename E2::value_type, E2>::result_type +prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E1::complexity == 0); + typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::storage_category storage_category; + typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::orientation_category orientation_category; + return prod (e1, e2, storage_category (), orientation_category ()); +} + +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, +typename type_traits<typename E2::value_type>::precision_type, E2>::result_type +prec_prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2, + unknown_storage_tag, + column_major_tag) { + typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// Dispatcher +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, +typename type_traits<typename E2::value_type>::precision_type, E2>::result_type +prec_prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E1::complexity == 0); + typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category; + typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category; + return prec_prod (e1, e2, storage_category (), orientation_category ()); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V & +prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2, + V &v) { + return v.assign (prod (e1, e2)); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V & +prec_prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2, + V &v) { + return v.assign (prec_prod (e1, e2)); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V +prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2) { + return V (prod (e1, e2)); +} + +template<class V, class E1, class E2> +BOOST_UBLAS_INLINE +V +prec_prod (const vector_expression<E1> &e1, + const matrix_expression<E2> &e2) { + return V (prec_prod (e1, e2)); +} + +template<class E1, class E2, class F> +class matrix_matrix_binary: + public matrix_expression<matrix_matrix_binary<E1, E2, F> > { + +public: + typedef E1 expression1_type; + typedef E2 expression2_type; +private: + typedef F functor_type; +public: + typedef typename E1::const_closure_type expression1_closure_type; + typedef typename E2::const_closure_type expression2_closure_type; +private: + typedef matrix_matrix_binary<E1, E2, F> self_type; +public: #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS - using matrix_expression<self_type>::operator (); -#endif - static const unsigned complexity = 1; - typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; - typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; - typedef typename F::result_type value_type; - typedef value_type const_reference; - typedef const_reference reference; - typedef const self_type const_closure_type; - typedef const_closure_type closure_type; - typedef unknown_orientation_tag orientation_category; - typedef unknown_storage_tag storage_category; - - // Construction and destruction - BOOST_UBLAS_INLINE - matrix_matrix_binary (const expression1_type &e1, const expression2_type &e2): - e1_ (e1), e2_ (e2) {} - - // Accessors - BOOST_UBLAS_INLINE - size_type size1 () const { - return e1_.size1 (); - } - BOOST_UBLAS_INLINE - size_type size2 () const { - return e2_.size2 (); - } - - public: - // Expression accessors - BOOST_UBLAS_INLINE - const expression1_closure_type &expression1 () const { - return e1_; - } - BOOST_UBLAS_INLINE - const expression2_closure_type &expression2 () const { - return e2_; - } - - public: - // Element access - BOOST_UBLAS_INLINE - const_reference operator () (size_type i, size_type j) const { - return functor_type::apply (e1_, e2_, i, j); - } - - // Closure comparison - BOOST_UBLAS_INLINE - bool same_closure (const matrix_matrix_binary &mmb) const { - return (*this).expression1 ().same_closure (mmb.expression1 ()) && - (*this).expression2 ().same_closure (mmb.expression2 ()); - } - - // Iterator types - private: - typedef typename E1::const_iterator1 const_iterator11_type; - typedef typename E1::const_iterator2 const_iterator12_type; - typedef typename E2::const_iterator1 const_iterator21_type; - typedef typename E2::const_iterator2 const_iterator22_type; - typedef const value_type *const_pointer; - - public: + using matrix_expression<self_type>::operator (); +#endif + static const unsigned complexity = 1; + typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type; + typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type; + typedef typename F::result_type value_type; + typedef value_type const_reference; + typedef const_reference reference; + typedef const self_type const_closure_type; + typedef const_closure_type closure_type; + typedef unknown_orientation_tag orientation_category; + typedef unknown_storage_tag storage_category; + + // Construction and destruction + BOOST_UBLAS_INLINE + matrix_matrix_binary (const expression1_type &e1, const expression2_type &e2): + e1_ (e1), e2_ (e2) {} + + // Accessors + BOOST_UBLAS_INLINE + size_type size1 () const { + return e1_.size1 (); + } + BOOST_UBLAS_INLINE + size_type size2 () const { + return e2_.size2 (); + } + +public: + // Expression accessors + BOOST_UBLAS_INLINE + const expression1_closure_type &expression1 () const { + return e1_; + } + BOOST_UBLAS_INLINE + const expression2_closure_type &expression2 () const { + return e2_; + } + +public: + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i, size_type j) const { + return functor_type::apply (e1_, e2_, i, j); + } + + // Element access + BOOST_UBLAS_INLINE + const_reference operator () (size_type i) const { + return functor_type::apply (e1_, e2_, i); + } + + // Closure comparison + BOOST_UBLAS_INLINE + bool same_closure (const matrix_matrix_binary &mmb) const { + return (*this).expression1 ().same_closure (mmb.expression1 ()) && + (*this).expression2 ().same_closure (mmb.expression2 ()); + } + + // Iterator types +private: + typedef typename E1::const_iterator1 const_iterator11_type; + typedef typename E1::const_iterator2 const_iterator12_type; + typedef typename E2::const_iterator1 const_iterator21_type; + typedef typename E2::const_iterator2 const_iterator22_type; + typedef const value_type *const_pointer; + +public: #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category, - typename const_iterator22_type::iterator_category>::iterator_category iterator_category; - typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1; - typedef const_iterator1 iterator1; - typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2; - typedef const_iterator2 iterator2; + typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category, + typename const_iterator22_type::iterator_category>::iterator_category iterator_category; + typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1; + typedef const_iterator1 iterator1; + typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2; + typedef const_iterator2 iterator2; #else - class const_iterator1; - typedef const_iterator1 iterator1; - class const_iterator2; - typedef const_iterator2 iterator2; -#endif - typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; - typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; - - // Element lookup - BOOST_UBLAS_INLINE - const_iterator1 find1 (int /* rank */, size_type i, size_type j) const { - // FIXME sparse matrix tests fail! - // const_iterator11_type it11 (e1_.find1 (rank, i, 0)); - const_iterator11_type it11 (e1_.find1 (0, i, 0)); + class const_iterator1; + typedef const_iterator1 iterator1; + class const_iterator2; + typedef const_iterator2 iterator2; +#endif + typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1; + typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2; + + // Element lookup + BOOST_UBLAS_INLINE + const_iterator1 find1 (int /* rank */, size_type i, size_type j) const { + // FIXME sparse matrix tests fail! + // const_iterator11_type it11 (e1_.find1 (rank, i, 0)); + const_iterator11_type it11 (e1_.find1 (0, i, 0)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator1 (*this, it11.index1 (), j); + return const_iterator1 (*this, it11.index1 (), j); #else - // FIXME sparse matrix tests fail! - // const_iterator22_type it22 (e2_.find2 (rank, 0, j)); - const_iterator22_type it22 (e2_.find2 (0, 0, j)); - return const_iterator1 (*this, it11, it22); -#endif - } - BOOST_UBLAS_INLINE - const_iterator2 find2 (int /* rank */, size_type i, size_type j) const { - // FIXME sparse matrix tests fail! - // const_iterator22_type it22 (e2_.find2 (rank, 0, j)); - const_iterator22_type it22 (e2_.find2 (0, 0, j)); + // FIXME sparse matrix tests fail! + // const_iterator22_type it22 (e2_.find2 (rank, 0, j)); + const_iterator22_type it22 (e2_.find2 (0, 0, j)); + return const_iterator1 (*this, it11, it22); +#endif + } + BOOST_UBLAS_INLINE + const_iterator2 find2 (int /* rank */, size_type i, size_type j) const { + // FIXME sparse matrix tests fail! + // const_iterator22_type it22 (e2_.find2 (rank, 0, j)); + const_iterator22_type it22 (e2_.find2 (0, 0, j)); #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR - return const_iterator2 (*this, i, it22.index2 ()); + return const_iterator2 (*this, i, it22.index2 ()); #else - // FIXME sparse matrix tests fail! - // const_iterator11_type it11 (e1_.find1 (rank, i, 0)); - const_iterator11_type it11 (e1_.find1 (0, i, 0)); - return const_iterator2 (*this, it11, it22); + // FIXME sparse matrix tests fail! + // const_iterator11_type it11 (e1_.find1 (rank, i, 0)); + const_iterator11_type it11 (e1_.find1 (0, i, 0)); + return const_iterator2 (*this, it11, it22); #endif - } + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator1: - public container_const_reference<matrix_matrix_binary>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category>::template - iterator_base<const_iterator1, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; - typedef typename matrix_matrix_binary::difference_type difference_type; - typedef typename matrix_matrix_binary::value_type value_type; - typedef typename matrix_matrix_binary::const_reference reference; - typedef typename matrix_matrix_binary::const_pointer pointer; - - typedef const_iterator2 dual_iterator_type; - typedef const_reverse_iterator2 dual_reverse_iterator_type; - - // Construction and destruction + class const_iterator1: + public container_const_reference<matrix_matrix_binary>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category>::template + iterator_base<const_iterator1, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; + typedef typename matrix_matrix_binary::difference_type difference_type; + typedef typename matrix_matrix_binary::value_type value_type; + typedef typename matrix_matrix_binary::const_reference reference; + typedef typename matrix_matrix_binary::const_pointer pointer; + + typedef const_iterator2 dual_iterator_type; + typedef const_reverse_iterator2 dual_reverse_iterator_type; + + // Construction and destruction #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it1_ (), it2_ (), it2_begin_ (), it2_end_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): - container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it2_begin_ (it2.begin ()), it2_end_ (it2.end ()) {} + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it1_ (), it2_ (), it2_begin_ (), it2_end_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): + container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it2_begin_ (it2.begin ()), it2_end_ (it2.end ()) {} #else - BOOST_UBLAS_INLINE - const_iterator1 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): - container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {} -#endif - - private: - // Random access specialization - BOOST_UBLAS_INLINE - value_type dereference (dense_random_access_iterator_tag) const { - const self_type &mmb = (*this) (); + BOOST_UBLAS_INLINE + const_iterator1 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): + container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {} +#endif + + private: + // Random access specialization + BOOST_UBLAS_INLINE + value_type dereference (dense_random_access_iterator_tag) const { + const self_type &mmb = (*this) (); #ifdef BOOST_UBLAS_USE_INDEXING - return mmb (index1 (), index2 ()); + return mmb (index1 (), index2 ()); #elif BOOST_UBLAS_USE_ITERATING - difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); + difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, it1_.begin (), it2_begin_); + return functor_type::apply (size, it1_.begin (), it2_begin_); #else - return functor_type::apply (size, it1_.begin (), it2_.begin ()); + return functor_type::apply (size, it1_.begin (), it2_.begin ()); #endif #else - difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); - if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) + difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); + if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, it1_.begin (), it2_begin_); + return functor_type::apply (size, it1_.begin (), it2_begin_); #else - return functor_type::apply (size, it1_.begin (), it2_.begin ()); + return functor_type::apply (size, it1_.begin (), it2_.begin ()); #endif - else - return mmb (index1 (), index2 ()); + else + return mmb (index1 (), index2 ()); #endif - } + } - // Packed bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (packed_random_access_iterator_tag) const { + // Packed bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (packed_random_access_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (it1_.begin (), it1_.end (), - it2_begin_, it2_end_, packed_random_access_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + it2_begin_, it2_end_, packed_random_access_iterator_tag ()); #else #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (it1_.begin (), it1_.end (), - it2_.begin (), it2_.end (), packed_random_access_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + it2_.begin (), it2_.end (), packed_random_access_iterator_tag ()); #else - return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), - boost::numeric::ublas::end (it1_, iterator1_tag ()), - boost::numeric::ublas::begin (it2_, iterator2_tag ()), - boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ()); + return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), + boost::numeric::ublas::end (it1_, iterator1_tag ()), + boost::numeric::ublas::begin (it2_, iterator2_tag ()), + boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ()); #endif #endif - } + } - // Sparse bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (sparse_bidirectional_iterator_tag) const { + // Sparse bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (sparse_bidirectional_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (it1_.begin (), it1_.end (), - it2_begin_, it2_end_, sparse_bidirectional_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + it2_begin_, it2_end_, sparse_bidirectional_iterator_tag ()); #else #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (it1_.begin (), it1_.end (), - it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); #else - return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), - boost::numeric::ublas::end (it1_, iterator1_tag ()), - boost::numeric::ublas::begin (it2_, iterator2_tag ()), - boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ()); -#endif -#endif - } - - public: - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator1 &operator ++ () { - ++ it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -- () { - -- it1_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator += (difference_type n) { - it1_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator1 &operator -= (difference_type n) { - it1_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ - it.it1_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return dereference (iterator_category ()); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), + boost::numeric::ublas::end (it1_, iterator1_tag ()), + boost::numeric::ublas::begin (it2_, iterator2_tag ()), + boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ()); +#endif +#endif + } + + public: + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator1 &operator ++ () { + ++ it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -- () { + -- it1_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator += (difference_type n) { + it1_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator1 &operator -= (difference_type n) { + it1_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ - it.it1_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return dereference (iterator_category ()); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 begin () const { - return (*this) ().find2 (1, index1 (), 0); - } - BOOST_UBLAS_INLINE + const_iterator2 begin () const { + return (*this) ().find2 (1, index1 (), 0); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator2 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 end () const { - return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); - } - BOOST_UBLAS_INLINE + const_iterator2 end () const { + return (*this) ().find2 (1, index1 (), (*this) ().size2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator2 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator2 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rbegin () const { - return const_reverse_iterator2 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin () const { + return const_reverse_iterator2 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator2 rend () const { - return const_reverse_iterator2 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator2 rend () const { + return const_reverse_iterator2 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator2 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it1_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it2_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator1 &operator = (const const_iterator1 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; + typename self_type:: +#endif + const_reverse_iterator2 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it1_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it2_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator1 &operator = (const const_iterator1 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - it2_begin_ = it.it2_begin_; - it2_end_ = it.it2_end_; -#endif - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ == it.it1_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator1 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); - return it1_ < it.it1_; - } - - private: - const_iterator11_type it1_; - // Mutable due to assignment - /* const */ const_iterator22_type it2_; + it2_begin_ = it.it2_begin_; + it2_end_ = it.it2_end_; +#endif + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ == it.it1_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator1 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ()); + return it1_ < it.it1_; + } + + private: + const_iterator11_type it1_; + // Mutable due to assignment + /* const */ const_iterator22_type it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - /* const */ const_iterator21_type it2_begin_; - /* const */ const_iterator21_type it2_end_; -#endif - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator1 begin1 () const { - return find1 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cbegin1 () const { - return begin1 (); - } - BOOST_UBLAS_INLINE - const_iterator1 end1 () const { - return find1 (0, size1 (), 0); - } - BOOST_UBLAS_INLINE - const_iterator1 cend1 () const { - return end1 (); - } + /* const */ const_iterator21_type it2_begin_; + /* const */ const_iterator21_type it2_end_; +#endif + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator1 begin1 () const { + return find1 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cbegin1 () const { + return begin1 (); + } + BOOST_UBLAS_INLINE + const_iterator1 end1 () const { + return find1 (0, size1 (), 0); + } + BOOST_UBLAS_INLINE + const_iterator1 cend1 () const { + return end1 (); + } #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR - class const_iterator2: - public container_const_reference<matrix_matrix_binary>, - public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category>::template - iterator_base<const_iterator2, value_type>::type { - public: - typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, - typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; - typedef typename matrix_matrix_binary::difference_type difference_type; - typedef typename matrix_matrix_binary::value_type value_type; - typedef typename matrix_matrix_binary::const_reference reference; - typedef typename matrix_matrix_binary::const_pointer pointer; - - typedef const_iterator1 dual_iterator_type; - typedef const_reverse_iterator1 dual_reverse_iterator_type; - - // Construction and destruction + class const_iterator2: + public container_const_reference<matrix_matrix_binary>, + public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category>::template + iterator_base<const_iterator2, value_type>::type { + public: + typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, + typename E2::const_iterator2::iterator_category>::iterator_category iterator_category; + typedef typename matrix_matrix_binary::difference_type difference_type; + typedef typename matrix_matrix_binary::value_type value_type; + typedef typename matrix_matrix_binary::const_reference reference; + typedef typename matrix_matrix_binary::const_pointer pointer; + + typedef const_iterator1 dual_iterator_type; + typedef const_reverse_iterator1 dual_reverse_iterator_type; + + // Construction and destruction #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it1_ (), it2_ (), it1_begin_ (), it1_end_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): - container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it1_begin_ (it1.begin ()), it1_end_ (it1.end ()) {} + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it1_ (), it2_ (), it1_begin_ (), it1_end_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): + container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it1_begin_ (it1.begin ()), it1_end_ (it1.end ()) {} #else - BOOST_UBLAS_INLINE - const_iterator2 (): - container_const_reference<self_type> (), it1_ (), it2_ () {} - BOOST_UBLAS_INLINE - const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): - container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {} -#endif - - private: - // Random access specialization - BOOST_UBLAS_INLINE - value_type dereference (dense_random_access_iterator_tag) const { - const self_type &mmb = (*this) (); + BOOST_UBLAS_INLINE + const_iterator2 (): + container_const_reference<self_type> (), it1_ (), it2_ () {} + BOOST_UBLAS_INLINE + const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2): + container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {} +#endif + + private: + // Random access specialization + BOOST_UBLAS_INLINE + value_type dereference (dense_random_access_iterator_tag) const { + const self_type &mmb = (*this) (); #ifdef BOOST_UBLAS_USE_INDEXING - return mmb (index1 (), index2 ()); + return mmb (index1 (), index2 ()); #elif BOOST_UBLAS_USE_ITERATING - difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); + difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, it1_begin_, it2_.begin ()); + return functor_type::apply (size, it1_begin_, it2_.begin ()); #else - return functor_type::apply (size, it1_.begin (), it2_.begin ()); + return functor_type::apply (size, it1_.begin (), it2_.begin ()); #endif #else - difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); - if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) + difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ()); + if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD) #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (size, it1_begin_, it2_.begin ()); + return functor_type::apply (size, it1_begin_, it2_.begin ()); #else - return functor_type::apply (size, it1_.begin (), it2_.begin ()); + return functor_type::apply (size, it1_.begin (), it2_.begin ()); #endif - else - return mmb (index1 (), index2 ()); + else + return mmb (index1 (), index2 ()); #endif - } + } - // Packed bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (packed_random_access_iterator_tag) const { + // Packed bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (packed_random_access_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (it1_begin_, it1_end_, - it2_.begin (), it2_.end (), packed_random_access_iterator_tag ()); + return functor_type::apply (it1_begin_, it1_end_, + it2_.begin (), it2_.end (), packed_random_access_iterator_tag ()); #else #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (it1_.begin (), it1_.end (), - it2_.begin (), it2_.end (), packed_random_access_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + it2_.begin (), it2_.end (), packed_random_access_iterator_tag ()); #else - return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), - boost::numeric::ublas::end (it1_, iterator1_tag ()), - boost::numeric::ublas::begin (it2_, iterator2_tag ()), - boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ()); + return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), + boost::numeric::ublas::end (it1_, iterator1_tag ()), + boost::numeric::ublas::begin (it2_, iterator2_tag ()), + boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ()); #endif #endif - } + } - // Sparse bidirectional specialization - BOOST_UBLAS_INLINE - value_type dereference (sparse_bidirectional_iterator_tag) const { + // Sparse bidirectional specialization + BOOST_UBLAS_INLINE + value_type dereference (sparse_bidirectional_iterator_tag) const { #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - return functor_type::apply (it1_begin_, it1_end_, - it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); + return functor_type::apply (it1_begin_, it1_end_, + it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); #else #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - return functor_type::apply (it1_.begin (), it1_.end (), - it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); + return functor_type::apply (it1_.begin (), it1_.end (), + it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ()); #else - return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), - boost::numeric::ublas::end (it1_, iterator1_tag ()), - boost::numeric::ublas::begin (it2_, iterator2_tag ()), - boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ()); -#endif -#endif - } - - public: - // Arithmetic - BOOST_UBLAS_INLINE - const_iterator2 &operator ++ () { - ++ it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -- () { - -- it2_; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator += (difference_type n) { - it2_ += n; - return *this; - } - BOOST_UBLAS_INLINE - const_iterator2 &operator -= (difference_type n) { - it2_ -= n; - return *this; - } - BOOST_UBLAS_INLINE - difference_type operator - (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ - it.it2_; - } - - // Dereference - BOOST_UBLAS_INLINE - const_reference operator * () const { - return dereference (iterator_category ()); - } - BOOST_UBLAS_INLINE - const_reference operator [] (difference_type n) const { - return *(*this + n); - } + return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()), + boost::numeric::ublas::end (it1_, iterator1_tag ()), + boost::numeric::ublas::begin (it2_, iterator2_tag ()), + boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ()); +#endif +#endif + } + + public: + // Arithmetic + BOOST_UBLAS_INLINE + const_iterator2 &operator ++ () { + ++ it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -- () { + -- it2_; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator += (difference_type n) { + it2_ += n; + return *this; + } + BOOST_UBLAS_INLINE + const_iterator2 &operator -= (difference_type n) { + it2_ -= n; + return *this; + } + BOOST_UBLAS_INLINE + difference_type operator - (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ - it.it2_; + } + + // Dereference + BOOST_UBLAS_INLINE + const_reference operator * () const { + return dereference (iterator_category ()); + } + BOOST_UBLAS_INLINE + const_reference operator [] (difference_type n) const { + return *(*this + n); + } #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION - BOOST_UBLAS_INLINE + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 begin () const { - return (*this) ().find1 (1, 0, index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 begin () const { + return (*this) ().find1 (1, 0, index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cbegin () const { - return begin (); - } - BOOST_UBLAS_INLINE + const_iterator1 cbegin () const { + return begin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 end () const { - return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); - } - BOOST_UBLAS_INLINE + const_iterator1 end () const { + return (*this) ().find1 (1, (*this) ().size1 (), index2 ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_iterator1 cend () const { - return end (); - } - BOOST_UBLAS_INLINE + const_iterator1 cend () const { + return end (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rbegin () const { - return const_reverse_iterator1 (end ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin () const { + return const_reverse_iterator1 (end ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 crbegin () const { - return rbegin (); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin () const { + return rbegin (); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: + typename self_type:: #endif - const_reverse_iterator1 rend () const { - return const_reverse_iterator1 (begin ()); - } - BOOST_UBLAS_INLINE + const_reverse_iterator1 rend () const { + return const_reverse_iterator1 (begin ()); + } + BOOST_UBLAS_INLINE #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION - typename self_type:: -#endif - const_reverse_iterator1 crend () const { - return rend (); - } -#endif - - // Indices - BOOST_UBLAS_INLINE - size_type index1 () const { - return it1_.index1 (); - } - BOOST_UBLAS_INLINE - size_type index2 () const { - return it2_.index2 (); - } - - // Assignment - BOOST_UBLAS_INLINE - const_iterator2 &operator = (const const_iterator2 &it) { - container_const_reference<self_type>::assign (&it ()); - it1_ = it.it1_; - it2_ = it.it2_; + typename self_type:: +#endif + const_reverse_iterator1 crend () const { + return rend (); + } +#endif + + // Indices + BOOST_UBLAS_INLINE + size_type index1 () const { + return it1_.index1 (); + } + BOOST_UBLAS_INLINE + size_type index2 () const { + return it2_.index2 (); + } + + // Assignment + BOOST_UBLAS_INLINE + const_iterator2 &operator = (const const_iterator2 &it) { + container_const_reference<self_type>::assign (&it ()); + it1_ = it.it1_; + it2_ = it.it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - it1_begin_ = it.it1_begin_; - it1_end_ = it.it1_end_; -#endif - return *this; - } - - // Comparison - BOOST_UBLAS_INLINE - bool operator == (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ == it.it2_; - } - BOOST_UBLAS_INLINE - bool operator < (const const_iterator2 &it) const { - BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); - BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); - return it2_ < it.it2_; - } - - private: - // Mutable due to assignment - /* const */ const_iterator11_type it1_; - const_iterator22_type it2_; + it1_begin_ = it.it1_begin_; + it1_end_ = it.it1_end_; +#endif + return *this; + } + + // Comparison + BOOST_UBLAS_INLINE + bool operator == (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ == it.it2_; + } + BOOST_UBLAS_INLINE + bool operator < (const const_iterator2 &it) const { + BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ()); + BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ()); + return it2_ < it.it2_; + } + + private: + // Mutable due to assignment + /* const */ const_iterator11_type it1_; + const_iterator22_type it2_; #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING - /* const */ const_iterator12_type it1_begin_; - /* const */ const_iterator12_type it1_end_; -#endif - }; -#endif - - BOOST_UBLAS_INLINE - const_iterator2 begin2 () const { - return find2 (0, 0, 0); - } - BOOST_UBLAS_INLINE - const_iterator2 cbegin2 () const { - return begin2 (); - } - BOOST_UBLAS_INLINE - const_iterator2 end2 () const { - return find2 (0, 0, size2 ()); - } - BOOST_UBLAS_INLINE - const_iterator2 cend2 () const { - return end2 (); - } - - // Reverse iterators - - BOOST_UBLAS_INLINE - const_reverse_iterator1 rbegin1 () const { - return const_reverse_iterator1 (end1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crbegin1 () const { - return rbegin1 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 rend1 () const { - return const_reverse_iterator1 (begin1 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator1 crend1 () const { - return rend1 (); - } - - BOOST_UBLAS_INLINE - const_reverse_iterator2 rbegin2 () const { - return const_reverse_iterator2 (end2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crbegin2 () const { - return rbegin2 (); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 rend2 () const { - return const_reverse_iterator2 (begin2 ()); - } - BOOST_UBLAS_INLINE - const_reverse_iterator2 crend2 () const { - return rend2 (); - } - - private: - expression1_closure_type e1_; - expression2_closure_type e2_; - }; - - template<class T1, class E1, class T2, class E2> - struct matrix_matrix_binary_traits { - typedef unknown_storage_tag storage_category; - typedef unknown_orientation_tag orientation_category; - typedef typename promote_traits<T1, T2>::promote_type promote_type; - typedef matrix_matrix_binary<E1, E2, matrix_matrix_prod<E1, E2, promote_type> > expression_type; + /* const */ const_iterator12_type it1_begin_; + /* const */ const_iterator12_type it1_end_; +#endif + }; +#endif + + BOOST_UBLAS_INLINE + const_iterator2 begin2 () const { + return find2 (0, 0, 0); + } + BOOST_UBLAS_INLINE + const_iterator2 cbegin2 () const { + return begin2 (); + } + BOOST_UBLAS_INLINE + const_iterator2 end2 () const { + return find2 (0, 0, size2 ()); + } + BOOST_UBLAS_INLINE + const_iterator2 cend2 () const { + return end2 (); + } + + // Reverse iterators + + BOOST_UBLAS_INLINE + const_reverse_iterator1 rbegin1 () const { + return const_reverse_iterator1 (end1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crbegin1 () const { + return rbegin1 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 rend1 () const { + return const_reverse_iterator1 (begin1 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator1 crend1 () const { + return rend1 (); + } + + BOOST_UBLAS_INLINE + const_reverse_iterator2 rbegin2 () const { + return const_reverse_iterator2 (end2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crbegin2 () const { + return rbegin2 (); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 rend2 () const { + return const_reverse_iterator2 (begin2 ()); + } + BOOST_UBLAS_INLINE + const_reverse_iterator2 crend2 () const { + return rend2 (); + } + +private: + expression1_closure_type e1_; + expression2_closure_type e2_; +}; + +template<class T1, class E1, class T2, class E2> +struct matrix_matrix_binary_traits { + typedef unknown_storage_tag storage_category; + typedef unknown_orientation_tag orientation_category; + typedef typename promote_traits<T1, T2>::promote_type promote_type; + typedef matrix_matrix_binary<E1, E2, matrix_matrix_prod<E1, E2, promote_type> > expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename E1::matrix_temporary_type result_type; -#endif - }; - - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_matrix_binary_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::result_type - prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2, - unknown_storage_tag, - unknown_orientation_tag) { - typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // Dispatcher - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_matrix_binary_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::result_type - prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0); - typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::storage_category storage_category; - typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1, - typename E2::value_type, E2>::orientation_category orientation_category; - return prod (e1, e2, storage_category (), orientation_category ()); - } - - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::result_type - prec_prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2, - unknown_storage_tag, - unknown_orientation_tag) { - typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type; - return expression_type (e1 (), e2 ()); - } - - // Dispatcher - template<class E1, class E2> - BOOST_UBLAS_INLINE - typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::result_type - prec_prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0); - typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category; - typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, - typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category; - return prec_prod (e1, e2, storage_category (), orientation_category ()); - } - - template<class M, class E1, class E2> - BOOST_UBLAS_INLINE - M & - prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2, - M &m) { - return m.assign (prod (e1, e2)); - } - - template<class M, class E1, class E2> - BOOST_UBLAS_INLINE - M & - prec_prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2, - M &m) { - return m.assign (prec_prod (e1, e2)); - } - - template<class M, class E1, class E2> - BOOST_UBLAS_INLINE - M - prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - return M (prod (e1, e2)); - } - - template<class M, class E1, class E2> - BOOST_UBLAS_INLINE - M - prec_prod (const matrix_expression<E1> &e1, - const matrix_expression<E2> &e2) { - return M (prec_prod (e1, e2)); - } - - template<class E, class F> - class matrix_scalar_unary: - public scalar_expression<matrix_scalar_unary<E, F> > { - public: - typedef E expression_type; - typedef F functor_type; - typedef typename F::result_type value_type; - typedef typename E::const_closure_type expression_closure_type; - - // Construction and destruction - BOOST_UBLAS_INLINE - explicit matrix_scalar_unary (const expression_type &e): - e_ (e) {} - - private: - // Expression accessors - BOOST_UBLAS_INLINE - const expression_closure_type &expression () const { - return e_; - } - - public: - BOOST_UBLAS_INLINE - operator value_type () const { - return functor_type::apply (e_); - } - - private: - expression_closure_type e_; - }; - - template<class E, class F> - struct matrix_scalar_unary_traits { - typedef matrix_scalar_unary<E, F> expression_type; + typedef typename E1::matrix_temporary_type result_type; +#endif +}; + +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_matrix_binary_traits<typename E1::value_type, E1, +typename E2::value_type, E2>::result_type +prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2, + unknown_storage_tag, + unknown_orientation_tag) { + typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// Dispatcher +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_matrix_binary_traits<typename E1::value_type, E1, +typename E2::value_type, E2>::result_type +prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0); + typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::storage_category storage_category; + typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1, + typename E2::value_type, E2>::orientation_category orientation_category; + return prod (e1, e2, storage_category (), orientation_category ()); +} + +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, +typename type_traits<typename E2::value_type>::precision_type, E2>::result_type +prec_prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2, + unknown_storage_tag, + unknown_orientation_tag) { + typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type; + return expression_type (e1 (), e2 ()); +} + +// Dispatcher +template<class E1, class E2> +BOOST_UBLAS_INLINE +typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, +typename type_traits<typename E2::value_type>::precision_type, E2>::result_type +prec_prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0); + typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category; + typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1, + typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category; + return prec_prod (e1, e2, storage_category (), orientation_category ()); +} + +template<class M, class E1, class E2> +BOOST_UBLAS_INLINE +M & +prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2, + M &m) { + return m.assign (prod (e1, e2)); +} + +template<class M, class E1, class E2> +BOOST_UBLAS_INLINE +M & +prec_prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2, + M &m) { + return m.assign (prec_prod (e1, e2)); +} + +template<class M, class E1, class E2> +BOOST_UBLAS_INLINE +M +prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + return M (prod (e1, e2)); +} + +template<class M, class E1, class E2> +BOOST_UBLAS_INLINE +M +prec_prod (const matrix_expression<E1> &e1, + const matrix_expression<E2> &e2) { + return M (prec_prod (e1, e2)); +} + +template<class E, class F> +class matrix_scalar_unary: + public scalar_expression<matrix_scalar_unary<E, F> > { +public: + typedef E expression_type; + typedef F functor_type; + typedef typename F::result_type value_type; + typedef typename E::const_closure_type expression_closure_type; + + // Construction and destruction + BOOST_UBLAS_INLINE + explicit matrix_scalar_unary (const expression_type &e): + e_ (e) {} + +private: + // Expression accessors + BOOST_UBLAS_INLINE + const expression_closure_type &expression () const { + return e_; + } + +public: + BOOST_UBLAS_INLINE + operator value_type () const { + return functor_type::apply (e_); + } + +private: + expression_closure_type e_; +}; + +template<class E, class F> +struct matrix_scalar_unary_traits { + typedef matrix_scalar_unary<E, F> expression_type; #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG - typedef expression_type result_type; + typedef expression_type result_type; #else - typedef typename F::result_type result_type; -#endif - }; - - template<class E> - BOOST_UBLAS_INLINE - typename matrix_scalar_unary_traits<E, matrix_norm_1<E> >::result_type - norm_1 (const matrix_expression<E> &e) { - typedef typename matrix_scalar_unary_traits<E, matrix_norm_1<E> >::expression_type expression_type; - return expression_type (e ()); - } - - template<class E> - BOOST_UBLAS_INLINE - typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<E> >::result_type - norm_frobenius (const matrix_expression<E> &e) { - typedef typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<E> >::expression_type expression_type; - return expression_type (e ()); - } - - template<class E> - BOOST_UBLAS_INLINE - typename matrix_scalar_unary_traits<E, matrix_norm_inf<E> >::result_type - norm_inf (const matrix_expression<E> &e) { - typedef typename matrix_scalar_unary_traits<E, matrix_norm_inf<E> >::expression_type expression_type; - return expression_type (e ()); - } + typedef typename F::result_type result_type; +#endif +}; + +template<class E> +BOOST_UBLAS_INLINE +typename matrix_scalar_unary_traits<E, matrix_norm_1<E> >::result_type +norm_1 (const matrix_expression<E> &e) { + typedef typename matrix_scalar_unary_traits<E, matrix_norm_1<E> >::expression_type expression_type; + return expression_type (e ()); +} + +template<class E> +BOOST_UBLAS_INLINE +typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<E> >::result_type +norm_frobenius (const matrix_expression<E> &e) { + typedef typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<E> >::expression_type expression_type; + return expression_type (e ()); +} + +template<class E> +BOOST_UBLAS_INLINE +typename matrix_scalar_unary_traits<E, matrix_norm_inf<E> >::result_type +norm_inf (const matrix_expression<E> &e) { + typedef typename matrix_scalar_unary_traits<E, matrix_norm_inf<E> >::expression_type expression_type; + return expression_type (e ()); +} }}} diff --git a/boost/numeric/ublas/matrix_sparse.hpp b/boost/numeric/ublas/matrix_sparse.hpp index b702743349..9a70029fbc 100644 --- a/boost/numeric/ublas/matrix_sparse.hpp +++ b/boost/numeric/ublas/matrix_sparse.hpp @@ -368,7 +368,7 @@ namespace boost { namespace numeric { namespace ublas { // Reserving BOOST_UBLAS_INLINE - void reserve (size_type non_zeros, bool preserve = true) { + void reserve (size_type non_zeros, bool /*preserve*/ = true) { detail::map_reserve (data (), restrict_capacity (non_zeros)); } @@ -1461,7 +1461,7 @@ namespace boost { namespace numeric { namespace ublas { data_ [layout_type::size_M (size1_, size2_)] = vector_data_value_type (); } BOOST_UBLAS_INLINE - mapped_vector_of_mapped_vector (size_type size1, size_type size2, size_type non_zeros = 0): + mapped_vector_of_mapped_vector (size_type size1, size_type size2, size_type /*non_zeros*/ = 0): matrix_container<self_type> (), size1_ (size1), size2_ (size2), data_ () { data_ [layout_type::size_M (size1_, size2_)] = vector_data_value_type (); @@ -1472,7 +1472,7 @@ namespace boost { namespace numeric { namespace ublas { size1_ (m.size1_), size2_ (m.size2_), data_ (m.data_) {} template<class AE> BOOST_UBLAS_INLINE - mapped_vector_of_mapped_vector (const matrix_expression<AE> &ae, size_type non_zeros = 0): + mapped_vector_of_mapped_vector (const matrix_expression<AE> &ae, size_type /*non_zeros*/ = 0): matrix_container<self_type> (), size1_ (ae ().size1 ()), size2_ (ae ().size2 ()), data_ () { data_ [layout_type::size_M (size1_, size2_)] = vector_data_value_type (); diff --git a/boost/numeric/ublas/matrix_vector.hpp b/boost/numeric/ublas/matrix_vector.hpp index fec1f65df5..cf032bffb1 100644 --- a/boost/numeric/ublas/matrix_vector.hpp +++ b/boost/numeric/ublas/matrix_vector.hpp @@ -9,7 +9,7 @@ #ifndef BOOST_UBLAS_MATRIX_VECTOR_HPP #define BOOST_UBLAS_MATRIX_VECTOR_HPP -#include <boost/numeric/ublas/matrix_proxy.hpp>//for matrix_row, matrix_column and matrix_expression +#include <boost/numeric/ublas/matrix_proxy.hpp> //for matrix_row, matrix_column and matrix_expression #include <boost/numeric/ublas/vector.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/range/iterator_range.hpp> @@ -43,10 +43,12 @@ public: matrix_vector_iterator(){} ///\brief constructs a matrix_vector_iterator as pointing to the i-th proxy + BOOST_UBLAS_INLINE matrix_vector_iterator(Matrix& matrix, std::size_t position) : matrix_(&matrix),position_(position) {} template<class M, class R> + BOOST_UBLAS_INLINE matrix_vector_iterator(matrix_vector_iterator<M,R> const& other) : matrix_(other.matrix_),position_(other.position_) {} @@ -54,28 +56,36 @@ private: friend class boost::iterator_core_access; template <class M,class R> friend class matrix_vector_iterator; + BOOST_UBLAS_INLINE void increment() { ++position_; } + + BOOST_UBLAS_INLINE void decrement() { --position_; } + BOOST_UBLAS_INLINE void advance(std::ptrdiff_t n){ position_ += n; } template<class M,class R> + BOOST_UBLAS_INLINE std::ptrdiff_t distance_to(matrix_vector_iterator<M,R> const& other) const{ BOOST_UBLAS_CHECK (matrix_ == other.matrix_, external_logic ()); return (std::ptrdiff_t)other.position_ - (std::ptrdiff_t)position_; } template<class M,class R> + BOOST_UBLAS_INLINE bool equal(matrix_vector_iterator<M,R> const& other) const{ BOOST_UBLAS_CHECK (matrix_ == other.matrix_, external_logic ()); return (position_ == other.position_); } + + BOOST_UBLAS_INLINE Reference dereference() const { return Reference(*matrix_,position_); } @@ -109,81 +119,103 @@ public: typedef typename boost::iterator_difference<iterator>::type difference_type; typedef typename Matrix::size_type size_type; - matrix_row_vector(Matrix& matrix) : - matrix_(matrix) { + BOOST_UBLAS_INLINE + explicit matrix_row_vector(Matrix& matrix) : + matrix_(&matrix) { } - + BOOST_UBLAS_INLINE iterator begin(){ - return iterator(matrix_, 0); + return iterator(*matrix_, 0); } + BOOST_UBLAS_INLINE const_iterator begin() const { - return const_iterator(matrix_, 0); + return const_iterator(*matrix_, 0); } + BOOST_UBLAS_INLINE const_iterator cbegin() const { return begin(); } + BOOST_UBLAS_INLINE iterator end() { - return iterator(matrix_, matrix_.size1()); + return iterator(*matrix_, matrix_->size1()); } + BOOST_UBLAS_INLINE const_iterator end() const { - return const_iterator(matrix_, matrix_.size1()); + return const_iterator(*matrix_, matrix_->size1()); } + BOOST_UBLAS_INLINE const_iterator cend() const { return end(); } + BOOST_UBLAS_INLINE reverse_iterator rbegin() { return reverse_iterator(end()); } + BOOST_UBLAS_INLINE const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + BOOST_UBLAS_INLINE const_reverse_iterator crbegin() const { return rbegin(); } + BOOST_UBLAS_INLINE reverse_iterator rend() { return reverse_iterator(begin()); } + BOOST_UBLAS_INLINE const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + BOOST_UBLAS_INLINE const_reverse_iterator crend() const { return end(); } - value_type operator()(difference_type index) const { - return value_type(matrix_, index); + BOOST_UBLAS_INLINE + value_type operator()(size_type index) { + return value_type(*matrix_, index); + } + + BOOST_UBLAS_INLINE + value_type operator()(size_type index) const { + return value_type(*matrix_, index); } - reference operator[](difference_type index){ - return reference(matrix_, index); + BOOST_UBLAS_INLINE + reference operator[](size_type index){ + return (*this) (index); } - const_reference operator[](difference_type index) const { - return const_reference(matrix_, index); + BOOST_UBLAS_INLINE + const_reference operator[](size_type index) const { + return (*this) (index); } + BOOST_UBLAS_INLINE size_type size() const { - return matrix_.size1(); + return matrix_->size1(); } + BOOST_UBLAS_INLINE void resize(size_type size, bool preserve = true) { - matrix_.resize(size, matrix_.size2(), preserve); + matrix_->resize(size, matrix_->size2(), preserve); } private: - Matrix& matrix_; + Matrix* matrix_; }; @@ -196,6 +228,7 @@ private: * \tparam Matrix the type of matrix that \c matrix_row_vector is referring. */ template<class Matrix> +BOOST_UBLAS_INLINE matrix_row_vector<Matrix> make_row_vector(matrix_expression<Matrix>& matrix){ return matrix_row_vector<Matrix>(matrix()); } @@ -210,6 +243,7 @@ matrix_row_vector<Matrix> make_row_vector(matrix_expression<Matrix>& matrix){ * \tparam Matrix the type of matrix that \c matrix_row_vector is referring. */ template<class Matrix> +BOOST_UBLAS_INLINE matrix_row_vector<Matrix const> make_row_vector(matrix_expression<Matrix> const& matrix){ return matrix_row_vector<Matrix const>(matrix()); } @@ -224,8 +258,7 @@ matrix_row_vector<Matrix const> make_row_vector(matrix_expression<Matrix> const& * the underlaying matrix. */ template<class Matrix> -class matrix_column_vector -{ +class matrix_column_vector { public: typedef ublas::matrix_column<Matrix> value_type; typedef ublas::matrix_column<Matrix> reference; @@ -239,80 +272,103 @@ public: typedef typename boost::iterator_difference<iterator>::type difference_type; typedef typename Matrix::size_type size_type; - matrix_column_vector(Matrix& matrix) : - matrix_(matrix){ + BOOST_UBLAS_INLINE + explicit matrix_column_vector(Matrix& matrix) : + matrix_(&matrix){ } + BOOST_UBLAS_INLINE iterator begin() { - return iterator(matrix_, 0); + return iterator(*matrix_, 0); } + BOOST_UBLAS_INLINE const_iterator begin() const { - return const_iterator(matrix_, 0); + return const_iterator(*matrix_, 0); } + BOOST_UBLAS_INLINE const_iterator cbegin() const { return begin(); } + BOOST_UBLAS_INLINE iterator end() { - return iterator(matrix_, matrix_.size2()); + return iterator(*matrix_, matrix_->size2()); } + BOOST_UBLAS_INLINE const_iterator end() const { - return const_iterator(matrix_, matrix_.size2()); + return const_iterator(*matrix_, matrix_->size2()); } + BOOST_UBLAS_INLINE const_iterator cend() const { return end(); } + BOOST_UBLAS_INLINE reverse_iterator rbegin() { return reverse_iterator(end()); } + BOOST_UBLAS_INLINE const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + BOOST_UBLAS_INLINE const_reverse_iterator crbegin() const { return rbegin(); - } + } + BOOST_UBLAS_INLINE reverse_iterator rend() { return reverse_iterator(begin()); } + BOOST_UBLAS_INLINE const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + BOOST_UBLAS_INLINE const_reverse_iterator crend() const { return rend(); } - value_type operator()(difference_type index) const { - return value_type(matrix_, index); + BOOST_UBLAS_INLINE + value_type operator()(size_type index) { + return value_type(*matrix_, index); + } + + BOOST_UBLAS_INLINE + value_type operator()(size_type index) const { + return value_type(*matrix_, index); } - reference operator[](difference_type index) { - return reference(matrix_, index); + BOOST_UBLAS_INLINE + reference operator[](size_type index) { + return (*this) (index); } - const_reference operator[](difference_type index) const { - return const_reference(matrix_, index); + BOOST_UBLAS_INLINE + const_reference operator[](size_type index) const { + return (*this) (index); } + BOOST_UBLAS_INLINE size_type size() const { - return matrix_.size2(); + return matrix_->size2(); } + BOOST_UBLAS_INLINE void resize(size_type size, bool preserve = true) { - matrix_.resize(matrix_.size1(), size, preserve); + matrix_->resize(matrix_->size1(), size, preserve); } private: - Matrix& matrix_; + Matrix* matrix_; }; @@ -325,6 +381,7 @@ private: * \tparam Matrix the type of matrix that \c matrix_column_vector is referring. */ template<class Matrix> +BOOST_UBLAS_INLINE matrix_column_vector<Matrix> make_column_vector(matrix_expression<Matrix>& matrix){ return matrix_column_vector<Matrix>(matrix()); } @@ -339,6 +396,7 @@ matrix_column_vector<Matrix> make_column_vector(matrix_expression<Matrix>& matri * \tparam Matrix the type of matrix that \c matrix_column_vector is referring. */ template<class Matrix> +BOOST_UBLAS_INLINE matrix_column_vector<Matrix const> make_column_vector(matrix_expression<Matrix> const& matrix){ return matrix_column_vector<Matrix const>(matrix()); } diff --git a/boost/numeric/ublas/opencl.hpp b/boost/numeric/ublas/opencl.hpp new file mode 100644 index 0000000000..9258046104 --- /dev/null +++ b/boost/numeric/ublas/opencl.hpp @@ -0,0 +1,16 @@ +// +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_hpp_ +#define boost_numeric_ublas_opencl_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/opencl/vector.hpp> +#include <boost/numeric/ublas/opencl/matrix.hpp> +#include <boost/numeric/ublas/opencl/operations.hpp> + +#endif diff --git a/boost/numeric/ublas/opencl/elementwise.hpp b/boost/numeric/ublas/opencl/elementwise.hpp new file mode 100644 index 0000000000..72da6a0de9 --- /dev/null +++ b/boost/numeric/ublas/opencl/elementwise.hpp @@ -0,0 +1,508 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_elementwise_hpp_ +#define boost_numeric_ublas_opencl_elementwise_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/opencl/vector.hpp> +#include <boost/numeric/ublas/opencl/matrix.hpp> + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +namespace compute = boost::compute; +namespace lambda = boost::compute::lambda; + +template <typename T, typename L1, typename L2, typename L3, class O> +void element_wise(ublas::matrix<T, L1, opencl::storage> const &a, + ublas::matrix<T, L2, opencl::storage> const &b, + ublas::matrix<T, L3, opencl::storage> &result, + O op, compute::command_queue& queue) +{ + assert(a.device() == b.device() && + a.device() == result.device() && + a.device() == queue.get_device()); + assert(a.size1() == b.size1() && a.size2() == b.size2()); + + compute::transform(a.begin(), + a.end(), + b.begin(), + result.begin(), + op, + queue); + queue.finish(); +} + +template <typename T, typename L1, typename L2, typename L3, typename A, class O> +void element_wise(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + ublas::matrix<T, L3, A> &result, + O op, + compute::command_queue &queue) +{ + ublas::matrix<T, L1, opencl::storage> adev(a, queue); + ublas::matrix<T, L2, opencl::storage> bdev(b, queue); + ublas::matrix<T, L3, opencl::storage> rdev(a.size1(), b.size2(), queue.get_context()); + element_wise(adev, bdev, rdev, op, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename L1, typename L2, typename A, typename O> +ublas::matrix<T, L1, A> element_wise(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + O op, + compute::command_queue &queue) +{ + ublas::matrix<T, L1, A> result(a.size1(), b.size2()); + element_wise(a, b, result, op, queue); + return result; +} + +template <typename T, typename O> +void element_wise(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + O op, + compute::command_queue& queue) +{ + assert(a.device() == b.device() && + a.device() == result.device() && + a.device() == queue.get_device()); + assert(a.size() == b.size()); + compute::transform(a.begin(), + a.end(), + b.begin(), + result.begin(), + op, + queue); + queue.finish(); +} + +template <typename T, typename A, typename O> +void element_wise(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + ublas::vector<T, A>& result, + O op, + compute::command_queue &queue) +{ + ublas::vector<T, opencl::storage> adev(a, queue); + ublas::vector<T, opencl::storage> bdev(b, queue); + ublas::vector<T, opencl::storage> rdev(a.size(), queue.get_context()); + element_wise(adev, bdev, rdev, op, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename A, typename O> +ublas::vector<T, A> element_wise(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + O op, + compute::command_queue &queue) +{ + ublas::vector<T, A> result(a.size()); + element_wise(a, b, result, op, queue); + return result; +} + +template <typename T, typename L1, typename L2, typename L3> +void element_add(ublas::matrix<T, L1, opencl::storage> const &a, + ublas::matrix<T, L2, opencl::storage> const &b, + ublas::matrix<T, L3, opencl::storage> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::plus<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename L3, typename A> +void element_add(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + ublas::matrix<T, L3, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::plus<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename A> +ublas::matrix<T, L1, A> element_add(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::plus<T>(), queue); +} + +template <typename T> +void element_add(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, result, compute::plus<T>(), queue); +} + +template <typename T, typename A> +void element_add(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + ublas::vector<T, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::plus<T>(), queue); +} + +template <typename T, typename A> +ublas::vector<T, A> element_add(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::plus<T>(), queue); +} + +template<typename T, typename L> +void element_add(ublas::matrix<T, L, opencl::storage> const &m, T value, + ublas::matrix<T, L, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(m.device() == result.device() && m.device() == queue.get_device()); + assert(m.size1() == result.size1() && m.size2() == result.size2()); + compute::transform(m.begin(), m.end(), result.begin(), lambda::_1 + value, queue); + queue.finish(); +} + +template<typename T, typename L, typename A> +void element_add(ublas::matrix<T, L, A> const &m, T value, + ublas::matrix<T, L, A> &result, + compute::command_queue& queue) +{ + ublas::matrix<T, L, opencl::storage> mdev(m, queue); + ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context()); + element_add(mdev, value, rdev, queue); + rdev.to_host(result, queue); +} + +template<typename T, typename L, typename A> +ublas::matrix<T, L, A> element_add(ublas::matrix<T, L, A> const &m, T value, + compute::command_queue& queue) +{ + ublas::matrix<T, L, A> result(m.size1(), m.size2()); + element_add(m, value, result, queue); + return result; +} + +template<typename T> +void element_add(ublas::vector<T, opencl::storage> const &v, T value, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(v.device() == result.device() && v.device() == queue.get_device()); + assert(v.size() == result.size()); + compute::transform(v.begin(), v.end(), result.begin(), lambda::_1 + value, queue); + queue.finish(); +} + +template<typename T, typename A> +void element_add(ublas::vector<T, A> const &v, T value, + ublas::vector<T, A> &result, + compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> vdev(v, queue); + ublas::vector<T, opencl::storage> rdev(v.size(), queue.get_context()); + element_add(vdev, value, rdev, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename A> +ublas::vector<T, A> element_add(ublas::vector<T, A> const &v, T value, + compute::command_queue& queue) +{ + ublas::vector<T, A> result(v.size()); + element_add(v, value, result, queue); + return result; +} + +template <typename T, typename L1, typename L2, typename L3> +void element_sub(ublas::matrix<T, L1, opencl::storage> const &a, + ublas::matrix<T, L2, opencl::storage> const &b, + ublas::matrix<T, L3, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, compute::minus<T>(), result, queue); +} + +template <typename T, typename L1, typename L2, typename L3, typename A> +void element_sub(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + ublas::matrix<T, L3, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::minus<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename A> +ublas::matrix<T, L1, A> element_sub(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::minus<T>(), queue); +} + +template <typename T> +void element_sub(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, result, compute::minus<T>(), queue); +} + +template <typename T, typename A> +void element_sub(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + ublas::vector<T, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::minus<T>(), queue); +} + +template <typename T, typename A> +ublas::vector<T, A> element_sub(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::minus<T>(), queue); +} + +template <typename T, typename L> +void element_sub(ublas::matrix<T, L, opencl::storage> const &m, T value, + ublas::matrix<T, L, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(m.device() == result.device() && m.device() == queue.get_device()); + assert(m.size1() == result.size1() && m.size2() == result.size2()); + compute::transform(m.begin(), m.end(), result.begin(), lambda::_1 - value, queue); + queue.finish(); +} + +template <typename T, typename L, typename A> +void element_sub(ublas::matrix<T, L, A> const &m, T value, + ublas::matrix<T, L, A> &result, + compute::command_queue& queue) +{ + ublas::matrix<T, L, opencl::storage> mdev(m, queue); + ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context()); + element_sub(mdev, value, rdev, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename L, typename A> +ublas::matrix<T, L, A> element_sub(ublas::matrix<T, L, A> const &m, T value, + compute::command_queue& queue) +{ + ublas::matrix<T, L, A> result(m.size1(), m.size2()); + element_sub(m, value, result, queue); + return result; +} + +template <typename T> +void element_sub(ublas::vector<T, opencl::storage> const &v, T value, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(v.device() == result.device() && v.device() == queue.get_device()); + assert(v.size() == result.size()); + compute::transform(v.begin(), v.end(), result.begin(), lambda::_1 - value, queue); + queue.finish(); +} + +template <typename T, typename A> +void element_sub(ublas::vector<T, A> const &v, T value, + ublas::vector<T, A> &result, + compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> vdev(v, queue); + ublas::vector<T, opencl::storage> rdev(v.size(), queue.get_context()); + element_sub(vdev, value, rdev, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename A> +ublas::vector<T, A> element_sub(ublas::vector<T, A> const &v, T value, + compute::command_queue& queue) +{ + ublas::vector<T, A> result(v.size()); + element_sub(v, value, result, queue); + return result; +} + +template <typename T, typename L1, typename L2, typename L3> +void element_prod(ublas::matrix<T, L1, opencl::storage> const &a, + ublas::matrix<T, L2, opencl::storage> const &b, + ublas::matrix<T, L3, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, result, compute::multiplies<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename L3, typename A> +void element_prod(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + ublas::matrix<T, L3, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::multiplies<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename A> +ublas::matrix<T, L1, A> element_prod(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::multiplies<T>(), queue); +} + +template <typename T> +void element_prod(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, result, compute::multiplies<T>(), queue); +} + +template <typename T, typename A> +void element_prod(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + ublas::vector<T, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::multiplies<T>(), queue); +} + +template <typename T, typename A> +ublas::vector<T, A> element_prod(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::multiplies<T>(), queue); +} + +template <typename T, typename L> +void element_scale(ublas::matrix<T, L, opencl::storage> const &m, T value, + ublas::matrix<T, L, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(m.device() == result.device() && m.device() == queue.get_device()); + assert(m.size1() == result.size1() && m.size2() == result.size2()); + compute::transform(m.begin(), m.end(), result.begin(), lambda::_1 * value, queue); + queue.finish(); +} + +template <typename T, typename L, typename A> +void element_scale(ublas::matrix<T, L, A> const &m, T value, + ublas::matrix<T, L, A> &result, + compute::command_queue& queue) +{ + ublas::matrix<T, L, opencl::storage> mdev(m, queue); + ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context()); + element_scale(mdev, value, rdev, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename L, typename A> +ublas::matrix<T, L, A> element_scale(ublas::matrix<T, L, A> const &m, T value, + compute::command_queue& queue) +{ + ublas::matrix<T, L, A> result(m.size1(), m.size2()); + element_scale(m, value, result, queue); + return result; +} + +template <typename T> +void element_scale(ublas::vector<T, opencl::storage> const &v, T value, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(v.device() == result.device() && v.device() == queue.get_device()); + assert(v.size() == result.size()); + compute::transform(v.begin(), v.end(), result.begin(), lambda::_1 * value, queue); + queue.finish(); +} + +template <typename T, typename A> +void element_scale(ublas::vector<T, A> const &v, T value, + ublas::vector<T, A> & result, + compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> vdev(v, queue); + ublas::vector<T, opencl::storage> rdev(v.size(), queue.get_context()); + element_scale(vdev, value, rdev, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename A> +ublas::vector<T,A> element_scale(ublas::vector<T, A> const &v, T value, + compute::command_queue& queue) +{ + ublas::vector<T, A> result(v.size()); + element_scale(v, value, result, queue); + return result; +} + +template <typename T, typename L1, typename L2, typename L3> +void element_div(ublas::matrix<T, L1, opencl::storage> const &a, + ublas::matrix<T, L2, opencl::storage> const &b, + ublas::matrix<T, L3, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, result, compute::divides<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename L3, typename A> +void element_div(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + ublas::matrix<T, L3, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::divides<T>(), queue); +} + +template <typename T, typename L1, typename L2, typename A> +ublas::matrix<T, L1, A> element_div(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::divides<T>(), queue); +} + +template <typename T> +void element_div(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + compute::command_queue& queue) +{ + element_wise(a, b, result, compute::divides<T>(), queue); +} + +template <typename T, typename A> +void element_div(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + ublas::vector<T, A> &result, + compute::command_queue &queue) +{ + element_wise(a, b, result, compute::divides<T>(), queue); +} + +template <typename T, typename A> +ublas::vector<T, A> element_div(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue &queue) +{ + return element_wise(a, b, compute::divides<T>(), queue); +} + +}}}} + +#endif diff --git a/boost/numeric/ublas/opencl/library.hpp b/boost/numeric/ublas/opencl/library.hpp new file mode 100644 index 0000000000..badee4d2ee --- /dev/null +++ b/boost/numeric/ublas/opencl/library.hpp @@ -0,0 +1,38 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_library_hpp_ +#define boost_numeric_ublas_opencl_library_hpp_ + +#include <clBLAS.h> +#include <type_traits> +#include <complex> + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +class library +{ +public: + library() { clblasSetup();} + ~library() { clblasTeardown();} +}; + +template <typename T> +struct is_numeric +{ + static bool const value = + std::is_same<T, float>::value | + std::is_same<T, double>::value | + std::is_same<T, std::complex<float>>::value | + std::is_same<T, std::complex<double>>::value; +}; + +}}}} + +#endif diff --git a/boost/numeric/ublas/opencl/matrix.hpp b/boost/numeric/ublas/opencl/matrix.hpp new file mode 100644 index 0000000000..d8b400d542 --- /dev/null +++ b/boost/numeric/ublas/opencl/matrix.hpp @@ -0,0 +1,123 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_matrix_hpp_ +#define boost_numeric_ublas_opencl_matrix_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/matrix.hpp> +#include <boost/numeric/ublas/functional.hpp> +#include <boost/compute/core.hpp> +#include <boost/compute/algorithm.hpp> +#include <boost/compute/buffer.hpp> + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +class storage; + +namespace compute = boost::compute; + +} // namespace opencl + +template<class T, class L> +class matrix<T, L, opencl::storage> : public matrix_container<matrix<T, L, opencl::storage> > +{ + typedef typename boost::compute::buffer_allocator<T>::size_type size_type; + typedef L layout_type; + typedef matrix<T, L, opencl::storage> self_type; +public: + matrix() + : matrix_container<self_type>(), + size1_(0), size2_(0), data_() , device_() + {} + + matrix(size_type size1, size_type size2, compute::context c) + : matrix_container<self_type>(), + size1_(size1), size2_(size2), device_(c.get_device()) + { + compute::buffer_allocator<T> allocator(c); + data_ = allocator.allocate(layout_type::storage_size(size1, size2)).get_buffer(); + } + + matrix(size_type size1, size_type size2, T const &value, compute::command_queue &q) + : matrix_container<self_type>(), + size1_(size1), size2_(size2), device_(q.get_device()) + { + compute::buffer_allocator<T> allocator(q.get_context()); + data_ = allocator.allocate(layout_type::storage_size(size1, size2)).get_buffer(); + compute::fill(this->begin(), this->end(), value, q); + q.finish(); + } + + template <typename A> + matrix(matrix<T, L, A> const &m, compute::command_queue &queue) + : matrix(m.size1(), m.size2(), queue.get_context()) + { + this->from_host(m, queue); + } + + size_type size1() const { return size1_;} + size_type size2() const { return size2_;} + + const compute::buffer_iterator<T> begin() const { return compute::make_buffer_iterator<T>(data_);} + compute::buffer_iterator<T> begin() { return compute::make_buffer_iterator<T>(data_);} + + compute::buffer_iterator<T> end() { return compute::make_buffer_iterator<T>(data_, layout_type::storage_size(size1_, size2_));} + const compute::buffer_iterator<T> end() const { return compute::make_buffer_iterator<T>(data_, layout_type::storage_size(size1_, size2_));} + + const compute::device &device() const { return device_;} + compute::device &device() { return device_;} + + void fill(T value, compute::command_queue &queue) + { + assert(device_ == queue.get_device()); + compute::fill(this->begin(), this->end(), value, queue); + queue.finish(); + } + + /** Copies a matrix to a device + * \param m is a matrix that is not on the device _device and it is copied to it + * \param queue is the command queue that will execute the operation + */ + template<class A> + void from_host(ublas::matrix<T, L, A> const &m, compute::command_queue &queue) + { + assert(device_ == queue.get_device()); + compute::copy(m.data().begin(), + m.data().end(), + this->begin(), + queue); + queue.finish(); + } + + /** Copies a matrix from a device + * \param m is a matrix that will be reized to (size1_,size2) and the values of (*this) will be copied in it + * \param queue is the command queue that will execute the operation + */ + template<class A> + void to_host(ublas::matrix<T, L, A> &m, compute::command_queue &queue) const + { + assert(device_ == queue.get_device()); + compute::copy(this->begin(), + this->end(), + m.data().begin(), + queue); + queue.finish(); + } + +private: + size_type size1_; + size_type size2_; + compute::buffer data_; + compute::device device_; +}; + +}}} + +#endif diff --git a/boost/numeric/ublas/opencl/misc.hpp b/boost/numeric/ublas/opencl/misc.hpp new file mode 100644 index 0000000000..5ed48f47f8 --- /dev/null +++ b/boost/numeric/ublas/opencl/misc.hpp @@ -0,0 +1,182 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_misc_hpp_ +#define boost_numeric_ublas_opencl_misc_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/opencl/vector.hpp> +#include <boost/numeric/ublas/opencl/matrix.hpp> + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +template <typename T> +typename std::enable_if<is_numeric<T>::value, T>::type +a_sum(ublas::vector<T, opencl::storage> const &v, compute::command_queue& queue) +{ + compute::vector<T> scratch_buffer(v.size(), queue.get_context()); + compute::vector<T> result_buffer(1, queue.get_context()); + cl_event event; + if (std::is_same<T, float>::value) + clblasSasum(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + else if (std::is_same<T, double>::value) + clblasDasum(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + else if (std::is_same<T, std::complex<float>>::value) + clblasScasum(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + else if (std::is_same<T, std::complex<double>>::value) + clblasDzasum(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + clWaitForEvents(1, &event); + return result_buffer[0]; +} + +template <typename T, typename A> +typename std::enable_if<is_numeric<T>::value, T>::type +a_sum(ublas::vector<T, A> const &v, compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> vdev(v, queue); + return a_sum(vdev, queue); +} + +template <typename T> +typename std::enable_if<std::is_same<T, float>::value | + std::is_same<T, double>::value, + T>::type +norm_1(ublas::vector<T, opencl::storage> const &v, compute::command_queue& queue) +{ + return a_sum(v, queue); +} + +template <typename T, typename A> +typename std::enable_if<std::is_same<T, float>::value | + std::is_same<T, double>::value, + T>::type +norm_1(ublas::vector<T, A> const &v, compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> vdev(v, queue); + return norm_1(vdev, queue); +} + +template <typename T> +typename std::enable_if<is_numeric<T>::value, T>::type +norm_2(ublas::vector<T, opencl::storage> const &v, compute::command_queue& queue) +{ + compute::vector<T> scratch_buffer(2*v.size(), queue.get_context()); + compute::vector<T> result_buffer(1, queue.get_context()); + cl_event event; + if (std::is_same<T, float>::value) + clblasSnrm2(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + else if (std::is_same<T, double>::value) + clblasDnrm2(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + else if (std::is_same<T, std::complex<float>>::value) + clblasScnrm2(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + else if (std::is_same<T, std::complex<double>>::value) + clblasDznrm2(v.size(), + result_buffer.begin().get_buffer().get(), //result buffer + 0, //offset in result buffer + v.begin().get_buffer().get(), //input buffer + 0, //offset in input buffer + 1, //increment in input buffer + scratch_buffer.begin().get_buffer().get(), + 1, //number of command queues + &(queue.get()), //queue + 0, // number of events waiting list + NULL, //event waiting list + &event); //event + clWaitForEvents(1, &event); + return result_buffer[0]; +} + +template <typename T, typename A> +typename std::enable_if<is_numeric<T>::value, T>::type +norm_2(ublas::vector<T, A> const &v, compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> vdev(v, queue); + return norm_2(vdev, queue); +} + +}}}} + +#endif diff --git a/boost/numeric/ublas/opencl/operations.hpp b/boost/numeric/ublas/opencl/operations.hpp new file mode 100644 index 0000000000..2c9e7348d6 --- /dev/null +++ b/boost/numeric/ublas/opencl/operations.hpp @@ -0,0 +1,18 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_operations_hpp_ +#define boost_numeric_ublas_opencl_operations_hpp_ + +#include <boost/numeric/ublas/opencl/transpose.hpp> +#include <boost/numeric/ublas/opencl/prod.hpp> +#include <boost/numeric/ublas/opencl/elementwise.hpp> +#include <boost/numeric/ublas/opencl/misc.hpp> + +#endif diff --git a/boost/numeric/ublas/opencl/prod.hpp b/boost/numeric/ublas/opencl/prod.hpp new file mode 100644 index 0000000000..4318eff008 --- /dev/null +++ b/boost/numeric/ublas/opencl/prod.hpp @@ -0,0 +1,364 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_prod_hpp_ +#define boost_numeric_ublas_opencl_prod_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/opencl/vector.hpp> +#include <boost/numeric/ublas/opencl/matrix.hpp> +#include <boost/numeric/ublas/opencl/transpose.hpp> +#include <boost/compute/buffer.hpp> + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +#define ONE_DOUBLE_COMPLEX {{1.0, 00.0}} +#define ONE_FLOAT_COMPLEX {{1.0f, 00.0f}} + +template <typename T, typename L1, typename L2> +typename std::enable_if<is_numeric<T>::value>::type +prod(ublas::matrix<T, L1, opencl::storage> const &a, + ublas::matrix<T, L2, opencl::storage> const &b, + ublas::matrix<T, L1, opencl::storage> &result, + compute::command_queue &queue) +{ + assert(a.device() == b.device() && + a.device() == result.device() && + a.device() == queue.get_device()); + assert(a.size2() == b.size1()); + + result.fill(0, queue); + + //to hold matrix b with layout 1 if the b has different layout + std::unique_ptr<ublas::matrix<T, L1, opencl::storage>> bl1; + + cl_event event = NULL; + + cl_mem buffer_a = a.begin().get_buffer().get(); + cl_mem buffer_b = b.begin().get_buffer().get(); + cl_mem buffer_result = result.begin().get_buffer().get(); + + if (!(std::is_same<L1, L2>::value)) + { + bl1.reset(new ublas::matrix<T, L1, opencl::storage>(b.size1(), b.size2(), queue.get_context())); + change_layout(b, *bl1, queue); + buffer_b = bl1->begin().get_buffer().get(); + } + + clblasOrder Order = std::is_same<L1, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor; + size_t lda = Order == clblasRowMajor ? a.size2() : a.size1(); + size_t ldb = Order == clblasRowMajor ? b.size2() : a.size2(); + size_t ldc = Order == clblasRowMajor ? b.size2() : a.size1(); + + if (std::is_same<T, float>::value) + clblasSgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), b.size2(), a.size2(), + 1, buffer_a, 0, lda, + buffer_b, 0, ldb, 1, + buffer_result, 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, double>::value) + clblasDgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), b.size2(), a.size2(), + 1, buffer_a, 0, lda, + buffer_b, 0, ldb, 1, + buffer_result, 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<float>>::value) + clblasCgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), b.size2(), a.size2(), + ONE_FLOAT_COMPLEX, buffer_a, 0, lda, + buffer_b, 0, ldb, ONE_FLOAT_COMPLEX, + buffer_result, 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<double>>::value) + clblasZgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), b.size2(), a.size2(), + ONE_DOUBLE_COMPLEX, buffer_a, 0, lda, + buffer_b, 0, ldb, ONE_DOUBLE_COMPLEX, + buffer_result, 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + clWaitForEvents(1, &event); +} + +template <typename T, typename L1, typename L2, typename A> +typename std::enable_if<is_numeric<T>::value>::type +prod(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + ublas::matrix<T, L1, A> &result, + compute::command_queue &queue) +{ + ublas::matrix<T, L1, opencl::storage> adev(a, queue); + ublas::matrix<T, L2, opencl::storage> bdev(b, queue); + ublas::matrix<T, L1, opencl::storage> rdev(a.size1(), b.size2(), queue.get_context()); + prod(adev, bdev, rdev, queue); + rdev.to_host(result,queue); +} + +template <typename T, typename L1, typename L2, typename A> +typename std::enable_if<is_numeric<T>::value, ublas::matrix<T, L1, A>>::type +prod(ublas::matrix<T, L1, A> const &a, + ublas::matrix<T, L2, A> const &b, + compute::command_queue &queue) +{ + ublas::matrix<T, L1, A> result(a.size1(), b.size2()); + prod(a, b, result, queue); + return result; +} + +template <typename T, typename L> +typename std::enable_if<is_numeric<T>::value>::type +prod(ublas::matrix<T, L, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + compute::command_queue &queue) +{ + assert(a.device() == b.device() && + a.device() == result.device() && + a.device() == queue.get_device()); + assert(a.size2() == b.size()); + result.fill(0, queue); + + cl_event event = NULL; + clblasOrder Order = std::is_same<L, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor; + int lda = Order == clblasRowMajor ? a.size2() : a.size1(); + int ldb = Order == clblasRowMajor ? 1 : a.size2(); + int ldc = Order == clblasRowMajor ? 1 : a.size1(); + + if (std::is_same<T, float>::value) + clblasSgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), 1, a.size2(), + 1, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, 1, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, double>::value) + clblasDgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), 1, a.size2(), + 1, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, 1, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<float>>::value) + clblasCgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), 1, a.size2(), + ONE_FLOAT_COMPLEX, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, ONE_FLOAT_COMPLEX, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<double>>::value) + clblasZgemm(Order, clblasNoTrans, clblasNoTrans, + a.size1(), 1, a.size2(), + ONE_DOUBLE_COMPLEX, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, ONE_DOUBLE_COMPLEX, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + clWaitForEvents(1, &event); +} + +template <typename T, typename L, typename A> +typename std::enable_if<is_numeric<T>::value>::type +prod(ublas::matrix<T, L, A> const &a, + ublas::vector<T, A> const &b, + ublas::vector<T, A> &result, + compute::command_queue &queue) +{ + ublas::matrix<T, L, opencl::storage> adev(a, queue); + ublas::vector<T, opencl::storage> bdev(b, queue); + ublas::vector<T, opencl::storage> rdev(a.size1(), queue.get_context()); + prod(adev, bdev, rdev, queue); + rdev.to_host(result, queue); +} + +template <typename T, typename L, typename A> +typename std::enable_if<is_numeric<T>::value, ublas::vector<T, A>>::type +prod(ublas::matrix<T, L, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue &queue) +{ + ublas::vector<T, A> result(a.size1()); + prod(a, b, result, queue); + return result; +} + +template <typename T, typename L> +typename std::enable_if<is_numeric<T>::value>::type +prod(ublas::vector<T, opencl::storage> const &a, + ublas::matrix<T, L, opencl::storage> const &b, + ublas::vector<T, opencl::storage> &result, + compute::command_queue &queue) +{ + assert(a.device() == b.device() && + a.device() == result.device() && + a.device() == queue.get_device()); + assert(a.size() == b.size1()); + result.fill(0, queue); + cl_event event = NULL; + clblasOrder Order = std::is_same<L, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor; + size_t lda = Order == clblasRowMajor ? a.size() : 1; + size_t ldb = Order == clblasRowMajor ? b.size2() : a.size(); + size_t ldc = Order == clblasRowMajor ? b.size2() : 1; + + if (std::is_same<T, float>::value) + clblasSgemm(Order, clblasNoTrans, clblasNoTrans, + 1, b.size2(), a.size(), + 1, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, 1, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, double>::value) + clblasDgemm(Order, clblasNoTrans, clblasNoTrans, + 1, b.size2(), a.size(), + 1, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, 1, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<float>>::value) + clblasCgemm(Order, clblasNoTrans, clblasNoTrans, + 1, b.size2(), a.size(), + ONE_FLOAT_COMPLEX, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, ONE_FLOAT_COMPLEX, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<double>>::value) + clblasZgemm(Order, clblasNoTrans, clblasNoTrans, + 1, b.size2(), a.size(), + ONE_DOUBLE_COMPLEX, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, ONE_DOUBLE_COMPLEX, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + clWaitForEvents(1, &event); +} + +template <class T, class L, class A> +typename std::enable_if<is_numeric<T>::value>::type +prod(ublas::vector<T, A> const &a, + ublas::matrix<T, L, A> const &b, + ublas::vector<T, A> &result, + compute::command_queue &queue) +{ + ublas::vector<T, opencl::storage> adev(a, queue); + ublas::matrix<T, L, opencl::storage> bdev(b, queue); + ublas::vector<T, opencl::storage> rdev(b.size2(), queue.get_context()); + prod(adev, bdev, rdev, queue); + rdev.to_host(result, queue); +} + +template <class T, class L, class A> +typename std::enable_if<is_numeric<T>::value, ublas::vector<T, A>>::type +prod(ublas::vector<T, A> const &a, + ublas::matrix<T, L, A> const &b, + compute::command_queue &queue) +{ + ublas::vector<T, A> result(b.size2()); + prod(a, b, result, queue); + return result; +} + +template<class T> +typename std::enable_if<std::is_fundamental<T>::value, T>::type +inner_prod(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + compute::command_queue &queue) +{ + assert(a.device() == b.device() && a.device() == queue.get_device()); + assert(a.size() == b.size()); + return compute::inner_product(a.begin(), a.end(), b.begin(), T(0), queue); +} + +template<class T, class A> +typename std::enable_if<std::is_fundamental<T>::value, T>::type +inner_prod(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue& queue) +{ + ublas::vector<T, opencl::storage> adev(a, queue); + ublas::vector<T, opencl::storage> bdev(b, queue); + return inner_prod(adev, bdev, queue); +} + +template <class T, class L> +typename std::enable_if<is_numeric<T>::value>::type +outer_prod(ublas::vector<T, opencl::storage> const &a, + ublas::vector<T, opencl::storage> const &b, + ublas::matrix<T, L, opencl::storage> &result, + compute::command_queue & queue) +{ + assert(a.device() == b.device() && + a.device() == result.device() && + a.device() == queue.get_device()); + result.fill(0, queue); + cl_event event = NULL; + clblasOrder Order = std::is_same<L, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor; + size_t lda = Order == clblasRowMajor ? 1 : a.size(); + size_t ldb = Order == clblasRowMajor ? b.size() : 1; + size_t ldc = Order == clblasRowMajor ? b.size() : a.size(); + + if (std::is_same<T, float>::value) + clblasSgemm(Order, clblasNoTrans, clblasNoTrans, + a.size(), b.size(), 1, + 1, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, 1, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, double>::value) + clblasDgemm(Order, clblasNoTrans, clblasNoTrans, + a.size(), b.size(), 1, + 1, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, 1, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<float>>::value) + clblasCgemm(Order, clblasNoTrans, clblasNoTrans, + a.size(), b.size(), 1, + ONE_FLOAT_COMPLEX, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, ONE_FLOAT_COMPLEX, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + else if (std::is_same<T, std::complex<double>>::value) + clblasZgemm(Order, clblasNoTrans, clblasNoTrans, + a.size(), b.size(), 1, + ONE_DOUBLE_COMPLEX, a.begin().get_buffer().get(), 0, lda, + b.begin().get_buffer().get(), 0, ldb, ONE_DOUBLE_COMPLEX, + result.begin().get_buffer().get(), 0, ldc, + 1, &(queue.get()), 0, NULL, &event); + clWaitForEvents(1, &event); +} + +template <class T, class L, class A> +typename std::enable_if<is_numeric<T>::value>::type +outer_prod(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + ublas::matrix<T, L, A> &result, + compute::command_queue &queue) +{ + ublas::vector<T, opencl::storage> adev(a, queue); + ublas::vector<T, opencl::storage> bdev(b, queue); + ublas::matrix<T, L, opencl::storage> rdev(a.size(), b.size(), queue.get_context()); + outer_prod(adev, bdev, rdev, queue); + rdev.to_host(result, queue); +} + +template <class T,class L = ublas::basic_row_major<>, class A> +typename std::enable_if<is_numeric<T>::value, ublas::matrix<T, L, A>>::type +outer_prod(ublas::vector<T, A> const &a, + ublas::vector<T, A> const &b, + compute::command_queue &queue) +{ + ublas::matrix<T, L, A> result(a.size(), b.size()); + outer_prod(a, b, result, queue); + return result; +} + +#undef ONE_DOUBLE_COMPLEX +#undef ONE_FLOAT_COMPLEX + +}}}} + +#endif diff --git a/boost/numeric/ublas/opencl/transpose.hpp b/boost/numeric/ublas/opencl/transpose.hpp new file mode 100644 index 0000000000..93508c8971 --- /dev/null +++ b/boost/numeric/ublas/opencl/transpose.hpp @@ -0,0 +1,142 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_transpose_hpp_ +#define boost_numeric_ublas_opencl_transpose_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/opencl/vector.hpp> +#include <boost/numeric/ublas/opencl/matrix.hpp> + +// Kernel for transposition of various data types +#define OPENCL_TRANSPOSITION_KERNEL(DATA_TYPE) \ +"__kernel void transpose(__global " #DATA_TYPE "* in, __global " #DATA_TYPE "* result, unsigned int width, unsigned int height) \n" \ +"{ \n" \ +" unsigned int column_index = get_global_id(0); \n" \ +" unsigned int row_index = get_global_id(1); \n" \ +" if (column_index < width && row_index < height) \n" \ +" { \n" \ +" unsigned int index_in = column_index + width * row_index; \n" \ +" unsigned int index_result = row_index + height * column_index; \n" \ +" result[index_result] = in[index_in]; \n" \ +" } \n" \ +"} \n" + + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +template<class T, class L1, class L2> +typename std::enable_if<is_numeric<T>::value>::type +change_layout(ublas::matrix<T, L1, opencl::storage> const &m, + ublas::matrix<T, L2, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(m.size1() == result.size1() && m.size2() == result.size2()); + assert(m.device() == result.device() && m.device() == queue.get_device()); + assert(!(std::is_same<L1, L2>::value)); + char const *kernel; + if (std::is_same<T, float>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(float); + else if (std::is_same<T, double>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(double); + else if (std::is_same<T, std::complex<float>>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(float2); + else if (std::is_same<T, std::complex<double>>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(double2); + size_t len = strlen(kernel); + cl_int err; + cl_context c_context = queue.get_context().get(); + cl_program program = clCreateProgramWithSource(c_context, 1, &kernel, &len, &err); + clBuildProgram(program, 1, &queue.get_device().get(), NULL, NULL, NULL); + cl_kernel c_kernel = clCreateKernel(program, "transpose", &err); + size_t width = std::is_same < L1, ublas::basic_row_major<>>::value ? m.size2() : m.size1(); + size_t height = std::is_same < L1, ublas::basic_row_major<>>::value ? m.size1() : m.size2(); + size_t global_size[2] = { width , height }; + clSetKernelArg(c_kernel, 0, sizeof(T*), &m.begin().get_buffer().get()); + clSetKernelArg(c_kernel, 1, sizeof(T*), &result.begin().get_buffer().get()); + clSetKernelArg(c_kernel, 2, sizeof(unsigned int), &width); + clSetKernelArg(c_kernel, 3, sizeof(unsigned int), &height); + cl_command_queue c_queue = queue.get(); + cl_event event = NULL; + clEnqueueNDRangeKernel(c_queue, c_kernel, 2, NULL, global_size, NULL, 0, NULL, &event); + clWaitForEvents(1, &event); +} + +template<class T, class L1, class L2, class A> +typename std::enable_if<is_numeric<T>::value>::type +change_layout(ublas::matrix<T, L1, A> const &m, + ublas::matrix<T, L2, A> &result, + compute::command_queue& queue) +{ + ublas::matrix<T, L1, opencl::storage> mdev(m, queue); + ublas::matrix<T, L2, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context()); + change_layout(mdev, rdev, queue); + rdev.to_host(result, queue); +} + +template<class T, class L> +typename std::enable_if<is_numeric<T>::value>::type +trans(ublas::matrix<T, L, opencl::storage> const &m, + ublas::matrix<T, L, opencl::storage> &result, + compute::command_queue& queue) +{ + assert(m.size1() == result.size2() && m.size2() == result.size1()); + assert(m.device() == result.device() && m.device() == queue.get_device()); + char const *kernel; + if (std::is_same<T, float>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(float); + else if (std::is_same<T, double>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(double); + else if (std::is_same<T, std::complex<float>>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(float2); + else if (std::is_same<T, std::complex<double>>::value) + kernel = OPENCL_TRANSPOSITION_KERNEL(double2); + size_t len = strlen(kernel); + cl_int err; + cl_context c_context = queue.get_context().get(); + cl_program program = clCreateProgramWithSource(c_context, 1, &kernel, &len, &err); + clBuildProgram(program, 1, &queue.get_device().get(), NULL, NULL, NULL); + cl_kernel c_kernel = clCreateKernel(program, "transpose", &err); + size_t width = std::is_same <L, ublas::basic_row_major<>>::value ? m.size2() : m.size1(); + size_t height = std::is_same <L, ublas::basic_row_major<>>::value ? m.size1() : m.size2(); + size_t global_size[2] = { width , height }; + clSetKernelArg(c_kernel, 0, sizeof(T*), &m.begin().get_buffer().get()); + clSetKernelArg(c_kernel, 1, sizeof(T*), &result.begin().get_buffer().get()); + clSetKernelArg(c_kernel, 2, sizeof(unsigned int), &width); + clSetKernelArg(c_kernel, 3, sizeof(unsigned int), &height); + cl_command_queue c_queue = queue.get(); + cl_event event = NULL; + clEnqueueNDRangeKernel(c_queue, c_kernel, 2, NULL, global_size, NULL, 0, NULL, &event); + clWaitForEvents(1, &event); +} + +template<class T, class L, class A> +typename std::enable_if<is_numeric<T>::value>::type +trans(ublas::matrix<T, L, A> const &m, + ublas::matrix<T, L, A> &result, + compute::command_queue& queue) +{ + ublas::matrix<T, L, opencl::storage> mdev(m, queue); + ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context()); + trans(mdev, rdev, queue); + rdev.to_host(result, queue); +} + +template<class T, class L, class A> +typename std::enable_if<is_numeric<T>::value, ublas::matrix<T, L, A>>::type +trans(ublas::matrix<T, L, A>& m, compute::command_queue& queue) +{ + ublas::matrix<T, L, A> result(m.size2(), m.size1()); + trans(m, result, queue); + return result; +} + +}}}} + +#endif diff --git a/boost/numeric/ublas/opencl/vector.hpp b/boost/numeric/ublas/opencl/vector.hpp new file mode 100644 index 0000000000..1defa80461 --- /dev/null +++ b/boost/numeric/ublas/opencl/vector.hpp @@ -0,0 +1,90 @@ +// Boost.uBLAS +// +// Copyright (c) 2018 Fady Essam +// Copyright (c) 2018 Stefan Seefeld +// +// 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_numeric_ublas_opencl_vector_hpp_ +#define boost_numeric_ublas_opencl_vector_hpp_ + +#include <boost/numeric/ublas/opencl/library.hpp> +#include <boost/numeric/ublas/functional.hpp> +#include <boost/compute/core.hpp> +#include <boost/compute/algorithm.hpp> +#include <boost/compute/buffer.hpp> +#include <boost/compute/container/vector.hpp> + +namespace boost { namespace numeric { namespace ublas { namespace opencl { + +class storage; + +namespace compute = boost::compute; + +} // namespace opencl + +template <class T> +class vector<T, opencl::storage> : public boost::compute::vector<T> +{ + typedef std::size_t size_type; +public: + vector() : compute::vector<T>() {} + vector(size_type size, compute::context context) + : compute::vector<T>(size, context) + { device_ = context.get_device();} + vector(size_type size, T value, compute::command_queue queue) + : compute::vector<T>(size, value, queue.get_context()) + { + queue.finish(); + device_ = queue.get_device(); + } + + template <typename A> + vector(vector<T, A> const &v, compute::command_queue &queue) + : vector(v.size(), queue.get_context()) + { + this->from_host(v, queue); + } + + + const compute::device device() const { return device_;} + compute::device device() { return device_;} + + template<class A> + void from_host(ublas::vector<T, A> const &v, compute::command_queue & queue) + { + assert(this->device() == queue.get_device()); + compute::copy(v.begin(), + v.end(), + this->begin(), + queue); + queue.finish(); + } + + template<class A> + void to_host(ublas::vector<T, A>& v, compute::command_queue& queue) const + { + assert(this->device() == queue.get_device()); + compute::copy(this->begin(), + this->end(), + v.begin(), + queue); + queue.finish(); + } + + void fill(T value, compute::command_queue & queue) + { + assert(this->device() == queue.get_device()); + compute::fill(this->begin(), this->end(), value, queue); + queue.finish(); + } + +private: + compute::device device_; +}; + +}}} + +#endif diff --git a/boost/numeric/ublas/operation/begin.hpp b/boost/numeric/ublas/operation/begin.hpp index d14bb35cac..ea71349d64 100644 --- a/boost/numeric/ublas/operation/begin.hpp +++ b/boost/numeric/ublas/operation/begin.hpp @@ -28,289 +28,289 @@ namespace boost { namespace numeric { namespace ublas { namespace detail { - /** - * \brief Auxiliary class for implementing the \c begin operation. - * \tparam CategoryT The expression category type (e.g., vector_tag). - * \tparam TagT The dimension type tag (e.g., tag::major). - * \tparam OrientationT The orientation category type (e.g., row_major_tag). - */ - template <typename CategoryT, typename TagT=void, typename OrientationT=void> - struct begin_impl; - - - /// \brief Specialization of \c begin_impl for iterating vector expressions. - template <> - struct begin_impl<vector_tag,void,void> - { - /** - * \brief Return an iterator to the first element of the given vector - * expression. - * \tparam ExprT A model of VectorExpression type. - * \param e A vector expression. - * \return An iterator over the given vector expression. - */ - template <typename ExprT> - static typename ExprT::iterator apply(ExprT& e) - { - return e.begin(); - } - - - /** - * \brief Return a const iterator to the first element of the given vector - * expression. - * \tparam ExprT A model of VectorExpression type. - * \param e A vector expression. - * \return A const iterator to the first element of the given vector - * expression. - */ - template <typename ExprT> - static typename ExprT::const_iterator apply(ExprT const& e) - { - return e.begin(); - } - }; - - - /// \brief Specialization of \c begin_impl for iterating matrix expressions with - /// a row-major orientation over the major dimension. - template <> - struct begin_impl<matrix_tag,tag::major,row_major_tag> - { - /** - * \brief Return an iterator to the first element of the given row-major - * matrix expression over the major dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return An iterator over the major dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::iterator1 apply(ExprT& e) - { - return e.begin1(); - } - - - /** - * \brief Return a const iterator to the first element of the given - * row-major matrix expression over the major dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return A const iterator over the major dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::const_iterator1 apply(ExprT const& e) - { - return e.begin1(); - } - }; - - - /// \brief Specialization of \c begin_impl for iterating matrix expressions with - /// a column-major orientation over the major dimension. - template <> - struct begin_impl<matrix_tag,tag::major,column_major_tag> - { - /** - * \brief Return an iterator to the first element of the given column-major - * matrix expression over the major dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return An iterator over the major dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::iterator2 apply(ExprT& e) - { - return e.begin2(); - } - - - /** - * \brief Return a const iterator to the first element of the given - * column-major matrix expression over the major dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return A const iterator over the major dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::const_iterator2 apply(ExprT const& e) - { - return e.begin2(); - } - }; - - - /// \brief Specialization of \c begin_impl for iterating matrix expressions with - /// a row-major orientation over the minor dimension. - template <> - struct begin_impl<matrix_tag,tag::minor,row_major_tag> - { - /** - * \brief Return an iterator to the first element of the given row-major - * matrix expression over the minor dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return An iterator over the minor dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::iterator2 apply(ExprT& e) - { - return e.begin2(); - } - - - /** - * \brief Return a const iterator to the first element of the given - * row-major matrix expression over the minor dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return A const iterator over the minor dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::const_iterator2 apply(ExprT const& e) - { - return e.begin2(); - } - }; - - - - /// \brief Specialization of \c begin_impl for iterating matrix expressions with - /// a column-major orientation over the minor dimension. - template <> - struct begin_impl<matrix_tag,tag::minor,column_major_tag> - { - /** - * \brief Return an iterator to the first element of the given column-major - * matrix expression over the minor dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return An iterator over the minor dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::iterator1 apply(ExprT& e) - { - return e.begin1(); - } - - - /** - * \brief Return a const iterator to the first element of the given - * column-major matrix expression over the minor dimension. - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return A const iterator over the minor dimension of the given matrix - * expression. - */ - template <typename ExprT> - static typename ExprT::const_iterator1 apply(ExprT const& e) - { - return e.begin1(); - } - }; - - } // Namespace detail - - - /** - * \brief An iterator to the first element of the given vector expression. - * \tparam ExprT A model of VectorExpression type. - * \param e A vector expression. - * \return An iterator to the first element of the given vector expression. - */ - template <typename ExprT> - BOOST_UBLAS_INLINE - typename ExprT::iterator begin(vector_expression<ExprT>& e) - { - return detail::begin_impl<typename ExprT::type_category>::apply(e()); - } - - - /** - * \brief A const iterator to the first element of the given vector expression. - * \tparam ExprT A model of VectorExpression type. - * \param e A vector expression. - * \return A const iterator to the first element of the given vector expression. - */ - template <typename ExprT> - BOOST_UBLAS_INLINE - typename ExprT::const_iterator begin(vector_expression<ExprT> const& e) - { - return detail::begin_impl<typename ExprT::type_category>::apply(e()); - } - - - /** - * \brief An iterator to the first element of the given matrix expression - * according to its orientation. - * \tparam DimTagT A dimension tag type (e.g., tag::major). - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return An iterator to the first element of the given matrix expression - * according to its orientation. - */ - template <typename TagT, typename ExprT> - BOOST_UBLAS_INLINE - typename iterator_type<ExprT,TagT>::type begin(matrix_expression<ExprT>& e) - { - return detail::begin_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e()); - } - - - /** - * \brief A const iterator to the first element of the given matrix expression - * according to its orientation. - * \tparam TagT A dimension tag type (e.g., tag::major). - * \tparam ExprT A model of MatrixExpression type. - * \param e A matrix expression. - * \return A const iterator to the first element of the given matrix expression - * according to its orientation. - */ - template <typename TagT, typename ExprT> - BOOST_UBLAS_INLINE - typename const_iterator_type<ExprT,TagT>::type begin(matrix_expression<ExprT> const& e) - { - return detail::begin_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e()); - } - - - /** - * \brief An iterator to the first element over the dual dimension of the given - * iterator. - * \tparam IteratorT A model of Iterator type. - * \param it An iterator. - * \return An iterator to the first element over the dual dimension of the given - * iterator. - */ - template <typename IteratorT> - BOOST_UBLAS_INLINE - typename IteratorT::dual_iterator_type begin(IteratorT& it) - { - return it.begin(); - } - - - /** - * \brief A const iterator to the first element over the dual dimension of the - * given iterator. - * \tparam IteratorT A model of Iterator type. - * \param it An iterator. - * \return A const iterator to the first element over the dual dimension of the - * given iterator. - */ - template <typename IteratorT> - BOOST_UBLAS_INLINE - typename IteratorT::dual_iterator_type begin(IteratorT const& it) - { - return it.begin(); - } + /** + * \brief Auxiliary class for implementing the \c begin operation. + * \tparam CategoryT The expression category type (e.g., vector_tag). + * \tparam TagT The dimension type tag (e.g., tag::major). + * \tparam OrientationT The orientation category type (e.g., row_major_tag). + */ + template <typename CategoryT, typename TagT=void, typename OrientationT=void> + struct begin_impl; + + + /// \brief Specialization of \c begin_impl for iterating vector expressions. + template <> + struct begin_impl<vector_tag,void,void> + { + /** + * \brief Return an iterator to the first element of the given vector + * expression. + * \tparam ExprT A model of VectorExpression type. + * \param e A vector expression. + * \return An iterator over the given vector expression. + */ + template <typename ExprT> + static typename ExprT::iterator apply(ExprT& e) + { + return e.begin(); + } + + + /** + * \brief Return a const iterator to the first element of the given vector + * expression. + * \tparam ExprT A model of VectorExpression type. + * \param e A vector expression. + * \return A const iterator to the first element of the given vector + * expression. + */ + template <typename ExprT> + static typename ExprT::const_iterator apply(ExprT const& e) + { + return e.begin(); + } + }; + + + /// \brief Specialization of \c begin_impl for iterating matrix expressions with + /// a row-major orientation over the major dimension. + template <> + struct begin_impl<matrix_tag,tag::major,row_major_tag> + { + /** + * \brief Return an iterator to the first element of the given row-major + * matrix expression over the major dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return An iterator over the major dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::iterator1 apply(ExprT& e) + { + return e.begin1(); + } + + + /** + * \brief Return a const iterator to the first element of the given + * row-major matrix expression over the major dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return A const iterator over the major dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::const_iterator1 apply(ExprT const& e) + { + return e.begin1(); + } + }; + + + /// \brief Specialization of \c begin_impl for iterating matrix expressions with + /// a column-major orientation over the major dimension. + template <> + struct begin_impl<matrix_tag,tag::major,column_major_tag> + { + /** + * \brief Return an iterator to the first element of the given column-major + * matrix expression over the major dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return An iterator over the major dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::iterator2 apply(ExprT& e) + { + return e.begin2(); + } + + + /** + * \brief Return a const iterator to the first element of the given + * column-major matrix expression over the major dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return A const iterator over the major dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::const_iterator2 apply(ExprT const& e) + { + return e.begin2(); + } + }; + + + /// \brief Specialization of \c begin_impl for iterating matrix expressions with + /// a row-major orientation over the minor dimension. + template <> + struct begin_impl<matrix_tag,tag::minor,row_major_tag> + { + /** + * \brief Return an iterator to the first element of the given row-major + * matrix expression over the minor dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return An iterator over the minor dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::iterator2 apply(ExprT& e) + { + return e.begin2(); + } + + + /** + * \brief Return a const iterator to the first element of the given + * row-major matrix expression over the minor dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return A const iterator over the minor dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::const_iterator2 apply(ExprT const& e) + { + return e.begin2(); + } + }; + + + + /// \brief Specialization of \c begin_impl for iterating matrix expressions with + /// a column-major orientation over the minor dimension. + template <> + struct begin_impl<matrix_tag,tag::minor,column_major_tag> + { + /** + * \brief Return an iterator to the first element of the given column-major + * matrix expression over the minor dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return An iterator over the minor dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::iterator1 apply(ExprT& e) + { + return e.begin1(); + } + + + /** + * \brief Return a const iterator to the first element of the given + * column-major matrix expression over the minor dimension. + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return A const iterator over the minor dimension of the given matrix + * expression. + */ + template <typename ExprT> + static typename ExprT::const_iterator1 apply(ExprT const& e) + { + return e.begin1(); + } + }; + + } // Namespace detail + + + /** + * \brief An iterator to the first element of the given vector expression. + * \tparam ExprT A model of VectorExpression type. + * \param e A vector expression. + * \return An iterator to the first element of the given vector expression. + */ + template <typename ExprT> + BOOST_UBLAS_INLINE + typename ExprT::iterator begin(vector_expression<ExprT>& e) + { + return detail::begin_impl<typename ExprT::type_category>::apply(e()); + } + + + /** + * \brief A const iterator to the first element of the given vector expression. + * \tparam ExprT A model of VectorExpression type. + * \param e A vector expression. + * \return A const iterator to the first element of the given vector expression. + */ + template <typename ExprT> + BOOST_UBLAS_INLINE + typename ExprT::const_iterator begin(vector_expression<ExprT> const& e) + { + return detail::begin_impl<typename ExprT::type_category>::apply(e()); + } + + + /** + * \brief An iterator to the first element of the given matrix expression + * according to its orientation. + * \tparam DimTagT A dimension tag type (e.g., tag::major). + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return An iterator to the first element of the given matrix expression + * according to its orientation. + */ + template <typename TagT, typename ExprT> + BOOST_UBLAS_INLINE + typename iterator_type<ExprT,TagT>::type begin(matrix_expression<ExprT>& e) + { + return detail::begin_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e()); + } + + + /** + * \brief A const iterator to the first element of the given matrix expression + * according to its orientation. + * \tparam TagT A dimension tag type (e.g., tag::major). + * \tparam ExprT A model of MatrixExpression type. + * \param e A matrix expression. + * \return A const iterator to the first element of the given matrix expression + * according to its orientation. + */ + template <typename TagT, typename ExprT> + BOOST_UBLAS_INLINE + typename const_iterator_type<ExprT,TagT>::type begin(matrix_expression<ExprT> const& e) + { + return detail::begin_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e()); + } + + + /** + * \brief An iterator to the first element over the dual dimension of the given + * iterator. + * \tparam IteratorT A model of Iterator type. + * \param it An iterator. + * \return An iterator to the first element over the dual dimension of the given + * iterator. + */ + template <typename IteratorT> + BOOST_UBLAS_INLINE + typename IteratorT::dual_iterator_type begin(IteratorT& it) + { + return it.begin(); + } + + + /** + * \brief A const iterator to the first element over the dual dimension of the + * given iterator. + * \tparam IteratorT A model of Iterator type. + * \param it An iterator. + * \return A const iterator to the first element over the dual dimension of the + * given iterator. + */ + template <typename IteratorT> + BOOST_UBLAS_INLINE + typename IteratorT::dual_iterator_type begin(IteratorT const& it) + { + return it.begin(); + } }}} // Namespace boost::numeric::ublas diff --git a/boost/numeric/ublas/storage.hpp b/boost/numeric/ublas/storage.hpp index bd648925a9..e28ac7c1b4 100644 --- a/boost/numeric/ublas/storage.hpp +++ b/boost/numeric/ublas/storage.hpp @@ -66,7 +66,15 @@ namespace boost { namespace numeric { namespace ublas { alloc_(a), size_ (size) { if (size_) { data_ = alloc_.allocate (size_); +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (! detail::has_trivial_constructor<T>::value) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif for (pointer d = data_; d != data_ + size_; ++d) alloc_.construct(d, value_type()); } @@ -96,10 +104,28 @@ namespace boost { namespace numeric { namespace ublas { else data_ = 0; } +#ifdef BOOST_UBLAS_CPP_GE_2011 + BOOST_UBLAS_INLINE + unbounded_array (unbounded_array &&c) : + storage_array<unbounded_array<T, ALLOC> >(), + alloc_ (std::move(c.alloc_)), size_ (c.size_), data_(c.data_) + { + c.size_ = 0; + c.data_ = nullptr; + } +#endif BOOST_UBLAS_INLINE ~unbounded_array () { if (size_) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (! detail::has_trivial_destructor<T>::value) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif // std::_Destroy (begin(), end(), alloc_); const iterator i_end = end(); for (iterator i = begin (); i != i_end; ++i) { @@ -138,7 +164,15 @@ namespace boost { namespace numeric { namespace ublas { } } else { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (! detail::has_trivial_constructor<T>::value) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif for (pointer di = data_; di != data_ + size; ++di) alloc_.construct (di, value_type()); } @@ -146,7 +180,15 @@ namespace boost { namespace numeric { namespace ublas { } if (size_) { +//Disabled warning C4127 because the conditional expression is constant +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif if (! detail::has_trivial_destructor<T>::value) { +#ifdef _MSC_VER +#pragma warning(pop) +#endif for (pointer si = p_data; si != p_data + size_; ++si) alloc_.destroy (si); } @@ -303,6 +345,7 @@ namespace boost { namespace numeric { namespace ublas { // Handle explict destroy on a (possibly indexed) iterator BOOST_UBLAS_INLINE static void iterator_destroy (iterator &i) { + (void)(i); (&(*i)) -> ~value_type (); } ALLOC alloc_; diff --git a/boost/numeric/ublas/storage_sparse.hpp b/boost/numeric/ublas/storage_sparse.hpp index c8a64a9d55..f87685c796 100644 --- a/boost/numeric/ublas/storage_sparse.hpp +++ b/boost/numeric/ublas/storage_sparse.hpp @@ -195,14 +195,13 @@ namespace boost { namespace numeric { namespace ublas { // Default map type is simply forwarded to std::map - // FIXME should use ALLOC for map but std::allocator of std::pair<const I, T> and std::pair<I,T> fail to compile template<class I, class T, class ALLOC> - class map_std : public std::map<I, T /*, ALLOC */> { + class map_std : public std::map<I, T, std::less<I>, ALLOC> { public: // Serialization template<class Archive> void serialize(Archive & ar, const unsigned int /* file_version */){ - ar & serialization::make_nvp("base", boost::serialization::base_object< std::map<I, T /*, ALLOC */> >(*this)); + ar & serialization::make_nvp("base", boost::serialization::base_object< std::map<I, T, std::less<I>, ALLOC> >(*this)); } }; @@ -398,7 +397,7 @@ namespace boost { namespace numeric { namespace ublas { } // Form Sorted Associative Container concept // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. - iterator insert (iterator hint, const value_type &p) { + iterator insert (iterator /*hint*/, const value_type &p) { return insert (p).first; } // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. diff --git a/boost/numeric/ublas/tensor.hpp b/boost/numeric/ublas/tensor.hpp new file mode 100644 index 0000000000..5a72d43bbc --- /dev/null +++ b/boost/numeric/ublas/tensor.hpp @@ -0,0 +1,26 @@ +// Copyright (c) 2018-2019 +// Cem Bassoy +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + +/// \file tensor.hpp Definition for the class vector and its derivative + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_HPP + +#include "tensor/functions.hpp" +#include "tensor/operators_arithmetic.hpp" +#include "tensor/operators_comparison.hpp" +#include "tensor/extents.hpp" +#include "tensor/strides.hpp" +#include "tensor/ostream.hpp" +#include "tensor/tensor.hpp" + +#endif // BOOST_NUMERIC_UBLAS_TENSOR_HPP diff --git a/boost/numeric/ublas/tensor/algorithms.hpp b/boost/numeric/ublas/tensor/algorithms.hpp new file mode 100644 index 0000000000..c6b9dba482 --- /dev/null +++ b/boost/numeric/ublas/tensor/algorithms.hpp @@ -0,0 +1,345 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP +#define _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP + + +#include <stdexcept> +#include <complex> +#include <functional> + +namespace boost { +namespace numeric { +namespace ublas { + + + +/** @brief Copies a tensor to another tensor with different layouts + * + * Implements C[i1,i2,...,ip] = A[i1,i2,...,ip] + * + * @param[in] p rank of input and output tensor + * @param[in] n pointer to the extents of input or output tensor of length p + * @param[in] pi pointer to a one-based permutation tuple of length p + * @param[out] c pointer to the output tensor + * @param[in] wc pointer to the strides of output tensor c + * @param[in] a pointer to the input tensor + * @param[in] wa pointer to the strides of input tensor a +*/ +template <class PointerOut, class PointerIn, class SizeType> +void copy(const SizeType p, SizeType const*const n, + PointerOut c, SizeType const*const wc, + PointerIn a, SizeType const*const wa) +{ + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value, + "Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types."); + if( p == 0 ) + return; + + if(c == nullptr || a == nullptr) + throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + + if(wc == nullptr || wa == nullptr) + throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + + if(n == nullptr) + throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers."); + + + std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda; + + lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) + lambda(r-1, c, a ); + else + for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) + *c = *a; + }; + + lambda( p-1, c, a ); +} + + + +/** @brief Copies a tensor to another tensor with different layouts applying a unary operation + * + * Implements C[i1,i2,...,ip] = op ( A[i1,i2,...,ip] ) + * + * @param[in] p rank of input and output tensor + * @param[in] n pointer to the extents of input or output tensor of length p + * @param[in] pi pointer to a one-based permutation tuple of length p + * @param[out] c pointer to the output tensor + * @param[in] wc pointer to the strides of output tensor c + * @param[in] a pointer to the input tensor + * @param[in] wa pointer to the strides of input tensor a + * @param[in] op unary operation +*/ +template <class PointerOut, class PointerIn, class SizeType, class UnaryOp> +void transform(const SizeType p, + SizeType const*const n, + PointerOut c, SizeType const*const wc, + PointerIn a, SizeType const*const wa, + UnaryOp op) +{ + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + if( p == 0 ) + return; + + if(c == nullptr || a == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + if(wc == nullptr || wa == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + if(n == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + + std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda; + + lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d) + *c = op(*a); + }; + + lambda( p-1, c, a ); + +} + + +/** @brief Performs a reduce operation with all elements of the tensor and an initial value + * + * Implements k = sum_{i1,..,ip} A[i1,i2,...,ip] + * + * @param[in] r zero-based recursion level starting with r=p-1 + * @param[in] n pointer to the extents of input or output tensor + * @param[in] a pointer to the first input tensor + * @param[in] w pointer to the strides of input tensor a + * @param[in] k accumulated value +*/ +template <class PointerIn, class ValueType, class SizeType> +ValueType accumulate(SizeType const p, SizeType const*const n, + PointerIn a, SizeType const*const w, + ValueType k) +{ + static_assert(std::is_pointer<PointerIn>::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + + if( p == 0 ) + return k; + + if(a == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + if(w == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + if(n == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + + std::function<ValueType(SizeType r, PointerIn a, ValueType k)> lambda; + + lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k) + { + if(r > 0u) + for(auto d = 0u; d < n[r]; a += w[r], ++d) + k = lambda(r-1, a, k); + else + for(auto d = 0u; d < n[0]; a += w[0], ++d) + k += *a; + return k; + }; + + return lambda( p-1, a, k ); +} + +/** @brief Performs a reduce operation with all elements of the tensor and an initial value + * + * Implements k = op ( k , A[i1,i2,...,ip] ), for all ir + * + * @param[in] r zero-based recursion level starting with r=p-1 + * @param[in] n pointer to the extents of input or output tensor + * @param[in] a pointer to the first input tensor + * @param[in] w pointer to the strides of input tensor a + * @param[in] k accumulated value + * @param[in] op binary operation +*/ + +template <class PointerIn, class ValueType, class SizeType, class BinaryOp> +ValueType accumulate(SizeType const p, SizeType const*const n, + PointerIn a, SizeType const*const w, + ValueType k, BinaryOp op) +{ + static_assert(std::is_pointer<PointerIn>::value, + "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types."); + + + if( p == 0 ) + return k; + + if(a == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + if(w == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + if(n == nullptr) + throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers."); + + + std::function<ValueType(SizeType r, PointerIn a, ValueType k)> lambda; + + lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k) + { + if(r > 0u) + for(auto d = 0u; d < n[r]; a += w[r], ++d) + k = lambda(r-1, a, k); + else + for(auto d = 0u; d < n[0]; a += w[0], ++d) + k = op ( k, *a ); + return k; + }; + + return lambda( p-1, a, k ); +} + +/** @brief Transposes a tensor + * + * Implements C[tau[i1],tau[i2],...,tau[ip]] = A[i1,i2,...,ip] + * + * @note is used in function trans + * + * @param[in] p rank of input and output tensor + * @param[in] na pointer to the extents of the input tensor a of length p + * @param[in] pi pointer to a one-based permutation tuple of length p + * @param[out] c pointer to the output tensor + * @param[in] wc pointer to the strides of output tensor c + * @param[in] a pointer to the input tensor + * @param[in] wa pointer to the strides of input tensor a +*/ + +template <class PointerOut, class PointerIn, class SizeType> +void trans( SizeType const p, SizeType const*const na, SizeType const*const pi, + PointerOut c, SizeType const*const wc, + PointerIn a, SizeType const*const wa) +{ + + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value, + "Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types."); + + if( p < 2) + return; + + if(c == nullptr || a == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + if(na == nullptr) + throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null."); + + if(wc == nullptr || wa == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + if(na == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + if(pi == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + + std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda; + + lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a) + { + if(r > 0) + for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) + *c = *a; + }; + + lambda( p-1, c, a ); +} + + +/** @brief Transposes a tensor + * + * Implements C[tau[i1],tau[i2],...,tau[ip]] = A[i1,i2,...,ip] + * + * @note is used in function trans + * + * @param[in] p rank of input and output tensor + * @param[in] na pointer to the extents of the input tensor a of length p + * @param[in] pi pointer to a one-based permutation tuple of length p + * @param[out] c pointer to the output tensor + * @param[in] wc pointer to the strides of output tensor c + * @param[in] a pointer to the input tensor + * @param[in] wa pointer to the strides of input tensor a +*/ + +template <class ValueType, class SizeType> +void trans( SizeType const p, + SizeType const*const na, + SizeType const*const pi, + std::complex<ValueType>* c, SizeType const*const wc, + std::complex<ValueType>* a, SizeType const*const wa) +{ + if( p < 2) + return; + + if(c == nullptr || a == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + if(wc == nullptr || wa == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + if(na == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + if(pi == nullptr) + throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers."); + + + std::function<void(SizeType r, std::complex<ValueType>* c, std::complex<ValueType>* a)> lambda; + + lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex<ValueType>* c, std::complex<ValueType>* a) + { + if(r > 0) + for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d) + lambda(r-1, c, a); + else + for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d) + *c = std::conj(*a); + }; + + lambda( p-1, c, a ); + +} + + + + +} +} +} + +#endif diff --git a/boost/numeric/ublas/tensor/expression.hpp b/boost/numeric/ublas/tensor/expression.hpp new file mode 100644 index 0000000000..2677a0e6f1 --- /dev/null +++ b/boost/numeric/ublas/tensor/expression.hpp @@ -0,0 +1,181 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP +#define BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP + +#include <cstddef> +#include <boost/numeric/ublas/expression_types.hpp> + + +namespace boost { +namespace numeric { +namespace ublas { + + +template<class element_type, class storage_format, class storage_type> +class tensor; + +template<class size_type> +class basic_extents; + + +//TODO: put in fwd.hpp +struct tensor_tag {}; + +} +} +} + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + +/** @\brief base class for tensor expressions + * + * \note implements crtp - no use of virtual function calls + * + * \tparam T type of the tensor + * \tparam E type of the derived expression (crtp) + * + **/ +template<class T, class E> +struct tensor_expression + : public ublas_expression<E> +{ + // static const unsigned complexity = 0; + using expression_type = E; + using type_category = tensor_tag; + using tensor_type = T; + + BOOST_UBLAS_INLINE + auto const& operator()() const { return *static_cast<const expression_type*> (this); } + +protected : + explicit tensor_expression() = default; + tensor_expression(const tensor_expression&) = delete; + tensor_expression& operator=(const tensor_expression&) = delete; +}; + + +template<class T, class EL, class ER, class OP> +struct binary_tensor_expression + : public tensor_expression <T, binary_tensor_expression<T,EL,ER,OP>> +{ + using self_type = binary_tensor_expression<T,EL,ER,OP>; + using tensor_type = T; + using binary_operation = OP; + using expression_type_left = EL; + using expression_type_right = ER; + using derived_type = tensor_expression <tensor_type,self_type>; + + using size_type = typename tensor_type::size_type; + + explicit binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) + : el(l) , er(r) , op(o) {} + binary_tensor_expression() = delete; + binary_tensor_expression(const binary_tensor_expression& l) = delete; + binary_tensor_expression(binary_tensor_expression&& l) + : el(l.el), er(l.er), op(l.op) {} + + BOOST_UBLAS_INLINE + decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } + + expression_type_left const& el; + expression_type_right const& er; + binary_operation op; +}; + +/// @brief helper function to simply instantiation of lambda proxy class +template<class T, class EL, class ER, class OP> +auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, tensor_expression<T,ER> const& er, OP op) +{ + return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; +} + +template<class T, class EL, class ER, class OP> +auto make_binary_tensor_expression( matrix_expression<EL> const& el, tensor_expression<T,ER> const& er, OP op) +{ + return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; +} + +template<class T, class EL, class ER, class OP> +auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, matrix_expression<ER> const& er, OP op) +{ + return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; +} + +template<class T, class EL, class ER, class OP> +auto make_binary_tensor_expression( vector_expression<EL> const& el, tensor_expression<T,ER> const& er, OP op) +{ + return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; +} + +template<class T, class EL, class ER, class OP> +auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, vector_expression<ER> const& er, OP op) +{ + return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; +} + + + +template<class T, class E, class OP> +struct unary_tensor_expression + : public tensor_expression <T, unary_tensor_expression<T,E,OP>> +{ + + using self_type = unary_tensor_expression<T,E,OP>; + using tensor_type = T; + using expression_type = E; + + using derived_type = tensor_expression <T, unary_tensor_expression<T,E,OP>>; + + using size_type = typename tensor_type::size_type; + + explicit unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {} + unary_tensor_expression() = delete; + unary_tensor_expression(const unary_tensor_expression& l) = delete; + unary_tensor_expression(unary_tensor_expression&& l) + : e(l.e), op(op.l) {} + + BOOST_UBLAS_INLINE + decltype(auto) operator()(size_type i) const { return op(e(i)); } + + E const& e; + OP op; +}; + +// \brief helper function to simply instantiation of lambda proxy class +template<class T, class E, class OP> +auto make_unary_tensor_expression( tensor_expression<T,E> const& e, OP op) +{ + return unary_tensor_expression<T,E,OP>( e() , op); +} + +template<class T, class E, class OP> +auto make_unary_tensor_expression( matrix_expression<E> const& e, OP op) +{ + return unary_tensor_expression<T,E,OP>( e() , op); +} + +template<class T, class E, class OP> +auto make_unary_tensor_expression( vector_expression<E> const& e, OP op) +{ + return unary_tensor_expression<T,E,OP>( e() , op); +} + + +} +} +} +} +#endif diff --git a/boost/numeric/ublas/tensor/expression_evaluation.hpp b/boost/numeric/ublas/tensor/expression_evaluation.hpp new file mode 100644 index 0000000000..a7948639a9 --- /dev/null +++ b/boost/numeric/ublas/tensor/expression_evaluation.hpp @@ -0,0 +1,288 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_ +#define _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_ + +#include <type_traits> +#include <stdexcept> + + +namespace boost::numeric::ublas { + +template<class element_type, class storage_format, class storage_type> +class tensor; + +template<class size_type> +class basic_extents; + +} + +namespace boost::numeric::ublas::detail { + +template<class T, class D> +struct tensor_expression; + +template<class T, class EL, class ER, class OP> +struct binary_tensor_expression; + +template<class T, class E, class OP> +struct unary_tensor_expression; + +} + +namespace boost::numeric::ublas::detail { + +template<class T, class E> +struct has_tensor_types +{ static constexpr bool value = false; }; + +template<class T> +struct has_tensor_types<T,T> +{ static constexpr bool value = true; }; + +template<class T, class D> +struct has_tensor_types<T, tensor_expression<T,D>> +{ static constexpr bool value = std::is_same<T,D>::value || has_tensor_types<T,D>::value; }; + + +template<class T, class EL, class ER, class OP> +struct has_tensor_types<T, binary_tensor_expression<T,EL,ER,OP>> +{ static constexpr bool value = std::is_same<T,EL>::value || std::is_same<T,ER>::value || has_tensor_types<T,EL>::value || has_tensor_types<T,ER>::value; }; + +template<class T, class E, class OP> +struct has_tensor_types<T, unary_tensor_expression<T,E,OP>> +{ static constexpr bool value = std::is_same<T,E>::value || has_tensor_types<T,E>::value; }; + +} // namespace boost::numeric::ublas::detail + + +namespace boost::numeric::ublas::detail { + + + + + +/** @brief Retrieves extents of the tensor + * +*/ +template<class T, class F, class A> +auto retrieve_extents(tensor<T,F,A> const& t) +{ + return t.extents(); +} + +/** @brief Retrieves extents of the tensor expression + * + * @note tensor expression must be a binary tree with at least one tensor type + * + * @returns extents of the child expression if it is a tensor or extents of one child of its child. +*/ +template<class T, class D> +auto retrieve_extents(tensor_expression<T,D> const& expr) +{ + static_assert(detail::has_tensor_types<T,tensor_expression<T,D>>::value, + "Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors."); + + auto const& cast_expr = static_cast<D const&>(expr); + + if constexpr ( std::is_same<T,D>::value ) + return cast_expr.extents(); + else + return retrieve_extents(cast_expr); +} + +/** @brief Retrieves extents of the binary tensor expression + * + * @note tensor expression must be a binary tree with at least one tensor type + * + * @returns extents of the (left and if necessary then right) child expression if it is a tensor or extents of a child of its (left and if necessary then right) child. +*/ +template<class T, class EL, class ER, class OP> +auto retrieve_extents(binary_tensor_expression<T,EL,ER,OP> const& expr) +{ + static_assert(detail::has_tensor_types<T,binary_tensor_expression<T,EL,ER,OP>>::value, + "Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors."); + + if constexpr ( std::is_same<T,EL>::value ) + return expr.el.extents(); + + if constexpr ( std::is_same<T,ER>::value ) + return expr.er.extents(); + + else if constexpr ( detail::has_tensor_types<T,EL>::value ) + return retrieve_extents(expr.el); + + else if constexpr ( detail::has_tensor_types<T,ER>::value ) + return retrieve_extents(expr.er); +} + +/** @brief Retrieves extents of the binary tensor expression + * + * @note tensor expression must be a binary tree with at least one tensor type + * + * @returns extents of the child expression if it is a tensor or extents of a child of its child. +*/ +template<class T, class E, class OP> +auto retrieve_extents(unary_tensor_expression<T,E,OP> const& expr) +{ + + static_assert(detail::has_tensor_types<T,unary_tensor_expression<T,E,OP>>::value, + "Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors."); + + if constexpr ( std::is_same<T,E>::value ) + return expr.e.extents(); + + else if constexpr ( detail::has_tensor_types<T,E>::value ) + return retrieve_extents(expr.e); +} + +} // namespace boost::numeric::ublas::detail + + +/////////////// + +namespace boost::numeric::ublas::detail { + +template<class T, class F, class A, class S> +auto all_extents_equal(tensor<T,F,A> const& t, basic_extents<S> const& extents) +{ + return extents == t.extents(); +} + +template<class T, class D, class S> +auto all_extents_equal(tensor_expression<T,D> const& expr, basic_extents<S> const& extents) +{ + static_assert(detail::has_tensor_types<T,tensor_expression<T,D>>::value, + "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); + auto const& cast_expr = static_cast<D const&>(expr); + + + if constexpr ( std::is_same<T,D>::value ) + if( extents != cast_expr.extents() ) + return false; + + if constexpr ( detail::has_tensor_types<T,D>::value ) + if ( !all_extents_equal(cast_expr, extents)) + return false; + + return true; + +} + +template<class T, class EL, class ER, class OP, class S> +auto all_extents_equal(binary_tensor_expression<T,EL,ER,OP> const& expr, basic_extents<S> const& extents) +{ + static_assert(detail::has_tensor_types<T,binary_tensor_expression<T,EL,ER,OP>>::value, + "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); + + if constexpr ( std::is_same<T,EL>::value ) + if(extents != expr.el.extents()) + return false; + + if constexpr ( std::is_same<T,ER>::value ) + if(extents != expr.er.extents()) + return false; + + if constexpr ( detail::has_tensor_types<T,EL>::value ) + if(!all_extents_equal(expr.el, extents)) + return false; + + if constexpr ( detail::has_tensor_types<T,ER>::value ) + if(!all_extents_equal(expr.er, extents)) + return false; + + return true; +} + + +template<class T, class E, class OP, class S> +auto all_extents_equal(unary_tensor_expression<T,E,OP> const& expr, basic_extents<S> const& extents) +{ + + static_assert(detail::has_tensor_types<T,unary_tensor_expression<T,E,OP>>::value, + "Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors."); + + if constexpr ( std::is_same<T,E>::value ) + if(extents != expr.e.extents()) + return false; + + if constexpr ( detail::has_tensor_types<T,E>::value ) + if(!all_extents_equal(expr.e, extents)) + return false; + + return true; +} + +} // namespace boost::numeric::ublas::detail + + +namespace boost::numeric::ublas::detail { + + +/** @brief Evaluates expression for a tensor + * + * Assigns the results of the expression to the tensor. + * + * \note Checks if shape of the tensor matches those of all tensors within the expression. +*/ +template<class tensor_type, class derived_type> +void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type> const& expr) +{ + if constexpr (detail::has_tensor_types<tensor_type, tensor_expression<tensor_type,derived_type> >::value ) + if(!detail::all_extents_equal(expr, lhs.extents() )) + throw std::runtime_error("Error in boost::numeric::ublas::tensor: expression contains tensors with different shapes."); + +#pragma omp parallel for + for(auto i = 0u; i < lhs.size(); ++i) + lhs(i) = expr()(i); +} + +/** @brief Evaluates expression for a tensor + * + * Applies a unary function to the results of the expressions before the assignment. + * Usually applied needed for unary operators such as A += C; + * + * \note Checks if shape of the tensor matches those of all tensors within the expression. +*/ +template<class tensor_type, class derived_type, class unary_fn> +void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type> const& expr, unary_fn const fn) +{ + + if constexpr (detail::has_tensor_types< tensor_type, tensor_expression<tensor_type,derived_type> >::value ) + if(!detail::all_extents_equal( expr, lhs.extents() )) + throw std::runtime_error("Error in boost::numeric::ublas::tensor: expression contains tensors with different shapes."); + +#pragma omp parallel for + for(auto i = 0u; i < lhs.size(); ++i) + fn(lhs(i), expr()(i)); +} + + + +/** @brief Evaluates expression for a tensor + * + * Applies a unary function to the results of the expressions before the assignment. + * Usually applied needed for unary operators such as A += C; + * + * \note Checks if shape of the tensor matches those of all tensors within the expression. +*/ +template<class tensor_type, class unary_fn> +void eval(tensor_type& lhs, unary_fn const fn) +{ +#pragma omp parallel for + for(auto i = 0u; i < lhs.size(); ++i) + fn(lhs(i)); +} + + +} +#endif diff --git a/boost/numeric/ublas/tensor/extents.hpp b/boost/numeric/ublas/tensor/extents.hpp new file mode 100644 index 0000000000..5d4bf8e5cf --- /dev/null +++ b/boost/numeric/ublas/tensor/extents.hpp @@ -0,0 +1,335 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP +#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP + +#include <algorithm> +#include <initializer_list> +#include <limits> +#include <numeric> +#include <stdexcept> +#include <vector> + +#include <cassert> + +namespace boost { +namespace numeric { +namespace ublas { + + +/** @brief Template class for storing tensor extents with runtime variable size. + * + * Proxy template class of std::vector<int_type>. + * + */ +template<class int_type> +class basic_extents +{ + static_assert( std::numeric_limits<typename std::vector<int_type>::value_type>::is_integer, "Static error in basic_layout: type must be of type integer."); + static_assert(!std::numeric_limits<typename std::vector<int_type>::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer."); + +public: + using base_type = std::vector<int_type>; + using value_type = typename base_type::value_type; + using const_reference = typename base_type::const_reference; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_extents + * + * @code auto ex = basic_extents<unsigned>{}; + */ + constexpr explicit basic_extents() + : _base{} + { + } + + /** @brief Copy constructs basic_extents from a one-dimensional container + * + * @code auto ex = basic_extents<unsigned>( std::vector<unsigned>(3u,3u) ); + * + * @note checks if size > 1 and all elements > 0 + * + * @param b one-dimensional std::vector<int_type> container + */ + explicit basic_extents(base_type const& b) + : _base(b) + { + if (!this->valid()){ + throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Move constructs basic_extents from a one-dimensional container + * + * @code auto ex = basic_extents<unsigned>( std::vector<unsigned>(3u,3u) ); + * + * @note checks if size > 1 and all elements > 0 + * + * @param b one-dimensional container of type std::vector<int_type> + */ + explicit basic_extents(base_type && b) + : _base(std::move(b)) + { + if (!this->valid()){ + throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements."); + } + } + + /** @brief Constructs basic_extents from an initializer list + * + * @code auto ex = basic_extents<unsigned>{3,2,4}; + * + * @note checks if size > 1 and all elements > 0 + * + * @param l one-dimensional list of type std::initializer<int_type> + */ + basic_extents(std::initializer_list<value_type> l) + : basic_extents( base_type(std::move(l)) ) + { + } + + /** @brief Constructs basic_extents from a range specified by two iterators + * + * @code auto ex = basic_extents<unsigned>(a.begin(), a.end()); + * + * @note checks if size > 1 and all elements > 0 + * + * @param first iterator pointing to the first element + * @param last iterator pointing to the next position after the last element + */ + basic_extents(const_iterator first, const_iterator last) + : basic_extents ( base_type( first,last ) ) + { + } + + /** @brief Copy constructs basic_extents */ + basic_extents(basic_extents const& l ) + : _base(l._base) + { + } + + /** @brief Move constructs basic_extents */ + basic_extents(basic_extents && l ) noexcept + : _base(std::move(l._base)) + { + } + + ~basic_extents() = default; + + basic_extents& operator=(basic_extents other) noexcept + { + swap (*this, other); + return *this; + } + + friend void swap(basic_extents& lhs, basic_extents& rhs) { + std::swap(lhs._base , rhs._base ); + } + + + + /** @brief Returns true if this has a scalar shape + * + * @returns true if (1,1,[1,...,1]) + */ + bool is_scalar() const + { + return + _base.size() != 0 && + std::all_of(_base.begin(), _base.end(), + [](const_reference a){ return a == 1;}); + } + + /** @brief Returns true if this has a vector shape + * + * @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1 + */ + bool is_vector() const + { + if(_base.size() == 0){ + return false; + } + + if(_base.size() == 1){ + return _base.at(0) > 1; + } + + auto greater_one = [](const_reference a){ return a > 1;}; + auto equal_one = [](const_reference a){ return a == 1;}; + + return + std::any_of(_base.begin(), _base.begin()+2, greater_one) && + std::any_of(_base.begin(), _base.begin()+2, equal_one ) && + std::all_of(_base.begin()+2, _base.end(), equal_one); + } + + /** @brief Returns true if this has a matrix shape + * + * @returns true if (m,n,[1,...,1]) with m > 1 and n > 1 + */ + bool is_matrix() const + { + if(_base.size() < 2){ + return false; + } + + auto greater_one = [](const_reference a){ return a > 1;}; + auto equal_one = [](const_reference a){ return a == 1;}; + + return + std::all_of(_base.begin(), _base.begin()+2, greater_one) && + std::all_of(_base.begin()+2, _base.end(), equal_one ); + } + + /** @brief Returns true if this is has a tensor shape + * + * @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix() + */ + bool is_tensor() const + { + if(_base.size() < 3){ + return false; + } + + auto greater_one = [](const_reference a){ return a > 1;}; + + return std::any_of(_base.begin()+2, _base.end(), greater_one); + } + + const_pointer data() const + { + return this->_base.data(); + } + + const_reference operator[] (size_type p) const + { + return this->_base[p]; + } + + const_reference at (size_type p) const + { + return this->_base.at(p); + } + + reference operator[] (size_type p) + { + return this->_base[p]; + } + + reference at (size_type p) + { + return this->_base.at(p); + } + + + bool empty() const + { + return this->_base.empty(); + } + + size_type size() const + { + return this->_base.size(); + } + + /** @brief Returns true if size > 1 and all elements > 0 */ + bool valid() const + { + return + this->size() > 1 && + std::none_of(_base.begin(), _base.end(), + [](const_reference a){ return a == value_type(0); }); + } + + /** @brief Returns the number of elements a tensor holds with this */ + size_type product() const + { + if(_base.empty()){ + return 0; + } + + return std::accumulate(_base.begin(), _base.end(), 1ul, std::multiplies<>()); + + } + + + /** @brief Eliminates singleton dimensions when size > 2 + * + * squeeze { 1,1} -> { 1,1} + * squeeze { 2,1} -> { 2,1} + * squeeze { 1,2} -> { 1,2} + * + * squeeze {1,2,3} -> { 2,3} + * squeeze {2,1,3} -> { 2,3} + * squeeze {1,3,1} -> { 3,1} + * + */ + basic_extents squeeze() const + { + if(this->size() <= 2){ + return *this; + } + + auto new_extent = basic_extents{}; + auto insert_iter = std::back_insert_iterator<typename basic_extents::base_type>(new_extent._base); + std::remove_copy(this->_base.begin(), this->_base.end(), insert_iter ,value_type{1}); + return new_extent; + + } + + void clear() + { + this->_base.clear(); + } + + bool operator == (basic_extents const& b) const + { + return _base == b._base; + } + + bool operator != (basic_extents const& b) const + { + return !( _base == b._base ); + } + + const_iterator + begin() const + { + return _base.begin(); + } + + const_iterator + end() const + { + return _base.end(); + } + + base_type const& base() const { return _base; } + +private: + + base_type _base; + +}; + +using shape = basic_extents<std::size_t>; + +} // namespace ublas +} // namespace numeric +} // namespace boost + +#endif diff --git a/boost/numeric/ublas/tensor/functions.hpp b/boost/numeric/ublas/tensor/functions.hpp new file mode 100644 index 0000000000..e2043ceb11 --- /dev/null +++ b/boost/numeric/ublas/tensor/functions.hpp @@ -0,0 +1,558 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_UBLAS_TENSOR_FUNCTIONS_HPP +#define BOOST_UBLAS_TENSOR_FUNCTIONS_HPP + + +#include <stdexcept> +#include <vector> +#include <algorithm> +#include <numeric> + + +#include "multiplication.hpp" +#include "algorithms.hpp" +#include "expression.hpp" +#include "expression_evaluation.hpp" +#include "storage_traits.hpp" + +namespace boost { +namespace numeric { +namespace ublas { + +template<class Value, class Format, class Allocator> +class tensor; + +template<class Value, class Format, class Allocator> +class matrix; + +template<class Value, class Allocator> +class vector; + + + + +/** @brief Computes the m-mode tensor-times-vector product + * + * Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im] + * + * @note calls ublas::ttv + * + * @param[in] m contraction dimension with 1 <= m <= p + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * + * @returns tensor object C with order p-1, the same storage format and allocator type as A +*/ +template<class V, class F, class A1, class A2> +auto prod(tensor<V,F,A1> const& a, vector<V,A2> const& b, const std::size_t m) +{ + + using tensor_type = tensor<V,F,A1>; + using extents_type = typename tensor_type::extents_type; + using ebase_type = typename extents_type::base_type; + using value_type = typename tensor_type::value_type; + using size_type = typename extents_type::value_type; + + auto const p = std::size_t(a.rank()); + + if( m == 0) + throw std::length_error("error in boost::numeric::ublas::prod(ttv): contraction mode must be greater than zero."); + + if( p < m ) + throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than or equal to the modus."); + + if( p == 0) + throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than zero."); + + if( a.empty() ) + throw std::length_error("error in boost::numeric::ublas::prod(ttv): first argument tensor should not be empty."); + + if( b.size() == 0) + throw std::length_error("error in boost::numeric::ublas::prod(ttv): second argument vector should not be empty."); + + + auto nc = ebase_type(std::max(p-1, size_type(2)) , size_type(1)); + auto nb = ebase_type{b.size(),1}; + + + for(auto i = 0u, j = 0u; i < p; ++i) + if(i != m-1) + nc[j++] = a.extents().at(i); + + auto c = tensor_type(extents_type(nc),value_type{}); + + auto bb = &(b(0)); + + ttv(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), nb.data()); + + + return c; +} + + + +/** @brief Computes the m-mode tensor-times-matrix product + * + * Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im] + * + * @note calls ublas::ttm + * + * @param[in] a tensor object A with order p + * @param[in] b vector object B + * @param[in] m contraction dimension with 1 <= m <= p + * + * @returns tensor object C with order p, the same storage format and allocator type as A +*/ +template<class V, class F, class A1, class A2> +auto prod(tensor<V,F,A1> const& a, matrix<V,F,A2> const& b, const std::size_t m) +{ + + using tensor_type = tensor<V,F,A1>; + using extents_type = typename tensor_type::extents_type; + using strides_type = typename tensor_type::strides_type; + using value_type = typename tensor_type::value_type; + + + auto const p = a.rank(); + + if( m == 0) + throw std::length_error("error in boost::numeric::ublas::prod(ttm): contraction mode must be greater than zero."); + + if( p < m || m > a.extents().size()) + throw std::length_error("error in boost::numeric::ublas::prod(ttm): rank of the tensor must be greater equal the modus."); + + if( p == 0) + throw std::length_error("error in boost::numeric::ublas::prod(ttm): rank of the tensor must be greater than zero."); + + if( a.empty() ) + throw std::length_error("error in boost::numeric::ublas::prod(ttm): first argument tensor should not be empty."); + + if( b.size1()*b.size2() == 0) + throw std::length_error("error in boost::numeric::ublas::prod(ttm): second argument matrix should not be empty."); + + + auto nc = a.extents().base(); + auto nb = extents_type {b.size1(),b.size2()}; + auto wb = strides_type (nb); + + nc[m-1] = nb[0]; + + auto c = tensor_type(extents_type(nc),value_type{}); + + auto bb = &(b(0,0)); + + ttm(m, p, + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + bb, nb.data(), wb.data()); + + + return c; +} + + + + +/** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phia[x]] = nb[phib[x]] for 1 <= x <= q + * + * @param[in] phia one-based permutation tuple of length q for the first input tensor a + * @param[in] phib one-based permutation tuple of length q for the second input tensor b + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @result tensor with order r+s +*/ +template<class V, class F, class A1, class A2> +auto prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b, + std::vector<std::size_t> const& phia, std::vector<std::size_t> const& phib) +{ + + using tensor_type = tensor<V,F,A1>; + using extents_type = typename tensor_type::extents_type; + using value_type = typename tensor_type::value_type; + using size_type = typename extents_type::value_type; + + auto const pa = a.rank(); + auto const pb = b.rank(); + + auto const q = size_type(phia.size()); + + if(pa == 0ul) + throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0."); + if(pb == 0ul) + throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0."); + if(pa < q) + throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor."); + if(pb < q) + throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor."); + + if(q != phib.size()) + throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length."); + + if(pa < phia.size()) + throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order."); + if(pb < phib.size()) + throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order."); + + + auto const& na = a.extents(); + auto const& nb = b.extents(); + + for(auto i = 0ul; i < q; ++i) + if( na.at(phia.at(i)-1) != nb.at(phib.at(i)-1)) + throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct."); + + auto const r = pa - q; + auto const s = pb - q; + + + std::vector<std::size_t> phia1(pa), phib1(pb); + std::iota(phia1.begin(), phia1.end(), 1ul); + std::iota(phib1.begin(), phib1.end(), 1ul); + + std::vector<std::size_t> nc( std::max ( r+s , size_type(2) ), size_type(1) ); + + for(auto i = 0ul; i < phia.size(); ++i) + * std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i); + + //phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ; + + assert(phia1.size() == pa); + + for(auto i = 0ul; i < r; ++i) + nc[ i ] = na[ phia1[ i ] - 1 ]; + + for(auto i = 0ul; i < phib.size(); ++i) + * std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i) ; + //phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ; + + assert(phib1.size() == pb); + + for(auto i = 0ul; i < s; ++i) + nc[ r + i ] = nb[ phib1[ i ] - 1 ]; + + // std::copy( phib.begin(), phib.end(), phib1.end() ); + + assert( phia1.size() == pa ); + assert( phib1.size() == pb ); + + auto c = tensor_type(extents_type(nc), value_type{}); + + ttt(pa, pb, q, + phia1.data(), phib1.data(), + c.data(), c.extents().data(), c.strides().data(), + a.data(), a.extents().data(), a.strides().data(), + b.data(), b.extents().data(), b.strides().data()); + + return c; +} + +//template<class V, class F, class A1, class A2, std::size_t N, std::size_t M> +//auto operator*( tensor_index<V,F,A1,N> const& lhs, tensor_index<V,F,A2,M> const& rhs) + + + + +/** @brief Computes the q-mode tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls ublas::ttt + * + * na[phi[x]] = nb[phi[x]] for 1 <= x <= q + * + * @param[in] phi one-based permutation tuple of length q for bot input tensors + * @param[in] a left-hand side tensor with order r+q + * @param[in] b right-hand side tensor with order s+q + * @result tensor with order r+s +*/ +template<class V, class F, class A1, class A2> +auto prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b, + std::vector<std::size_t> const& phi) +{ + return prod(a, b, phi, phi); +} + + +/** @brief Computes the inner product of two tensors + * + * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp]) + * + * @note calls inner function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns a value type. +*/ +template<class V, class F, class A1, class A2> +auto inner_prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b) +{ + using value_type = typename tensor<V,F,A1>::value_type; + + if( a.rank() != b.rank() ) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same."); + + if( a.empty() || b.empty()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty."); + + if( a.extents() != b.extents()) + throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same."); + + return inner(a.rank(), a.extents().data(), + a.data(), a.strides().data(), + b.data(), b.strides().data(), value_type{0}); +} + +/** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls outer function + * + * @param[in] a tensor object A + * @param[in] b tensor object B + * + * @returns tensor object C with the same storage format F and allocator type A1 +*/ +template<class V, class F, class A1, class A2> +auto outer_prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b) +{ + using tensor_type = tensor<V,F,A1>; + using extents_type = typename tensor_type::extents_type; + + if( a.empty() || b.empty() ) + throw std::runtime_error("error in boost::numeric::ublas::outer_prod: tensors should not be empty."); + + auto nc = typename extents_type::base_type(a.rank() + b.rank()); + for(auto i = 0u; i < a.rank(); ++i) + nc.at(i) = a.extents().at(i); + + for(auto i = 0u; i < b.rank(); ++i) + nc.at(a.rank()+i) = b.extents().at(i); + + auto c = tensor_type(extents_type(nc)); + + outer(c.data(), c.rank(), c.extents().data(), c.strides().data(), + a.data(), a.rank(), a.extents().data(), a.strides().data(), + b.data(), b.rank(), b.extents().data(), b.strides().data()); + + return c; +} + + + +/** @brief Transposes a tensor according to a permutation tuple + * + * Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip] + * + * @note calls trans function + * + * @param[in] a tensor object of rank p + * @param[in] tau one-based permutation tuple of length p + * @returns a transposed tensor object with the same storage format F and allocator type A +*/ +template<class V, class F, class A> +auto trans(tensor<V,F,A> const& a, std::vector<std::size_t> const& tau) +{ + using tensor_type = tensor<V,F,A>; + using extents_type = typename tensor_type::extents_type; + // using strides_type = typename tensor_type::strides_type; + + if( a.empty() ) + return tensor<V,F,A>{}; + + auto const p = a.rank(); + auto const& na = a.extents(); + + auto nc = typename extents_type::base_type (p); + for(auto i = 0u; i < p; ++i) + nc.at(tau.at(i)-1) = na.at(i); + + // auto wc = strides_type(extents_type(nc)); + + auto c = tensor_type(extents_type(nc)); + + + trans( a.rank(), a.extents().data(), tau.data(), + c.data(), c.strides().data(), + a.data(), a.strides().data()); + + // auto wc_pi = typename strides_type::base_type (p); + // for(auto i = 0u; i < p; ++i) + // wc_pi.at(tau.at(i)-1) = c.strides().at(i); + + + //copy(a.rank(), + // a.extents().data(), + // c.data(), wc_pi.data(), + // a.data(), a.strides().data() ); + + return c; +} + +/** @brief Computes the frobenius norm of a tensor expression + * + * @note evaluates the tensor expression and calls the accumulate function + * + * + * Implements the two-norm with + * k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 ) + * + * @param[in] a tensor object of rank p + * @returns the frobenius norm of the tensor +*/ +//template<class V, class F, class A> +//auto norm(tensor<V,F,A> const& a) +template<class T, class D> +auto norm(detail::tensor_expression<T,D> const& expr) +{ + + using tensor_type = typename detail::tensor_expression<T,D>::tensor_type; + using value_type = typename tensor_type::value_type; + + auto a = tensor_type( expr ); + + if( a.empty() ) + throw std::runtime_error("error in boost::numeric::ublas::norm: tensors should not be empty."); + + return std::sqrt( accumulate( a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{}, + [](auto const& l, auto const& r){ return l + r*r; } ) ) ; +} + + + +/** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression +*/ +template<class T, class D> +auto real(detail::tensor_expression<T,D> const& expr) { + return detail::make_unary_tensor_expression<T> (expr(), [] (auto const& l) { return std::real( l ); } ); +} + +/** @brief Extract the real component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression +*/ +template<class V, class F, class A, class D> +auto real(detail::tensor_expression<tensor<std::complex<V>,F,A>,D> const& expr) +{ + using tensor_complex_type = tensor<std::complex<V>,F,A>; + using tensor_type = tensor<V,F,typename storage_traits<A>::template rebind<V>>; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_complex_type( expr ); + auto c = tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } ); + + return c; +} + + +/** @brief Extract the imaginary component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression +*/ +template<class T, class D> +auto imag(detail::tensor_expression<T,D> const& lhs) { + return detail::make_unary_tensor_expression<T> (lhs(), [] (auto const& l) { return std::imag( l ); } ); +} + + +/** @brief Extract the imag component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression +*/ +template<class V, class A, class F, class D> +auto imag(detail::tensor_expression<tensor<std::complex<V>,F,A>,D> const& expr) +{ + using tensor_complex_type = tensor<std::complex<V>,F,A>; + using tensor_type = tensor<V,F,typename storage_traits<A>::template rebind<V>>; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty."); + + auto a = tensor_complex_type( expr ); + auto c = tensor_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } ); + + return c; +} + +/** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] expr tensor expression + * @returns complex tensor +*/ +template<class T, class D> +auto conj(detail::tensor_expression<T,D> const& expr) +{ + using tensor_type = T; + using value_type = typename tensor_type::value_type; + using layout_type = typename tensor_type::layout_type; + using array_type = typename tensor_type::array_type; + + using new_value_type = std::complex<value_type>; + using new_array_type = typename storage_traits<array_type>::template rebind<new_value_type>; + + using tensor_complex_type = tensor<new_value_type,layout_type, new_array_type>; + + if( detail::retrieve_extents( expr ).empty() ) + throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty."); + + auto a = tensor_type( expr ); + auto c = tensor_complex_type( a.extents() ); + + std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } ); + + return c; +} + + +/** @brief Computes the complex conjugate component of tensor elements within a tensor expression + * + * @param[in] lhs tensor expression + * @returns unary tensor expression +*/ +template<class V, class A, class F, class D> +auto conj(detail::tensor_expression<tensor<std::complex<V>,F,A>,D> const& expr) +{ + return detail::make_unary_tensor_expression<tensor<std::complex<V>,F,A>> (expr(), [] (auto const& l) { return std::conj( l ); } ); +} + + + +} +} +} + + +#endif diff --git a/boost/numeric/ublas/tensor/index.hpp b/boost/numeric/ublas/tensor/index.hpp new file mode 100644 index 0000000000..a8a40deb85 --- /dev/null +++ b/boost/numeric/ublas/tensor/index.hpp @@ -0,0 +1,89 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_INDEX_HPP +#define BOOST_UBLAS_TENSOR_INDEX_HPP + + +#include <cstddef> +#include <array> +#include <vector> + +namespace boost { +namespace numeric { +namespace ublas { +namespace index { + +/** @brief Proxy template class for the einstein summation notation + * + * @note index::index_type<K> for 0<=K<=16 is used in tensor::operator() + * + * @tparam I wrapped integer +*/ +template<std::size_t I> +struct index_type +{ + static constexpr std::size_t value = I; + + constexpr bool operator == (std::size_t other) const { return value == other; } + constexpr bool operator != (std::size_t other) const { return value != other; } + + template <std::size_t K> + constexpr bool operator == (index_type<K> /*other*/) const { return I==K; } + template <std::size_t K> + constexpr bool operator != (index_type<K> /*other*/) const { return I!=K; } + + constexpr bool operator == (index_type /*other*/) const { return true; } + constexpr bool operator != (index_type /*other*/) const { return false; } + + constexpr std::size_t operator()() const { return I; } +}; + +/** @brief Proxy classes for the einstein summation notation + * + * @note index::_a ... index::_z is used in tensor::operator() +*/ + +static constexpr index_type< 0> _; +static constexpr index_type< 1> _a; +static constexpr index_type< 2> _b; +static constexpr index_type< 3> _c; +static constexpr index_type< 4> _d; +static constexpr index_type< 5> _e; +static constexpr index_type< 6> _f; +static constexpr index_type< 7> _g; +static constexpr index_type< 8> _h; +static constexpr index_type< 9> _i; +static constexpr index_type<10> _j; +static constexpr index_type<11> _k; +static constexpr index_type<12> _l; +static constexpr index_type<13> _m; +static constexpr index_type<14> _n; +static constexpr index_type<15> _o; +static constexpr index_type<16> _p; +static constexpr index_type<17> _q; +static constexpr index_type<18> _r; +static constexpr index_type<19> _s; +static constexpr index_type<20> _t; +static constexpr index_type<21> _u; +static constexpr index_type<22> _v; +static constexpr index_type<23> _w; +static constexpr index_type<24> _x; +static constexpr index_type<25> _y; +static constexpr index_type<26> _z; + +} // namespace indices + +} +} +} + +#endif // _BOOST_UBLAS_TENSOR_INDEX_HPP_ diff --git a/boost/numeric/ublas/tensor/multi_index.hpp b/boost/numeric/ublas/tensor/multi_index.hpp new file mode 100644 index 0000000000..3cc86e2fdf --- /dev/null +++ b/boost/numeric/ublas/tensor/multi_index.hpp @@ -0,0 +1,110 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_MULTI_INDEX_HPP +#define BOOST_UBLAS_TENSOR_MULTI_INDEX_HPP + + +#include <cstddef> +#include <array> +#include <vector> + +#include "multi_index_utility.hpp" + +namespace boost { +namespace numeric { +namespace ublas { +namespace index { + +template<std::size_t I> +struct index_type; + +} // namespace indices +} +} +} + + +namespace boost { +namespace numeric { +namespace ublas { + +/** @brief Proxy class for the einstein summation notation + * + * Denotes an array of index_type types ::_a for 0<=K<=16 is used in tensor::operator() +*/ +template<std::size_t N> +class multi_index +{ +public: + multi_index() = delete; + + template<std::size_t I, class ... indexes> + constexpr multi_index(index::index_type<I> const& i, indexes ... is ) + : _base{i(), is()... } + { + static_assert( sizeof...(is)+1 == N, + "Static assert in boost::numeric::ublas::multi_index: number of constructor arguments is not equal to the template parameter." ); + + static_assert( valid_multi_index<std::tuple<index::index_type<I>, indexes ...> >::value, + "Static assert in boost::numeric::ublas::multi_index: indexes occur twice in multi-index." ); + } + + multi_index(multi_index const& other) + : _base(other._base) + { + } + + multi_index& operator=(multi_index const& other) + { + this->_base = other._base; + return *this; + } + + ~multi_index() = default; + + auto const& base() const { return _base; } + constexpr auto size() const { return _base.size(); } + constexpr auto at(std::size_t i) const { return _base.at(i); } + constexpr auto operator[](std::size_t i) const { return _base.at(i); } + +private: + std::array<std::size_t, N> _base; +}; + +template<std::size_t K, std::size_t N> +constexpr auto get(multi_index<N> const& m) { return std::get<K>(m.base()); } + +template<std::size_t M, std::size_t N> +auto array_to_vector(multi_index<M> const& lhs, multi_index<N> const& rhs) +{ + using vtype = std::vector<std::size_t>; + + auto pair_of_vector = std::make_pair( vtype {}, vtype{} ); + + for(auto i = 0u; i < N; ++i) + for(auto j = 0u; j < M; ++j) + if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_()) + pair_of_vector.first .push_back( i+1 ), + pair_of_vector.second.push_back( j+1 ); + + return pair_of_vector; +} + + + + + +} // namespace ublas +} // namespace numeric +} // namespace boost + +#endif // MULTI_INDEX_HPP diff --git a/boost/numeric/ublas/tensor/multi_index_utility.hpp b/boost/numeric/ublas/tensor/multi_index_utility.hpp new file mode 100644 index 0000000000..f04c0e8672 --- /dev/null +++ b/boost/numeric/ublas/tensor/multi_index_utility.hpp @@ -0,0 +1,364 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP +#define BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP + + +#include <tuple> +#include <type_traits> + + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + + +template<class ... index_types> +struct has_index_impl; + +template<class itype_left, class itype_right> +struct has_index_impl<itype_left, itype_right> +{ + static constexpr bool value = itype_left::value == itype_right::value; +}; + +template<class itype_left> +struct has_index_impl <itype_left, std::tuple<> > +{ + static constexpr bool value = false; +}; + +template<class itype_left, class itype_right> +struct has_index_impl <itype_left, std::tuple<itype_right> > +{ + static constexpr bool value = has_index_impl<itype_left,itype_right>::value; +}; + +template<class itype_left, class itype_right, class ... index_types> +struct has_index_impl <itype_left, std::tuple<itype_right, index_types...> > +{ + using next_type = has_index_impl<itype_left, std::tuple<index_types...>>; + static constexpr bool value = has_index_impl<itype_left,itype_right>::value || next_type::value; +}; +} // namespace detail + + + +/** @brief has_index is true if index occurs once or more in a multi-index + * + * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type + * + * @code auto has_index_value = has_index<index_type<1>, std::tuple<index_type<2>,index_type<1>> >::value; @endcode + * + * @tparam index_type type of index + * @tparam tuple_type type of std::tuple representing a multi-index +*/ +template<class index_type, class tuple_type> +struct has_index +{ + static constexpr bool value = detail::has_index_impl<std::decay_t<index_type>,std::decay_t<tuple_type>>::value; +}; + +} // namespace ublas +} // namespace numeric +} // namespace boost + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + + +template<class ... index_types> +struct valid_multi_index_impl; + +template<> +struct valid_multi_index_impl<std::tuple<>> +{ + static constexpr bool value = true; +}; + +template<class itype> +struct valid_multi_index_impl<std::tuple<itype>> +{ + static constexpr bool value = true; +}; + + +template<class itype, class ... index_types> +struct valid_multi_index_impl<std::tuple<itype,index_types...>> +{ + using ttype = std::tuple<index_types...>; + using has_index_type = has_index<itype, ttype>; + + static constexpr bool is_index_zero = itype::value==0ul; + static constexpr bool has_index_value = has_index_type::value && !is_index_zero; + static constexpr bool value = !has_index_value && valid_multi_index_impl<ttype>::value; +}; +} // namespace detail + +/** @brief valid_multi_index is true if indexes occur only once in a multi-index + * + * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type + * + * @code auto valid = valid_multi_index< std::tuple<index_type<2>,index_type<1>> >::value; + * @endcode + * + * @tparam tuple_type type of std::tuple representing a multi-index +*/ +template<class tupe_type> +struct valid_multi_index +{ + static constexpr bool value = detail::valid_multi_index_impl<std::decay_t<tupe_type>>::value; +}; + +} // namespace ublas +} // namespace numeric +} // namespace boost + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + +template<class ... index_types > +struct number_equal_indexes_impl; + +template<class ... itypes_right > +struct number_equal_indexes_impl < std::tuple<>, std::tuple<itypes_right...>> +{ + static constexpr unsigned value = 0; +}; + +template<class itype, class ... itypes_left, class ... itypes_right> +struct number_equal_indexes_impl < std::tuple<itype,itypes_left...>, std::tuple<itypes_right...>> +{ + using tuple_right = std::tuple<itypes_right...>; + using has_index_type = has_index<itype, tuple_right>; + + static constexpr bool is_index_zero = itype::value==0ul; + static constexpr bool has_index_value = has_index_type::value && !is_index_zero; + + using next_type = number_equal_indexes_impl< std::tuple<itypes_left...>, tuple_right >; + static constexpr unsigned v = has_index_value ? 1 : 0; + static constexpr unsigned value = v + next_type::value; +}; +} // namespace detail + + +/** @brief number_equal_indexes contains the number of equal indexes of two multi-indexes + * + * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type + * + * + * @code auto num = number_equal_indexes< + * std::tuple<index_type<2>,index_type<1>>, + * std::tuple<index_type<1>,index_type<3>> >::value; + * @endcode + * + * @tparam tuple_type_left type of left std::tuple representing a multi-index + * @tparam tuple_type_right type of right std::tuple representing a multi-index +*/ +template<class tuple_left, class tuple_right> +struct number_equal_indexes +{ + static constexpr unsigned value = + detail::number_equal_indexes_impl< std::decay_t<tuple_left>, std::decay_t<tuple_right>>::value; +}; + +} // namespace ublas +} // namespace numeric +} // namespace boost + + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + + +template<std::size_t r, std::size_t m, class itype, class ttype> +struct index_position_impl +{ + static constexpr auto is_same = std::is_same< std::decay_t<itype>, std::decay_t<std::tuple_element_t<r,ttype>> >::value; + static constexpr auto value = is_same ? r : index_position_impl<r+1,m,itype,ttype>::value; +}; + + + +template<std::size_t m, class itype, class ttype> +struct index_position_impl < m, m, itype, ttype> +{ + static constexpr auto value = std::tuple_size<ttype>::value; +}; + +} // namespace detail + + + +/** @brief index_position contains the zero-based index position of an index type within a multi-index + * + * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type + * + * @code auto num = index_position< + * index_type<1>, + * std::tuple<index_type<2>,index_type<1>> >::value; + * @endcode + * + * @returns value returns 0 and N-1 if index_type is found, N otherwise where N is tuple_size_v<tuple_type>. + * + * @tparam index_type type of index + * @tparam tuple_type type of std::tuple that is searched for index +*/ +template<class index_type, class tuple_type> +struct index_position +{ + static constexpr auto value = detail::index_position_impl<0ul,std::tuple_size<tuple_type>::value,std::decay_t<index_type>,std::decay_t<tuple_type>>::value; +}; + +} // namespace ublas +} // namespace numeric +} // namespace boost + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + +template<std::size_t r, std::size_t m> +struct index_position_pairs_impl +{ + template<class array_type, class tuple_left, class tuple_right> + static constexpr void run(array_type& out, tuple_left const& lhs, tuple_right const& rhs, std::size_t p) + { + using index_type = std::tuple_element_t<r-1,tuple_left>; + using has_index_type = has_index<index_type, tuple_right>; + using get_index_type = index_position<index_type,tuple_right>; + using next_type = index_position_pairs_impl<r+1,m>; + if constexpr ( has_index_type::value && index_type::value != 0) + out[p++] = std::make_pair(r-1,get_index_type::value); + next_type::run( out, lhs, rhs, p ); + } +}; + +template<std::size_t m> +struct index_position_pairs_impl<m,m> +{ + template<class array_type, class tuple_left, class tuple_right> + static constexpr void run(array_type& out, tuple_left const& , tuple_right const& , std::size_t p) + { + using index_type = std::tuple_element_t<m-1,tuple_left>; + using has_index_type = has_index<index_type, tuple_right>; + using get_index_type = index_position<index_type, tuple_right>; + if constexpr ( has_index_type::value && index_type::value != 0 ) + out[p] = std::make_pair(m-1,get_index_type::value); + } +}; + +template<std::size_t r> +struct index_position_pairs_impl<r,0> +{ + template<class array_type, class tuple_left, class tuple_right> + static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t) + {} +}; + + +} // namespace detail + + +/** @brief index_position_pairs returns zero-based index positions of matching indexes of two multi-indexes + * + * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type + * + * @code auto pairs = index_position_pairs(std::make_tuple(_a,_b), std::make_tuple(_b,_c)); + * @endcode + * + * @returns a std::array instance containing index position pairs of type std::pair<std::size_t, std::size_t>. + * + * @param lhs left std::tuple instance representing a multi-index + * @param rhs right std::tuple instance representing a multi-index +*/ +template<class tuple_left, class tuple_right> +auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs) +{ + using pair_type = std::pair<std::size_t,std::size_t>; + constexpr auto m = std::tuple_size<tuple_left >::value; + constexpr auto p = number_equal_indexes<tuple_left, tuple_right>::value; + auto array = std::array<pair_type,p>{}; + detail::index_position_pairs_impl<1,m>::run(array, lhs, rhs,0); + return array; +} + +} // namespace ublas +} // namespace numeric +} // namespace boost + +//////////////////////////// +//////////////////////////// +//////////////////////////// +//////////////////////////// + + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + +template<class array_type, std::size_t ... R> +constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence<R...> ) +{ + return std::make_pair( + std::vector<std::size_t>{std::get<0>( std::get<R>(array) )+1 ...} , + std::vector<std::size_t>{std::get<1>( std::get<R>(array) )+1 ...} ); +} + +} // namespace detail + + +/** @brief array_to_vector converts a std::array of zero-based index position pairs into two std::vector of one-based index positions + * + * @code auto two_vectors = array_to_vector(std::make_array ( std::make_pair(1,2), std::make_pair(3,4) ) ) ; + * @endcode + * + * @returns two std::vector of one-based index positions + * + * @param array std::array of zero-based index position pairs +*/ +template<class pair_type, std::size_t N> +constexpr auto array_to_vector( std::array<pair_type,N> const& array) +{ + constexpr auto sequence = std::make_index_sequence<N>{}; + return detail::array_to_vector_impl( array, sequence ); +} + + +} // namespace ublas +} // namespace numeric +} // namespace boost + + +#endif // _BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP_ diff --git a/boost/numeric/ublas/tensor/multiplication.hpp b/boost/numeric/ublas/tensor/multiplication.hpp new file mode 100644 index 0000000000..f415a3e2fa --- /dev/null +++ b/boost/numeric/ublas/tensor/multiplication.hpp @@ -0,0 +1,945 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + + +#ifndef BOOST_UBLAS_TENSOR_MULTIPLICATION +#define BOOST_UBLAS_TENSOR_MULTIPLICATION + +#include <cassert> + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { +namespace recursive { + + +/** @brief Computes the tensor-times-tensor product for q contraction modes + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * nc[x] = na[phia[x] ] for 1 <= x <= r + * nc[r+x] = nb[phib[x] ] for 1 <= x <= s + * na[phia[r+x]] = nb[phib[s+x]] for 1 <= x <= q + * + * @note is used in function ttt + * + * @param k zero-based recursion level starting with 0 + * @param r number of non-contraction indices of A + * @param s number of non-contraction indices of B + * @param q number of contraction indices with q > 0 + * @param phia pointer to the permutation tuple of length q+r for A + * @param phib pointer to the permutation tuple of length q+s for B + * @param c pointer to the output tensor C with rank(A)=r+s + * @param nc pointer to the extents of tensor C + * @param wc pointer to the strides of tensor C + * @param a pointer to the first input tensor with rank(A)=r+q + * @param na pointer to the extents of the first input tensor A + * @param wa pointer to the strides of the first input tensor A + * @param b pointer to the second input tensor B with rank(B)=s+q + * @param nb pointer to the extents of the second input tensor B + * @param wb pointer to the strides of the second input tensor B +*/ + +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttt(SizeType const k, + SizeType const r, SizeType const s, SizeType const q, + SizeType const*const phia, SizeType const*const phib, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + if(k < r) + { + assert(nc[k] == na[phia[k]-1]); + for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) + ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s) + { + assert(nc[k] == nb[phib[k-r]-1]); + for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) + ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s+q-1) + { + assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); + for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) + ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else + { + assert(na[phia[k-s]-1] == nb[phib[k-r]-1]); + for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia) + *c += *a * *b; + } +} + + + + +/** @brief Computes the tensor-times-tensor product for q contraction modes + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note no permutation tuple is used + * + * nc[x] = na[x ] for 1 <= x <= r + * nc[r+x] = nb[x ] for 1 <= x <= s + * na[r+x] = nb[s+x] for 1 <= x <= q + * + * @note is used in function ttt + * + * @param k zero-based recursion level starting with 0 + * @param r number of non-contraction indices of A + * @param s number of non-contraction indices of B + * @param q number of contraction indices with q > 0 + * @param c pointer to the output tensor C with rank(A)=r+s + * @param nc pointer to the extents of tensor C + * @param wc pointer to the strides of tensor C + * @param a pointer to the first input tensor with rank(A)=r+q + * @param na pointer to the extents of the first input tensor A + * @param wa pointer to the strides of the first input tensor A + * @param b pointer to the second input tensor B with rank(B)=s+q + * @param nb pointer to the extents of the second input tensor B + * @param wb pointer to the strides of the second input tensor B +*/ + +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttt(SizeType const k, + SizeType const r, SizeType const s, SizeType const q, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + if(k < r) + { + assert(nc[k] == na[k]); + for(size_t ic = 0u; ic < nc[k]; a += wa[k], c += wc[k], ++ic) + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s) + { + assert(nc[k] == nb[k-r]); + for(size_t ic = 0u; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic) + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s+q-1) + { + assert(na[k-s] == nb[k-r]); + for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) + ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb); + } + else + { + assert(na[k-s] == nb[k-r]); + for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia) + *c += *a * *b; + } +} + + +/** @brief Computes the tensor-times-matrix product for the contraction mode m > 0 + * + * Implements C[i1,i2,...,im-1,j,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * B[j,im]) + * + * @note is used in function ttm + * + * @param m zero-based contraction mode with 0<m<p + * @param r zero-based recursion level starting with p-1 + * @param c pointer to the output tensor + * @param nc pointer to the extents of tensor c + * @param wc pointer to the strides of tensor c + * @param a pointer to the first input tensor + * @param na pointer to the extents of input tensor a + * @param wa pointer to the strides of input tensor a + * @param b pointer to the second input tensor + * @param nb pointer to the extents of input tensor b + * @param wb pointer to the strides of input tensor b +*/ + +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttm(SizeType const m, SizeType const r, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + + if(r == m) { + ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(r == 0){ + for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) { + auto cm = c; + auto b0 = b; + for(auto i0 = 0ul; i0 < nc[m]; cm += wc[m], b0 += wb[0], ++i0){ + auto am = a; + auto b1 = b0; + for(auto i1 = 0ul; i1 < nb[1]; am += wa[m], b1 += wb[1], ++i1) + *cm += *am * *b1; + } + } + } + + else{ + for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) + ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb); + } +} + +/** @brief Computes the tensor-times-matrix product for the contraction mode m = 0 + * + * Implements C[j,i2,...,ip] = sum(A[i1,i2,...,ip] * B[j,i1]) + * + * @note is used in function ttm + * + * @param m zero-based contraction mode with 0<m<p + * @param r zero-based recursion level starting with p-1 + * @param c pointer to the output tensor + * @param nc pointer to the extents of tensor c + * @param wc pointer to the strides of tensor c + * @param a pointer to the first input tensor + * @param na pointer to the extents of input tensor a + * @param wa pointer to the strides of input tensor a + * @param b pointer to the second input tensor + * @param nb pointer to the extents of input tensor b + * @param wb pointer to the strides of input tensor b +*/ +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttm0( SizeType const r, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + + if(r > 1){ + for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i) + ttm0(r-1, c, nc, wc, a, na, wa, b, nb, wb); + } + else{ + for(auto i1 = 0ul; i1 < nc[1]; c += wc[1], a += wa[1], ++i1) { + auto cm = c; + auto b0 = b; + // r == m == 0 + for(auto i0 = 0ul; i0 < nc[0]; cm += wc[0], b0 += wb[0], ++i0){ + + auto am = a; + auto b1 = b0; + for(auto i1 = 0u; i1 < nb[1]; am += wa[0], b1 += wb[1], ++i1){ + + *cm += *am * *b1; + } + } + } + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + + +/** @brief Computes the tensor-times-vector product for the contraction mode m > 0 + * + * Implements C[i1,i2,...,im-1,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * b[im]) + * + * @note is used in function ttv + * + * @param m zero-based contraction mode with 0<m<p + * @param r zero-based recursion level starting with p-1 for tensor A + * @param q zero-based recursion level starting with p-1 for tensor C + * @param c pointer to the output tensor + * @param nc pointer to the extents of tensor c + * @param wc pointer to the strides of tensor c + * @param a pointer to the first input tensor + * @param na pointer to the extents of input tensor a + * @param wa pointer to the strides of input tensor a + * @param b pointer to the second input tensor +*/ + +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttv( SizeType const m, SizeType const r, SizeType const q, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b) +{ + + if(r == m) { + ttv(m, r-1, q, c, nc, wc, a, na, wa, b); + } + else if(r == 0){ + for(auto i0 = 0u; i0 < na[0]; c += wc[0], a += wa[0], ++i0) { + auto c1 = c; auto a1 = a; auto b1 = b; + for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) + *c1 += *a1 * *b1; + } + } + else{ + for(auto i = 0u; i < na[r]; c += wc[q], a += wa[r], ++i) + ttv(m, r-1, q-1, c, nc, wc, a, na, wa, b); + } +} + + +/** @brief Computes the tensor-times-vector product for the contraction mode m = 0 + * + * Implements C[i2,...,ip] = sum(A[i1,...,ip] * b[i1]) + * + * @note is used in function ttv + * + * @param m zero-based contraction mode with m=0 + * @param r zero-based recursion level starting with p-1 + * @param c pointer to the output tensor + * @param nc pointer to the extents of tensor c + * @param wc pointer to the strides of tensor c + * @param a pointer to the first input tensor + * @param na pointer to the extents of input tensor a + * @param wa pointer to the strides of input tensor a + * @param b pointer to the second input tensor +*/ +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttv0(SizeType const r, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b) +{ + + if(r > 1){ + for(auto i = 0u; i < na[r]; c += wc[r-1], a += wa[r], ++i) + ttv0(r-1, c, nc, wc, a, na, wa, b); + } + else{ + for(auto i1 = 0u; i1 < na[1]; c += wc[0], a += wa[1], ++i1) + { + auto c1 = c; auto a1 = a; auto b1 = b; + for(auto i0 = 0u; i0 < na[0]; a1 += wa[0], ++b1, ++i0) + *c1 += *a1 * *b1; + } + } +} + + +/** @brief Computes the matrix-times-vector product + * + * Implements C[i1] = sum(A[i1,i2] * b[i2]) or C[i2] = sum(A[i1,i2] * b[i1]) + * + * @note is used in function ttv + * + * @param[in] m zero-based contraction mode with m=0 or m=1 + * @param[out] c pointer to the output tensor C + * @param[in] nc pointer to the extents of tensor C + * @param[in] wc pointer to the strides of tensor C + * @param[in] a pointer to the first input tensor A + * @param[in] na pointer to the extents of input tensor A + * @param[in] wa pointer to the strides of input tensor A + * @param[in] b pointer to the second input tensor B +*/ +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void mtv(SizeType const m, + PointerOut c, SizeType const*const , SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b) +{ + // decides whether matrix multiplied with vector or vector multiplied with matrix + const auto o = (m == 0) ? 1 : 0; + + for(auto io = 0u; io < na[o]; c += wc[o], a += wa[o], ++io) { + auto c1 = c; auto a1 = a; auto b1 = b; + for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im) + *c1 += *a1 * *b1; + } +} + + +/** @brief Computes the matrix-times-matrix product + * + * Implements C[i1,i3] = sum(A[i1,i2] * B[i2,i3]) + * + * @note is used in function ttm + * + * @param[out] c pointer to the output tensor C + * @param[in] nc pointer to the extents of tensor C + * @param[in] wc pointer to the strides of tensor C + * @param[in] a pointer to the first input tensor A + * @param[in] na pointer to the extents of input tensor A + * @param[in] wa pointer to the strides of input tensor A + * @param[in] b pointer to the second input tensor B + * @param[in] nb pointer to the extents of input tensor B + * @param[in] wb pointer to the strides of input tensor B +*/ +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void mtm(PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + + // C(i,j) = A(i,k) * B(k,j) + + assert(nc[0] == na[0]); + assert(nc[1] == nb[1]); + assert(na[1] == nb[0]); + + auto cj = c; auto bj = b; + for(auto j = 0u; j < nc[1]; cj += wc[1], bj += wb[1], ++j) { + + auto bk = bj; auto ak = a; + for(auto k = 0u; k < na[1]; ak += wa[1], bk += wb[0], ++k) { + + auto ci = cj; auto ai = ak; + for(auto i = 0u; i < na[0]; ai += wa[0], ci += wc[0], ++i){ + *ci += *ai * *bk; + } + + } + + } +} + + + +/** @brief Computes the inner product of two tensors + * + * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,ip]) + * + * @note is used in function inner + * + * @param r zero-based recursion level starting with p-1 + * @param n pointer to the extents of input or output tensor + * @param a pointer to the first input tensor + * @param wa pointer to the strides of input tensor a + * @param b pointer to the second input tensor + * @param wb pointer to the strides of tensor b + * @param v previously computed value (start with v = 0). + * @return inner product of two tensors. +*/ +template <class PointerIn1, class PointerIn2, class value_t, class SizeType> +value_t inner(SizeType const r, SizeType const*const n, + PointerIn1 a, SizeType const*const wa, + PointerIn2 b, SizeType const*const wb, + value_t v) +{ + if(r == 0) + for(auto i0 = 0u; i0 < n[0]; a += wa[0], b += wb[0], ++i0) + v += *a * *b; + else + for(auto ir = 0u; ir < n[r]; a += wa[r], b += wb[r], ++ir) + v = inner(r-1, n, a, wa, b, wb, v); + return v; +} + + +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void outer_2x2(SizeType const pa, + PointerOut c, SizeType const*const , SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + // assert(rc == 3); + // assert(ra == 1); + // assert(rb == 1); + + for(auto ib1 = 0u; ib1 < nb[1]; b += wb[1], c += wc[pa+1], ++ib1) { + auto c2 = c; + auto b0 = b; + for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) { + const auto b = *b0; + auto c1 = c2; + auto a1 = a; + for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) { + auto a0 = a1; + auto c0 = c1; + for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0) + *c0 = *a0 * b; + } + } + } +} + +/** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note called by outer + * + * + * @param[in] pa number of dimensions (rank) of the first input tensor A with pa > 0 + * + * @param[in] rc recursion level for C that starts with pc-1 + * @param[out] c pointer to the output tensor + * @param[in] nc pointer to the extents of output tensor c + * @param[in] wc pointer to the strides of output tensor c + * + * @param[in] ra recursion level for A that starts with pa-1 + * @param[in] a pointer to the first input tensor + * @param[in] na pointer to the extents of the first input tensor a + * @param[in] wa pointer to the strides of the first input tensor a + * + * @param[in] rb recursion level for B that starts with pb-1 + * @param[in] b pointer to the second input tensor + * @param[in] nb pointer to the extents of the second input tensor b + * @param[in] wb pointer to the strides of the second input tensor b +*/ +template<class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void outer(SizeType const pa, + SizeType const rc, PointerOut c, SizeType const*const nc, SizeType const*const wc, + SizeType const ra, PointerIn1 a, SizeType const*const na, SizeType const*const wa, + SizeType const rb, PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + if(rb > 1) + for(auto ib = 0u; ib < nb[rb]; b += wb[rb], c += wc[rc], ++ib) + outer(pa, rc-1, c, nc, wc, ra, a, na, wa, rb-1, b, nb, wb); + else if(ra > 1) + for(auto ia = 0u; ia < na[ra]; a += wa[ra], c += wc[ra], ++ia) + outer(pa, rc-1, c, nc, wc, ra-1, a, na, wa, rb, b, nb, wb); + else + outer_2x2(pa, c, nc, wc, a, na, wa, b, nb, wb); //assert(ra==1 && rb==1 && rc==3); +} + + + + +/** @brief Computes the outer product with permutation tuples + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir] * B[j1,...,js] ) + * + * nc[x] = na[phia[x]] for 1 <= x <= r + * nc[r+x] = nb[phib[x]] for 1 <= x <= s + * + * @note maybe called by ttt function + * + * @param k zero-based recursion level starting with 0 + * @param r number of non-contraction indices of A + * @param s number of non-contraction indices of B + * @param phia pointer to the permutation tuple of length r for A + * @param phib pointer to the permutation tuple of length s for B + * @param c pointer to the output tensor C with rank(A)=r+s + * @param nc pointer to the extents of tensor C + * @param wc pointer to the strides of tensor C + * @param a pointer to the first input tensor with rank(A)=r + * @param na pointer to the extents of the first input tensor A + * @param wa pointer to the strides of the first input tensor A + * @param b pointer to the second input tensor B with rank(B)=s + * @param nb pointer to the extents of the second input tensor B + * @param wb pointer to the strides of the second input tensor B +*/ + +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void outer(SizeType const k, + SizeType const r, SizeType const s, + SizeType const*const phia, SizeType const*const phib, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + if(k < r) + { + assert(nc[k] == na[phia[k]-1]); + for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic) + outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else if(k < r+s-1) + { + assert(nc[k] == nb[phib[k-r]-1]); + for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) + outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb); + } + else + { + assert(nc[k] == nb[phib[k-r]-1]); + for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic) + *c = *a * *b; + } +} + + +} // namespace recursive +} // namespace detail +} // namespace ublas +} // namespace numeric +} // namespace boost + + + + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + + +#include <stdexcept> + +namespace boost { +namespace numeric { +namespace ublas { + +/** @brief Computes the tensor-times-vector product + * + * Implements + * C[i1,i2,...,im-1,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * b[im]) for m>1 and + * C[i2,...,ip] = sum(A[i1,...,ip] * b[i1]) for m=1 + * + * @note calls detail::ttv, detail::ttv0 or detail::mtv + * + * @param[in] m contraction mode with 0 < m <= p + * @param[in] p number of dimensions (rank) of the first input tensor with p > 0 + * @param[out] c pointer to the output tensor with rank p-1 + * @param[in] nc pointer to the extents of tensor c + * @param[in] wc pointer to the strides of tensor c + * @param[in] a pointer to the first input tensor + * @param[in] na pointer to the extents of input tensor a + * @param[in] wa pointer to the strides of input tensor a + * @param[in] b pointer to the second input tensor + * @param[in] nb pointer to the extents of input tensor b + * @param[in] wb pointer to the strides of input tensor b +*/ +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void ttv(SizeType const m, SizeType const p, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + const PointerIn1 a, SizeType const*const na, SizeType const*const wa, + const PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value, + "Static error in boost::numeric::ublas::ttv: Argument types for pointers are not pointer types."); + + if( m == 0) + throw std::length_error("Error in boost::numeric::ublas::ttv: Contraction mode must be greater than zero."); + + if( p < m ) + throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater equal the modus."); + + if( p == 0) + throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater than zero."); + + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttv: Pointers shall not be null pointers."); + + for(auto i = 0u; i < m-1; ++i) + if(na[i] != nc[i]) + throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); + + for(auto i = m; i < p; ++i) + if(na[i] != nc[i-1]) + throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal."); + + const auto max = std::max(nb[0], nb[1]); + if( na[m-1] != max) + throw std::length_error("Error in boost::numeric::ublas::ttv: Extent of dimension mode of A and b must be equal."); + + + if((m != 1) && (p > 2)) + detail::recursive::ttv(m-1, p-1, p-2, c, nc, wc, a, na, wa, b); + else if ((m == 1) && (p > 2)) + detail::recursive::ttv0(p-1, c, nc, wc, a, na, wa, b); + else if( p == 2 ) + detail::recursive::mtv(m-1, c, nc, wc, a, na, wa, b); + else /*if( p == 1 )*/{ + auto v = std::remove_pointer_t<std::remove_cv_t<PointerOut>>{}; + *c = detail::recursive::inner(SizeType(0), na, a, wa, b, wb, v); + } + +} + + + +/** @brief Computes the tensor-times-matrix product + * + * Implements + * C[i1,i2,...,im-1,j,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * B[j,im]) for m>1 and + * C[j,i2,...,ip] = sum(A[i1,i2,...,ip] * B[j,i1]) for m=1 + * + * @note calls detail::ttm or detail::ttm0 + * + * @param[in] m contraction mode with 0 < m <= p + * @param[in] p number of dimensions (rank) of the first input tensor with p > 0 + * @param[out] c pointer to the output tensor with rank p-1 + * @param[in] nc pointer to the extents of tensor c + * @param[in] wc pointer to the strides of tensor c + * @param[in] a pointer to the first input tensor + * @param[in] na pointer to the extents of input tensor a + * @param[in] wa pointer to the strides of input tensor a + * @param[in] b pointer to the second input tensor + * @param[in] nb pointer to the extents of input tensor b + * @param[in] wb pointer to the strides of input tensor b +*/ + +template <class PointerIn1, class PointerIn2, class PointerOut, class SizeType> +void ttm(SizeType const m, SizeType const p, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + const PointerIn1 a, SizeType const*const na, SizeType const*const wa, + const PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + + if( m == 0 ) + throw std::length_error("Error in boost::numeric::ublas::ttm: Contraction mode must be greater than zero."); + + if( p < m ) + throw std::length_error("Error in boost::numeric::ublas::ttm: Rank must be greater equal than the specified mode."); + + if( p == 0) + throw std::length_error("Error in boost::numeric::ublas::ttm:Rank must be greater than zero."); + + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + + for(auto i = 0u; i < m-1; ++i) + if(na[i] != nc[i]) + throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); + + for(auto i = m; i < p; ++i) + if(na[i] != nc[i]) + throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal."); + + if(na[m-1] != nb[1]) + throw std::length_error("Error in boost::numeric::ublas::ttm: 2nd Extent of B and M-th Extent of A must be the equal."); + + if(nc[m-1] != nb[0]) + throw std::length_error("Error in boost::numeric::ublas::ttm: 1nd Extent of B and M-th Extent of C must be the equal."); + + if ( m != 1 ) + detail::recursive::ttm (m-1, p-1, c, nc, wc, a, na, wa, b, nb, wb); + else /*if (m == 1 && p > 2)*/ + detail::recursive::ttm0( p-1, c, nc, wc, a, na, wa, b, nb, wb); + +} + + +/** @brief Computes the tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls detail::recursive::ttt or ttm or ttv or inner or outer + * + * nc[x] = na[phia[x] ] for 1 <= x <= r + * nc[r+x] = nb[phib[x] ] for 1 <= x <= s + * na[phia[r+x]] = nb[phib[s+x]] for 1 <= x <= q + * + * @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0 + * @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0 + * @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0 + * @param[in] phia pointer to a permutation tuple for the first input tensor a + * @param[in] phib pointer to a permutation tuple for the second input tensor b + * @param[out] c pointer to the output tensor with rank p-1 + * @param[in] nc pointer to the extents of tensor c + * @param[in] wc pointer to the strides of tensor c + * @param[in] a pointer to the first input tensor + * @param[in] na pointer to the extents of input tensor a + * @param[in] wa pointer to the strides of input tensor a + * @param[in] b pointer to the second input tensor + * @param[in] nb pointer to the extents of input tensor b + * @param[in] wb pointer to the strides of input tensor b +*/ + +template <class PointerIn1, class PointerIn2, class PointerOut, class SizeType> +void ttt(SizeType const pa, SizeType const pb, SizeType const q, + SizeType const*const phia, SizeType const*const phib, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + + if( pa == 0 || pb == 0) + throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); + + if( q > pa && q > pb) + throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); + + + SizeType const r = pa - q; + SizeType const s = pb - q; + + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + + for(auto i = 0ul; i < r; ++i) + if( na[phia[i]-1] != nc[i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); + + for(auto i = 0ul; i < s; ++i) + if( nb[phib[i]-1] != nc[r+i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); + + for(auto i = 0ul; i < q; ++i) + if( nb[phib[s+i]-1] != na[phia[r+i]-1] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); + + + if(q == 0ul) + detail::recursive::outer(SizeType{0},r,s, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); + else + detail::recursive::ttt(SizeType{0},r,s,q, phia,phib, c,nc,wc, a,na,wa, b,nb,wb); +} + + + +/** @brief Computes the tensor-times-tensor product + * + * Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] ) + * + * @note calls detail::recursive::ttt or ttm or ttv or inner or outer + * + * nc[x] = na[x ] for 1 <= x <= r + * nc[r+x] = nb[x ] for 1 <= x <= s + * na[r+x] = nb[s+x] for 1 <= x <= q + * + * @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0 + * @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0 + * @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0 + * @param[out] c pointer to the output tensor with rank p-1 + * @param[in] nc pointer to the extents of tensor c + * @param[in] wc pointer to the strides of tensor c + * @param[in] a pointer to the first input tensor + * @param[in] na pointer to the extents of input tensor a + * @param[in] wa pointer to the strides of input tensor a + * @param[in] b pointer to the second input tensor + * @param[in] nb pointer to the extents of input tensor b + * @param[in] wb pointer to the strides of input tensor b +*/ + +template <class PointerIn1, class PointerIn2, class PointerOut, class SizeType> +void ttt(SizeType const pa, SizeType const pb, SizeType const q, + PointerOut c, SizeType const*const nc, SizeType const*const wc, + PointerIn1 a, SizeType const*const na, SizeType const*const wa, + PointerIn2 b, SizeType const*const nb, SizeType const*const wb) +{ + static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value, + "Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types."); + + if( pa == 0 || pb == 0) + throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero."); + + if( q > pa && q > pb) + throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order."); + + + SizeType const r = pa - q; + SizeType const s = pb - q; + SizeType const pc = r+s; + + if(c == nullptr || a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers."); + + for(auto i = 0ul; i < r; ++i) + if( na[i] != nc[i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct."); + + for(auto i = 0ul; i < s; ++i) + if( nb[i] != nc[r+i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct."); + + for(auto i = 0ul; i < q; ++i) + if( nb[s+i] != na[r+i] ) + throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct."); + + using value_type = std::decay_t<decltype(*c)>; + + + + if(q == 0ul) + detail::recursive::outer(pa, pc-1, c,nc,wc, pa-1, a,na,wa, pb-1, b,nb,wb); + else if(r == 0ul && s == 0ul) + *c = detail::recursive::inner(q-1, na, a,wa, b,wb, value_type(0) ); + else + detail::recursive::ttt(SizeType{0},r,s,q, c,nc,wc, a,na,wa, b,nb,wb); +} + + +/** @brief Computes the inner product of two tensors + * + * Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,ip]) + * + * @note calls detail::inner + * + * @param[in] p number of dimensions (rank) of the first input tensor with p > 0 + * @param[in] n pointer to the extents of input or output tensor + * @param[in] a pointer to the first input tensor + * @param[in] wa pointer to the strides of input tensor a + * @param[in] b pointer to the second input tensor + * @param[in] wb pointer to the strides of input tensor b + * @param[in] v inital value + * + * @return inner product of two tensors. +*/ +template <class PointerIn1, class PointerIn2, class value_t, class SizeType> +auto inner(const SizeType p, SizeType const*const n, + const PointerIn1 a, SizeType const*const wa, + const PointerIn2 b, SizeType const*const wb, + value_t v) +{ + static_assert( std::is_pointer<PointerIn1>::value && std::is_pointer<PointerIn2>::value, + "Static error in boost::numeric::ublas::inner: Argument types for pointers must be pointer types."); + if(p<2) + throw std::length_error("Error in boost::numeric::ublas::inner: Rank must be greater than zero."); + if(a == nullptr || b == nullptr) + throw std::length_error("Error in boost::numeric::ublas::inner: Pointers shall not be null pointers."); + + return detail::recursive::inner(p-1, n, a, wa, b, wb, v); + +} + + +/** @brief Computes the outer product of two tensors + * + * Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq] + * + * @note calls detail::outer + * + * @param[out] c pointer to the output tensor + * @param[in] pc number of dimensions (rank) of the output tensor c with pc > 0 + * @param[in] nc pointer to the extents of output tensor c + * @param[in] wc pointer to the strides of output tensor c + * @param[in] a pointer to the first input tensor + * @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0 + * @param[in] na pointer to the extents of the first input tensor a + * @param[in] wa pointer to the strides of the first input tensor a + * @param[in] b pointer to the second input tensor + * @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0 + * @param[in] nb pointer to the extents of the second input tensor b + * @param[in] wb pointer to the strides of the second input tensor b +*/ +template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType> +void outer(PointerOut c, SizeType const pc, SizeType const*const nc, SizeType const*const wc, + const PointerIn1 a, SizeType const pa, SizeType const*const na, SizeType const*const wa, + const PointerIn2 b, SizeType const pb, SizeType const*const nb, SizeType const*const wb) +{ + static_assert( std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value & std::is_pointer<PointerOut>::value, + "Static error in boost::numeric::ublas::outer: argument types for pointers must be pointer types."); + if(pa < 2u || pb < 2u) + throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs and rhs tensor must be equal or greater than two."); + if((pa + pb) != pc) + throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs plus rhs tensor must be equal to the number of extents of C."); + if(a == nullptr || b == nullptr || c == nullptr) + throw std::length_error("Error in boost::numeric::ublas::outer: pointers shall not be null pointers."); + + detail::recursive::outer(pa, pc-1, c, nc, wc, pa-1, a, na, wa, pb-1, b, nb, wb); + +} + + + + +} +} +} + +#endif diff --git a/boost/numeric/ublas/tensor/operators_arithmetic.hpp b/boost/numeric/ublas/tensor/operators_arithmetic.hpp new file mode 100644 index 0000000000..c9de6d30c6 --- /dev/null +++ b/boost/numeric/ublas/tensor/operators_arithmetic.hpp @@ -0,0 +1,244 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_OPERATORS_ARITHMETIC_HPP +#define BOOST_UBLAS_TENSOR_OPERATORS_ARITHMETIC_HPP + +#include "expression.hpp" +#include "expression_evaluation.hpp" +#include "multi_index_utility.hpp" +#include "functions.hpp" + +#include <type_traits> +#include <functional> +#include <algorithm> + +namespace boost{ +namespace numeric{ +namespace ublas { + + +template<class element_type, class storage_format, class storage_type> +class tensor; + +template<class E> +class matrix_expression; + + +template<class E> +class vector_expression; + +} +} +} + +#define FIRST_ORDER_OPERATOR_RIGHT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \ +template<class T, class L, class R> \ +auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L <T,L> const& lhs, boost::numeric::ublas:: EXPR_TYPE_R <R> const& rhs) { \ + return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), \ + [](auto const& l, auto const& r){ return l OP r; }); \ +} \ + +FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , vector_expression) +FIRST_ORDER_OPERATOR_RIGHT (+, detail:: tensor_expression , vector_expression) +FIRST_ORDER_OPERATOR_RIGHT (-, detail:: tensor_expression , vector_expression) +FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , vector_expression) + +FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , matrix_expression) +FIRST_ORDER_OPERATOR_RIGHT (+, detail:: tensor_expression , matrix_expression) +FIRST_ORDER_OPERATOR_RIGHT (-, detail:: tensor_expression , matrix_expression) +FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , matrix_expression) + + +#define FIRST_ORDER_OPERATOR_LEFT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \ +template<class T, class L, class R> \ +auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L <L> const& lhs, boost::numeric::ublas:: EXPR_TYPE_R <T,R> const& rhs) { \ + return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), \ + [](auto const& l, auto const& r){ return l OP r; }); \ +} \ + +FIRST_ORDER_OPERATOR_LEFT (*, vector_expression, detail:: tensor_expression) +FIRST_ORDER_OPERATOR_LEFT (+, vector_expression, detail:: tensor_expression) +FIRST_ORDER_OPERATOR_LEFT (-, vector_expression, detail:: tensor_expression) +FIRST_ORDER_OPERATOR_LEFT (/, vector_expression, detail:: tensor_expression) + +FIRST_ORDER_OPERATOR_LEFT (*, matrix_expression, detail:: tensor_expression) +FIRST_ORDER_OPERATOR_LEFT (+, matrix_expression, detail:: tensor_expression) +FIRST_ORDER_OPERATOR_LEFT (-, matrix_expression, detail:: tensor_expression) +FIRST_ORDER_OPERATOR_LEFT (/, matrix_expression, detail:: tensor_expression) + + + + +template<class T, class L, class R> +auto operator+( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; }); +} +template<class T, class L, class R> +auto operator-( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l - r; }); +// return boost::numeric::ublas::detail::make_lambda<T>([&lhs,&rhs](std::size_t i){ return lhs(i) - rhs(i);}); +} +template<class T, class L, class R> +auto operator*( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; }); +} +template<class T, class L, class R> +auto operator/( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l / r; }); +} + + +// Overloaded Arithmetic Operators with Scalars +template<class T, class R> +auto operator+(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs + r; }); + //return boost::numeric::ublas::detail::make_lambda<T>( [&lhs,&rhs](std::size_t i) {return lhs + rhs(i); } ); +} +template<class T, class R> +auto operator-(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs - r; }); +} +template<class T, class R> +auto operator*(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs * r; }); +} +template<class T, class R> +auto operator/(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs / r; }); +} + + +template<class T, class L> +auto operator+(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l + rhs; } ); +} +template<class T, class L> +auto operator-(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l - rhs; } ); +} +template<class T, class L> +auto operator*(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l * rhs; } ); +} +template<class T, class L> +auto operator/(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l / rhs; } ); +} + + + +template<class T, class D> +auto& operator += (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) { + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } ); + return lhs; +} + +template<class T, class D> +auto& operator -= (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) { + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } ); + return lhs; +} + +template<class T, class D> +auto& operator *= (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) { + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } ); + return lhs; +} + +template<class T, class D> +auto& operator /= (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) { + boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } ); + return lhs; +} + + + + +template<class E, class F, class A> +auto& operator += (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) { + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } ); + return lhs; +} + +template<class E, class F, class A> +auto& operator -= (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) { + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } ); + return lhs; +} + +template<class E, class F, class A> +auto& operator *= (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) { + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } ); + return lhs; +} + +template<class E, class F, class A> +auto& operator /= (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) { + boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } ); + return lhs; +} + + + + + + +template<class T, class D> +auto const& operator +(const boost::numeric::ublas::detail::tensor_expression<T,D>& lhs) { + return lhs; +} + +template<class T, class D> +auto operator -(boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs) { + return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [] (auto const& l) { return -l; } ); +} + + + + + +/** @brief Performs a tensor contraction, not an elementwise multiplication + * +*/ + +template<class tensor_type_left, class tuple_type_left, class tensor_type_right, class tuple_type_right> +auto operator*( + std::pair< tensor_type_left const&, tuple_type_left > lhs, + std::pair< tensor_type_right const&, tuple_type_right > rhs) +{ + + using namespace boost::numeric::ublas; + + auto const& tensor_left = lhs.first; + auto const& tensor_right = rhs.first; + + auto multi_index_left = lhs.second; + auto multi_index_right = rhs.second; + + static constexpr auto num_equal_ind = number_equal_indexes<tuple_type_left, tuple_type_right>::value; + + if constexpr ( num_equal_ind == 0 ){ + return tensor_left * tensor_right; + } + else if constexpr ( num_equal_ind==std::tuple_size<tuple_type_left>::value && std::is_same<tuple_type_left, tuple_type_right>::value ){ + + return boost::numeric::ublas::inner_prod( tensor_left, tensor_right ); + } + else { + auto array_index_pairs = index_position_pairs(multi_index_left,multi_index_right); + auto index_pairs = array_to_vector( array_index_pairs ); + return boost::numeric::ublas::prod( tensor_left, tensor_right, index_pairs.first, index_pairs.second ); + } + +} + +#endif diff --git a/boost/numeric/ublas/tensor/operators_comparison.hpp b/boost/numeric/ublas/tensor/operators_comparison.hpp new file mode 100644 index 0000000000..e54b47af49 --- /dev/null +++ b/boost/numeric/ublas/tensor/operators_comparison.hpp @@ -0,0 +1,175 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP +#define BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP + +#include <boost/numeric/ublas/tensor/expression.hpp> +#include <boost/numeric/ublas/tensor/expression_evaluation.hpp> +#include <type_traits> +#include <functional> + +namespace boost::numeric::ublas { +template<class element_type, class storage_format, class storage_type> +class tensor; +} + +namespace boost::numeric::ublas::detail { + +template<class T, class F, class A, class BinaryPred> +bool compare(tensor<T,F,A> const& lhs, tensor<T,F,A> const& rhs, BinaryPred pred) +{ + + if(lhs.extents() != rhs.extents()){ + if constexpr(!std::is_same<BinaryPred,std::equal_to<>>::value && !std::is_same<BinaryPred,std::not_equal_to<>>::value) + throw std::runtime_error("Error in boost::numeric::ublas::detail::compare: cannot compare tensors with different shapes."); + else + return false; + } + + if constexpr(std::is_same<BinaryPred,std::greater<>>::value || std::is_same<BinaryPred,std::less<>>::value) + if(lhs.empty()) + return false; + + for(auto i = 0u; i < lhs.size(); ++i) + if(!pred(lhs(i), rhs(i))) + return false; + return true; +} + +template<class T, class F, class A, class UnaryPred> +bool compare(tensor<T,F,A> const& rhs, UnaryPred pred) +{ + for(auto i = 0u; i < rhs.size(); ++i) + if(!pred(rhs(i))) + return false; + return true; +} + + +template<class T, class L, class R, class BinaryPred> +bool compare(tensor_expression<T,L> const& lhs, tensor_expression<T,R> const& rhs, BinaryPred pred) +{ + constexpr bool lhs_is_tensor = std::is_same<T,L>::value; + constexpr bool rhs_is_tensor = std::is_same<T,R>::value; + + if constexpr (lhs_is_tensor && rhs_is_tensor) + return compare(static_cast<T const&>( lhs ), static_cast<T const&>( rhs ), pred); + else if constexpr (lhs_is_tensor && !rhs_is_tensor) + return compare(static_cast<T const&>( lhs ), T( rhs ), pred); + else if constexpr (!lhs_is_tensor && rhs_is_tensor) + return compare(T( lhs ), static_cast<T const&>( rhs ), pred); + else + return compare(T( lhs ), T( rhs ), pred); + +} + +template<class T, class D, class UnaryPred> +bool compare(tensor_expression<T,D> const& expr, UnaryPred pred) +{ + if constexpr (std::is_same<T,D>::value) + return compare(static_cast<T const&>( expr ), pred); + else + return compare(T( expr ), pred); +} + +} + + +template<class T, class L, class R> +bool operator==( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, + boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::equal_to<>{} ); +} +template<class T, class L, class R> +auto operator!=(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, + boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::not_equal_to<>{} ); +} +template<class T, class L, class R> +auto operator< ( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, + boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::less<>{} ); +} +template<class T, class L, class R> +auto operator<=( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, + boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::less_equal<>{} ); +} +template<class T, class L, class R> +auto operator> ( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, + boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater<>{} ); +} +template<class T, class L, class R> +auto operator>=( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, + boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) { + return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater_equal<>{} ); +} + + + + + +template<class T, class D> +bool operator==( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs == r; } ); +} +template<class T, class D> +auto operator!=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs != r; } ); +} +template<class T, class D> +auto operator< ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs < r; } ); +} +template<class T, class D> +auto operator<=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs <= r; } ); +} +template<class T, class D> +auto operator> ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs > r; } ); +} +template<class T, class D> +auto operator>=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) { + return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs >= r; } ); +} + + + +template<class T, class D> +bool operator==( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l == rhs; } ); +} +template<class T, class D> +auto operator!=( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l != rhs; } ); +} +template<class T, class D> +auto operator< ( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l < rhs; } ); +} +template<class T, class D> +auto operator<=( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l <= rhs; } ); +} +template<class T, class D> +auto operator> ( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l > rhs; } ); +} +template<class T, class D> +auto operator>=( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) { + return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l >= rhs; } ); +} + + +#endif diff --git a/boost/numeric/ublas/tensor/ostream.hpp b/boost/numeric/ublas/tensor/ostream.hpp new file mode 100644 index 0000000000..74ee77ea63 --- /dev/null +++ b/boost/numeric/ublas/tensor/ostream.hpp @@ -0,0 +1,122 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// + +#ifndef BOOST_UBLAS_TENSOR_OSTREAM_HPP +#define BOOST_UBLAS_TENSOR_OSTREAM_HPP + +#include <ostream> +#include <complex> + +namespace boost { +namespace numeric { +namespace ublas { +namespace detail { + +template <class value_type> +void print(std::ostream& out, value_type const& p) +{ + out << p << " "; +} + +template <class value_type> +void print(std::ostream& out, const std::complex<value_type>& p) +{ + out << std::real(p) << "+" << std::imag(p) << "i "; +} + + +template <class size_type, class value_type> +void print(std::ostream& out, size_type r, const value_type* p, const size_type* w, const size_type* n) +{ + + if(r < 2) + { + out << "[ ... " << std::endl; + + for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column + { + auto p1 = p; + for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row + { + print(out,*p1); + } + if(row < n[0]-1) + out << "; " << std::endl; + } + out << "]"; + } + else + { + out << "cat("<< r+1 <<",..." << std::endl; + for(auto d = 0u; d < n[r]-1; p += w[r], ++d){ + print(out, r-1, p, w, n); + out << ",..." << std::endl; + } + print(out, r-1, p, w, n); + } + if(r>1) + out << ")"; +} + +//////////////////////////// + + +} +} +} +} + + +namespace boost { +namespace numeric { +namespace ublas { + +template<class T, class F, class A> +class tensor; + +template<class T, class F, class A> +class matrix; + +template<class T, class A> +class vector; + +} +} +} + + +template <class V, class F, class A> +std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor<V,F,A> const& t) +{ + + if(t.extents().is_scalar()){ + out << '['; + boost::numeric::ublas::detail::print(out,t[0]); + out << ']'; + } + else if(t.extents().is_vector()) { + const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ','; + out << '['; + for(auto i = 0u; i < t.size()-1; ++i){ + boost::numeric::ublas::detail::print(out,t[i]); + out << cat << ' '; + } + boost::numeric::ublas::detail::print(out,t[t.size()-1]); + out << ']'; + } + else{ + boost::numeric::ublas::detail::print(out, t.rank()-1, t.data(), t.strides().data(), t.extents().data()); + } + return out; +} + + +#endif diff --git a/boost/numeric/ublas/tensor/storage_traits.hpp b/boost/numeric/ublas/tensor/storage_traits.hpp new file mode 100644 index 0000000000..52840e9684 --- /dev/null +++ b/boost/numeric/ublas/tensor/storage_traits.hpp @@ -0,0 +1,84 @@ +// +// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen Germany +// + + +#ifndef _BOOST_STORAGE_TRAITS_HPP_ +#define _BOOST_STORAGE_TRAITS_HPP_ + +#include <vector> +#include <array> + +namespace boost { +namespace numeric { +namespace ublas { + + +template <class A> +struct storage_traits; + + +template <class V, class A> +struct storage_traits<std::vector<V,A>> +{ + using array_type = std::vector<V,A>; + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + template<class U> + using rebind = std::vector<U, typename std::allocator_traits<A>::template rebind_alloc<U>>; +}; + + +template <class V, std::size_t N> +struct storage_traits<std::array<V,N>> +{ + using array_type = std::array<V,N>; + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + template<class U> + using rebind = std::array<U,N>; +}; + +} // ublas +} // numeric +} // boost + + +#endif // _BOOST_STORAGE_TRAITS_HPP_ diff --git a/boost/numeric/ublas/tensor/strides.hpp b/boost/numeric/ublas/tensor/strides.hpp new file mode 100644 index 0000000000..53de553bb7 --- /dev/null +++ b/boost/numeric/ublas/tensor/strides.hpp @@ -0,0 +1,251 @@ +// +// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer IOSB, Ettlingen, Germany +// +/// \file strides.hpp Definition for the basic_strides template class + + +#ifndef BOOST_UBLAS_TENSOR_STRIDES_HPP +#define BOOST_UBLAS_TENSOR_STRIDES_HPP + +#include <vector> +#include <limits> +#include <numeric> +#include <stdexcept> +#include <initializer_list> +#include <algorithm> +#include <cassert> + +#include <boost/numeric/ublas/functional.hpp> + +namespace boost { +namespace numeric { +namespace ublas { + +using first_order = column_major; +using last_order = row_major; + +template<class T> +class basic_extents; + + +/** @brief Template class for storing tensor strides for iteration with runtime variable size. + * + * Proxy template class of std::vector<int_type>. + * + */ +template<class __int_type, class __layout> +class basic_strides +{ +public: + + using base_type = std::vector<__int_type>; + + static_assert( std::numeric_limits<typename base_type::value_type>::is_integer, + "Static error in boost::numeric::ublas::basic_strides: type must be of type integer."); + static_assert(!std::numeric_limits<typename base_type::value_type>::is_signed, + "Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer."); + static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value, + "Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order"); + + + using layout_type = __layout; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using size_type = typename base_type::size_type; + using const_pointer = typename base_type::const_pointer; + using const_iterator = typename base_type::const_iterator; + + + /** @brief Default constructs basic_strides + * + * @code auto ex = basic_strides<unsigned>{}; + */ + constexpr explicit basic_strides() + : _base{} + { + } + + /** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats + * + * @code auto strides = basic_strides<unsigned>( basic_extents<std::size_t>{2,3,4} ); + * + */ + template <class T> + basic_strides(basic_extents<T> const& s) + : _base(s.size(),1) + { + if(s.empty()) + return; + + if(!s.valid()) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid."); + + if(s.is_vector() || s.is_scalar()) + return; + + if(this->size() < 2) + throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2."); + + + if constexpr (std::is_same<layout_type,first_order>::value){ + size_type k = 1ul, kend = this->size(); + for(; k < kend; ++k) + _base[k] = _base[k-1] * s[k-1]; + } + else { + size_type k = this->size()-2, kend = 0ul; + for(; k > kend; --k) + _base[k] = _base[k+1] * s[k+1]; + _base[0] = _base[1] * s[1]; + } + } + + basic_strides(basic_strides const& l) + : _base(l._base) + {} + + basic_strides(basic_strides && l ) + : _base(std::move(l._base)) + {} + + basic_strides(base_type const& l ) + : _base(l) + {} + + basic_strides(base_type && l ) + : _base(std::move(l)) + {} + + ~basic_strides() = default; + + + basic_strides& operator=(basic_strides other) + { + swap (*this, other); + return *this; + } + + friend void swap(basic_strides& lhs, basic_strides& rhs) { + std::swap(lhs._base , rhs._base); + } + + const_reference operator[] (size_type p) const{ + return _base[p]; + } + + const_pointer data() const{ + return _base.data(); + } + + const_reference at (size_type p) const{ + return _base.at(p); + } + + + bool empty() const{ + return _base.empty(); + } + + size_type size() const{ + return _base.size(); + } + + template<class other_layout> + bool operator == (basic_strides<value_type, other_layout> const& b) const{ + return b.base() == this->base(); + } + + template<class other_layout> + bool operator != (basic_strides<value_type, other_layout> const& b) const{ + return b.base() != this->base(); + } + + bool operator == (basic_strides const& b) const{ + return b._base == _base; + } + + bool operator != (basic_strides const& b) const{ + return b._base != _base; + } + + const_iterator begin() const{ + return _base.begin(); + } + + const_iterator end() const{ + return _base.end(); + } + + void clear() { + this->_base.clear(); + } + + base_type const& base() const{ + return this->_base; + } + + +protected: + base_type _base; +}; + +template<class layout_type> +using strides = basic_strides<std::size_t, layout_type>; + +namespace detail { + + +/** @brief Returns relative memory index with respect to a multi-index + * + * @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode + * + * @param[in] i multi-index of length p + * @param[in] w stride vector of length p + * @returns relative memory location depending on \c i and \c w +*/ +BOOST_UBLAS_INLINE +template<class size_type, class layout_type> +auto access(std::vector<size_type> const& i, basic_strides<size_type,layout_type> const& w) +{ + const auto p = i.size(); + size_type sum = 0u; + for(auto r = 0u; r < p; ++r) + sum += i[r]*w[r]; + return sum; +} + +/** @brief Returns relative memory index with respect to a multi-index + * + * @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode + * + * @param[in] i first element of the partial multi-index + * @param[in] is the following elements of the partial multi-index + * @param[in] sum the current relative memory index + * @returns relative memory location depending on \c i and \c w +*/ +BOOST_UBLAS_INLINE +template<std::size_t r, class layout_type, class ... size_types> +auto access(std::size_t sum, basic_strides<std::size_t, layout_type> const& w, std::size_t i, size_types ... is) +{ + sum+=i*w[r]; + if constexpr (sizeof...(is) == 0) + return sum; + else + return detail::access<r+1>(sum,w,std::forward<size_types>(is)...); +} + +} + +} +} +} + +#endif diff --git a/boost/numeric/ublas/tensor/tensor.hpp b/boost/numeric/ublas/tensor/tensor.hpp new file mode 100644 index 0000000000..ea4521c29e --- /dev/null +++ b/boost/numeric/ublas/tensor/tensor.hpp @@ -0,0 +1,734 @@ +// Copyright (c) 2018-2019 +// Cem Bassoy +// +// 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) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + +/// \file tensor.hpp Definition for the tensor template class + +#ifndef BOOST_UBLAS_TENSOR_IMPL_HPP +#define BOOST_UBLAS_TENSOR_IMPL_HPP + +#include <boost/config.hpp> + +#include <initializer_list> + +#include "algorithms.hpp" +#include "expression.hpp" +#include "expression_evaluation.hpp" +#include "extents.hpp" +#include "strides.hpp" +#include "index.hpp" + +namespace boost { namespace numeric { namespace ublas { + +template<class T, class F, class A> +class tensor; + +template<class T, class F, class A> +class matrix; + +template<class T, class A> +class vector; + +///** \brief Base class for Tensor container models +// * +// * it does not model the Tensor concept but all derived types should. +// * The class defines a common base type and some common interface for all +// * statically derived Tensor classes +// * We implement the casts to the statically derived type. +// */ +//template<class C> +//class tensor_container: +// public detail::tensor_expression<C> +//{ +//public: +// static const unsigned complexity = 0; +// typedef C container_type; +// typedef tensor_tag type_category; + +// BOOST_UBLAS_INLINE +// const container_type &operator () () const { +// return *static_cast<const container_type *> (this); +// } +// BOOST_UBLAS_INLINE +// container_type &operator () () { +// return *static_cast<container_type *> (this); +// } +//}; + + + +/** @brief A dense tensor of values of type \c T. + * + * For a \f$n\f$-dimensional tensor \f$v\f$ and \f$0\leq i < n\f$ every element \f$v_i\f$ is mapped + * to the \f$i\f$-th element of the container. A storage type \c A can be specified which defaults to \c unbounded_array. + * Elements are constructed by \c A, which need not initialise their value. + * + * @tparam T type of the objects stored in the tensor (like int, double, complex,...) + * @tparam A The type of the storage array of the tensor. Default is \c unbounded_array<T>. \c <bounded_array<T> and \c std::vector<T> can also be used + */ +template<class T, class F = first_order, class A = std::vector<T,std::allocator<T>> > +class tensor: + public detail::tensor_expression<tensor<T, F, A>,tensor<T, F, A>> +{ + + static_assert( std::is_same<F,first_order>::value || + std::is_same<F,last_order >::value, "boost::numeric::tensor template class only supports first- or last-order storage formats."); + + using self_type = tensor<T, F, A>; +public: + + + + template<class derived_type> + using tensor_expression_type = detail::tensor_expression<self_type,derived_type>; + + template<class derived_type> + using matrix_expression_type = matrix_expression<derived_type>; + + template<class derived_type> + using vector_expression_type = vector_expression<derived_type>; + + using super_type = tensor_expression_type<self_type>; + +// static_assert(std::is_same_v<tensor_expression_type<self_type>, detail::tensor_expression<tensor<T,F,A>,tensor<T,F,A>>>, "tensor_expression_type<self_type>"); + + using array_type = A; + using layout_type = F; + + + using size_type = typename array_type::size_type; + using difference_type = typename array_type::difference_type; + using value_type = typename array_type::value_type; + + using reference = typename array_type::reference; + using const_reference = typename array_type::const_reference; + + using pointer = typename array_type::pointer; + using const_pointer = typename array_type::const_pointer; + + using iterator = typename array_type::iterator; + using const_iterator = typename array_type::const_iterator; + + using reverse_iterator = typename array_type::reverse_iterator; + using const_reverse_iterator = typename array_type::const_reverse_iterator; + + using tensor_temporary_type = self_type; + using storage_category = dense_tag; + + using strides_type = basic_strides<std::size_t,layout_type>; + using extents_type = shape; + + using matrix_type = matrix<value_type,layout_type,array_type>; + using vector_type = vector<value_type,array_type>; + + + /** @brief Constructs a tensor. + * + * @note the tensor is empty. + * @note the tensor needs to reshaped for further use. + * + */ + BOOST_UBLAS_INLINE + constexpr tensor () + : tensor_expression_type<self_type>() // container_type + , extents_() + , strides_() + , data_() + { + } + + + /** @brief Constructs a tensor with an initializer list + * + * By default, its elements are initialized to 0. + * + * @code tensor<float> A{4,2,3}; @endcode + * + * @param l initializer list for setting the dimension extents of the tensor + */ + explicit BOOST_UBLAS_INLINE + tensor (std::initializer_list<size_type> l) + : tensor_expression_type<self_type>() + , extents_ (std::move(l)) + , strides_ (extents_) + , data_ (extents_.product()) + { + } + + + /** @brief Constructs a tensor with a \c shape + * + * By default, its elements are initialized to 0. + * + * @code tensor<float> A{extents{4,2,3}}; @endcode + * + * @param s initial tensor dimension extents + */ + explicit BOOST_UBLAS_INLINE + tensor (extents_type const& s) + : tensor_expression_type<self_type>() //tensor_container<self_type>() + , extents_ (s) + , strides_ (extents_) + , data_ (extents_.product()) + {} + + + /** @brief Constructs a tensor with a \c shape and initiates it with one-dimensional data + * + * @code tensor<float> A{extents{4,2,3}, array }; @endcode + * + * + * @param s initial tensor dimension extents + * @param a container of \c array_type that is copied according to the storage layout + */ + BOOST_UBLAS_INLINE + tensor (extents_type const& s, const array_type &a) + : tensor_expression_type<self_type>() //tensor_container<self_type>() + , extents_ (s) + , strides_ (extents_) + , data_ (a) + { + if(this->extents_.product() != this->data_.size()) + throw std::runtime_error("Error in boost::numeric::ublas::tensor: size of provided data and specified extents do not match."); + } + + + + /** @brief Constructs a tensor using a shape tuple and initiates it with a value. + * + * @code tensor<float> A{extents{4,2,3}, 1 }; @endcode + * + * @param e initial tensor dimension extents + * @param i initial value of all elements of type \c value_type + */ + BOOST_UBLAS_INLINE + tensor (extents_type const& e, const value_type &i) + : tensor_expression_type<self_type>() //tensor_container<self_type> () + , extents_ (e) + , strides_ (extents_) + , data_ (extents_.product(), i) + {} + + + + /** @brief Constructs a tensor from another tensor + * + * @param v tensor to be copied. + */ + BOOST_UBLAS_INLINE + tensor (const tensor &v) + : tensor_expression_type<self_type>() + , extents_ (v.extents_) + , strides_ (v.strides_) + , data_ (v.data_ ) + {} + + + + /** @brief Constructs a tensor from another tensor + * + * @param v tensor to be moved. + */ + BOOST_UBLAS_INLINE + tensor (tensor &&v) + : tensor_expression_type<self_type>() //tensor_container<self_type> () + , extents_ (std::move(v.extents_)) + , strides_ (std::move(v.strides_)) + , data_ (std::move(v.data_ )) + {} + + + /** @brief Constructs a tensor with a matrix + * + * \note Initially the tensor will be two-dimensional. + * + * @param v matrix to be copied. + */ + BOOST_UBLAS_INLINE + tensor (const matrix_type &v) + : tensor_expression_type<self_type>() + , extents_ () + , strides_ () + , data_ (v.data()) + { + if(!data_.empty()){ + extents_ = extents_type{v.size1(),v.size2()}; + strides_ = strides_type(extents_); + } + } + + /** @brief Constructs a tensor with a matrix + * + * \note Initially the tensor will be two-dimensional. + * + * @param v matrix to be moved. + */ + BOOST_UBLAS_INLINE + tensor (matrix_type &&v) + : tensor_expression_type<self_type>() + , extents_ {} + , strides_ {} + , data_ {} + { + if(v.size1()*v.size2() != 0){ + extents_ = extents_type{v.size1(),v.size2()}; + strides_ = strides_type(extents_); + data_ = std::move(v.data()); + } + } + + /** @brief Constructs a tensor using a \c vector + * + * @note It is assumed that vector is column vector + * @note Initially the tensor will be one-dimensional. + * + * @param v vector to be copied. + */ + BOOST_UBLAS_INLINE + tensor (const vector_type &v) + : tensor_expression_type<self_type>() + , extents_ () + , strides_ () + , data_ (v.data()) + { + if(!data_.empty()){ + extents_ = extents_type{data_.size(),1}; + strides_ = strides_type(extents_); + } + } + + /** @brief Constructs a tensor using a \c vector + * + * @param v vector to be moved. + */ + BOOST_UBLAS_INLINE + tensor (vector_type &&v) + : tensor_expression_type<self_type>() + , extents_ {} + , strides_ {} + , data_ {} + { + if(v.size() != 0){ + extents_ = extents_type{v.size(),1}; + strides_ = strides_type(extents_); + data_ = std::move(v.data()); + } + } + + + /** @brief Constructs a tensor with another tensor with a different layout + * + * @param other tensor with a different layout to be copied. + */ + BOOST_UBLAS_INLINE + template<class other_layout> + tensor (const tensor<value_type, other_layout> &other) + : tensor_expression_type<self_type> () + , extents_ (other.extents()) + , strides_ (other.extents()) + , data_ (other.extents().product()) + { + copy(this->rank(), this->extents().data(), + this->data(), this->strides().data(), + other.data(), other.strides().data()); + } + + /** @brief Constructs a tensor with an tensor expression + * + * @code tensor<float> A = B + 3 * C; @endcode + * + * @note type must be specified of tensor must be specified. + * @note dimension extents are extracted from tensors within the expression. + * + * @param expr tensor expression + */ + BOOST_UBLAS_INLINE + template<class derived_type> + tensor (const tensor_expression_type<derived_type> &expr) + : tensor_expression_type<self_type> () + , extents_ ( detail::retrieve_extents(expr) ) + , strides_ ( extents_ ) + , data_ ( extents_.product() ) + { + static_assert( detail::has_tensor_types<self_type, tensor_expression_type<derived_type>>::value, + "Error in boost::numeric::ublas::tensor: expression does not contain a tensor. cannot retrieve shape."); + detail::eval( *this, expr ); + } + + /** @brief Constructs a tensor with a matrix expression + * + * @code tensor<float> A = B + 3 * C; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr matrix expression + */ + BOOST_UBLAS_INLINE + template<class derived_type> + tensor (const matrix_expression_type<derived_type> &expr) + : tensor( matrix_type ( expr ) ) + { + } + + /** @brief Constructs a tensor with a vector expression + * + * @code tensor<float> A = b + 3 * b; @endcode + * + * @note matrix expression is evaluated and pushed into a temporary matrix before assignment. + * @note extents are automatically extracted from the temporary matrix + * + * @param expr vector expression + */ + BOOST_UBLAS_INLINE + template<class derived_type> + tensor (const vector_expression_type<derived_type> &expr) + : tensor( vector_type ( expr ) ) + { + } + + /** @brief Evaluates the tensor_expression and assigns the results to the tensor + * + * @code A = B + C * 2; @endcode + * + * @note rank and dimension extents of the tensors in the expressions must conform with this tensor. + * + * @param expr expression that is evaluated. + */ + BOOST_UBLAS_INLINE + template<class derived_type> + tensor &operator = (const tensor_expression_type<derived_type> &expr) + { + detail::eval(*this, expr); + return *this; + } + + tensor& operator=(tensor other) + { + swap (*this, other); + return *this; + } + + tensor& operator=(const_reference v) + { + std::fill(this->begin(), this->end(), v); + return *this; + } + + /** @brief Returns true if the tensor is empty (\c size==0) */ + BOOST_UBLAS_INLINE + bool empty () const { + return this->data_.empty(); + } + + + /** @brief Returns the size of the tensor */ + BOOST_UBLAS_INLINE + size_type size () const { + return this->data_.size (); + } + + /** @brief Returns the size of the tensor */ + BOOST_UBLAS_INLINE + size_type size (size_type r) const { + return this->extents_.at(r); + } + + /** @brief Returns the number of dimensions/modes of the tensor */ + BOOST_UBLAS_INLINE + size_type rank () const { + return this->extents_.size(); + } + + /** @brief Returns the number of dimensions/modes of the tensor */ + BOOST_UBLAS_INLINE + size_type order () const { + return this->extents_.size(); + } + + /** @brief Returns the strides of the tensor */ + BOOST_UBLAS_INLINE + strides_type const& strides () const { + return this->strides_; + } + + /** @brief Returns the extents of the tensor */ + BOOST_UBLAS_INLINE + extents_type const& extents () const { + return this->extents_; + } + + + /** @brief Returns a \c const reference to the container. */ + BOOST_UBLAS_INLINE + const_pointer data () const { + return this->data_.data(); + } + + /** @brief Returns a \c const reference to the container. */ + BOOST_UBLAS_INLINE + pointer data () { + return this->data_.data(); + } + + /** @brief Element access using a single index. + * + * @code auto a = A[i]; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + BOOST_UBLAS_INLINE + const_reference operator [] (size_type i) const { + return this->data_[i]; + } + + /** @brief Element access using a single index. + * + * + * @code A[i] = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + BOOST_UBLAS_INLINE + reference operator [] (size_type i) + { + return this->data_[i]; + } + + + /** @brief Element access using a multi-index or single-index. + * + * + * @code auto a = A.at(i,j,k); @endcode or + * @code auto a = A.at(i); @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + template<class ... size_types> + BOOST_UBLAS_INLINE + const_reference at (size_type i, size_types ... is) const { + if constexpr (sizeof...(is) == 0) + return this->data_[i]; + else + return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)]; + } + + /** @brief Element access using a multi-index or single-index. + * + * + * @code A.at(i,j,k) = a; @endcode or + * @code A.at(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0) + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + BOOST_UBLAS_INLINE + template<class ... size_types> + reference at (size_type i, size_types ... is) { + if constexpr (sizeof...(is) == 0) + return this->data_[i]; + else + return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)]; + } + + + + + /** @brief Element access using a single index. + * + * + * @code A(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + BOOST_UBLAS_INLINE + const_reference operator()(size_type i) const { + return this->data_[i]; + } + + + /** @brief Element access using a single index. + * + * @code A(i) = a; @endcode + * + * @param i zero-based index where 0 <= i < this->size() + */ + BOOST_UBLAS_INLINE + reference operator()(size_type i){ + return this->data_[i]; + } + + + + + /** @brief Generates a tensor index for tensor contraction + * + * + * @code auto Ai = A(_i,_j,k); @endcode + * + * @param i placeholder + * @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank() + */ + BOOST_UBLAS_INLINE + template<std::size_t I, class ... index_types> + decltype(auto) operator() (index::index_type<I> p, index_types ... ps) const + { + constexpr auto N = sizeof...(ps)+1; + if( N != this->rank() ) + throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank."); + + return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward<index_types>(ps)... ) ); + } + + + + + + /** @brief Reshapes the tensor + * + * + * (1) @code A.reshape(extents{m,n,o}); @endcode or + * (2) @code A.reshape(extents{m,n,o},4); @endcode + * + * If the size of this smaller than the specified extents than + * default constructed (1) or specified (2) value is appended. + * + * @note rank of the tensor might also change. + * + * @param e extents with which the tensor is reshaped. + * @param v value which is appended if the tensor is enlarged. + */ + BOOST_UBLAS_INLINE + void reshape (extents_type const& e, value_type v = value_type{}) + { + this->extents_ = e; + this->strides_ = strides_type(this->extents_); + + if(e.product() != this->size()) + this->data_.resize (this->extents_.product(), v); + } + + + + + + friend void swap(tensor& lhs, tensor& rhs) { + std::swap(lhs.data_ , rhs.data_ ); + std::swap(lhs.extents_, rhs.extents_); + std::swap(lhs.strides_, rhs.strides_); + } + + + /// \brief return an iterator on the first element of the tensor + BOOST_UBLAS_INLINE + const_iterator begin () const { + return data_.begin (); + } + + /// \brief return an iterator on the first element of the tensor + BOOST_UBLAS_INLINE + const_iterator cbegin () const { + return data_.cbegin (); + } + + /// \brief return an iterator after the last element of the tensor + BOOST_UBLAS_INLINE + const_iterator end () const { + return data_.end(); + } + + /// \brief return an iterator after the last element of the tensor + BOOST_UBLAS_INLINE + const_iterator cend () const { + return data_.cend (); + } + + /// \brief Return an iterator on the first element of the tensor + BOOST_UBLAS_INLINE + iterator begin () { + return data_.begin(); + } + + /// \brief Return an iterator at the end of the tensor + BOOST_UBLAS_INLINE + iterator end () { + return data_.end(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) + BOOST_UBLAS_INLINE + const_reverse_iterator rbegin () const { + return data_.rbegin(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) + BOOST_UBLAS_INLINE + const_reverse_iterator crbegin () const { + return data_.crbegin(); + } + + /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) + BOOST_UBLAS_INLINE + const_reverse_iterator rend () const { + return data_.rend(); + } + + /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) + BOOST_UBLAS_INLINE + const_reverse_iterator crend () const { + return data_.crend(); + } + + /// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor) + BOOST_UBLAS_INLINE + reverse_iterator rbegin () { + return data_.rbegin(); + } + + /// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor) + BOOST_UBLAS_INLINE + reverse_iterator rend () { + return data_.rend(); + } + + +#if 0 + // ------------- + // Serialization + // ------------- + + /// Serialize a tensor into and archive as defined in Boost + /// \param ar Archive object. Can be a flat file, an XML file or any other stream + /// \param file_version Optional file version (not yet used) + template<class Archive> + void serialize(Archive & ar, const unsigned int /* file_version */){ + ar & serialization::make_nvp("data",data_); + } +#endif + + + +private: + + extents_type extents_; + strides_type strides_; + array_type data_; +}; + +}}} // namespaces + + + + + +#endif diff --git a/boost/numeric/ublas/traits.hpp b/boost/numeric/ublas/traits.hpp index ecd52cad8f..cc8a050424 100644 --- a/boost/numeric/ublas/traits.hpp +++ b/boost/numeric/ublas/traits.hpp @@ -32,10 +32,17 @@ #include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_unsigned.hpp> #include <boost/mpl/and.hpp> +#include <boost/mpl/if.hpp> +#include <boost/typeof/typeof.hpp> + // anonymous namespace to avoid ADL issues namespace { - template<class T> T boost_numeric_ublas_sqrt (const T& t) { + template<class T> + typename boost::mpl::if_c<boost::is_integral<T>::value, + double, + T>::type + boost_numeric_ublas_sqrt (const T& t) { using namespace std; // we'll find either std::sqrt or else another version via ADL: return sqrt (t); @@ -46,7 +53,8 @@ inline typename boost::disable_if< boost::is_unsigned<T>, T >::type boost_numeric_ublas_abs (const T &t ) { using namespace std; - return abs( t ); + // force a type conversion back to T for char and short types + return static_cast<T>(abs( t )); } template<typename T> @@ -140,24 +148,10 @@ namespace boost { namespace numeric { namespace ublas { return in1 / R (in2); } - // Use Joel de Guzman's return type deduction // uBLAS assumes a common return type for all binary arithmetic operators template<class X, class Y> struct promote_traits { - typedef type_deduction_detail::base_result_of<X, Y> base_type; - static typename base_type::x_type x; - static typename base_type::y_type y; - static const std::size_t size = sizeof ( - type_deduction_detail::test< - typename base_type::x_type - , typename base_type::y_type - >(x + y) // Use x+y to stand of all the arithmetic actions - ); - - static const std::size_t index = (size / sizeof (char)) - 1; - typedef typename mpl::at_c< - typename base_type::types, index>::type id; - typedef typename id::type promote_type; + typedef BOOST_TYPEOF_TPL(X() + Y()) promote_type; }; diff --git a/boost/numeric/ublas/vector.hpp b/boost/numeric/ublas/vector.hpp index c1384c1455..73a387dcd3 100644 --- a/boost/numeric/ublas/vector.hpp +++ b/boost/numeric/ublas/vector.hpp @@ -903,21 +903,14 @@ namespace boost { namespace numeric { namespace ublas { vector_assign<scalar_assign> (*this, ae); } - /// \brief Construct a fixed_vector from a list of values - /// This constructor enables initialization by using any of: - /// fixed_vector<double, 3> v = { 1, 2, 3 } or fixed_vector<double,3> v( {1, 2, 3} ) or fixed_vector<double,3> v( 1, 2, 3 ) -#if defined(BOOST_MSVC) - // This may or may not work. Maybe use this for all instead only for MSVC - template <typename... U> - fixed_vector(U&&... values) : - vector_container<self_type> (), - data_{{ std::forward<U>(values)... }} {} -#else + /// \brief Construct a fixed_vector from a list of values + /// This constructor enables initialization by using any of: + /// fixed_vector<double, 3> v = { 1, 2, 3 } or fixed_vector<double,3> v( {1, 2, 3} ) or fixed_vector<double,3> v( 1, 2, 3 ) template <typename... Types> + BOOST_UBLAS_INLINE fixed_vector(value_type v0, Types... vrest) : vector_container<self_type> (), - data_{ { v0, vrest... } } {} -#endif + data_( array_type{ v0, vrest... } ) {} // ----------------------- // Random Access Container diff --git a/boost/numeric/ublas/vector_expression.hpp b/boost/numeric/ublas/vector_expression.hpp index aebb403b65..6f952a4646 100644 --- a/boost/numeric/ublas/vector_expression.hpp +++ b/boost/numeric/ublas/vector_expression.hpp @@ -739,11 +739,11 @@ namespace boost { namespace numeric { namespace ublas { } BOOST_UBLAS_INLINE value_type dereference (packed_random_access_iterator_tag) const { - value_type t1 = value_type/*zero*/(); + typename E1::value_type t1 = typename E1::value_type/*zero*/(); if (it1_ != it1_end_) if (it1_.index () == i_) t1 = *it1_; - value_type t2 = value_type/*zero*/(); + typename E2::value_type t2 = typename E2::value_type/*zero*/(); if (it2_ != it2_end_) if (it2_.index () == i_) t2 = *it2_; @@ -811,15 +811,15 @@ namespace boost { namespace numeric { namespace ublas { } BOOST_UBLAS_INLINE value_type dereference (sparse_bidirectional_iterator_tag) const { - value_type t1 = value_type/*zero*/(); + typename E1::value_type t1 = typename E1::value_type/*zero*/(); if (it1_ != it1_end_) if (it1_.index () == i_) t1 = *it1_; - value_type t2 = value_type/*zero*/(); + typename E2::value_type t2 = typename E2::value_type/*zero*/(); if (it2_ != it2_end_) if (it2_.index () == i_) t2 = *it2_; - return functor_type::apply (t1, t2); + return static_cast<value_type>(functor_type::apply (t1, t2)); } public: @@ -1235,7 +1235,7 @@ namespace boost { namespace numeric { namespace ublas { // (t * v) [i] = t * v [i] template<class T1, class E2> BOOST_UBLAS_INLINE - typename enable_if< is_convertible<T1, typename E2::value_type >, + typename boost::enable_if< is_convertible<T1, typename E2::value_type >, typename vector_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type >::type operator * (const T1 &e1, @@ -1478,7 +1478,7 @@ namespace boost { namespace numeric { namespace ublas { // (v * t) [i] = v [i] * t template<class E1, class T2> BOOST_UBLAS_INLINE - typename enable_if< is_convertible<T2, typename E1::value_type >, + typename boost::enable_if< is_convertible<T2, typename E1::value_type >, typename vector_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::result_type >::type operator * (const vector_expression<E1> &e1, @@ -1490,7 +1490,7 @@ namespace boost { namespace numeric { namespace ublas { // (v / t) [i] = v [i] / t template<class E1, class T2> BOOST_UBLAS_INLINE - typename enable_if< is_convertible<T2, typename E1::value_type >, + typename boost::enable_if< is_convertible<T2, typename E1::value_type >, typename vector_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::result_type >::type operator / (const vector_expression<E1> &e1, @@ -1609,6 +1609,16 @@ namespace boost { namespace numeric { namespace ublas { return expression_type (e ()); } + // real: norm_2_square v = sum(v [i] * v [i]) + // complex: norm_2_square v = sum(v [i] * conj (v [i])) + template<class E> + BOOST_UBLAS_INLINE + typename vector_scalar_unary_traits<E, vector_norm_2_square<E> >::result_type + norm_2_square (const vector_expression<E> &e) { + typedef typename vector_scalar_unary_traits<E, vector_norm_2_square<E> >::expression_type expression_type; + return expression_type (e ()); + } + // real: norm_inf v = maximum (abs (v [i])) // complex: norm_inf v = maximum (maximum (abs (real (v [i])), abs (imag (v [i])))) template<class E> diff --git a/boost/numeric/ublas/vector_of_vector.hpp b/boost/numeric/ublas/vector_of_vector.hpp index de87a668ac..e18c9a908a 100644 --- a/boost/numeric/ublas/vector_of_vector.hpp +++ b/boost/numeric/ublas/vector_of_vector.hpp @@ -66,7 +66,7 @@ namespace boost { namespace numeric { namespace ublas { storage_invariants (); } BOOST_UBLAS_INLINE - generalized_vector_of_vector (size_type size1, size_type size2, size_type non_zeros = 0): + generalized_vector_of_vector (size_type size1, size_type size2, size_type /*non_zeros = 0*/): matrix_container<self_type> (), size1_ (size1), size2_ (size2), data_ (layout_type::size_M (size1_, size2_) + 1) { const size_type sizeM = layout_type::size_M (size1_, size2_); @@ -84,7 +84,7 @@ namespace boost { namespace numeric { namespace ublas { } template<class AE> BOOST_UBLAS_INLINE - generalized_vector_of_vector (const matrix_expression<AE> &ae, size_type non_zeros = 0): + generalized_vector_of_vector (const matrix_expression<AE> &ae, size_type /*non_zeros = 0*/): matrix_container<self_type> (), size1_ (ae ().size1 ()), size2_ (ae ().size2 ()), data_ (layout_type::size_M (size1_, size2_) + 1) { const size_type sizeM = layout_type::size_M (size1_, size2_); diff --git a/boost/numeric/ublas/vector_sparse.hpp b/boost/numeric/ublas/vector_sparse.hpp index 07c64cbf0e..0a021b063d 100644 --- a/boost/numeric/ublas/vector_sparse.hpp +++ b/boost/numeric/ublas/vector_sparse.hpp @@ -13,6 +13,31 @@ #ifndef _BOOST_UBLAS_VECTOR_SPARSE_ #define _BOOST_UBLAS_VECTOR_SPARSE_ +#include <boost/config.hpp> + +// In debug mode, MSCV enables iterator debugging, which additional checks are +// executed for consistency. So, when two iterators are compared, it is tested +// that they point to elements of the same container. If the check fails, then +// the program is aborted. +// +// When matrices MVOV are traversed by column and then by row, the previous +// check fails. +// +// MVOV::iterator2 iter2 = mvov.begin2(); +// for (; iter2 != mvov.end() ; iter2++) { +// MVOV::iterator1 iter1 = iter2.begin(); +// ..... +// } +// +// These additional checks in iterators are disabled in this file, but their +// status are restored at the end of file. +// https://msdn.microsoft.com/en-us/library/hh697468.aspx +#ifdef BOOST_MSVC +#define _BACKUP_ITERATOR_DEBUG_LEVEL _ITERATOR_DEBUG_LEVEL +#undef _ITERATOR_DEBUG_LEVEL +#define _ITERATOR_DEBUG_LEVEL 0 +#endif + #include <boost/numeric/ublas/storage_sparse.hpp> #include <boost/numeric/ublas/vector_expression.hpp> #include <boost/numeric/ublas/detail/vector_assign.hpp> @@ -372,7 +397,7 @@ namespace boost { namespace numeric { namespace ublas { // Reserving BOOST_UBLAS_INLINE - void reserve (size_type non_zeros = 0, bool preserve = true) { + void reserve (size_type non_zeros, bool /*preserve*/ = true) { detail::map_reserve (data (), restrict_capacity (non_zeros)); } @@ -2212,4 +2237,10 @@ namespace boost { namespace numeric { namespace ublas { }}} +#ifdef BOOST_MSVC +#undef _ITERATOR_DEBUG_LEVEL +#define _ITERATOR_DEBUG_LEVEL _BACKUP_ITERATOR_DEBUG_LEVEL +#undef _BACKUP_ITERATOR_DEBUG_LEVEL +#endif + #endif |