# Boost :

From: Michael Fawcett (michael.fawcett_at_[hidden])
Date: 2006-06-08 15:40:25

On 6/8/06, Andy Little <andy_at_[hidden]> wrote:
> A transformation matrix can perform the operations of translation and scaling.
>
> Translation of an entity(lets say a position vector implemented as length
> quantities) is basically an addition. Therefore the translation part of the
> matrix must be comprised of length quantities. However scaling of a quantity can
> only be performed by a numeric type. We can deduce from this that some elements
> of the transformation matrix must be numeric, and some length quantities.
>
> In fact the type makeup of a matrix for 2d transforms ends up looking like the
> following:
>
> where N is a numeric, Q is a quantity and R is the reciprocal of the quantity or
> 1/Q
>
> ( N N R )
> ( NN R )
> ( QQ N )
>
> The 3D transform version is similar except with the extra row and column of
> course.
>
> The problem is that this is quite a heavy modification to ask of a numeric
> matrix library, especially when most users will be using it for numeric values.
> (Incidentallly numerics work in the above of course. they just all resolve to
> N).
> The point of all this is that the price of strong type checking (ie using PQS
> rather than numerics) may be discarding all your current libraries, which are
> based on the assumption of numerics. That is quite a high price!.
>
> I dont know any solution to this problem( except to exit the strong type
> checking) but basically there it is.

What the library would be concerned with is that the result of the
operation was possible (made sense) given the types that were held
within the matrix or vector.

Contrived example using theoretical code:

// Multiply accumulate (Is there a simpler way?)
template
<
typename X, typename Y, typename Z,
typename VX, typename VY, typename VZ
>
struct macc
{
// X * VX + Y * VY + Z * VZ
typedef typename boost::result_of_multiplies<X, VX>::type x_times_x;
typedef typename boost::result_of_multiplies<Y, VY>::type y_times_y;
typedef typename boost::result_of_multiplies<Z, VZ>::type z_times_z;
typedef typename boost::result_of_plus<y_times_y, z_times_z>::type
y_times_y_plus_z_times_z;
typedef typename boost::result_of_plus<x_times_x,
y_times_y_plus_z_times_z>::type x_plus_y_plus_z;
typedef x_plus_y_plus_z type;
};

template
<
typename X, typename Y, typename Z,
typename VX, typename VY, typename VZ
>
typename macc<X, Y, Z, VX, VY, VZ>::type
dot_product(const vec3<X, Y, Z> &lhs, const vec3<VX, VY, VZ> &rhs)
{
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
}

blas::vec3<int, short, float> a(1, 0, 0);
blas::vec3<double, int, float> b(0, 1, 0);
double result = dot_product(a, b); // returns double

I left out PQS types there for simplicity, but I think you can see
where I'm going. If the result_of struct isn't specialized for the
types you are trying to combine, then you get a compile-time error.
So given:

blas::vec3<length::m> len(1, 2, 3);
blas::vec3<velocity::s> vel(5, 6, 7);
// Note the result type
blas::vec3<velocity::m_per_s2> result = len / (vel * vel);

You only have to specialize for the very base operations between
types. Everything more complex (matrix multiplies, etc) can be built
on top of that. For the above, operator / would need to have been
implemented to return boost::result_of_divides<length::m,
velocity::s2>::type, while operator * would need to have been
implemented to return boost::result_of_multiplies<velocity::s,
velocity::s>::type. I see you were using BOOST_AUTO in some other
posts which would probably clean some of my code up, but I'm not
familiar enough with it to use in my examples.

This would require the math library be more heavily templated than it
currently is. Note that a matrix would need to hold mutliple types
(up to NxN). For instance, what would be the syntax for a 3D
transform? Perhaps something like:

matrix4x4
<
float, float, float, length,
float, float, float, length,
float, float, float, length,
length, length, length, float
> m;

maybe?

--Michael Fawcett