From: Andy Little (andy_at_[hidden])
Date: 2006-06-07 05:59:36
"Leland Brown" wrote
> Hello! I'm a newbie to the Boost mailing list, but I want to add my comments
> because I believe Andy's PQS library is very useful for scientific
> programming. I hope that it gets accepted into Boost, either in its present
> form, or possibly with some improvements as I'll discuss below.
> Unfortunately I haven't had time to examine the code in depth, but I feel very
> qualified to comment because I have implemented a similar template library as
> part of my job. (I got the inspiration from Barton & Nackman's book,
> _Scientific and Engineering C++_.) I can't share the code because it's
> proprietary, but we have been using it for the last six years in an
> that's heavy on physical and geometric calculation and numerical analysis. It
> has provided all the benefits Andy promises - self-documenting code, compiler
> detection of errors in physical formulas, elimination of units confusion, etc.
> The benefits are excellent, and it's easy to use for the most part. It has
> saved us a lot of headaches. Andy's library looks to be similar in all those
> respects, and I expect it will provide the same benefits. Many of our design
> choices are the same. Actually, the PQS library is in many ways much more
> extensive than my work and should be useful in a broader range of
> One important point is that we found that our library was extremely efficient,
> with all of the work being done at compile-time. A comparison of run-times
> using the quantities library versus built-in floating-point types showed a
> speed degradation of only 1% on highly math-intensive code.
FWIW, one area that is lacking in the documentation/examples/tests is some
comparative performance testing versus built-in types. Another thing on the
> What I implemented was more similar to Andy's "t2_quantity" and "t3_quantity,"
> and I find these (his future planned parts of the library) to be the most
> useful in what I do. I look forward especially to their completion, and I can
> testify to their utility. If the value of the library is not evident to some
> people as it stands now, I think a vision of the completed library may make it
> more clear. For that reason (and because it's what I'm most familiar with),
> I'll make a comment about where I think the library is going - realizing that
> I'm departing briefly from the topic of reviewing the library as it is today.
> Then I'll come back to specific comments on the current code.
> In my work, the advantage of the "t2_quantity" is that it provides an
> abstraction like a "length" that's independent of the units used to represent
> it - i.e., 1000 m is the *same* as 1 km, and a variable of type "t2_quantity"
> could contain that length as a value. All my scientific formulas then work on
> values like length and time rather than meters and seconds. A specific choice
> of units to represent the values is then only needed for input (e.g., from
> numeric values in a text file or hard-coded constants) or output (e.g., for
> human-readable results). All the computations become independent of units,
> all numeric values input or output are enforced by the compiler to have
> documented units. Code is clear and simple, like this:
> length x = 1000.0 * meter;
> velocty v = 2.0 * nautical_mile / hour;
> time t = x / v; // typically LOTS of computations here
> cout << "Time in seconds = " << t / second;
That is very reminiscent of the approach taken by a pioneering units library by
This approach can be simulated by PQS library. There is an example in
<libs/examples/clcpp_response.cpp> (The example was originally written in
response to an article on comp.std.c++, hence the title.) The example compares
(I hope) types that dont have units as part of the type as opposed to those
that do. In the unitless type accuracy in calculations is lost. Demonstrating
this another way, If you want to work in units of parsecs and you have a
variable representing 1 parsec with the unitless version you will have a
variable whose internal numeric value is
whereas if the internal value is held in the unit of parsecs the internal value
will be just 1.
However, when implementing the (so called) t2_quantity with runtime modifiable
units, this type of problem must occur. The t2_quantity was implemented in a
previous implementation of pqs. I removed it from the tentative Boost version
for lack of time
The t2_quantity was implemented in terms of the t1_quantity. Basically the
t2_quantity held a pointer to an abstract base class which indirected always to
a t1_quantity member. This meant that the t1_quantity output function overloads
and conversion functions were available. I think the functionality is quite
similar to Boost Variant FWIW
Typical usage might be like this extrapolated from an example from a previous
version of pqs:
namespace pqs = boost::pqs;
typedef pqs::t2_quantity<pqs::length::abstract_quantity> t2_length;
// default ctor units of meters. Numeric value of 0
// t2_quantity initialised by t1_quantity
std::cout << "get units to string : " << length.units_str() <<'\n';
std::cout << "get numeric_value : " << length.numeric_value() <<'\n';
// set the numeric_value of the quantity
//change t2_quantity internal units - pq value scaled to new units
// alt version using expression
// assign t2_quantity from t1_ length of arbitrary units
// internal value changed, but units not changed (here miles)
length = pqs::length::mi(1);
// install t2_quantity from lt1_ ength of arbitrary units
// internally pq replaced by new type
// return a t1_quantity cast from t2_quantity
// t2_quantity value unaffected
pqs::length::yd yds = length;
> I think the currently implemented PQS library is a good start and provides
> of the same benefits to the user. The unit-specific types of the
> probably in some cases can also avoid some of the multiplication/division that
> would occur with my example above.
The t1_quantity is designed to be fast with as much calculation as possible at
compile time rarther then runtime.
OTOH It will be interesting to see whether the implementation of the
t1_quantity/t2_quantity combo will have the functionality you need. If not it is
very simple to simulate using the t1_quantity by always using only the default
units and not including output functions. This will effectively give you a
Again, examples demonstrating such use will help I hope.
> Returning to the current library per se, I want to add some specific comments
> to some of those that have already been made in the reviews:
> There's been quite a bit of discussion about names. First, the name of the
> library. I wouldn't mind a different name than PQS, but I'd prefer to stay
> away from calling it "units" - precisely because of what I said above
> about "t2_quantity" - the advantage is actually in the ability to make your
> physical formulas units-INDEPENDENT. Obviously, units are still needed and
> handling them is a big part of the library, but the part of value is in making
> the units more transparent to the users. So to focus on the units (meters,
> seconds) versus the dimensions/quantities (length, time) would seem misleading
> in the library name. Then again, it's just a name.
OK. I will obviously need to have a good think about names!
> Secondly, the term "historical units" has been suggested to replace
> units." To me, "historical units" suggests they are archaic and no longer in
> use, and as an American I unfortunately know better. Even in certain
> scientific applications, units like feet and nautical miles, for instance, are
> still in common use. "Traditional units" was also suggested - I like that one
I kind of like 'traditional units' too...
> I have to agree with the other reviewers that the
> names "t1_quantity," "t2_quantity," and "t3_quantity" are not very
> Let me explain the naming scheme I used - maybe it will help get
> us thinking about better names. In my case, I tried to stick to one class
> template (the equivalent of t2_quantity), but I found a need for a type that
> did its dimension-checking at runtime so that the dimensions were not part of
> the type itself.
Now this sounds more like the t3_quantity.
> This came up whenever I had an aggregate class (such as a
> covariance matrix, or a set of polynomial coefficients) that needed to contain
> a mix of values with different physical dimensions. Even though (in my
> application) the dimensions of each element of the aggregate are known a
> priori, I couldn't find another way to implement those aggregates that was
> efficient without also being impossibly cumbersome.
This sounds like the sort of problem that pqs needs to be able to deal with.
So, because of this
> property of being able to have different kinds of quantities "mixed" within an
> aggregate, I called this type "mix_measure" (i.e., t3_quantity), while the
> other type was simply "measure" (for t2_quantity). I'm not necessarily
> proposing you use my names, but I'm saying I think it's possible to find names
> that do reflect something of their differences in functionality or purpose.
OK. I'm interested in all suggestions re naming ... :-)
> Lastly, it does seem from some of the other reviews that the documentation
> could be more clear. I'm disappointed that the purpose and the value and ease
> of use of the library is not more obvious to people from reading the
> documentation. It's clear to me because I'm very familiar with the concept
> I've used it successfully.
OK. I think the main problem has been putting the definition of terms section,
at the start rather than the end, a suggestion that I ignored previously FWIW
> One example is the questions about adding monetary conversions or pixel units
> to the library. I think PQS is definitely the wrong place to put these
> things. It's more than just a units conversion tool. The most obvious
> difference is that I've never heard anyone talk in units like dollars squared.
> The PQS library provides functionality meant for scientific comoutations
> involving things like cubic meters per second squared. Dollars (and to a
> lesser extent, pixels) are just a linear thing that does not make use of the
> machinery afforded by this library.
Yes. These things really need a different library. In both cases(money and
pixels) conversion factors arent constant. (In case of pixels a runtime mode
change for example)
> One final note: I do think it's important that this library eventually be
> extended and completed, and also that the various parts (t1_quantity,
> t2_quantity, etc.) work well together and have similar interfaces. It's
> possible that in implementing the future parts of the library, Andy will find
> he needs to change some things in the current code to make this happen. I'm
> not too familiar with the Boost process for changing existing libraries. So I
> don't know if there would be any value in putting the acceptance on hold until
> the other parts of the library are complete.
The situation as I understand is that ,if the review manager decides the library
should be accepted, he will often add requirements and suggests changes. As the
author I also need to consider the needs of existing users, so ideally the
interface shouldnt change too much from the current one. However from watching
the progress of other libraries the (indeterminate) period between acceptance
and inclusion in a boost release can sometimes result in radical modifications.
A solution to the current dissatisfaction with names in PQS is going to break
the interface and there isnt any way around that.
With regard to extending the library, I intend to add the t2_quantity,
t3_quantity, matrix, vector, complex and quaternion.
> But I would hate to see this
> important work get dropped, and I recommend its acceptance, with this one
> caveat about possibly accepting a more extended version instead at a later
> date. However, I think the library is quite useful as it stands now, and it
> provides a good foundation for the future work.
Thanks again for your review.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk