Boost logo

Boost Users :

From: dmatt001 (dmatt001_at_[hidden])
Date: 2003-05-26 23:23:57


Inline 3d cross-product evaluation with inlining and no temps!
It is done! Wow.

I had some serious misunderstandings, but by staring at the source
until it made sense I was able to understand the role of element
access and the expression types in producing the inline code.

I now have some follow-up questions.

Why do we use E1::()(i) to access expressions?
How do I lock down the evaluation to when size()==3?

Why are the functors / traits / evaluators named aaa_bbb_9 (eg
vector_scalar_binary2) and follow-on dependencies named in a similar
manner. Couldn't vector_scalar_binary be templated with a functor
evaluation policy?

Kind Regards and Thanks,

Matt

--- Code Follows ---

namespace boost {
  namespace numeric {
    namespace ublas {

      template<class E1, class E2, class F>
      class vector_binary2:
        public vector_expression<vector_binary2<E1, E2, F> > {
        public:
#ifndef BOOST_UBLAS_NO_PROXY_SHORTCUTS
        BOOST_UBLAS_USING vector_expression<vector_binary2<E1, E2, F>
>::operator ();
#endif
        typedef E1 expression1_type;
        typedef E2 expression2_type;
        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 value_type *const_pointer;
        typedef const_pointer pointer;
        typedef typename E1::const_closure_type expression1_closure_type;
        typedef typename E2::const_closure_type expression2_closure_type;
        typedef const vector_binary2<E1, E2, F> const_self_type;
        typedef vector_binary2<E1, E2, F> self_type;
        typedef const_self_type const_closure_type;
        typedef const_closure_type closure_type;
        typedef typename E1::const_iterator const_iterator1_type;
        typedef typename E2::const_iterator const_iterator2_type;
        typedef unknown_storage_tag storage_category;

        // Construction and destruction
        BOOST_UBLAS_INLINE
        vector_binary2 ():
          e1_ (), e2_ () {}
        BOOST_UBLAS_INLINE
        vector_binary2 (const expression1_type &e1, const
expression2_type &e2):
          e1_ (e1), e2_ (e2) {}

        // Accessors
        BOOST_UBLAS_INLINE
        size_type size () const {
          return BOOST_UBLAS_SAME (e1_.size (), e2_.size ());
        }
        BOOST_UBLAS_INLINE
        const expression1_closure_type &expression1 () const {
          return e1_;
        }
        BOOST_UBLAS_INLINE
        const expression2_closure_type &expression2 () const {
          return e2_;
        }

        // Element access
        BOOST_UBLAS_INLINE
        const_reference operator () (size_type i) const {
          return functor_type () (e1_, e2_, i);
        }

        BOOST_UBLAS_INLINE
        const_reference operator [] (size_type i) const {
          return functor_type () (e1_, e2_, i);
        }

#ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
        typedef typename iterator_restrict_traits<typename
const_iterator1_type::iterator_category,
          typename
const_iterator2_type::iterator_category>::iterator_category
iterator_category;
        typedef indexed_const_iterator<const_closure_type,
iterator_category> const_iterator;
        typedef const_iterator iterator;
#else
        class const_iterator;
        typedef const_iterator iterator;
#endif

        // Element lookup
        BOOST_UBLAS_INLINE
        const_iterator find_first (size_type i) const {
          const_iterator1_type it1 (e1_.find_first (i));
          const_iterator1_type it1_end (e1_.find_first (size ()));
          const_iterator2_type it2 (e2_.find_first (i));
          const_iterator2_type it2_end (e2_.find_first (size ()));
          i = std::min (it1 != it1_end ? it1.index () : size (),
            it2 != it2_end ? it2.index () : size ());
#ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
          return const_iterator (*this, i);
#else
          return const_iterator (*this, i, it1, it1_end, it2, it2_end);
#endif
        }
        BOOST_UBLAS_INLINE
        const_iterator find_last (size_type i) const {
          const_iterator1_type it1 (e1_.find_last (i));
          const_iterator1_type it1_end (e1_.find_last (size ()));
          const_iterator2_type it2 (e2_.find_last (i));
          const_iterator2_type it2_end (e2_.find_last (size ()));
          i = std::max (it1 != it1_end ? it1.index () : size (),
            it2 != it2_end ? it2.index () : size ());
#ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
          return const_iterator (*this, i);
#else
          return const_iterator (*this, i, it1, it1_end, it2, it2_end);
#endif
        }

        // Iterator merges the iterators of the referenced expressions and
        // enhances them with the binary functor.

#ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
        class const_iterator:
          public container_const_reference<vector_binary2>,
#ifdef BOOST_UBLAS_USE_ITERATOR_BASE_TRAITS
          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_iterator, value_type>::type {
#else
          public random_access_iterator_base<typename
iterator_restrict_traits<typename E1::const_iterator::iterator_category,
            typename
E2::const_iterator::iterator_category>::iterator_category,
            const_iterator, value_type> {
#endif
          public:
          typedef typename iterator_restrict_traits<typename
E1::const_iterator::iterator_category,
            typename
E2::const_iterator::iterator_category>::iterator_category
iterator_category;
#ifdef BOOST_MSVC_STD_ITERATOR
          typedef const_reference reference;
#else
          typedef typename vector_binary2::difference_type
difference_type;
          typedef typename vector_binary2::value_type value_type;
          typedef typename vector_binary2::const_reference reference;
          typedef typename vector_binary2::const_pointer pointer;
#endif

          // Construction and destruction
          BOOST_UBLAS_INLINE
            const_iterator ():
            container_const_reference<self_type> (), i_ (), it1_ (),
it1_end_ (), it2_ (), it2_end_ () {}
          BOOST_UBLAS_INLINE
            const_iterator (const self_type &vb, size_type i,
              const const_iterator1_type &it1, const
const_iterator1_type &it1_end,
              const const_iterator2_type &it2, const
const_iterator2_type &it2_end):
            container_const_reference<self_type> (vb), i_ (i), it1_
(it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {}

          // 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
            value_type dereference (dense_random_access_iterator_tag)
const {
            return functor_type () (*it1_, *it2_);
          }

          // Packed specializations
          BOOST_UBLAS_INLINE
            void increment (packed_random_access_iterator_tag) {
            if (it1_ != it1_end_)
              if (it1_.index () <= i_)
                ++ it1_;
            if (it2_ != it2_end_)
              if (it2_.index () <= i_)
                ++ it2_;
            ++ i_;
          }
          BOOST_UBLAS_INLINE
            void decrement (packed_random_access_iterator_tag) {
            if (it1_ != it1_end_)
              if (i_ <= it1_.index ())
                -- it1_;
            if (it2_ != it2_end_)
              if (i_ <= it2_.index ())
                -- it2_;
            -- i_;
          }
          BOOST_UBLAS_INLINE
            value_type dereference (packed_random_access_iterator_tag)
const {
            value_type t1 = value_type ();
            if (it1_ != it1_end_)
              if (it1_.index () == i_)
                t1 = *it1_;
            value_type t2 = value_type ();
            if (it2_ != it2_end_)
              if (it2_.index () == i_)
                t2 = *it2_;
            return functor_type () (t1, t2);
          }

          // Sparse specializations
          BOOST_UBLAS_INLINE
            void increment (sparse_bidirectional_iterator_tag) {
            size_type index1 = (*this) ().size ();
            if (it1_ != it1_end_) {
              if (it1_.index () <= i_)
                ++ it1_;
              if (it1_ != it1_end_)
                index1 = it1_.index ();
            }
            size_type index2 = (*this) ().size ();
            if (it2_ != it2_end_) {
              if (it2_.index () <= i_)
                ++ it2_;
              if (it2_ != it2_end_)
                index2 = it2_.index ();
            }
            i_ = std::min (index1, index2);
          }
          BOOST_UBLAS_INLINE
            void decrement (sparse_bidirectional_iterator_tag) {
            size_type index1 = (*this) ().size ();
            if (it1_ != it1_end_) {
              if (i_ <= it1_.index ())
                -- it1_;
              if (it1_ != it1_end_)
                index1 = it1_.index ();
            }
            size_type index2 = (*this) ().size ();
            if (it2_ != it2_end_) {
              if (i_ <= it2_.index ())
                -- it2_;
              if (it2_ != it2_end_)
                index2 = it2_.index ();
            }
            i_ = std::max (index1, index2);
          }
          BOOST_UBLAS_INLINE
            value_type dereference (sparse_bidirectional_iterator_tag)
const {
            value_type t1 = value_type ();
            if (it1_ != it1_end_)
              if (it1_.index () == i_)
                t1 = *it1_;
            value_type t2 = value_type ();
            if (it2_ != it2_end_)
              if (it2_.index () == i_)
                t2 = *it2_;
            return functor_type () (t1, t2);
          }

          // Arithmetic
          BOOST_UBLAS_INLINE
            const_iterator &operator ++ () {
            increment (iterator_category ());
            return *this;
          }
          BOOST_UBLAS_INLINE
            const_iterator &operator -- () {
            decrement (iterator_category ());
            return *this;
          }
          BOOST_UBLAS_INLINE
            const_iterator &operator += (difference_type n) {
            i_ += n, it1_ += n, it2_ += n;
            return *this;
          }
          BOOST_UBLAS_INLINE
            const_iterator &operator -= (difference_type n) {
            i_ -= n, it1_ -= n, it2_ -= n;
            return *this;
          }
          BOOST_UBLAS_INLINE
            difference_type operator - (const const_iterator &it) const {
            BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
            return index () - it.index ();
          }

          // Dereference
          BOOST_UBLAS_INLINE
            reference operator * () const {
            return dereference (iterator_category ());
          }

          // Index
          BOOST_UBLAS_INLINE
            size_type index () const {
            return i_;
          }

          // Assignment
          BOOST_UBLAS_INLINE
            const_iterator &operator = (const const_iterator &it) {
            container_const_reference<self_type>::assign (&it ());
            i_ = it.i_;
            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_iterator &it) const {
            BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
            return index () == it.index ();
          }
          BOOST_UBLAS_INLINE
            bool operator < (const const_iterator &it) const {
            BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
            return index () < it.index ();
          }

          private:
          size_type i_;
          const_iterator1_type it1_;
          const_iterator1_type it1_end_;
          const_iterator2_type it2_;
          const_iterator2_type it2_end_;
        };
#endif

        BOOST_UBLAS_INLINE
        const_iterator begin () const {
        return find_first (0);
        }
        BOOST_UBLAS_INLINE
        const_iterator end () const {
        return find_first (size ());
        }

        // Reverse iterator

#ifdef BOOST_MSVC_STD_ITERATOR
        typedef reverse_iterator_base<const_iterator, value_type,
const_reference> const_reverse_iterator;
#else
        typedef reverse_iterator_base<const_iterator>
const_reverse_iterator;
#endif

        BOOST_UBLAS_INLINE
        const_reverse_iterator rbegin () const {
          return const_reverse_iterator (end ());
        }
        BOOST_UBLAS_INLINE
        const_reverse_iterator rend () const {
          return const_reverse_iterator (begin ());
        }

        private:
        expression1_closure_type e1_;
        expression2_closure_type e2_;
      };

      template<class E1, class E2, class F>
      struct vector_binary_traits2 {
        typedef vector_binary2<E1, E2, F> expression_type;
#ifdef BOOST_UBLAS_USE_ET
        typedef expression_type result_type;
#else
        typedef vector<typename F::result_type> result_type;
#endif
      };

      template<class E1, class E2, class TR>
      struct vector_scalar_binary_functor21 {
        typedef std::size_t size_type;
        typedef std::ptrdiff_t difference_type;
        typedef TR value_type;
        typedef TR result_type;
      };

      template<class E1, class E2>
      struct cross_3d_elem:
        public vector_scalar_binary_functor21<E1, E2,
          typename promote_traits<typename E1::value_type, typename
E2::value_type>::promote_type> {
        typedef typename promote_traits<typename E1::value_type, typename
E2::value_type>::promote_type promote_type;
        typedef typename vector_scalar_binary_functor21<E1, E2,
promote_type>::size_type size_type ;
        typedef typename vector_scalar_binary_functor21<E1, E2,
promote_type>::difference_type difference_type;
        typedef typename vector_scalar_binary_functor21<E1, E2,
promote_type>::value_type value_type;
        typedef typename vector_scalar_binary_functor21<E1, E2,
promote_type>::result_type result_type;

        template<class V1, class V2>
        BOOST_UBLAS_INLINE
        result_type operator () (const vector_expression<V1> &e1,
          const vector_expression<V2> &e2,
          size_type i) const {
          size_type size (BOOST_UBLAS_SAME (e1 ().size (), e2 ().size ()));
          result_type t (e1 () ((1 + i) % 3) * e2 () ((2 + i) % 3) - e2 ()
((1 + i) % 3) * e1 () ((2 + i) % 3));
          return t;
        }
      };

      template<class E1, class E2>
      BOOST_UBLAS_INLINE
        typename vector_binary_traits2<E1, E2, cross_3d_elem<E1, E2>
>::result_type
      cross_3d (const vector_expression<E1> &e1,
        const vector_expression<E2> &e2) {
        typedef BOOST_UBLAS_TYPENAME vector_binary_traits2<E1, E2,
          cross_3d_elem<E1, E2> >::expression_type expression_type;
        return expression_type (e1 (), e2 ());
      }
    } /* namespace ublas */
  } /* namespace numeric */
} /* namespace boost */

--- In Boost-Users_at_[hidden], "dmatt001" <dmatt001_at_y...> wrote:
> Hi Guys,
>
> After a significantly long break from using uBLAS, I have now been
> lucky enough to find myself in a new role where I can again use it!
>
> Having noted that there was no vector cross product in uBLAS, I
> thought I would implement my own. To make it really efficient and work
> in with the other uBLAS features, I thought I would try to make a
> compatible routine that eliminates temporaries and uses the other cool
> uBLAS features. So far so good.
>
> To start, I decided to use a simple case that I could easily check: a
> 3d vector. I also decided to copy some other routines as required to
> get going. For this reason I copied "scalar_plus".
>
> Now that I have written the short piece code, it doesn't quite get
> there. So far not so good. ;-)
>
> I am hoping that a reader please review the short code and output
> below and give some quick pointers about what I can do better...?
> Perhaps I need to get some better knowledge about the relevant tricks
> -- I was hoping to emulate another developer in the first instance.
>
> Thanks,
>
> Matt
>
> --- Code Follows ---
>
> <SNIP -- SNIP -- SNIP>


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net