[Units] A first step to ease the usage of Units' quantities inside of functors created with the Lambda library

Hello, I'm pleased to see so much activity in the development of Boost.Units recently. I try to apply it myself in some code to model physical systems. There it helps me a lot to ensure the correct use of the model parameters inside the model equations and to ensure the correct composition of components to a system model. Certain component behaviour, I would like to parametrize for each component instance by passing a functor describing, e.g., a signal waveform or a non-linear relation between to quantities. I therefore tried to combine Boost.Units with Boost.Lambda and Boost.Function. I noticed that currently Units and Lambda use two independent systems of trait classes to determine the return type of algebraic operations like +, -, *, /. This requires to litter the lambda expression with a lot of ret<return_type>(...) function calls to construct a functor containing boost::units::quantity<U, V> instances. However, the trait classes used by Units and Lambda are very similar, so I created as a first solution a header file <lambda.hpp> (see attachment), which extends Boost.Lambda's return type reduction system through partial specialization to use Boost.Units' trait classes in case boost::unit::quantity<U,V> are involved in operator[+|-|*|/]() calls. Maybe it's also useful for others and could even become part of Boost.Units after some further improvements. However, there are some open issues: - Can some of the partial specializations be dropped? - Is there a need to add other specializations (e.g, for boost::units::unit<Dim, System, Enable>)? - Is there a way to work around boost::lambda:bind's limitation concerning the binding of overloaded functions? The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious. The attached small test program <units_with_lambda_test.cpp> demonstrates its usage and tedious bind issue, for which I haven't found a solution yet. Boost.Lambda requires calls to functions to be postponed using boost::lambda::bind(), so that they are executed not only once upon functor creation but at each functor call. Bind has the unfortunate limitation that it cannot resolve calls to overloaded functions. Thus, each time a call to an overloaded function (e.g., all functions defined in <boost/units/cmath.hpp>) is made, a lengthy static_cast<return_type (*)(argument_type)>(function_name) is needed for the first bind argument to help the compiler to find the overloaded function, which can accept the function arguments passed by the other bind arguments. Could this be somehow avoided or at least the syntax simplified? I'm thinking of, e.g., a templated function or (more ugly) a preprocessor macro adding the required static_cast based on some trait class or typeof. I'm looking forward to your feedback. Best regards, Torsten Maehne .DEFAULT_GOAL := all # Install locations of Boost 1.35 and Boost.Units BOOSTROOT := /opt/boost_1_35_0 BOOSTUNITS := /opt/boost_units CPPFLAGS := -I$(BOOSTROOT)/boost/tr1/tr1 -I$(BOOSTROOT) -I$(BOOSTUNITS) CXXFLAGS := -g -Wall % : %.o $(CXX) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ | c++filt .PHONY : all clean all : units_with_lambda_test units_with_lambda_test : units_with_lambda_test.o units_with_lambda_test.o : units_with_lambda_test.cpp lambda.hpp clean : -rm units_with_lambda_test *.o *~ semantic.cache

AMDG Torsten Mähne wrote:
I noticed that currently Units and Lambda use two independent systems of trait classes to determine the return type of algebraic operations like +, -, *, /.
Boost.Units actually relies on Boost.Typeof for user types.
- Can some of the partial specializations be dropped?
I don't think so.
- Is there a need to add other specializations (e.g, for boost::units::unit<Dim, System, Enable>)?
Drop the Enable parameter, it's an implementation detail which I plan to remove soon.
- Is there a way to work around boost::lambda:bind's limitation concerning the binding of overloaded functions? The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious.
The problem is avoided by creating a function object. (untested) struct sin_t { template<class Args> struct sig { typedef typename boost::tuples::element<0>::type arg1_type; BOOST_TYPEOF_NESTED_TYPEDEF(nested, (sin(make<arg1_type>()))); typedef typename nested::type type; }; template<class T> ... operator()(const T& arg) { return(sin(arg)); } }; In Christ, Steven Watanabe

