Issues with division by scalar of boost::units::quantity

Issue #358 resolved
David Wright created an issue

Hello,

I have stumbled upon another issue in combination with boost.units. The DVecScalarDivExpr implements the division by scalar in the following way:

return ReturnType( ~vec, ScalarType(1)/ScalarType(scalar) );

However, the problem I am having is that boost.units prevents the direct cast from basic data types to a boost::units::quantity. The library requires a quantity to be passed to the constructor, such as boost::units::si::metre. I am not sure how I would resolve this while staying agnostic with respect to the data types being used, but for now I can make it work by inverting the scalar and then multiplying by the result.

Code with error message:

const boost::units::quantity<boost::units::si::length, double> bandwidth = 1.0 * boost::units::si::metre;
const blaze::StaticVector<boost::units::quantity<boost::units::si::length, double>, 2, blaze::columnVector>
                sample = {1.0 * boost::units::si::metre, 1.0 * boost::units::si::metre};
const double weights = blaze::norm(sample / bandwidth);

“Fixed” code:

const auto bandwidthInv = 1.0 / boost::units::si::metre;
const blaze::StaticVector<boost::units::quantity<boost::units::si::length, double>, 2, blaze::columnVector>
                sample = {1.0 * boost::units::si::metre, 1.0 * boost::units::si::metre};
const double weights = blaze::norm(sample * bandwidthInv);

Error log:

/usr/local/include/blaze/math/expressions/DVecScalarDivExpr.h:1085:32: error: no matching conversion for functional-style cast from 'int' to 'ScalarType' (aka 'boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<-1, 1> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>')
      return ReturnType( ~vec, ScalarType(1)/ScalarType(scalar) );
                               ^~~~~~~~~~~~
/Users/dwright/projects/dv-laser-calibration/maths/MeanShift.hpp:133:46: note: in instantiation of function template specialization 'blaze::operator/<blaze::StaticVector<boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>, 2, false, blaze::aligned, blaze::padded, blaze::GroupTag<0> >, boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>, false, nullptr>' requested here
                        const double weights = blaze::norm(sample / bandwidth);
                                                                  ^

Comments (7)

  1. Klaus Iglberger

    Hi David!

    Thanks again for taking the time to report this problem. This time, however, I feel like there is no easy fix for the problem. Due to the design of boost.units there seems to be no way to invert a given quantity in a generic way (including value and type!). For that reason at this point I believe that you’ve chosen the right approach to compute the inverse manually (using 1.0 / boost::units::si::metre, which inside Blaze I cannot do) and to use multiplication instead.

    I’m still trying to find a generic way suitable for Blaze. Depending on the outcome I’ll either provide a fix or write a section for the FAQ.

    Thanks again,

    Klaus!

  2. David Wright reporter

    Hi Klaus, thank you for looking into this! I agree that it is very difficult to implement a data type agnostic library while trying to provide support for boost::units. I almost got stuck designing a single template class! Boost::units does the best it can to prevent you from assigning unit-less values to variables, for understandable reasons. One thing I have figured out is that you can assign zero to a value by multiplying a value with zero, which the designers deem to be correct because it is valid in any type system. Other than that I have not figured a way to circumvent this. For example I would like to find a way to find the value “1” for a given type system, but I don’t see a way yet. Again, I think the library is designed well and does what it’s supposed to do, but it’s difficult to remain type agnostic for designing a generic class.

    You most likely know this already, but I used ‘boost::multiply_typeof_helper’ and alike to find the expected data types for the results of operations. This works for similar problems, but is certainly not data type agnostic.

  3. Klaus Iglberger

    Hi David!

    I found a good, general and type agnostic solution for the problem. With commit 8ebcb3e you’ll be able to use the original formulation (sample / bandwidth) without sacrificing any performance. Thanks again for reporting this problem,

    Best regards,

    Klaus!

  4. Klaus Iglberger

    Commit 8ebcb3e fixes the compilation issue with division by a boost::units::quantity scalar. The fix is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.8.

  5. Log in to comment