Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

User Defined Types

(quaternion.cpp)

This example demonstrates the use of boost::math::quaternion as a value type for quantity and the converse. For the first case, we first define specializations of power_typeof_helper and root_typeof_helper for powers and roots, respectively:

/// specialize power typeof helper
template<class Y,long N,long D>
struct power_typeof_helper<boost::math::quaternion<Y>,static_rational<N,D> >
{
    // boost::math::quaternion only supports integer powers
    BOOST_STATIC_ASSERT(D==1);

    typedef boost::math::quaternion<
        typename power_typeof_helper<Y,static_rational<N,D> >::type
    > type;

    static type value(const boost::math::quaternion<Y>& x)
    {
        return boost::math::pow(x,static_cast<int>(N));
    }
};

/// specialize root typeof helper
template<class Y,long N,long D>
struct root_typeof_helper<boost::math::quaternion<Y>,static_rational<N,D> >
{
    // boost::math::quaternion only supports integer powers
    BOOST_STATIC_ASSERT(N==1);

    typedef boost::math::quaternion<
        typename root_typeof_helper<Y,static_rational<N,D> >::type
    > type;

    static type value(const boost::math::quaternion<Y>& x)
    {
        return boost::math::pow(x,static_cast<int>(D));
    }
};

We can now declare a quantity of a quaternion :

typedef quantity<length,quaternion<double> >     length_dimension;

length_dimension    L(quaternion<double>(4.0,3.0,2.0,1.0)*meters);

so that all operations that are defined in the quaternion class behave correctly. If rational powers were defined for this class, it would be possible to compute rational powers and roots with no additional changes.

+L      = (4,3,2,1) m
-L      = (-4,-3,-2,-1) m
L+L     = (8,6,4,2) m
L-L     = (0,0,0,0) m
L*L     = (2,24,16,8) m^2
L/L     = (1,0,0,0) dimensionless
L^3     = (-104,102,68,34) m^3

Now, if for some reason we preferred the quantity to be the value type of the quaternion class we would have :

typedef quaternion<quantity<length> >     length_dimension;

length_dimension    L(4.0*meters,3.0*meters,2.0*meters,1.0*meters);

Here, the unary plus and minus and addition and subtraction operators function correctly. Unfortunately, the multiplication and division operations fail because quaternion implements them in terms of the *= and /= operators, respectively, which are incapable of representing the heterogeneous unit algebra needed for quantities (an identical problem occurs with std::complex<T>, for the same reason). In order to compute rational powers and roots, we need to specialize power_typeof_helper and root_typeof_helper as follows:

/// specialize power typeof helper for quaternion<quantity<Unit,Y> >
template<class Unit,long N,long D,class Y>
struct power_typeof_helper<
    boost::math::quaternion<quantity<Unit,Y> >,
    static_rational<N,D> >
{
    typedef typename power_typeof_helper<
        Y,
        static_rational<N,D>
    >::type     value_type;

    typedef typename power_typeof_helper<
        Unit,
        static_rational<N,D>
    >::type  unit_type;

    typedef quantity<unit_type,value_type>         quantity_type;
    typedef boost::math::quaternion<quantity_type> type;

    static type value(const boost::math::quaternion<quantity<Unit,Y> >& x)
    {
        const boost::math::quaternion<value_type>   tmp =
            pow<static_rational<N,D> >(boost::math::quaternion<Y>(
                x.R_component_1().value(),
                x.R_component_2().value(),
                x.R_component_3().value(),
                x.R_component_4().value()));

        return type(quantity_type::from_value(tmp.R_component_1()),
                    quantity_type::from_value(tmp.R_component_2()),
                    quantity_type::from_value(tmp.R_component_3()),
                    quantity_type::from_value(tmp.R_component_4()));
    }
};

/// specialize root typeof helper for quaternion<quantity<Unit,Y> >
template<class Unit,long N,long D,class Y>
struct root_typeof_helper<
    boost::math::quaternion<quantity<Unit,Y> >,
    static_rational<N,D> >
{
    typedef typename root_typeof_helper<
        Y,
        static_rational<N,D>
    >::type      value_type;

    typedef typename root_typeof_helper<
        Unit,
        static_rational<N,D>
    >::type   unit_type;

    typedef quantity<unit_type,value_type>         quantity_type;
    typedef boost::math::quaternion<quantity_type> type;

    static type value(const boost::math::quaternion<quantity<Unit,Y> >& x)
    {
        const boost::math::quaternion<value_type>   tmp =
            root<static_rational<N,D> >(boost::math::quaternion<Y>(
                x.R_component_1().value(),
                x.R_component_2().value(),
                x.R_component_3().value(),
                x.R_component_4().value()));

        return type(quantity_type::from_value(tmp.R_component_1()),
                    quantity_type::from_value(tmp.R_component_2()),
                    quantity_type::from_value(tmp.R_component_3()),
                    quantity_type::from_value(tmp.R_component_4()));
    }
};

giving:

+L      = (4 m,3 m,2 m,1 m)
-L      = (-4 m,-3 m,-2 m,-1 m)
L+L     = (8 m,6 m,4 m,2 m)
L-L     = (0 m,0 m,0 m,0 m)
L^3     = (-104 m^3,102 m^3,68 m^3,34 m^3)


PrevUpHomeNext