Hello Steven, thank you for your fast feedback and suggestions. I agreed to Matthias to work out a more elaborated example and test suite. I'll add further specializations as needed, if the tests expose missing once. I'll take your hints (for units::unit) into account. Steven Watanabe wrote:
- Is there a way to work around boost::lambda:bind's limitation concerning the binding of overloaded functions? The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious.
The problem is avoided by creating a function object. (untested)
struct sin_t { template<class Args> struct sig { typedef typename boost::tuples::element<0>::type arg1_type; BOOST_TYPEOF_NESTED_TYPEDEF(nested, (sin(make<arg1_type>()))); typedef typename nested::type type; }; template<class T> ... operator()(const T& arg) { return(sin(arg)); } };
Thank you for the proposed solution for the bind problem, I'll give it a try as soon as possible. I'll keep you updated on the results. Best regards, Torsten

AMDG Torsten Maehne wrote:
thank you for your fast feedback and suggestions. I agreed to Matthias to work out a more elaborated example and test suite. I'll add further specializations as needed, if the tests expose missing once.
I think that the class templates that you need to deal with are * quantity * unit * absolute In Christ, Steven Watanabe

Hello Steven, Steven Watanabe wrote:
- Is there a way to work around boost::lambda:bind's limitation concerning the binding of overloaded functions? The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious.
The problem is avoided by creating a function object. (untested)
struct sin_t { template<class Args> struct sig { typedef typename boost::tuples::element<0>::type arg1_type; BOOST_TYPEOF_NESTED_TYPEDEF(nested, (sin(make<arg1_type>()))); typedef typename nested::type type; }; template<class T> ... operator()(const T& arg) { return(sin(arg)); } };
I finally came around to test your proposed solutions: I got it working in the attached small example for two cases sin() and pow<static_rational<N, D> >(). What do you think about a header cmath_functor.hpp, which would collect functors under, e.g., boost::units::functor to replace the cmath functions in lambda expressions? Best regards, Torsten

AMDG Torsten Maehne wrote:
I finally came around to test your proposed solutions: I got it working in the attached small example for two cases sin() and pow<static_rational<N, D> >(). What do you think about a header cmath_functor.hpp, which would collect functors under, e.g., boost::units::functor to replace the cmath functions in lambda expressions?
I'd rather that all direct references to Boost.Units be purged and put this in a more general place. Something like boost::math::functional. For sin you can simply leave of the qualification boost::units::, since the correct function should be found by ADL. However, pow_t has to be in the Units library because it can't be found by ADL. In Christ, Steven Watanabe

Torsten,
I'm pleased to see so much activity in the development of Boost.Units recently. I try to apply it myself in some code to model physical systems. There it helps me a lot to ensure the correct use of the model parameters inside the model equations and to ensure the correct composition of components to a system model. Certain component behaviour, I would like to parametrize for each component instance by passing a functor describing, e.g., a signal waveform or a non-linear relation between to quantities. I therefore tried to combine Boost.Units with Boost.Lambda and Boost.Function.
This looks like a very nice starting point for integration of Boost.Units with Lambda/Function. We naturally are enthusiastic about anything that leverages existing Boost technology and will extend the applicability of the Units library. If you are interested in putting together some extended examples and a test suite for this stuff and working to ensure that it functions well on the covered range of compilers, I think a <boost/units/lambda.hpp> header would be a nice extension to the library. Matthias

Hello Matthias, Matthias Schabel wrote:
This looks like a very nice starting point for integration of Boost.Units with Lambda/Function. We naturally are enthusiastic about anything that leverages existing Boost technology and will extend the applicability of the Units library. If you are interested in putting together some extended examples and a test suite for this stuff and working to ensure that it functions well on the covered range of compilers, I think a <boost/units/lambda.hpp> header would be a nice extension to the library.
Matthias
Thank you for your fast and positive feedback! It would be nice, if lambda.hpp became an official part of Boost.Units as it would make it easier to keep in sync with the rest of the library and expose it to more eyes to find bugs. My work would also profit from its improvement as it promises to simplify the parametrization of my system models. I'm therefore willed to working out a more extented example and a test suite. However, I have to admit that I'm still a newbie to Boost and C++ library development. I'll try to follow the pattern from the files found in the libs/units/example/ and libs/units/test/ directories. For testing different compilers, I'm more or less limited to gcc on Debian/Stable and Cygwin. I'm open for any further hints and suggestions. Best regards, Torsten

