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 vector_binary2:
public vector_expression > {
public:
#ifndef BOOST_UBLAS_NO_PROXY_SHORTCUTS
BOOST_UBLAS_USING vector_expression
::operator ();
#endif
typedef E1 expression1_type;
typedef E2 expression2_type;
typedef F functor_type;
typedef typename promote_traits::promote_type size_type;
typedef typename promote_traits::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 const_self_type;
typedef vector_binary2 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::iterator_category
iterator_category;
typedef indexed_const_iterator 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,
#ifdef BOOST_UBLAS_USE_ITERATOR_BASE_TRAITS
public iterator_base_traits::iterator_category>::template
iterator_base::type {
#else
public random_access_iterator_base::iterator_category,
const_iterator, value_type> {
#endif
public:
typedef typename iterator_restrict_traits::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 (), 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 (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::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_reverse_iterator;
#else
typedef reverse_iterator_base
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
struct vector_binary_traits2 {
typedef vector_binary2 expression_type;
#ifdef BOOST_UBLAS_USE_ET
typedef expression_type result_type;
#else
typedef vector<typename F::result_type> result_type;
#endif
};
template
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
struct cross_3d_elem:
public vector_scalar_binary_functor21::promote_type> {
typedef typename promote_traits::promote_type promote_type;
typedef typename vector_scalar_binary_functor21::size_type size_type ;
typedef typename vector_scalar_binary_functor21::difference_type difference_type;
typedef typename vector_scalar_binary_functor21::value_type value_type;
typedef typename vector_scalar_binary_functor21::result_type result_type;
template
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
BOOST_UBLAS_INLINE
typename vector_binary_traits2
::result_type
cross_3d (const vector_expression<E1> &e1,
const vector_expression<E2> &e2) {
typedef BOOST_UBLAS_TYPENAME vector_binary_traits2 >::expression_type expression_type;
return expression_type (e1 (), e2 ());
}
} /* namespace ublas */
} /* namespace numeric */
} /* namespace boost */
--- In Boost-Users@yahoogroups.com, "dmatt001" 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 ---