Re: [eigen] State of eigen support for small integers(16 bit, signed/unsigned)

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


OK, let me try to put all my answers in 1 mail:

2009/8/20 Rohit Garg <rpg.314@xxxxxxxxx>:
> I have been adding stuff for both short and unsigned short so far.
> Mainly because I need right shifts for unsigned shorts, which are
> logical bit shifts, instead of algebraic bit shifts. I turns out that
> there are a few missing intrinsics in sse2, as usual, for signed and
> unsigned stuff. So it will perhaps be easier to just do short instead
> of unsigned short too. There is no unsigned int in eigen for instance.

Feel free to add unsigned int! So far we had no use for it. but I
understand that as one works with shorter int types, the benefit of
unsigned gets bigger, so there's a need for uint8 and uint16, and then
for consistency it makes sense to add uint32.

Especially if you start a new module SmallIntegers, it really doesn't
hurt to add more types.

> But since I need, unsigned shorts, I propose, that we offer both
> algebraic, logical bit shifting as a template parameter option.
> Comments?

I dont have an opinion as I didnt think much about it, just go ahead
with your plans, he who codes decides :)

> Yes, int and short do share an sse type. :(
> Now what?

Now I can see 2 options.

a) you make the packet types like Packet4f be structs containing a
typedef to the standard SSE type --- instead of being that typedef
themselves. In this way, you make sure that they are treated as
different types even if the underlying SSE type is the same.

or:

b) you rework our design here, ei_unpacket_traits doesnt work so you
come up with a design to do without it. That would mean that the
functions that are template only in the packet type and then use
ei_unpacket_traits to find back the scalar type, should be modified to
be template in the scalar type and use ei_packet_traits to find the
packet type.

Perhaps try b first (just my gut feeling) and fall back to a if it
gets too cumbersome.

>There is a Functors.h in both array and core. I looked at both. The
>array one provides a EIGEN_FUNCTOR_PLUGIN. But I dont know how to put
>it to use. Suggestions?

at the moment it escapes me why EIGEN_FUNCTOR_PLUGIN is needed and i
don't understand the comment there anymore :(

Let's explain.

Binary shifting is an operation that applies to every coeff of a
single matrix. That is what we call a "coefficient-wise unary
operation". Since such expressions share a lot of generic code, we
unified them in a CwiseUnaryOp class. See Core/CwiseUnaryOp.h. That
class is template in the matrix type (to which the operation is
applied) and also in another type describing the operation : that is
called the functor type. Whenever you want to add another such
operation, all you need to do is:
1) add the corresponding functor
2) add a specialization of ei_functor_traits for this functor
3) expose this operation in class MatrixBase or in class Cwise (the
latter means that the user will have to write .cwise() to use your
operation: in your case, I think that's what we want)

Here's an example. Let's look at the implementation between .cwise().abs().

Go to Core/Functors.h line 164:

/** \internal
  * \brief Template functor to compute the absolute value of a scalar
  *
  * \sa class CwiseUnaryOp, Cwise::abs
  */
template<typename Scalar> struct ei_scalar_abs_op EIGEN_EMPTY_STRUCT {
  typedef typename NumTraits<Scalar>::Real result_type;
  EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a)
const { return ei_abs(a); }
};
template<typename Scalar>
struct ei_functor_traits<ei_scalar_abs_op<Scalar> >
{
  enum {
    Cost = NumTraits<Scalar>::AddCost,
    PacketAccess = false // this could actually be vectorized with SSSE3.
  };
};

as you can see we define the functor class ei_scalar_abs_op, it
contains 2 informations: the result type, and an operator() doing the
computation, making objects of this class behave like functions --
whence the name functor. Note the EIGEN_EMPTY_STRUCT, it helps some
compiler generate better code by adding a dummy member. Then comes the
specialization of ei_functor_traits, where we give a rough estimate of
the cost of the operation, and we tell whether the operation could be
vectorized.

Note that if the operation could be vectorized, the functor should
provide a packetOp() method. Here's an example, line 30 in the same
file:

/** \internal
  * \brief Template functor to compute the sum of two scalars
  *
  * \sa class CwiseBinaryOp, MatrixBase::operator+, class
PartialRedux, MatrixBase::sum()
  */
template<typename Scalar> struct ei_scalar_sum_op EIGEN_EMPTY_STRUCT {
  EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const
Scalar& b) const { return a + b; }
  template<typename PacketScalar>
  EIGEN_STRONG_INLINE const PacketScalar packetOp(const PacketScalar&
a, const PacketScalar& b) const
  { return ei_padd(a,b); }
};
template<typename Scalar>
struct ei_functor_traits<ei_scalar_sum_op<Scalar> > {
  enum {
    Cost = NumTraits<Scalar>::AddCost,
    PacketAccess = ei_packet_traits<Scalar>::size>1
  };
};

Here we say that there is "packet access" i.e. vectorizability if the
scalar type has the property that packets contain more than one
scalar. That's a standard way of saying whether a scalar type is
vectorizable.

Notice how the packetOp method is templated in the packet type! That's
a little discrepancy with the operator(), i admit.

OK, then how is this exposed in the API ? Go to Core/CwiseUnaryOp.h line 130:


/** \returns an expression of the coefficient-wise absolute value of \c *this
  *
  * Example: \include Cwise_abs.cpp
  * Output: \verbinclude Cwise_abs.out
  *
  * \sa abs2()
  */
template<typename ExpressionType>
EIGEN_STRONG_INLINE const EIGEN_CWISE_UNOP_RETURN_TYPE(ei_scalar_abs_op)
Cwise<ExpressionType>::abs() const
{
  return _expression();
}


so this is a method in class Cwise, in practice the user constructs an
object of class Cwise by calling .cwise(), that's why the resulting
API is .cwise().abs().

> I am through modding Numtraits.h, MathFunctions .h to add shorts. In
> the PacketMath.h there are these 3 functions whose purpose I did not
> understand.
>
> ei_palign_impl
> ei_preduxp
> ei_predux

Have a look at Core/GenericPacketMath.h, this is where all the comments are ;)

Benoit



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/