Hello Matthias and Steven, following your suggestions, I've reworked my lambda.hpp (to go into, boost/units/) to cover all overloaded operators for the Boost.Units types quantity, unit, absolute, and one (I'm not sure, if the latter is necessary. I just found it while grepping for missing operators.). The open issues for lambda.hpp are: * Maybe drop specialization for quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(System),Y>? * Are the specializations for boost::units::one needed in the context of Boost.Lambda? It seems to be an implementation detail of Boost.Units. * Work out a solution for boost::lambda:bind's limitation concerning the binding of overloaded functions. The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious. (I had no time yet to test Steven's proposal to use functors with appropriate sig template.) I also created a unit test test_lambda.cpp (to go into boost/libs/units/test), which tries to check each operator, for which a specialization of Boost.Lambda's return type traits is included in lambda.hpp. The test exposed additional issues: * Are the checks for the operations involving quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(System),Y> correct? Are they needed? * All checks involving the multiplication/division of boost::units::unit and boost::units::absolute<boost::units::unit> types are not compiling. The compiler complains about ambiguous overloads for operator* and operator/ (originating from Boost.Units and Boost.Lambda). Therefore they are currently commented out. Some checks also involve the usage of Boost.Function * The check fo unit<Dim1, System1> - unit<Dim2, System2> is not compiling. The compiler finds no matching definition of operator-. * Are the checks for the operations involving absolute unit types correct? * All checks for the boost::units::one types are not compiling. The compiler complains about ambiguous overloads for operator* and operator/ (originating from Boost.Units and Boost.Lambda). Therefore they are currently commented out. * Add checks involving mathematical functions from boost/units/cmath.hpp once a solution for boost::lambda:bind's limitation concerning the binding of overloaded functions is found. I improved the example lambda.cpp (to go into, boost/libs/units/example) by adding more comments and a new thermal example demonstrating the use of absolute quantities. I developed the files inside a working copy of Boost.Units trunk. test_lambda.cpp and lambda.cpp could be compiled by bjam. However, I had to modify the Jamfile.v2 files in boost/libs/units/test and boost/libs/units/example to contain a definition of BOOST_ROOT like this: BOOST_ROOT = /opt/boost_1_35_0 ; Otherwise the other Boost libraries aren't found during compilation. How do you define this variable in Jamroot so that it becomes visible in the Jamfile.v2 files? Defining the variable as an OS environment variable doesn't help as the Boost.Build manual states. By googling for BOOST_ROOT, I found statements, which suggest to use use-project /boost : <path_to_Boost> ; instead. But this didn't help and the Boost.Build manual seems to be still incomplete about this issue. Maybe you can help me. This is how my Jamroot currently looks like: use-project /boost : /opt/boost_1_35_0 ; using gcc : 4.1 : g++-4.1 ; using xsltproc : "/usr/bin/xsltproc" ; using boostbook : "/usr/share/xml/docbook/stylesheet/nwalsh/" : "/usr/share/xml/docbook/schema/dtd/4.2" ; using doxygen : "/usr/bin/doxygen" ; using fop : "/usr/bin/fop" : "/usr/lib/jvm/java-6-sun-1.6.0.00" ; I'm looking forward to your comments! Best regards, Torsten

AMDG Torsten Maehne wrote:
* Maybe drop specialization for quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(System),Y>?
These specializations should not be needed.
* Are the specializations for boost::units::one needed in the context of Boost.Lambda? It seems to be an implementation detail of Boost.Units.
Yes it's an implementation detail. You can leave off these specializations.
* Work out a solution for boost::lambda:bind's limitation concerning the binding of overloaded functions. The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious. (I had no time yet to test Steven's proposal to use functors with appropriate sig template.)
This strikes me as being a separate issue, which doesn't belong in the units library.
* All checks involving the multiplication/division of boost::units::unit and boost::units::absolute<boost::units::unit> types are not compiling. The compiler complains about ambiguous overloads for operator* and operator/ (originating from Boost.Units and Boost.Lambda). Therefore they are currently commented out.
These shouldn't compile.
* The check fo unit<Dim1, System1> - unit<Dim2, System2> is not compiling. The compiler finds no matching definition of operator-.
Again these shouldn't compile. In Christ, Steven Watanabe

