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

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


one more information, if you want the coeff wise product of two int16
returns a int32, you can simply add the specialization:

template<> struct ei_scalar_product_traits<int16,int16> { typedef
int32 ReturnType; };

Also for the vectorization I think there is no other choice than using
structs instead of typdefs for the PacketXX SSE types because we need
to distinguish, e.g.:

ei_padd(Packet4i,Packet4i)

and

ei_padd(Packet8s,Packet8s)

so here Packet4i and Packet8s *must* be different types.

gael

On Thu, Aug 20, 2009 at 10:08 PM, Benoit Jacob<jacob.benoit.1@xxxxxxxxx> wrote:
> 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/