Steven, Where are we on the library? There's nothing obvious to me that needs dealing with other than some edits to the docs. I put a few sections bracketed with *** that I'd like you to take a look at and/or add a bit. Otherwise, I think we should consider merging with the trunk soon. How do you feel about that prospect? Matthias

Hello Steven, Thank you for your hints concerning my code. I have incorporated your comments in the attached new versions of lambda.hpp and test_lambda.cpp. Steven Watanabe schrieb:
AMDG
Torsten Maehne wrote:
* Maybe drop specialization for quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(System),Y>?
These specializations should not be needed.
I removed these specializations from lambda.hpp but left the tests for dimensionless types in test_lambda.cpp in place.
* Are the specializations for boost::units::one needed in the context of Boost.Lambda? It seems to be an implementation detail of Boost.Units.
Yes it's an implementation detail. You can leave off these specializations.
I removed all specializations concerning boost::one and removed the respective tests from test_lambda.cpp
* Work out a solution for boost::lambda:bind's limitation concerning the binding of overloaded functions. The required static_cast to the function pointer (referring, e.g., a function from boost/units/cmath.hpp) is tedious. (I had no time yet to test Steven's proposal to use functors with appropriate sig template.)
This strikes me as being a separate issue, which doesn't belong in the units library.
Well, I agree this is a seperate issue. However, the usefulness of quantities in lambda expressions without the possibility to easily use them in binded calls to functions defined in boost/units/cmath.hpp is quite limited.
* All checks involving the multiplication/division of boost::units::unit and boost::units::absolute<boost::units::unit> types are not compiling. The compiler complains about ambiguous overloads for operator* and operator/ (originating from Boost.Units and Boost.Lambda). Therefore they are currently commented out.
These shouldn't compile.
I modified the checks so that now units and absolute units are passed as well as arguments to the lambda expressions. Then the ambiguous overload errors disappear. However, for the absolute unit tests: // T * absolute<unit<D, S> > // Error: no match for operator== BOOST_CHECK(((bl::_1 * bl::_2)(300.0, bu::absolute<si::temperature>()) == 300.0 * bu::absolute<si::temperature>())); // absolute<unit<D, S> > * T // Error: no match for operator== BOOST_CHECK(((bl::_1 * bl::_2)(300.0, bu::absolute<si::temperature>()) == 300.0 * bu::absolute<si::temperature>())); this approach leads to new compiler errors: no match for operator==. I left the non-compiling commented-out tests in place for documentation purposes.
* The check of unit<Dim1, System1> - unit<Dim2, System2> is not compiling. The compiler finds no matching definition of operator-.
Again these shouldn't compile.
This strikes me as being inconsistent, because it works for: unit<Dim1, System1> + unit<Dim2, System2> So what is the conceptual difference between: // unit<Dim1, System1> + unit<Dim2, System2> BOOST_CHECK(((bl::_1 + bu::meter)(bu::meter) == bu::meter)); BOOST_CHECK(((bu::meter + bl::_1)(bu::meter) == bu::meter)); BOOST_CHECK(((bl::_1 + bl::_2)(bu::meter, bu::meter) == bu::meter)); , which compiles, and: // unit<Dim1, System1> - unit<Dim2, System2> // // Error: no match for operator- // BOOST_CHECK(((bl::_1 - bl::_2)(bu::meter, bu::meter) == bu::meter)); // // Error: no match for operator- // BOOST_CHECK(((bl::_1 - bu::meter)(bu::meter) == bu::meter)); // // Error: no match for operator- // BOOST_CHECK(((bu::meter - bl::_1)(bu::meter) == bu::meter)); , which compiles not. The files do compile fine on my Debian Linux/Stable P4 machine with g++ versions 3.4.6 and 4.1.2. I unfortunately have no access to non-GNU C++ compilers. However, do you think lambda.hpp, test_lambda.cpp, and lambda.cpp are getting into a mature enough state to be integrated into Boost.Units? Best regards, Torsten

AMDG Torsten Maehne wrote:
* All checks involving the multiplication/division of boost::units::unit and boost::units::absolute<boost::units::unit> types are not compiling. The compiler complains about ambiguous overloads for operator* and operator/ (originating from Boost.Units and Boost.Lambda). Therefore they are currently commented out.
These shouldn't compile.
I modified the checks so that now units and absolute units are passed as well as arguments to the lambda expressions. Then the ambiguous overload errors disappear. However, for the absolute unit tests: <snip>
I left the non-compiling commented-out tests in place for documentation purposes.
I looked at the tests. I misunderstood what you were testing. Allowing multiplication _1 * meters e.g. would require disambiguating overloads.
* The check of unit<Dim1, System1> - unit<Dim2, System2> is not compiling. The compiler finds no matching definition of operator-.
Again these shouldn't compile.
This strikes me as being inconsistent, because it works for:
unit<Dim1, System1> + unit<Dim2, System2>
I see. I didn't understand what you were testing, again. The problem is in units/lambda.hpp line 390 ff. /// Partial specialization of return type trait for action /// unit<Dim1, System1> - unit<Dim2, System2>. template<typename Dim1, typename Dim2, typename System1, typename System2> struct plain_return_type_2<arithmetic_action<minus_action>, boost::units::unit<Dim1, System1>, boost::units::unit<Dim2, System2> > { BOOST_STATIC_ASSERT((boost::is_same<System1, System2>::value == true)); typedef typename boost::units::subtract_typeof_helper< boost::units::*quantity*<Dim1, System1>, boost::units::*quantity*<Dim2, System2> >::type type; }; These two quantities ought to be units. In Christ, Steven Watanabe

Hello Steven, thank you for helping me in debugging lambda.hpp! Steven Watanabe wrote:
AMDG
Torsten Maehne wrote:
* All checks involving the multiplication/division of boost::units::unit and boost::units::absolute<boost::units::unit> types are not compiling. The compiler complains about ambiguous overloads for operator* and operator/ (originating from Boost.Units and Boost.Lambda). Therefore they are currently commented out.
These shouldn't compile.
I modified the checks so that now units and absolute units are passed as well as arguments to the lambda expressions. Then the ambiguous overload errors disappear. However, for the absolute unit tests: <snip>
I left the non-compiling commented-out tests in place for documentation purposes.
I looked at the tests. I misunderstood what you were testing. Allowing multiplication _1 * meters e.g. would require disambiguating overloads.
I have tried to add specializations to lambda.hpp like the following: /// Partial specialization of return type trait for action /// boost::lambda::functor<T> * unit<Dim, System>. template<typename System, typename Dim, typename T> struct plain_return_type_2<arithmetic_action<multiply_action>, boost::lambda::lambda_functor<T>, boost::units::unit<Dim, System> > { typedef typename boost::units::multiply_typeof_helper< boost::lambda::lambda_functor<T>, boost::units::unit<Dim, System> >::type type; }; , to disambiguate the overloads. However the specialization seems to be not picked up by the compiler -- it still uses either: boost::lambda::functor<T> * Y or Y * unit<Dim, System> when uncommenting the check for bl::_1 * bu::meters in test_lambda.cpp. (Note: I didn't add the specialization to the attached corrected lambda.hpp.) Do you have an idea, what I'm doing wrong here?
* The check of unit<Dim1, System1> - unit<Dim2, System2> is not compiling. The compiler finds no matching definition of operator-.
Again these shouldn't compile.
This strikes me as being inconsistent, because it works for:
unit<Dim1, System1> + unit<Dim2, System2>
I see. I didn't understand what you were testing, again. The problem is in units/lambda.hpp line 390 ff.
/// Partial specialization of return type trait for action /// unit<Dim1, System1> - unit<Dim2, System2>. template<typename Dim1, typename Dim2, typename System1, typename System2> struct plain_return_type_2<arithmetic_action<minus_action>, boost::units::unit<Dim1, System1>, boost::units::unit<Dim2, System2> > { BOOST_STATIC_ASSERT((boost::is_same<System1, System2>::value == true)); typedef typename boost::units::subtract_typeof_helper< boost::units::*quantity*<Dim1, System1>, boost::units::*quantity*<Dim2, System2> >::type type; };
These two quantities ought to be units.
Thanks for pointing me to this nasty copy & paste error. I corrected it in the attached new lambda.hpp. Best regards, Torsten

AMDG Torsten Maehne wrote:
I have tried to add specializations to lambda.hpp like the following:
/// Partial specialization of return type trait for action /// boost::lambda::functor<T> * unit<Dim, System>. template<typename System, typename Dim, typename T> struct plain_return_type_2<arithmetic_action<multiply_action>, boost::lambda::lambda_functor<T>, boost::units::unit<Dim, System> > { typedef typename boost::units::multiply_typeof_helper< boost::lambda::lambda_functor<T>, boost::units::unit<Dim, System> >::type type; };
, to disambiguate the overloads. However the specialization seems to be not picked up by the compiler -- it still uses either:
boost::lambda::functor<T> * Y
or
Y * unit<Dim, System>
when uncommenting the check for bl::_1 * bu::meters in test_lambda.cpp. (Note: I didn't add the specialization to the attached corrected lambda.hpp.) Do you have an idea, what I'm doing wrong here?
Yes. The correct solution is to add overloads for the operators, rather than specializations of plain_return_type_2. template<typename System, typename Dim, typename T> ... operator*(const boost::lambda::lambda_functor<T>&, const boost::units::unit<Dim, System>&); You'll have to peek at the internals of lambda to figure out what the return type should be. In Christ, Steven Watanabe

Hello Steven and Matthias, Steven Watanabe wrote:
Yes. The correct solution is to add overloads for the operators, rather than specializations of plain_return_type_2.
template<typename System, typename Dim, typename T> ... operator*(const boost::lambda::lambda_functor<T>&, const boost::units::unit<Dim, System>&);
You'll have to peek at the internals of lambda to figure out what the return type should be.
I finally got around to add the required disambiguation overloads for operator* and operator/ involving boost::units::quantity and boost::units::absolute. All checks in test_lambda.cpp compile and execute now as expected. You can find both files in the attachment. lambda.hpp works also well together with my library of functor wrappers for the cmath functions, which I'm currently working on. However, the latter is still missing some functions from cmath.hpp that's why I haven't included it in this posting. Thus all issues with lambda.hpp known to me are resolved. (Steven suggested to tackle the bind issue of overloaded functions separately.) Do you think this makes the files lambda.hpp, test_lambda.hpp, and lambda.cpp mature enough to become official part of Boost.Units? I'm looking forward to your feedback! Best regards, Torsten

AMDG Torsten Maehne wrote:
Do you think this makes the files lambda.hpp, test_lambda.hpp, and lambda.cpp mature enough to become official part of Boost.Units? I'm looking forward to your feedback!
I've added it to the trunk. I removed a few unnecessary specializations and tweaked it to work correctly when Boost.Typeof is in emulation mode. In Christ, Steven Watanabe

Hello Steven, Steven Watanabe wrote:
AMDG
Torsten Maehne wrote:
Do you think this makes the files lambda.hpp, test_lambda.hpp, and lambda.cpp mature enough to become official part of Boost.Units? I'm looking forward to your feedback!
I've added it to the trunk. I removed a few unnecessary specializations and tweaked it to work correctly when Boost.Typeof is in emulation mode.
Thanks a lot, this is great news for me. With your message, I also noticed that Boost.Units finally moved from the sandbox to the trunk of the Boost SVN repository. :-) I checked out your tweaked version and it works well for me. However, I noticed that the small example lambda.cpp (in the attachment) is not yet in the trunk. It would provide at least a preliminary documentation for lambda.hpp.
In Christ, Steven Watanabe
Best regards, Torsten
participants (4)
-
Matthias Schabel
-
Steven Watanabe
-
Torsten Maehne
-
Torsten Mähne