Interest in dimension/unit-checking library?

Would there be any interest in a library for attaching units (physical or otherwise) to numeric variables, so that the type system could enforce dimension- and unit-consistency in all calculations, and convert semi-automatically between compatible units? To make this a little more concrete, here's a sketch of the kind of code such a library could enable: --- quantity<meters, double> distance(1.0); quantity<newtons, double> force(5.0); quantity<joules, double> work = distance * force; quantity<calories, double> work_cal = unit_cast<calories>(work); work_cal = work; //Compile error or implicit conversion, // possibly depending on compiler flag quantity<watts, double> power = work; //Compile error- incompatible types --- This library would be somewhat similar to the dimensional-analysis code given by Abrahams and Gurtovoy in their book[1], but with two major enhancements: - it would be defined in terms of specific units (as Abrahams and Gurtovoy suggest in an exercise), rather than general dimensions, so it could catch unit-consistency errors as well as dimension-consistency errors, and it could convert between compatible units - it would allow client code to extend the system with arbitrary units in arbitrary dimensions I should note that although I gave the example in terms of physical units for clarity, I intend this library to be useful not just for physical calculation, but for numerical calculation in general. Almost any time software deals with numbers, it's really dealing with *quantities* (numbers that measure something in terms of some unit), and errors can result if variables with different units are inappropriately combined. The purpose of this library would be to allow developers to prevent those errors with strong typing and compile-time checking, as well as to somewhat ease the task of converting between units when necessary. I know there's been a lot of discussion of units for a GUI library, so I'm especially interested in what people involved in that thread think of this idea- I want to make something sufficiently powerful to be useful in a context like that. [1] http://www.boost.org/libs/mpl/doc/tutorial/tutorial-metafunctions.html

Geoffrey Romer wrote:
Would there be any interest in a library for attaching units (physical or otherwise) to numeric variables, so that the type system could enforce dimension- and unit-consistency in all calculations, and convert semi-automatically between compatible units?
To make this a little more concrete, here's a sketch of the kind of code such a library could enable:
Try searching the archives for "physical quantities" or "pqs"; you should find extensive discussion and references to several proposed libraries. -- Jonathan Turkanis www.kangaroologic.com

On Sun, 9 Oct 2005 15:17:27 -0700, Geoffrey Romer wrote
Would there be any interest in a library for attaching units (physical or otherwise) to numeric variables, so that the type system could enforce dimension- and unit-consistency in all calculations, and convert semi-automatically between compatible units?
There is certainly interest. Andy Little has worked on this for quite some time: http://www.servocomm.freeserve.co.uk/Cpp/physical_quantity/index.html This is one of the items on the C++ standardization wishlist as well... Unfortunately last I know Andy has officially 'given up' on making a library. Maybe you and others can help change his mind or work with him to bring something forward ;-) Jeff

"Jeff Garland" wrote
On Sun, 9 Oct 2005 15:17:27 -0700, Geoffrey Romer wrote
Would there be any interest in a library for attaching units (physical or otherwise) to numeric variables, so that the type system could enforce dimension- and unit-consistency in all calculations, and convert semi-automatically between compatible units?
There is certainly interest. Andy Little has worked on this for quite some time:
http://www.servocomm.freeserve.co.uk/Cpp/physical_quantity/index.html
This is one of the items on the C++ standardization wishlist as well...
Unfortunately last I know Andy has officially 'given up' on making a library. Maybe you and others can help change his mind or work with him to bring something forward ;-)
Just to put the record straight, pqs is in quite a useable state. However to make it suitable for a boost proposal requires a lot of work. Some part of the work has been done however. I guess that mention of dimensions n' units on boost certainly helps to prod me into doing work on it again. I'll have to get on with it. Meanwhile all feedback on pqs ( or dimensions n' units in general ) is welcome. regards Andy Little

I was working on a physical quantities library last year but stopped when I saw that there were already a few others working on their own. Now that it seems as though the others who were working on their implementations have stopped, I have picked up on work on it again (metamath has made this work much easier). I was going to wait until I had an uploadable implementation before I started talking about it, but since others are expressing interest right now, I'll try to finish up more quickly and present some concepts here. I've developed solutions to some problems that I noticed other implementations don't seem to address, and am currently adding optimizations not previously talked about. Some things which stand out about my implementation from others is that the concepts of scalars, vectors, and points are a necessity central to the system -- in a way that I haven't seen anyone talk about. As well, I use expression templates to [optionally] optimize expressions at a high level in a variety of ways. Finally, I take a completely nodular approach to conversions. Just so it's a little bit more clear before I upload a version, the reason that vectors, points, and scalars are so essential is because whenever we work with units, the logical differences between them exist, even when only working in 1 dimension, though we generally just don't acknowledge it. In code, it's essential to express these differences For instance, I have three different main templates for working with units (instantiated with unit type, value type, an operations policy for the provided value type i.e. vector and point operations, all which have appropriate defaults): quantity (which is a scalar quantity) quantity_vector quantity_point A quick example of why explicitly separating these types is important is easily examplified by the common case of temperature. Firstly, consider the temperature 2 degrees celsius. In order to convert this temperature to fahrenheit, we would multiply by 9/5 and then add 32. Applying this operation, we get the result 35.6 degrees celsius, as expected. On the other hand, consider a temperature difference. Let's say at the beginning of the day, the temperature was 8 degrees celsius. At the end of the day, the temperature was 10 degrees celsius. The change in temperature from the beginning of the day to the end of the day is 2 degrees celsius. Now, to convert that change in temperature to fahrenheit, we multiply by 9/5. Note that unlike the previous example, we do not at 32. This result is 3.6degrees fahrenheit, which is obviously very different from 35.6 degrees fahrenheit, despite that both come from a conversion of 2 degrees celsius. Taking it to a more abstract level, would it ever make sense to add two temperatures together? For instance, we subtracted 8 degrees from 10 degrees to get the change in temperature of the day. However, what meaning would we get out of adding the temperature at the beginning of the day to the temperature at the end of the day? In general such an operation does not make any sense. I believe this is the case for the simple reason that absolute temperatures, such as the temperature at a particular time of the day, are conceptually points, while the difference in two temperatures is a vector (just as a point minus a point yields a vector in geometry). The reason why the shift of 32 degrees is only applied on absolute temperatures is because you can think of them as being two different origins the the scaled n-dimensional space. To convert from one location to another's relative to their origins, you have to take into account the translation needed to get from one origin to the other (in this case 32). With vectors, however, this isn't the case, since a change between two points in similar space, regardless of the positions of the origin, is merely a translation on its own. All that is required is the scale change. Also note that just like with points and vectors, it generally doesn't make sense to add together two absolute temperatures, whereas it does make sense to subtract two. As well, it even makes sense to add the result of the subtraction to an absolute temperature, and the same goes for all other standard point and vector operations. Finally, just like in geometry, there are a few places where the rules can be broken regarding adding points, such as with barycentric combinations. With temperatures, a barycentric combination could be used to find the average temperature of the day. Just like with temperatures, the geometric representation applies to all other unit types. If users find it difficult to understand, most can get away with just using scalar quantities all of the time, though the more advanced users would recognize the benefits of using points and vectors. Indeed, the more you apply this logic, the more it appears as though vectors, points, and scalars provide a perfect model for working with units, and I even believe they are entirely essential to a proper design. What I'm currently working on is finishing up expression templates to optimize operations. This is done primarly through the rearrangement of expressions, examining subexpressions of a given full expression, and also through combining divisors through multiplication prior to evaluating a ratio (all of which will eventually be individually toggleable, though right now I'm worried about completing its functionality as a whole). Expression reorginization can optimize an overall expression quite a bit, which is why I decided to make it a part of the library. As a simple example, take the following expression after analysis: meters1 + feet1 + meters2 + feet2 Without expression rearrangement, a conversion could potentially take place at every operations. For instance, without rearrangement, the following logic could occur (obviously it would all be implicit, I am using just made up functions for clarity here): convert_to_feet( convert_to_meters( ( convert_to_feet( meters1 ) + feet1 ) ) + meters2 ) + feet2 However, with expression rearrangement, we can group like terms: feet1 + feet2 + convert_to_feet( meters1 + meters2 ) Note that the latter example (using rearrangement) only requires 1 conversion as opposed to 3. At first you may say why not arrange the terms manually, however, you should keep in mind that when working with generic code and objects passed to functions, you may not know which unit types will be used at the time of writing the generic code (and it can change depending on how you use it). After tests, the way I perform expression rearrangement is resolved entirely at compile-time in VC++ 7.1 ( I haven't yet tested other compilers). This is toggleable, like the other optimizations regarding expression templates, will be toggleable once I complete them (currently I have it working for additive expressions and partially for multiplicative expressions). I also use a nodular approach to representing unit conversions. By this, I mean the "natural unit type" for length can be "meters." When the "centimeters" unit type is created, it is represented as a conversion between "meters" and "centimeters" directly. Likewise, when the "feet" unit is created, its conversion to "meters" is represented directly. However, with an "inches" type, it is chosen to be expressed as a conversion to "feet." If you were to imagine this type of system, it forms a tree-like structure with unit types as nodes. Since the conversions are generally all known at compile-time and are expressed using compile-time mathematical types of MPL and metamath, they are still optimized together at compile-time. This is beneficial as opposed to a system which describes all conversions directly going back to the natural unit type of a classification of units for many reasons. For one, the conversions can often more simply be expressed between more related types (the conversion from inches to feet is more clear than inches to meters). In addition, the nodular approach can prevent loss in precision, since conversion to normally unrelated types often has to be an approximation. Finally, it is beneficial when working with types such as money, where the conversion between "pennies" and "dollars" is known at compile-time, the conversion between two denominations of another country's currency is known at compile-time, yet the conversion between american dollars and another unit of money may change at runtime. Since a nodular approach to conversion is used, conversion between related currencies is known through a compile-time coefficient, whereas between two currencies of different countries, the conversion is created and can change at runtime. The downsides of the runtime conversion isn't necessary unless you are using two unrelated currencies, unlike if a nodular approach to representing conversion was not used. Implementation-wise, I am using MPL maps to represent classifications and unit types, unlike Andy Little's if I remember correctly, providing more compile-time efficient type comparisons. I also provide a variety of simple ways of creating new unit types and classification types using compile-time metafunctions and variadic template argument lists. The only thing I am worried about is that I am using a fairly large amount of advanced language features and I'm currently not concerned about trying to get it to work on non-compliant compilers. Aside from everything I mentioned, there are also a few other interesting things I'd like to talk about later, though I really wanted to get a working implementation uploaded before getting into a big discussion about it. I'll try to get expression rearrangement done by the end of the week and upload a version for people to play with. Feedback would be nice for what I've said so far.

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Matt Calabrese | Sent: 10 October 2005 21:13 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | | I was working on a physical quantities library last year but stopped when I | saw that there were already a few others working on their own. Now that it | seems as though the others who were working on their | implementations have stopped, I have picked up on work on it again. <big snip> Please to learn that work is still done - IMO we still badly need a good solution to the ubiquitous (but hard) problem of units & dimensions. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

"Paul A Bristow" <pbristow@hetp.u-net.com> wrote in message news:E1EP4rn-0004h6-0Q@he303war.uk.vianw.net...
| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Matt Calabrese | Sent: 10 October 2005 21:13 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | | I was working on a physical quantities library last year but stopped when I | saw that there were already a few others working on their own. Now that it | seems as though the others who were working on their | implementations have stopped, I have picked up on work on it again.
<big snip>
Please to learn that work is still done - IMO we still badly need a good solution to the ubiquitous (but hard) problem of units & dimensions.
(BTW Its not That hard...) If t hadnt have been for you Paul... I'd never have continued with my own version...;-) regards Andy Little

"Matt Calabrese" wrote
I was working on a physical quantities library last year but stopped when I saw that there were already a few others working on their own.
[cut]
version for people to play with. Feedback would be nice for what I've said so far.
Basically .... Go for it. Particularly the point vector concept for particular quantities is great ... regards Andy Little

On 10/10/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Basically .... Go for it.
Particularly the point vector concept for particular quantities is great ...
regards Andy Little
Great, and thanks for the positive feedback on the central notion of points and vectors. That was the main thing I was worried about concerning acceptance by users, since traditionally people don't explicitly associate quantities with geometric representations and I was afraid they may just think it makes things more complex without understand its necessity. In realizing how great of a model points, vectors, and scalars are for working with all types of units, it completely changed the way I look at units even outside of programming, so I wouldn't be surprised if it does the same for anyone who would want to use it. I just hope that others agree that it is an accurate and highly beneficial model to use, despite the arguably drastic change in thinking that is associated it. -- -Matt Calabrese

"Matt Calabrese" <rivorus@gmail.com> wrote in message news:2142b7510510101604r55c20883h5dd10e9b592896e2@mail.gmail.com...
On 10/10/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Basically .... Go for it.
Particularly the point vector concept for particular quantities is great ...
Great, and thanks for the positive feedback on the central notion of points and vectors. That was the main thing I was worried about concerning acceptance by users, since traditionally people don't explicitly associate quantities with geometric representations and I was afraid they may just think it makes things more complex without understand its necessity. In realizing how great of a model points, vectors, and scalars are for working with all types of units, it completely changed the way I look at units even outside of programming, so I wouldn't be surprised if it does the same for anyone who would want to use it. I just hope that others agree that it is an accurate and highly beneficial model to use, despite the arguably drastic change in thinking that is associated it.
As a casual lurker, your description read very well and made perfect sense to me. It is a great formalization of these concepts. Have you read the concept section of the DateTime library, which seems analogous to your temperature example? Do your concepts handle the DateTime concepts? Thanks, Jeff

Andy Little wrote:
"Matt Calabrese" wrote
I was working on a physical quantities library last year but stopped when I saw that there were already a few others working on their own.
[cut]
version for people to play with. Feedback would be nice for what I've said so far.
Basically .... Go for it.
Particularly the point vector concept for particular quantities is great ...
Yes, I agree. If you dig back into the archives, you'll see that this was all discussed before. Unit/dimension analysis is indeed just geometry, as you have figured out.

Andy Little wrote:
"Deane Yang" <deane_yang@yahoo.com> wrote
Yes, I agree. If you dig back into the archives, you'll see that this was all discussed before. Unit/dimension analysis is indeed just geometry, as you have figured out.
Sorry for biteing your head off before ;-)
Thanks. Apology happily accepted but hardly necessary. I'm hoping to have some time to take a closer look at things and provide more constructive help this time. I'm also feeling a bit more motivated, too.
cheers
Andy Little
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Mon, 10 Oct 2005 16:12:53 -0400, Matt Calabrese wrote
...snip...
For instance, I have three different main templates for working with units (instantiated with unit type, value type, an operations policy for the provided value type i.e. vector and point operations, all which have appropriate defaults):
quantity (which is a scalar quantity) quantity_vector quantity_point
A quick example of why explicitly separating these types is important is easily examplified by the common case of temperature. Firstly, consider the temperature 2 degrees celsius. In order to convert this temperature to fahrenheit, we would multiply by 9/5 and then add 32. Applying this operation, we get the result 35.6 degrees celsius, as expected. On the other hand, consider a temperature difference. Let's say at the beginning of the day, the temperature was 8 degrees celsius. At the end of the day, the temperature was 10 degrees celsius. The change in temperature from the beginning of the day to the end of the day is 2 degrees celsius. Now, to convert that change in temperature to fahrenheit, we multiply by 9/5. Note that unlike the previous example, we do not at 32. This result is 3.6degrees fahrenheit, which is obviously very different from 35.6 degrees fahrenheit, despite that both come from a conversion of 2 degrees celsius.
Wow, that's amazing. Replace quantity_vector with time_duration and quantity_point with time_point and you have the core concepts behind date-time. And the 32 versus zero -- seems an awful lot like an epoch_time adjustment. So I suppose I'm saying I believe there is something fundamental here :-)
...snip...
Aside from everything I mentioned, there are also a few other interesting things I'd like to talk about later, though I really wanted to get a working implementation uploaded before getting into a big discussion about it. I'll try to get expression rearrangement done by the end of the week and upload a version for people to play with.
Expression rearrangement is really cool stuff, but it doesn't really impact the interface does it? If you're serious about putting it in boost it's really the interface and docs that will ultimately matter the most. Personally I'd like to see a units lib proposal sooner rather than later... Jeff

Jeff Garland wrote:
Wow, that's amazing. Replace quantity_vector with time_duration and quantity_point with time_point and you have the core concepts behind date-time. And the 32 versus zero -- seems an awful lot like an epoch_time adjustment. So I suppose I'm saying I believe there is something fundamental here :-)
Yes, there is. If you dig back in the archives, I tried to explain it all before, but obviously not very well. Suffice to say that a "time point" and a "point quantity" are the same type of thing and that the difference between any two such things is a "vector quantity" or equivalently a "time_duration". Mathematicians have identified the common abstract concepts underlying these things, and I went on and on about this earlier. But I think I'm going to resist reviving all that, because I don't think it's particularly helpful. I like Matt's terminology, because it seems to be more meaningful for everyone.

On 10/10/05, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Expression rearrangement is really cool stuff, but it doesn't really impact the interface does it? If you're serious about putting it in boost it's really the interface and docs that will ultimately matter the most. Personally I'd like to see a units lib proposal sooner rather than later...
Jeff
No, it doesn't impact the interface. You use operators just like you normally would. However, I do feel the need to make expression rearrangement toggleable even if the rearrangement is fully optimized to compile-time on almost all compilers, since rearrangement of expressions could have subtle effects on precision, or even cause things like overflow or underflow in different places than in the unorganized expression. These types of things generally shouldn't be an issue, but they cause enough concern to make a mechanism to turn off the behavior if necessary. Right now I plan on adding function templates which act as expression modifiers that turn on and off reordering i.e. strictly_ordered( expression_here ) to make it such that the internal expression isn't reordered, and loosely_ordered( expression_here ) to explicitly allow the internal expression to be reordered (which can be nested inside strictly_ordered expression). Similar toggles would be made for other optimizations through expression templates. Initially, I plan on making all expressions loosely_ordered by default, but I may provide additional point, vector, and scalar templates which default to strict ordering when used in expressions if people would want such functionality. As of now, I'd prefer not to add those additional point, vector, and scalar templates, just to avoid unecessarily bloating in the library, but this opinion may change if such templates would be commonly used. Much of how I am developing the library is dependent on expression templates and many impact optimization in ways some might not initially think about. For instance, last week I realized that even simple assignment operations benefit from the expression templates. As an example, take the expression your_quantity = some_meters + some_feet; Without expression templates, you pretty much arbitrarily choose whether to convert meters to feet or feet to meters on the right side of the equals, however since the operations are now expression templates, the choice can be determined better by context. If your_quantity is a quantity in meters, then some_feet should be converted to meters in the expression. If your_quantity is in feet, then some_meters should be converted to feet in the expression. Otherwise, the complexity of the conversion decides which unit_type should be used. Such analysis of context to produce the more optimized choice is entirely possible using expression templates. On 10/10/05, Deane Yang <deane_yang@yahoo.com> wrote:
If you dig back in the archives, I tried to explain it all before, but obviously not very well. Suffice to say that a "time point" and a "point quantity" are the same type of thing and that the difference between any two such things is a "vector quantity" or equivalently a "time_duration".
Mathematicians have identified the common abstract concepts underlying these things, and I went on and on about this earlier. But I think I'm going to resist reviving all that, because I don't think it's particularly helpful. I like Matt's terminology, because it seems to be more meaningful for everyone.
I wish I had seen that conversation when it was active. I'm glad that I'm not just going crazy about these relationship, as no places I've found even make mention of them. -- -Matt Calabrese

Matt Calabrese wrote:
On 10/10/05, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Expression rearrangement is really cool stuff
<snip>
Right now I plan on adding function templates which act as expression modifiers that turn on and off reordering i.e. strictly_ordered( expression_here ) to make it such that the internal expression isn't reordered, and loosely_ordered( expression_here ) to explicitly allow the internal expression to be reordered (which can be nested inside strictly_ordered expression). Similar toggles would be made for other optimizations through expression templates.
<snip> This set off a bell in my head. I had to do similar expression template manipulation in xpressive, and I wrote an expression template parser to help. It currently lives in boost/xpressive/proto. It is essentially a generic expression template framework and a handlful of generally useful "compilers" that plug into the framework to transform the expression template into a target form. For instance, there is a transform_compiler that finds a pattern in your expression template and transforms it according to a MPL-style lambda that you provide. There is no documentation for it yet, but if you think it might be useful, you may want to have a look at how xpressive uses it to transform an expression template into a regex. That code lives at boost/xpressive/detail/static/productions. If you decide to go this route, I'd could lend a hand. IMO, Boost could use a library for ET manipulation, and proto is a start. Yours sounds like a good application. -- Eric Niebler Boost Consulting www.boost-consulting.com

On Mon, 10 Oct 2005 23:22:24 -0400, Deane Yang wrote
Jeff Garland wrote:
Wow, that's amazing. Replace quantity_vector with time_duration and quantity_point with time_point and you have the core concepts behind date-time. And the 32 versus zero -- seems an awful lot like an epoch_time adjustment. So I suppose I'm saying I believe there is something fundamental here :-)
Yes, there is.
If you dig back in the archives, I tried to explain it all before, but obviously not very well. Suffice to say that a "time point" and a "point quantity" are the same type of thing and that the difference between any two such things is a "vector quantity" or equivalently a "time_duration".
Mathematicians have identified the common abstract concepts underlying these things, and I went on and on about this earlier. But I think I'm going to resist reviving all that, because I don't think it's particularly helpful. I like Matt's terminology, because it seems to be more meaningful for everyone.
Sorry if I missed or didn't respond to your comments the first time. However, I now have reasons to be more interested in the theoretical foundations. Specifically, the LWG committee is rightly an intense group that needs to ensure the quality and correctness of things that get added to the standard -- having additional theoretical foundations for the date-time concepts can't hurt. Any chance you can point me to some sort of references (preferably readable to folks that have only taken ~15 college math courses ;-) Thx, Jeff

Jeff Garland wrote:
On Mon, 10 Oct 2005 23:22:24 -0400, Deane Yang wrote
Jeff Garland wrote:
Wow, that's amazing. Replace quantity_vector with time_duration and quantity_point with time_point and you have the core concepts behind date-time. And the 32 versus zero -- seems an awful lot like an epoch_time adjustment. So I suppose I'm saying I believe there is something fundamental here :-)
Yes, there is.
If you dig back in the archives, I tried to explain it all before, but obviously not very well.
(stuff deleted)
Sorry if I missed or didn't respond to your comments the first time.
Definitely understandable.
However, I now have reasons to be more interested in the theoretical foundations. Specifically, the LWG committee is rightly an intense group that needs to ensure the quality and correctness of things that get added to the standard -- having additional theoretical foundations for the date-time concepts can't hurt. Any chance you can point me to some sort of references (preferably readable to folks that have only taken ~15 college math courses ;-)
Here's a brief summary of the idea (assuming that you learned about vector spaces (http://en.wikipedia.org/wiki/Vector_space) in linear algebra) (In anything you read about vector and affine spaces, if they say "field F", just assume that F is the set of real numbers): A "dimension" or, as Matt calls it, a "point quantity" or, as you call it the set of "time_points", without choosing any particular unit, corresponds to the mathematical concept of an "affine line" or an "1-dimensional affine space" A (see http://en.wikipedia.org/wiki/Affine_space). Associated with any "point quantity" or "dimension" or the set of "time_points" is the set of all possible differences between two points. Matt calls this a "vector quantity"; you call it the set of "time_durations"; mathematicians call it the (1-dimensional) vector space (http://en.wikipedia.org/wiki/Vector_space) associated with the affine space. Assigning (relative) units to a vector quantity corresponds to fixing a nontrivial real-valued linear function f: R -> V on the vector space V. Think of V as a straight line with the "zero vector" marked and the map f as like putting a ruler on top of the straight line, assigning a real number to each point on the line. Notice, however, that you have to line up the ruler so that the 0 on the ruler is placed against the zero-vector. So your only flexibility in what you do is stretching or shrinking the ruler. Assigning (absolute) units to a point quantity corresponds to fixing a non-trivial affine map (http://en.wikipedia.org/wiki/Affine_transformation) f: R -> A, where A is the set of all possible values of the point quantity. Think of A as a competely blank straight line and the map f as putting a ruler on top of the line. This time, since the line is blank, you can slide the ruler along the line and put the 0 on the ruler against any point on A. So you have more flexibility with your units; you can stretch, shrink, or slide the ruler. Unit casting corresponds to the situation where you have two different rulers you want to use, and you need to convert a number on one ruler into the corresponding number on the other. For vector quantities, you just need to multiply the number by a fixed proportionality constant. For point quantities (temperature is the best example here), you might also need to do an addition or subtraction, too. You can always turn any vector space V into an affine space, by simply "forgetting" where the zero vector is. You can always turn any affine space into a vector space V by arbitrarily choosing a point in A and declaring it to be the zero vector.

On Wed, 12 Oct 2005 10:21:55 -0400, Deane Yang wrote
Jeff Garland wrote:
However, I now have reasons to be more interested in the theoretical foundations. Specifically, the LWG committee is rightly an intense group that needs to ensure the quality and correctness of things that get added to the standard -- having additional theoretical foundations for the date-time concepts can't hurt. Any chance you can point me to some sort of references (preferably readable to folks that have only taken ~15 college math courses ;-)
Here's a brief summary of the idea (assuming that you learned about vector spaces (http://en.wikipedia.org/wiki/Vector_space) in linear algebra) (In anything you read about vector and affine spaces, if they say "field F", just assume that F is the set of real numbers): ... ...snip good stuff...
Cool, Thx! Jeff

Jeff Garland wrote:
On Wed, 12 Oct 2005 10:21:55 -0400, Deane Yang wrote
Jeff Garland wrote:
However, I now have reasons to be more interested in the theoretical foundations. Specifically, the LWG committee is rightly an intense group that needs to ensure the quality and correctness of things that get added to the standard -- having additional theoretical foundations for the date-time concepts can't hurt. Any chance you can point me to some sort of references (preferably readable to folks that have only taken ~15 college math courses ;-)
Here's a brief summary of the idea (assuming that you learned about vector spaces (http://en.wikipedia.org/wiki/Vector_space) in linear algebra) (In anything you read about vector and affine spaces, if they say "field F", just assume that F is the set of real numbers): ... ...snip good stuff...
An explanation of affine spaces and their role in computer graphics can be found at http://www.cs.fit.edu/~wds/classes/graphics/Transform/transform/transform.ht... When working with units and dimensions, we're just doing 1-dimensional geometry.

Deane Yang wrote:
An explanation of affine spaces and their role in computer graphics can be found at
http://www.cs.fit.edu/~wds/classes/graphics/Transform/transform/transform. html
When working with units and dimensions, we're just doing 1-dimensional geometry.
I agree completely that we're talking about a 1-dimensional geometry. I think the issue that people are arguing is, "What space are we using?" For some, like you and Matt Calabrese, the answer is an affine space. Unfortunately, affine spaces don't directly support point combinations, so you create a function that has no meaning in your chosen space. Others, such as I, view the natural geometry to be a Grassmann space which supports the addition and scalar weighting of points. Addition of points is a natural and proper operation. Unfortunately, the best discussion I've seen requires access to the ACM Digital Library: http://portal.acm.org/citation.cfm?id=504792 . The most important question comes down to safety & interface. I myself am not attracted to choosing a representation and then specifically breaking the rules of that representation. I also don't like the the idea of seeing N average functions: p=average(p1, p2); p=average(p1, p2, p3); p=average(p1, p2, p3, p4); And N barycentric combination functions: p=barycentric_combination(w1, p1, w2, p2); p=barycentric_combination(w1, p1, w2, p2, w3, p3); p=barycentric_combination(w1, p1, w2, p2, w3, p3, w4, p4); I don't like having two sets of N functions to handle something that is natural in another space. I, too, like the safety of affine space keeping a strong separation between points and vectors. Most of my code has a strong discrimination between the two. I think you can keep that without destroying the expressivity that others want. To me, I would like to see a new type added - grassman_point. Add the following functions to create them: grassman_point operator+(point, point); grassman_point operator*(scalar, point); grassman_point operator*(point, scalar); grassman_point operator/(point, scalar); And then you could combine points as in the following examples (p is a point, not a grassman_point): p=(p1+p2+p3+p4)/4; p=0.25*p1+0.25*p2+0.25*p3+0.25*p4; p=p1+p2+p3+p4; In a Grassman space, all of the above result in the same value. Grassman space is represented with the same homogeneous vector as is used frequently in computer graphics. Using the usual representation of (v,0) and (p,1), the points are projected to from (p,w) to (p/w,1) before p is stored back in the affine point. Thus the third equation is the same as the first. For safety's sake, you could require an explicit conversion instead of an implicit one to avoid accidentally performing unwanted point manipulations, the very reason for choosing an affine space over a simpler vector space. Thus it would look something like: p=combination(0.3*p1+0.25*p2+0.45*p3); Now, there's only one combination function instead of 2*N functions, and there's no arbitrary limit to the number of terms. It's rather safe from unintended point manipulation since, without a specific statement of intent, it will cause a compiler error. In addition, you could enforce that no projection occurs and thus the w term already be at 1. This would have the disadvantage of disallowing a simple average without resorting to a second class that handles weighting. -- Noah

Noah Stein wrote:
I agree completely that we're talking about a 1-dimensional geometry. I think the issue that people are arguing is, "What space are we using?" For some, like you and Matt Calabrese, the answer is an affine space. Unfortunately, affine spaces don't directly support point combinations, so you create a function that has no meaning in your chosen space.
Others, such as I, view the natural geometry to be a Grassmann space which supports the addition and scalar weighting of points. Addition of points is a natural and proper operation. Unfortunately, the best discussion I've seen requires access to the ACM Digital Library: http://portal.acm.org/citation.cfm?id=504792 .
(long discussion omitted) This is a very cool idea for those who are willing to understand the geometry behind it all, but I suspect it's a little too mysterious for most users of the units library. Also, don't you need to store two numbers for each scalar quantity? Isn't that a little costly in both space and computation time? I think your approach makes more sense for points in more than one dimension, where storing n-dimensional points as (n+1)-vectors is less costly. I don't really remember exactly what happened, but I think the last time we discussed this, I finally decided that it would be best to just implement a pure "vector quantity" library first. The "point quantity" interface could be added later, if a consensus develops. Otherwise, each of us can easily add our own layer on top of the vector quantity library. (So I'm retracting what I said in my post responding to Andy Little.) I think this will provide a core library that will be useful to everyone.

Deane Yang wrote:
Noah Stein wrote: (more snipping)
Others, such as I, view the natural geometry to be a Grassmann space which http://portal.acm.org/citation.cfm?id=504792 .
(long discussion omitted)
This is a very cool idea for those who are willing to understand the geometry behind it all, but I suspect it's a little too mysterious for most users of the units library. Also, don't you need to store two numbers for each scalar quantity? Isn't that a little costly in both space and computation time? I think your approach makes more sense for points in more than one dimension, where storing n-dimensional points as (n+1)-vectors is less costly.
The amount of mystery IMHO is minimal. The idea introduces one new class, possibly two. The grassman_point code would look almost identical to the regular vector code. The extra overhead is that you get one extra term per vector. In the case of quantities, you go from 1D to 2D. The new term is an accumulator for the addition of weights. This information has to be tracked in the two point combination functions anyhow. If you only promote up to the grassman_point for point-point and scalar-point operations, you have no overhead. The data is 1D except on the two functions that require an accumulator at which time the extra datum appears in the point object instead of a local in the function.
I don't really remember exactly what happened, but I think the last time we discussed this, I finally decided that it would be best to just implement a pure "vector quantity" library first. The "point quantity" interface could be added later, if a consensus develops. Otherwise, each of us can easily add our own layer on top of the vector quantity library. (So I'm retracting what I said in my post responding to Andy Little.)
A fine point indeed. This could be the best course of action. The grassman_point idea could be layered cleanly on top of a vector-only or even a vector/point solution. -- Noah

On 10/12/05, Noah Stein <noah@acm.org> wrote:
The grassman_point idea could be layered cleanly on top of a vector-only or even a vector/point solution.
This is also what I have decided. Sorry to Andy, as the quantity_points still will not have operator + defined. I knew I would have some disagreement, but this really is something that I've already given much thought to and is why I hoped to get a version out before talking about this. Deane has reiterated everything that I have talked about, and I am thankful for that. I firmly believe that this is the best decision and you're going to have a very hard time swaying me. If you want addition of points in affine space, then don't use points, use the concept of "position vectors". This is not some new restriction that I am just choosing to make for the library, this is just how geometry is and for good reasons, and I'm not going to change standard mathematics because you want addition of points. The concept of addition of points simply does not make sense on its own in affine space -- it's just an implementation detail of higher-level functionality such as barycentric combinations. Because of this, operator + is not going to be overloaded, and in the rare cases that you need the functionality of componentwise addition of points in order to form other high-level functions, you can use the componentwise_add function, again, whose name is long on purpose since it generally should not be used except as implementation details. If you find yourself having to use point addition in affine space very often, then you are probably just improperly using points instead of vectors or are missing a level of abstraction. As I said, I could always use expression templates to only allow expressions with point addition and other operations when the expression follows the form of barycentric combinations, but that would really be pushing it, and is completely unecessary since I'm already providing barycentric combination functions. I'm not going to make this library logically incorrect by directly supporting raw addition of points in affine space. -- -Matt Calabrese

"Matt Calabrese" <rivorus@gmail.com> wrote
On 10/12/05, Noah Stein <noah@acm.org> wrote:
The grassman_point idea could be layered cleanly on top of a vector-only or even a vector/point solution.
This is also what I have decided. Sorry to Andy, as the quantity_points still will not have operator + defined.
hmm... But there will be an add_components function? Anyway I guees I'd better let you get on with it ;-) regards Andy Little

"Deane Yang" <deane_yang@yahoo.com> wrote
Noah Stein wrote:
Others, such as I, view the natural geometry to be a Grassmann space which supports the addition and scalar weighting of points. Addition of points is a natural and proper operation. Unfortunately, the best discussion I've seen requires access to the ACM Digital Library: http://portal.acm.org/citation.cfm?id=504792 .
(long discussion omitted)
This is a very cool idea for those who are willing to understand the geometry behind it all, but I suspect it's a little too mysterious for most users of the units library. Also, don't you need to store two numbers for each scalar quantity? Isn't that a little costly in both space and computation time? I think your approach makes more sense for points in more than one dimension, where storing n-dimensional points as (n+1)-vectors is less costly.
As I understand it a grassman_point would only be used for intermediate results of an addition. regards Andy Little

Andy Little wrote: I think your approach makes more sense for
points in more than one dimension, where storing n-dimensional points as (n+1)-vectors is less costly.
As I understand it a grassman_point would only be used for intermediate results of an addition.
Good point. So what do you think of Noah's proposed syntax?

"Deane Yang" wrote
Andy Little wrote:
As I understand it a grassman_point would only be used for intermediate results of an addition.
Good point. So what do you think of Noah's proposed syntax?
If it can help to resolve one of the contentious problems at least regarding multi-dimensional points, then I think it is a good thing. I guess I'll have to try to implement it and see how it works out. regards Andy Little

"Matt Calabrese" <rivorus@gmail.com> wrote
Taking it to a more abstract level, would it ever make sense to add two temperatures together? For instance, we subtracted 8 degrees from 10 degrees to get the change in temperature of the day. However, what meaning would we get out of adding the temperature at the beginning of the day to the temperature at the end of the day? In general such an operation does not make any sense.
Actually this is not quite correct. if t1 ... t6 are temperatures then e.g.: (t1 + t2 + t3 + t4 + t5 + t6 ) / 6 is perfectly legal. regards Andy Little

"Matt Calabrese" wrote
Expression reorginization can optimize an overall expression quite a bit, which is why I decided to make it a part of the library. As a simple example, take the following expression after analysis:
meters1 + feet1 + meters2 + feet2
Without expression rearrangement, a conversion could potentially take place at every operations. For instance, without rearrangement, the following logic could occur (obviously it would all be implicit, I am using just made up functions for clarity here):
convert_to_feet( convert_to_meters( ( convert_to_feet( meters1 ) + feet1 ) ) + meters2 ) + feet2
However, with expression rearrangement, we can group like terms:
feet1 + feet2 + convert_to_feet( meters1 + meters2 )
The example works for addition but what about multiplication and division? Is the example realistic? FWIW pqs assumes/("prods") that all calculations would actually be done in SI units. (The whole idea behind SI is to use the so-called "coherent" units and phase out the others). In this scenario the conversion to-from "incoherent" units would only occur for user input/output. OTOH meters result = millimeters1 + meters2; In the above pqs would convert the intermediate result to millimeters under the rule that millimeters is the most fine grained unit. I guess that improvements could be made with expression templates. OTOH will the rules regarding the result of an operation be simple to understand? Maybe that doesnt matter. BTW Are there not subtleties with temporaries using ET that users need to know about? [cut]
Implementation-wise, I am using MPL maps to represent classifications and unit types, unlike Andy Little's if I remember correctly, providing more compile-time efficient type comparisons.
I used a home brewed version. It would be interesting to see if mpl::map is faster, but I think it will be slower because mine wasnt actually very generic ;-) . However the use of compile time double will have a major detrimental impact on compile times unfortunately. I dont know what one can do about that.
I also provide a variety of simple ways of creating new unit types and classification types using compile-time metafunctions and variadic template argument lists.
One problem in pqs was explaining how to add new types and units. If this can be simplified that would be great. regards Andy Little

Although I appreciate your efforts to implement an efficient way to automatically convert different units for the same quantity, I would still prefer a library that requires an explicit "cast" to change units, rather than implicit. Perhaps the library could be built in two layers, with the lower level requiring explicit casts and a layer above that that implements implicit casting for those who want it. What I'm more interested in learning is how you handle "composite quantities", which are obtained by multiplying and dividing existing units (like "meters/second"), as well as raising to a rational power (like the standard unit of volatility in finance, "1/square_root(years)".

On 10/11/05, Eric Niebler <eric@boost-consulting.com> wrote:
This set off a bell in my head. I had to do similar expression template manipulation in xpressive, and I wrote an expression template parser to help. It currently lives in boost/xpressive/proto. It is essentially a generic expression template framework and a handlful of generally useful "compilers" that plug into the framework to transform the expression template into a target form. For instance, there is a transform_compiler that finds a pattern in your expression template and transforms it according to a MPL-style lambda that you provide.
Very nice. I will most-likely use it in the future, but I probably won't use it until after I complete the current version of implementation since it is already well under way and I want to get this version out as soon as possible. On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Actually this is not quite correct. if t1 ... t6 are temperatures then e.g .:
(t1 + t2 + t3 + t4 + t5 + t6 ) / 6 is perfectly legal.
If you look back at my post, I mentioned this very case: "Finally, just like in geometry, there are a few places where the rules can be broken regarding adding points, such as with barycentric combinations. With temperatures, a barycentric combination could be used to find the average temperature of the day." The example you gave is actually a barycentric combination with all weights equal. Just like in geometry, this does not mean that the addition operator should be defined for points to perform component-wise addition. Instead, I provide a "componentwise_add" function for such rare cases, and I will also be making a set of average and a barycentric combination functions to abstract away the concepts. On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
The example works for addition but what about multiplication and division? Is the example realistic?
Yes, it works just the same. In a multiplicative expression, like-operands are grouped and multiplied prior to evaluated the overall expression. Divisors in a simple multiplicative expression are combine by multiplication and the expression is kept as a ratio until needing to be evaluated. This is the best solution I could come up with to minimize precision loss with integral/fixed point types. This is probably the most controversial of my optimizations. Again, though, it will be toggleable once complete. On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
In the above pqs would convert the intermediate result to millimeters under the rule that millimeters is the most fine grained unit. I guess that improvements could be made with expression templates. OTOH will the rules regarding the result of an operation be simple to understand? Maybe that doesnt matter. BTW Are there not subtleties with temporaries using ET that users need to know about?
I don't see a good reason to convert to the most fine-grained unit type. If anything, that can only cause more conversions which could not only make the expression less-optimized, but also have less-precise results depending on the value_type of the operands. I decided that determining the type to convert to be context is the best solution. In the case of a "tie" for which type should be used, I convert to the closest unit type to the "natural unit" in the nodular conversion tree I described. If that is a tie, the choice is really arbitrary (I use the left operand). Fortunately, users shouldn't ever have to worry about this. I am making sure to document any subtleties. Particularly with the optimizations such as expression rearrangement, I am going to give examples of where it may be a good idea to turn it off. On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
One problem in pqs was explaining how to add new types and units. If this can be simplified that would be great.
Adding new classification types and new unit types is actually very simple at the moment. For derived classification types, it's as simple as: // force is "length" times "mass" times "time" to the power of negative two. typedef classification< length, mass, power_c< time, -2 > > force; // The natural unit is newtons // (the above operations performed on the natural // unit types of the corresponding classifications) quantity< force::natural_unit > a_force_quantity_in_newtons; classification has a variadic template argument list which has the effect of multiplying together all of the operands. I also have a variadic "per" template which multiplies together all of the operands and then raises them to the power of negative one. In this example, length, mass, and time are all fundamental classifications, however you can also use derived classifications in the formation of force (such as velocity or acceleration if it is defined). In compilers that support typeof you can also do typeof( length() * mass() * power_fun< -2 >( time() ). I focused much time on making all of this as easy as possible. Making new derived units is just as easy: typedef unit< miles, per< hour > > mph; // or typedef typeof( miles() / hour() ) miles_per_hour; Creating new fundamental classifications is a little bit more complicated, but is still done in a single line, though with a macro call. Adding new fundamental classification is also simple, though is done through a macro: SURGE_TUCAN_BASE_CLASSIFICATION( money ) The reason why a macro is used is because internally a template is instantiated with a unique type tag which I create off of the passed argument, and that instantiated type is then typedefed to the argument passed. For those curious, surge is just the encapsulating namespace name I use for libraries I develop, and tucan is the name of this library, which stands for "Templated Unit Containment And Nodular conversion library). On 10/11/05, Jeff Flinn <TriumphSprint2000@hotmail.com> wrote:
As a casual lurker, your description read very well and made perfect sense to me. It is a great formalization of these concepts. Have you read the concept section of the DateTime library, which seems analogous to your temperature example? Do your concepts handle the DateTime concepts?
Thanks, Jeff
When I first started using boost I read through documentation on DateTime, but I haven't really had a need to use it and so don't remember much of the details. I will look back sometime in next couple of weeks and compare the concepts, but probably not before I have a version out for people to play with. On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
Although I appreciate your efforts to implement an efficient way to automatically convert different units for the same quantity, I would still prefer a library that requires an explicit "cast" to change units, rather than implicit. Perhaps the library could be built in two layers, with the lower level requiring explicit casts and a layer above that that implements implicit casting for those who want it.
When I first started with the library, I thought that might be a good idea, but as development went on I decided that it wasn't really necessary. Could you actually give any example as to why you would actually want such restrictions? Keep in mind that explicit unit casts are still available. -- -Matt Calabrese

Matt Calabrese wrote:
On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
Although I appreciate your efforts to implement an efficient way to automatically convert different units for the same quantity, I would still prefer a library that requires an explicit "cast" to change units, rather than implicit. Perhaps the library could be built in two layers, with the lower level requiring explicit casts and a layer above that that implements implicit casting for those who want it.
When I first started with the library, I thought that might be a good idea, but as development went on I decided that it wasn't really necessary. Could you actually give any example as to why you would actually want such restrictions? Keep in mind that explicit unit casts are still available.
I work mostly with calendar time. Although I want to view both years and months as units for the same vector quantity (time duration), I find that in any one code module, I always want to use a single consistent unit (which might be templatized). All the unit casting occurs only for inputs and outputs to the module. So if my code tries to add years to months, it's a coding error. I can't speak for the people programming in physical units, but I just can't imagine wanting to mix variables representing the same dimension with different units in a single arithmetic expression. Even with a dimensions library, it seems like a recipe for trouble to me. To me it's much safer to convert all inputs (which may have different units) into a single set of consistent units when entering a module and converting all outputs into the desired units when exiting. By using templates, this can all be done very cleanly without hardwiring either the internal units or the external units.

"Matt Calabrese" wrote
The example you gave is actually a barycentric combination with all weights equal. Just like in geometry, this does not mean that the addition operator should be defined for points to perform component-wise addition. Instead, I provide a "componentwise_add" function for such rare cases, and I will also be making a set of average and a barycentric combination functions to abstract away the concepts.
FWIW in pqs I worked very hard to make sure that operations worked smoothly without "rare cases". This approach made for ease of use with simple syntax. The other area I worked hard at was dimensionless results for which I returned the promoted value_type of the operands. It would have been easy to provide a dimensionless quantity but this too would fail in "rare cases".
Are there not subtleties with temporaries using ET that users need to know about?
I don't see a good reason to convert to the most fine-grained unit type. If anything, that can only cause more conversions which could not only make the expression less-optimized, but also have less-precise results depending on the value_type of the operands. I decided that determining the type to convert to be context is the best solution.
What would you output in a case such as : std::cout << millimeters(1) / seconds(1); Have you thought about stream output ?
Adding new classification types and new unit types is actually very simple at the moment. For derived classification types, it's as simple as:
[cut]
Making new derived units is just as easy:
typedef unit< miles, per< hour > > mph;
// or
typedef typeof( miles() / hour() ) miles_per_hour;
What do you do when two quantities have the same dimensional signature eg torque and energy? regards Andy Little

On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
FWIW in pqs I worked very hard to make sure that operations worked smoothly without "rare cases". This approach made for ease of use with simple syntax.
I'm not going to make bad code easy to write by allowing points to be added with operator +. Again, this is why in geometry you don't normally define addition of points, since on its own it makes no sense. In reality it only makes sense as an implementation detail of a higher-level operation. For instance, the rare case you mention and that I mention are still very easily expressible without the need for operator + to be defined. I suggested providing a function such as average( t1, t2, t3, t4, t5, t6 ), which internally uses component-wise addition through my componentwise_add function (NOT using operator +). As I said, I will provide this and barycentric combination function templates to cover those situations, but I'm not going to overload operator + for points, since it isn't a logical operation on its own and would just allow for illogical expressions, such as just the addition of the temperature at the beginning of the day with the temperature at the end of the day. If I really want to go far, using expression templates I could allow addition to compile only if it is a direct subexpression of a multiplicative expression containing division, or if the expression follows the form of a barycentric combination, but that would be going overboard. Using high-level functions which abstract the functionality is generally a much better approach. On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
What would you output in a case such as :
std::cout << millimeters(1) / seconds(1);
I have not yet set up output, though have it planned extensively. The way I plan on output working for unit types is, initially, when complex derived unit types are formed through operations, their output name is going to be described using all base classifications connected by operations I.E. if you did 2meters * 5kilograms / 5seconds^2 the name of the unit when output would be "5 ( meters * kilograms seconds^-2 )". Note that it would not say 5 Newtons. This is because such a name lookup could be extremely costly for derived units and requires some form of registration. More precisely, with registration, in order to figure out that the name "Newton" could be used, the algorithm would still have to take R*N*log(N) time in the worst case, where R is the number of units registered under that derived classification and N is the number of unique base unit types which make up the derived unit type. This complexity is necessary due to the nature of compile-time associative sequences as having an order dependent upon how they are created. If the person wishes to output the more simple name such as "Newtons", they would use an expression modifier such as simply_named( your_expression_here ) prior to output. I could provide that functionality by default, but avoiding it can provide much better compilation time, so I don't plan on it. In addition to this, I will also allow for shortened names such as kg for kilograms, etc. which would also be an option prior to output through an expression modifier. On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
What do you do when two quantities have the same dimensional signature eg
torque and energy?
Then the division of one by the other results in a type having "empty_classification" (which is the derived classification used by angles, etc. as with SI Units). On 10/11/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
The other area I worked hard at was dimensionless results for which I
returned the promoted value_type of the operands. It would have been easy to provide a dimensionless quantity but this too would fail in "rare cases".
I provide a dimension-less quantity called empty_classification, since it provides more information and is safer than a raw value. I understand why one might think it a good idea to result in just the raw value as opposed to an encapsulated one, but I don't believe it is the correct decision. This is because while the resultant quantity is of an empty classification, it does still have a unique unit type. I.E. Both radians and degrees have an empty_classification, yet have different unit types and their values mean different things. If you just result in the raw value as opposed to a quantity specifying units, you lose all of the unit information. Now that you have lost the unit information, using the value in an operation with other units of empty_classification would be seemingly ambiguous. For instance, I do not believe it is a good idea to allow for quantity< degrees >( 180. ) + 3.14159 By your logic, such an expression would have to be allowable. However, it really should not, since 3.14159, while is of empty_classification, does not state which unit type it has. Obviously here it is in radians, which happens to be the natural unit type of empty_classification, but you can never be sure of this and so shouldn't even always just assume raw values are in radians. One of the main purposes of a library like this is to make operations more typesafe, whereas what you suggest actually has the opposite effect. Another example is forming an angle in radians via a ratio: circumference_in_meters / radius_in_meters The resultant expression is a quantity in radians and should have that unit information accessible, despite that it is of empty classification. Your approach would have it be a raw value without units associated with it which just results in a loss in type information. You could just always assume raw values are radian values, but that's just asking for trouble as it opens the library up to misuse. If anything, I may provide a raw conversion operator to the raw value for units with empty_classification to allow for implicit conversion to ratios (which would be equivalent the yielding the raw value of the quantity after being converted to radians), however I have not yet decided if such an operation would be appropriate as implicit, and to be honest, I am leaning towards no. -- -Matt Calabrese

"Matt Calabrese" <rivorus@gmail.com> wrote
I have not yet set up output, though have it planned extensively. The way I plan on output working for unit types is, initially, when complex derived unit types are formed through operations, their output name is going to be described using all base classifications connected by operations I.E. if you did 2meters * 5kilograms / 5seconds^2 the name of the unit when output would be "5 ( meters * kilograms seconds^-2 )".
You might want to look at http://physics.nist.gov/cuu/Units/ cheers Andy Little

"Matt Calabrese" wrote
I'm not going to make bad code easy to write by allowing points to be added with operator +.
You seem to be making good code more difficult to write though. :-(
Again, this is why in geometry you don't normally define addition of points, since on its own it makes no sense.
hmm.... Geometry does define addition of points....
In reality it only makes sense as an implementation detail of a higher-level operation.
As you confirm here... ;-)
For instance, the rare case you mention.
Addition is pretty common e.g for curves, for piecewise integrals(e.g Simpsons rule) etc. Physical data is noisy more often then not.
and that I mention are still very easily expressible without the need for operator + to be defined. I suggested providing a function such as average( t1, t2, t3, t4, t5, t6 ), which internally uses component-wise addition through my componentwise_add function (NOT using operator +).
You havent actually removed addition. You've just given it a non-obvious name. ;-)
As I said, I will provide this and barycentric combination function templates to cover those situations, but I'm not going to overload operator + for points, since it isn't a logical operation on its own and would just allow for illogical expressions, such as just the addition of the temperature at the beginning of the day with the temperature at the end of the day.
I dont see how changing the name of the function helps. componentwise_add is an addition right?
If I really want to go far, using expression templates I could allow addition to compile only if it is a direct subexpression of a multiplicative expression containing division, or if the expression follows the form of a barycentric combination, but that would be going overboard.
For true safety you would need to check the calculation-constants are correct. OTOH... maybe I want to accumulate my values in a container....? You would need to do the check at runtime in that case. [cut]
On 10/11/05, Andy Little wrote:
What do you do when two quantities have the same dimensional signature eg
torque and energy?
Then the division of one by the other results in a type having "empty_classification" (which is the derived classification used by angles, etc. as with SI Units).
The term used by the SI is dimensionless. I believe that the radian and steradian are described as dimensionless derived units. Whatever...You need a means to distinguish dimensionally-equivalent types for output purposes.
On 10/11/05, Andy Little wrote:
The other area I worked hard at was dimensionless results for which I
returned the promoted value_type of the operands. It would have been easy to provide a dimensionless quantity but this too would fail in "rare cases".
I provide a dimension-less quantity called empty_classification, since it provides more information and is safer than a raw value.
Ah right. OK .Sorry I should have said "numeric results" rather than dimensionless results. A numeric type needs no extra information. Only when you have other information (as with angles) will a record of the extra information be necessary. When there is no extra information there is no reason not to return a numeric type.
I understand why one might think it a good idea to result in just the raw value as opposed to an encapsulated one, but I don't believe it is the correct decision.
Well the decision to use numeric types where possible as opposed to a dimensionless udt works fine in pqs. I have no reason to believe it was the wrong decision. It makes the library directly compatible with inbuilt types. Its easy to use and there are no oddities to learn.
I.E. Both radians and degrees have an empty_classification, yet have different unit types and their values mean different things.
Ok.
If you just result in the raw value as opposed to a quantity specifying units, you lose all of the unit information.
Well numeric types by nature dont have any unit information. I guess you could add scalinfg of eg *10^3 etc, but really all you are doing is creating an extended floating point type.
Now that you have lost the unit information, using the value in an operation with other units of empty_classification would be seemingly ambiguous. For instance, I do not believe it is a good idea to allow for
quantity< degrees >( 180. ) + 3.14159
By your logic, such an expression would have to be allowable.
No... OTOH ... quantity<radians>(pi ) + 3.14159 ; ... I would have no problem with. hmmm. You could add angle to the base-units, but then an angle quantity wouldnt be strictly dimensionless. It would have a dimension of {mass(0), length(0),.., angle(1)}. In pqs I made various distinctive types of angle separating them overall into two major types; fractions_of_revolution which comprised degrees,minutes etc. and radians. radians has an implicit conversion to and from a numeric type whereas the other types needed to be converted to radians and then to a numeric type. Previously I was against adding angle to the base-units but it might be worth revisting that, though I would try to keep similar semantics to those I have in pqs currently.
However, it really should not, since 3.14159, while is of empty_classification, does not state which unit type it has. Obviously here it is in radians, which happens to be the natural unit type of empty_classification, but you can never be sure of this and so shouldn't even always just assume raw values are in radians.
In pqs I assume that raw values are numeric. radians are different its true.
One of the main purposes of a library like this is to make operations more typesafe, whereas what you suggest actually has the opposite effect.
To be honest I'm nopt sure what I am meant to have suggested.. :-(
Another example is forming an angle in radians via a ratio:
circumference_in_meters / radius_in_meters
The resultant expression is a quantity in radians and should have that unit information accessible, despite that it is of empty classification.
dimensionless... sure.
Your approach would have it be a raw value without units associated with it which just results in a loss in type information.
Thats fine if there is no requirement for 'type information', which is the case with numeric types. regards Andy Little

Andy Little wrote:
"Matt Calabrese" wrote
I'm not going to make bad code easy to write by allowing points to be added with operator +.
You seem to be making good code more difficult to write though. :-(
I humbly disagree. He's trying to differentiate between interface and implementation, to make it easier to write good code. (As you probably recall, I raised this issue before and conceded the issue to you. But I think Matt raises good points.)
Again, this is why in geometry you don't normally define addition of points, since on its own it makes no sense.
hmm.... Geometry does define addition of points....
Not that I'm aware of. Could you elaborate? Given two points, A and B, "A+B" makes no geometric sense but "tA + (1-t)B" does. You should think of the latter as a primitive geometric operation. The fact that it can be written in terms of vector addition is an implementation detail and should be hidden from the interface. Allowing "A+B" makes it easier to write incorrect formulas involving points.
In reality it only makes sense as an implementation detail of a higher-level operation.
As you confirm here... ;-)
For instance, the rare case you mention.
Addition is pretty common e.g for curves, for piecewise integrals(e.g Simpsons rule) etc. Physical data is noisy more often then not.
If you parse these formulas carefully, you will see that they can always be written in terms of the following operations only: point +/- vector = point vector +/- vector = vector vector */ scalar = vector
and that I mention are still very easily expressible without the need for operator + to be defined. I suggested providing a function such as average( t1, t2, t3, t4, t5, t6 ), which internally uses component-wise addition through my componentwise_add function (NOT using operator +).
You havent actually removed addition. You've just given it a non-obvious name. ;-)
No. He's removed addition of points from the interface and hidden it in the implementation. I agree with this. This for me makes it easier to write good code, not harder, because it protects you from coding incorrect formulas involving points.
As I said, I will provide this and barycentric combination function templates to cover those situations, but I'm not going to overload operator + for points, since it isn't a logical operation on its own and would just allow for illogical expressions, such as just the addition of the temperature at the beginning of the day with the temperature at the end of the day.
I dont see how changing the name of the function helps. componentwise_add is an addition right?
By using a long and conspicuous name, it signals to the programmer that the formula should be checked with extra care, since the compiler cannot verify that only allowable operations are used in the formula. But I am fairly confident that you will need only barycentric combinations and nothing else.

"Deane Yang" wrote
Andy Little wrote:
"Matt Calabrese" wrote
I'm not going to make bad code easy to write by allowing points to be added with operator +.
You seem to be making good code more difficult to write though. :-(
I humbly disagree. He's trying to differentiate between interface and implementation, to make it easier to write good code.
You need + in the interface so users like me can write out the formulas as they see them written down. [cut]
hmm.... Geometry does define addition of points....
Not that I'm aware of. Could you elaborate? Given two points, A and B, "A+B" makes no geometric sense but "tA + (1-t)B" does. You should think of the latter as a primitive geometric operation.
err... hmm ... "tA + (1-t)B" is using '+' , Isnt it?
The fact that it can be written in terms of vector addition is an implementation detail and should be hidden from the interface.
Nonsense. '+' should be part of the interface. [cut]
Addition is pretty common e.g for curves, for piecewise integrals(e.g Simpsons rule) etc. Physical data is noisy more often then not.
If you parse these formulas carefully, you will see that they can always be written in terms of the following operations only:
point +/- vector = point vector +/- vector = vector vector */ scalar = vector
If the goal is to write good code, then please dont cooerce me to do home-made rearrangements of standard formulas to hide +. Thats a source of errors if ever there was one ;-)
You havent actually removed addition. You've just given it a non-obvious name. ;-)
No. He's removed addition of points from the interface and hidden it in the implementation.
No.. hes just changed the name . Its still in the interface., unless he's planning not to make the component_add function available to users. FWIW a reinterpret_cast to a vector looks like the easiest workaround!
I agree with this. This for me makes it easier to write good code, not harder, because it protects you from coding incorrect formulas involving points.
It certainly wastes my time trying to find workarounds or rearranging perfectly good formulae.to use '-'. More work for anyone reading or reviewing the code too. [cut]
I dont see how changing the name of the function helps. componentwise_add is an addition right?
By using a long and conspicuous name, it signals to the programmer that the formula should be checked with extra care, since the compiler cannot verify that only allowable operations are used in the formula.
Maybe it makes the programmer wonder why they didnt provide operator +. This type of code is usually written using floating point types. I would suggest making the library as simple to use as possible. regards Andy Little

Andy Little wrote:
You need + in the interface so users like me can write out the formulas as they see them written down.
...
The fact that it can
be written in terms of vector addition is an implementation detail and should be hidden from the interface.
Nonsense. '+' should be part of the interface.
...
If the goal is to write good code, then please dont cooerce me to do home-made rearrangements of standard formulas to hide +. Thats a source of errors if ever there was one ;-)
...
It certainly wastes my time trying to find workarounds or rearranging perfectly good formulae.to use '-'. More work for anyone reading or reviewing the code too.
...
Maybe it makes the programmer wonder why they didnt provide operator +.
In other words, you want to treat points as if they were vectors. But you can do so by simply ignoring and not using the classes that represent point quantities and simply using vector quantities for your points and vectors alike. On the other hand, if the library itself implements point quantities as if they have the same properties as vector quantities, then nothing is gained by defining point quantities as a different class from vector quantities. I have to say I have sympathy for your point of view. If you are programming physical or geometric formulas from a reference, then it will be given in terms of "+", so it would indeed take more work and effort to onvert them correctly into formulas that only use barycentric combinations and differences. I like going through this exercise and consider it helpful in writing correct code, but I can see how many programmers would consider it a complete waste of time. I would encourage you to try it out; I claim that the new formulas are often easier to understand than the traditional ones. But if you really don't like it, just stick to vectors and ignore everything in the library referring to affine spaces or point quantities. I'd like a library that can handle both points of view.

On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Well the decision to use numeric types where possible as opposed to a
dimensionless udt works fine in pqs. I have no reason to believe it was the wrong decision. It makes the library directly compatible with inbuilt types. Its easy to use and there are no oddities to learn.
The library still is compatible with built-in types and there really shouldn't be any oddities to learn. types with an empty classification still have units associated with them, whereas built-in types do not. As well, if I were to go the route of making them built-in types, then they would have to all be of one unit type and would not be easily useable in expression templates (since just a raw add without explicit encapsulation would use the built-in operator + or the overloaded operator + for that type).
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Well numeric types by nature dont have any unit information. I guess you
could add scalinfg of eg *10^3 etc, but really all you are doing is creating an extended floating point type.
When you form a value from division of two quantities, it has units with an empty classification. Like the example I gave above, division of a circle's circumference by its radius gives you a result in radians, which is a unit which has an empty classification (such as with SI units). An empty classification is not the same as a lack of units. Resulting in a raw value needlessly gets rid of this abstraction.
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote: No... OTOH ...
quantity<radians>(pi ) + 3.14159 ;
... I would have no problem with.
That's because the number is in radians. Basically what you're saying is "assume all raw values are quantities in radians", which is not a valid assumption. As well, what type of quantity is 3.14159? Is it a scalar quantity or a vector quantity or a point quantity? If it is a vector quantity or a point quantity then that operation should not be allowable, since you can't add a scalar to a vector or point. Unfortunately, since you suggest to allow raw values, you lose this abstraction. The fact of the matter is, you creating ambiguity but then arbitrarily allowing certain operations. On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
In pqs I assume that raw values are numeric. radians are different its true.
Then why did you state above that the radian value should be allowed to be added with the numeric? A quantity with units plus a raw numeric shouldn't make sense, even with radians. On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote: Thats fine if there is no requirement for 'type information', which is the
case with numeric types.
My argument is that what you call numeric types aren't always simply numeric types. Division of similar quantities result in a quantity with an empty classification but which has unique units, such as with radians. Completely separately, I do see an orthogonal problem. How should we handle multiplication of two quantities of empty classification. For instance, degrees * degrees should result in degrees^2, just like meters * meters results in meters^2. This concept does make sense, however, squaring a quantity which has an empty classification would result in another quantity having an empty classification (0^2 equals 0). So, we run into the odd case that degrees and degrees^2 have the same classification. At the moment I am not sure it is correct, however I do have some theories about the concept. Continuing with the case of degrees, I believe that degrees and degrees^2 should have the same classification, however considering scalars and vectors, conversion between those two types should be disallowed. Surprisingly, the conversion should be allowable for points. I haven't written the following logic in words yet, so bare with me. I'll do the best I can. At first this may seem strange, but it is based on a theory that I have been thinking about concerning support for units such as decibels or the richter scale. The concept is that while the two units, such as degrees and degrees^2, have the same classification, conversion between the two spaces is not defined by an affine transformation, but rather something more complex. In such a case, vectors in one space could be added with vectors the same space, however conversion from a vector in one space to vectors in the other space is not defined. This concept sounds odd, but I currently believe it is correct. I'll switch to decibels for a moment, since the situation is easier to create a common case for. Decibels are related to other units of the same classification logarithmically. This classification happens to be an empty classification -- the same as radians and degrees. What this means is that If you were to take "decibel" space and compare it to the natural space of radians and degrees, the distance between 0 and 1 in decibel space would not be the same magnitude in natural space as the distance between 1 and 2 in decibel space. Depending on where you are in decibel space changes magnitudes of vectors when looked at from natural space. For instance, a 2 decibel vector + a 3 decibel vector is a perfectly fine operation resulting in a 5 decibel vector, however, a vector quantity of 5 decibels + a vector quantity of 5 radians can't be performed, since the magnitude of "5 decibels" changes in radian space depending on where in that space you are. Since vectors on their own have no spacial location, the operation makes no sense. However, points do have a well-defined location in their space, and conversion from spaces such as radians to decibels is actually defined, just not through a simple scale change and phase shift. Instead, it is a logarithmic relationship. Because of this, you can convert from radian points to decibel points. This makes sense since decibels describe a ratio, which radians are, through a logarithmic scale. Unlike with two vectors from different spaces, you can even add a radian point with a decibel vector, since the radian point can be converted to a decibel and then added to the decibel vector! This type of odd relationship actually makes mathematical sense, and in my opinion, is necessary for representing concepts such as decibels, or the richter scale, or nepers. As with the above example, I believe the same type of concept exists for degrees and degrees^2, with an exponential relationship. The benefits of this are that we properly represent degrees and degrees^2 as both having an empty derived classification, yet, just as intuitively, you can't add a degree with a degrees^2 vector, though their points are convertible to each other. This is a concept which is difficult to understand, though that I believe is entirely correct. Thankfully, average users wouldn't be affected anyway. Again, this is all just theoretical stuff that I have been thinking about, and is currently the best model that I have come up with and seems to handle all cases that I throw at it. Because of this, I have no outside sources to provide and backup my theory, so hopefully all of the above logic makes sense. I'd appreciate it if people could provide some criticisms, particularly mathematicians, and if possible, provide other solutions if my theories are flawed. These situations definately must be handled prior to release, otherwise common units such as decibels or nepers can't be represented, and the concepts of degrees^2 or other similar units would remain unhandled. -- -Matt Calabrese

I went to bed but couldn't sleep as I believe I made a mistake here. Not regarding decibels, etc. but regarding the relationship between degrees and degrees^2. After more thinking about it, I believe that while they should share the same classification, as one would notice from dimension analysis, conversion between them should not be defined at all, even for points. I foolishly stated that the relationship should be exponential without fully thinking it through. So, basically, the result would be a unit type of the same classification with no way to convert to many other units of the same classification. On 10/13/05, Matt Calabrese <rivorus@gmail.com> wrote:
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Well the decision to use numeric types where possible as opposed to a
dimensionless udt works fine in pqs. I have no reason to believe it was the wrong decision. It makes the library directly compatible with inbuilt types. Its easy to use and there are no oddities to learn.
The library still is compatible with built-in types and there really shouldn't be any oddities to learn. types with an empty classification still have units associated with them, whereas built-in types do not. As well, if I were to go the route of making them built-in types, then they would have to all be of one unit type and would not be easily useable in expression templates (since just a raw add without explicit encapsulation would use the built-in operator + or the overloaded operator + for that type).
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Well numeric types by nature dont have any unit information. I guess you
could add scalinfg of eg *10^3 etc, but really all you are doing is creating an extended floating point type.
When you form a value from division of two quantities, it has units with an empty classification. Like the example I gave above, division of a circle's circumference by its radius gives you a result in radians, which is a unit which has an empty classification (such as with SI units). An empty classification is not the same as a lack of units. Resulting in a raw value needlessly gets rid of this abstraction.
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote: No... OTOH ...
quantity<radians>(pi ) + 3.14159 ;
... I would have no problem with.
That's because the number is in radians. Basically what you're saying is "assume all raw values are quantities in radians", which is not a valid assumption. As well, what type of quantity is 3.14159? Is it a scalar quantity or a vector quantity or a point quantity? If it is a vector quantity or a point quantity then that operation should not be allowable, since you can't add a scalar to a vector or point. Unfortunately, since you suggest to allow raw values, you lose this abstraction. The fact of the matter is, you creating ambiguity but then arbitrarily allowing certain operations.
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
In pqs I assume that raw values are numeric. radians are different its true.
Then why did you state above that the radian value should be allowed to be added with the numeric? A quantity with units plus a raw numeric shouldn't make sense, even with radians.
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
Thats fine if there is no requirement for 'type information', which is the
case with numeric types.
My argument is that what you call numeric types aren't always simply numeric types. Division of similar quantities result in a quantity with an empty classification but which has unique units, such as with radians. Completely separately, I do see an orthogonal problem. How should we handle multiplication of two quantities of empty classification. For instance, degrees * degrees should result in degrees^2, just like meters * meters results in meters^2. This concept does make sense, however, squaring a quantity which has an empty classification would result in another quantity having an empty classification (0^2 equals 0). So, we run into the odd case that degrees and degrees^2 have the same classification. At the moment I am not sure it is correct, however I do have some theories about the concept. Continuing with the case of degrees, I believe that degrees and degrees^2 should have the same classification, however considering scalars and vectors, conversion between those two types should be disallowed. Surprisingly, the conversion should be allowable for points. I haven't written the following logic in words yet, so bare with me. I'll do the best I can. At first this may seem strange, but it is based on a theory that I have been thinking about concerning support for units such as decibels or the richter scale. The concept is that while the two units, such as degrees and degrees^2, have the same classification, conversion between the two spaces is not defined by an affine transformation, but rather something more complex. In such a case, vectors in one space could be added with vectors the same space, however conversion from a vector in one space to vectors in the other space is not defined. This concept sounds odd, but I currently believe it is correct. I'll switch to decibels for a moment, since the situation is easier to create a common case for. Decibels are related to other units of the same classification logarithmically. This classification happens to be an empty classification -- the same as radians and degrees. What this means is that If you were to take "decibel" space and compare it to the natural space of radians and degrees, the distance between 0 and 1 in decibel space would not be the same magnitude in natural space as the distance between 1 and 2 in decibel space. Depending on where you are in decibel space changes magnitudes of vectors when looked at from natural space. For instance, a 2 decibel vector + a 3 decibel vector is a perfectly fine operation resulting in a 5 decibel vector, however, a vector quantity of 5 decibels + a vector quantity of 5 radians can't be performed, since the magnitude of "5 decibels" changes in radian space depending on where in that space you are. Since vectors on their own have no spacial location, the operation makes no sense. However, points do have a well-defined location in their space, and conversion from spaces such as radians to decibels is actually defined, just not through a simple scale change and phase shift. Instead, it is a logarithmic relationship. Because of this, you can convert from radian points to decibel points. This makes sense since decibels describe a ratio, which radians are, through a logarithmic scale. Unlike with two vectors from different spaces, you can even add a radian point with a decibel vector, since the radian point can be converted to a decibel and then added to the decibel vector! This type of odd relationship actually makes mathematical sense, and in my opinion, is necessary for representing concepts such as decibels, or the richter scale, or nepers. As with the above example, I believe the same type of concept exists for degrees and degrees^2, with an exponential relationship. The benefits of this are that we properly represent degrees and degrees^2 as both having an empty derived classification, yet, just as intuitively, you can't add a degree with a degrees^2 vector, though their points are convertible to each other. This is a concept which is difficult to understand, though that I believe is entirely correct. Thankfully, average users wouldn't be affected anyway. Again, this is all just theoretical stuff that I have been thinking about, and is currently the best model that I have come up with and seems to handle all cases that I throw at it. Because of this, I have no outside sources to provide and backup my theory, so hopefully all of the above logic makes sense. I'd appreciate it if people could provide some criticisms, particularly mathematicians, and if possible, provide other solutions if my theories are flawed. These situations definately must be handled prior to release, otherwise common units such as decibels or nepers can't be represented, and the concepts of degrees^2 or other similar units would remain unhandled.
-- -Matt Calabrese
-- -Matt Calabrese

"Matt Calabrese" <rivorus@gmail.com> wrote
My argument is that what you call numeric types aren't always simply numeric types. Division of similar quantities result in a quantity with an empty classification but which has unique units, such as with radians. Completely separately, I do see an orthogonal problem. How should we handle multiplication of two quantities of empty classification. For instance, degrees * degrees should result in degrees^2, just like meters * meters results in meters^2. This concept does make sense, however, squaring a quantity which has an empty classification would result in another quantity having an empty classification (0^2 equals 0). So, we run into the odd case that degrees and degrees^2 have the same classification.
FWIW angle * angle is known as a 'solid angle". steradian is a solid angle unit. regards Andy Little

"Matt Calabrese" <rivorus@gmail.com> wrote
When you form a value from division of two quantities, it has units with an empty classification.
When you divide length by time you get another quantity. When you divide a length by a length you get a number. Its that simple.
Like the example I gave above, division of a circle's circumference by its radius gives you a result in radians, which is a unit which has an empty classification (such as with SI units).
The ratio of the circumference of two circles is a number. The ratio of two lengths is a number. The ratio of two temperatures is a number. the ratio of two masses is a number. Etc. No units involved there.
An empty classification is not the same as a lack of units. Resulting in a raw value needlessly gets rid of this abstraction.
No . it gets rid of an unnecessary abstraction. Use a number to represent a number. Simple.
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote: No... OTOH ...
quantity<radians>(pi ) + 3.14159 ;
... I would have no problem with.
That's because the number is in radians. Basically what you're saying is "assume all raw values are quantities in radians", which is not a valid assumption.
Please. I havent said that at all. I have found it useful in practise to provide implicit conversion between radians and numeric types. Dimensional-analysis sees all dimensionless types as dimensionally-equivalent. If they are dimensionally-equivalent they are addable. Simple. radians unit is useful for output but thats about it. The tension (F = m *w^2 * r) in a string length r with a mass m at the end being whirled in a circle with angular-velocity w, is an example. F doesnt have any angular information. In your library I assume this equation would be invalid?
As well, what type of quantity is 3.14159? Is it a scalar quantity or a vector quantity or a point quantity? If it is a vector quantity or a point quantity then that operation should not be allowable, since you can't add a scalar to a vector or point. Unfortunately, since you suggest to allow raw values, you lose this abstraction. The fact of the matter is, you creating ambiguity but then arbitrarily allowing certain operations.
numeric constants are not going to be allowed in the units library because they are ambiguous? Youre joking now right? :-).
On 10/12/05, Andy Little <andy@servocomm.freeserve.co.uk> wrote:
In pqs I assume that raw values are numeric. radians are different its true.
Then why did you state above that the radian value should be allowed to be added with the numeric? A quantity with units plus a raw numeric shouldn't make sense, even with radians.
In pqs addition of a numeric and a radian results in a radian . However I make it easy to lose the units. A radians type is mainly useful for output and for conversion to degrees. cheers Andy Little

Andy Little wrote:
"Matt Calabrese" <rivorus@gmail.com> wrote
When you form a value from division of two quantities, it has units with an empty classification.
When you divide length by time you get another quantity. When you divide a length by a length you get a number. Its that simple.
...
The ratio of the circumference of two circles is a number. The ratio of two lengths is a number. The ratio of two temperatures is a number. the ratio of two masses is a number. Etc. No units involved there.
An empty classification is not the same as a lack of units. Resulting in a raw value needlessly gets rid of this abstraction.
No . it gets rid of an unnecessary abstraction. Use a number to represent a number. Simple.
I can't claim to have understood all of Matt's discussion about this and, as always, I am of two minds on this. Mathematically, I think Andy is entirely correct in what he says above. Once you take the ratio of two measurements of the same dimension (or quantity), you end up with a pure number that really can't be distinguished from other ratios or pure numbers. For example, notice that it is useful to feed pure numbers or ratios into nonlinear functions such as the exponential and logarithm functions (as well as trig functions). Such functions are pure mathematical functions that can only take pure unitless numbers as inputs and return unitless numbers as outputs. On the other hand, when coding, it would be nice to be able to protect against mixing radians and decibels inappropriately in the same formula, so assigning different types to them is an attractive idea. I have experimented with this, but have not found a satisfactory solution myself. Could you remind me what operations are permitted with an "empty classification"? What happens if you take the ratio of two values with the same empty classification? Are you allowed to feed it into the exponential function?

On 10/13/05, Deane Yang <deane_yang@yahoo.com> wrote:
Mathematically, I think Andy is entirely correct in what he says above. Once you take the ratio of two measurements of the same dimension (or quantity), you end up with a pure number that really can't be distinguished from other ratios or pure numbers.
I tend to disagree here. A ratio of two lengths, for example, is in fact a value in radians. For instance, a radian angle measure is formed by dividing an arc length by the corresponding radius. Both arc length and radius are units with a length classification. As such, the result is a unit having a derived classification with fundamental parts cancelled out (as described by SI units) and has the SI unit type of radians. If anything, as I described earlier, I believe implicit conversion from that type to a raw value may be allowable, such that they can easily be used with functions which take raw values, however storing them directly as raw values is not a good idea. Take this situation, for example, if one were to choose to make the result of length / length simply a raw value. What happens if you have: arc_length / radius + quantity< degrees >( 90 ); If you choose to have the result of the first operation be a raw value as opposed to a radian value, then what do we do here? Andy states that the operation shouldn't be allowed, however, I believe it should, since arc_length / radius is in fact an angle. The only way I see around this other than having the division result in radians is to always assume that numeric values without explicit units attached to them are in radians. If we do this, then we run into the problem that since we now store calculations which result in radians as simply raw values, multiplying together two radian values (now represented as raw values) will not result in steradians! The result of a raw value times a raw value would just be another raw value, which you have always assumed to be in radians, when in actuality it is not the case, since now they are logically steradians even though you have not represented them as such. This goes back to what I've been attempting to explain -- a radian when formed by the division of two lengths is still a radian and should have that information attached to it, otherwise the value cannot be used unambiguously in further expressions. Steradians and radians, just like my example of degrees^2 and degrees, are entirely different concepts, and representing radians as just raw values would be getting rid of the ability to have that difference in types. Thus, as soon as one starts working with concepts such as angles, much of the safety and proper implicit conversionsthat the rest of the library has would be lost. On 10/13/05, Deane Yang <deane_yang@yahoo.com> wrote:
Could you remind me what operations are permitted with an "empty classification"? What happens if you take the ratio of two values with the same empty classification? Are you allowed to feed it into the exponential function?
Everything that is allowed with units of other classifications. Intuitively, I believe that a quantity with an empty classification divided by a quantity with an empty classification would result in another value with an empty classification. Just like with length and length, the result would have an empty classification, however it would still have units associated with it, just like other calculations using quantities. If I decide to go the route of having units with an empty classification able to be implicitly converted to raw values, then yes, you would be able to feed them to math functions, such as those in <cmath>, taken that you are using standard types of course. Just so we're clear, if we allow this implicit conversion for simple ratios such as radians, I believe the same would have to be allowed for degrees and other simple angle unit types since logically they are just ratios as well, only represented under a transformation. The result of converting a degree to a raw value would be the equivalent of converting it to radians and then returning that value. -- -Matt Calabrese

Matt Calabrese wrote:
On 10/13/05, Deane Yang <deane_yang@yahoo.com> wrote:
Mathematically, I think Andy is entirely correct in what he says above. Once you take the ratio of two measurements of the same dimension (or quantity), you end up with a pure number that really can't be distinguished from other ratios or pure numbers.
I tend to disagree here. A ratio of two lengths, for example, is in fact a value in radians. For instance, a radian angle measure is formed by dividing an arc length by the corresponding radius. Both arc length and radius are units with a length classification. As such, the result is a unit having a derived classification with fundamental parts cancelled out (as described by SI units) and has the SI unit type of radians. If anything, as I described earlier, I believe implicit conversion from that type to a raw value may be allowable, such that they can easily be used with functions which take raw values, however storing them directly as raw values is not a good idea.
This, I don't understand. If I have a right triangle and take the ratio of the "opposite side" over the hypotenuse, what I get is something that I would not view as being in radians, it is in "units" of "sin(radians)", if you really want to assign units to it (but once you allow nonlinear functions of units, you really have a mess, I think).
Take this situation, for example, if one were to choose to make the result of length / length simply a raw value. What happens if you have:
arc_length / radius + quantity< degrees >( 90 );
If you choose to have the result of the first operation be a raw value as opposed to a radian value, then what do we do here? Andy states that the operation shouldn't be allowed, however, I believe it should, since arc_length / radius is in fact an angle. The only way I see around this other than having the division result in radians is to always assume that numeric values without explicit units attached to them are in radians. If we do this, then we run into the problem that since we now store calculations which result in radians as simply raw values, multiplying together two radian values (now represented as raw values) will not result in steradians! The result of a raw value times a raw value would just be another raw value, which you have always assumed to be in radians, when in actuality it is not the case, since now they are logically steradians even though you have not represented them as such.
Do you distinguish between meters-measuring-linear-length and meters-measuring-arclength? Is it desirable to do so?
This goes back to what I've been attempting to explain -- a radian when formed by the division of two lengths is still a radian and should have that information attached to it, otherwise the value cannot be used unambiguously in further expressions. Steradians and radians, just like my example of degrees^2 and degrees, are entirely different concepts, and representing radians as just raw values would be getting rid of the ability to have that difference in types. Thus, as soon as one starts working with concepts such as angles, much of the safety and proper implicit conversionsthat the rest of the library has would be lost.
On 10/13/05, Deane Yang <deane_yang@yahoo.com> wrote:
Could you remind me what operations are permitted with an "empty classification"? What happens if you take the ratio of two values with the same empty classification? Are you allowed to feed it into the exponential function?
Everything that is allowed with units of other classifications. Intuitively, I believe that a quantity with an empty classification divided by a quantity with an empty classification would result in another value with an empty classification. Just like with length and length, the result would have an empty classification, however it would still have units associated with it, just like other calculations using quantities. If I decide to go the route of having units with an empty classification able to be implicitly converted to raw values, then yes, you would be able to feed them to math functions, such as those in <cmath>, taken that you are using standard types of course. Just so we're clear, if we allow this implicit conversion for simple ratios such as radians, I believe the same would have to be allowed for degrees and other simple angle unit types since logically they are just ratios as well, only represented under a transformation. The result of converting a degree to a raw value would be the equivalent of converting it to radians and then returning that value.
I'm sorry, but I don't consider degrees to be pure ratios or pure numbers. Degrees should be viewed as the arclength of a piece of a circle that has circumference equal to 360. Given an angle x in radians, sin(x) = x - x^3/3! + ..... Does your approach to radians work coherently with this formula? In other words, does it assign the right "units" to each term and to the "sin(x)"? I don't see how this can be done, because x^3/3! has to have the same units as x in order to allow the addition. Unlike for dimensional quantities, I don't have a coherent mathematical theory for unitless quantities, but my observation has been that "pure mathematical functions" like exp, log, sin, cos can only accept and return pure unitless ratios (like radians but not degrees). I don't see any way to impose any coherent system of units in a mathematically precise way.

On 10/13/05, Deane Yang <deane_yang@yahoo.com> wrote:
Given an angle x in radians,
sin(x) = x - x^3/3! + .....
Does your approach to radians work coherently with this formula? In other words, does it assign the right "units" to each term and to the "sin(x)"? I don't see how this can be done, because x^3/3! has to have the same units as x in order to allow the addition.
I would say yes. I describe radians as being untransformed ratios of two quantities of the same dimension, much like wikipedia. The value where factorial is being applied is an untranformed ratio (hense, as I believe, radians). An analysis being: "x in radians" - ( x^3 in radians^3 ) / ( 3 radians * 2 radians * 1 radian ) ... etc Note that the second term is radians^3 / radians^3. This pattern repeats always having radians^n / radians^n for terms. As I described radians as untransformed ratios of units of the same dimension, the overall result would also be in radians, which would be convertible to a raw value. The function would work perfectly and the terms would be able to be combined fine. -- -Matt Calabrese

Also, you could look at the factorial as 3 radians * 2 radians, thus the term would be radians^3 / radians^2, which is again, just a radian. -- -Matt Calabrese

Also, the fact that the result is in radians makes sense with my description of radians, since sine describes the ratio of the the opposite side of a right triangle to the hypoteneuse. This is an untransformed ratio of two quantities having the same dimension, which is, I believe uncoincidentally, exactly how I described radians. They are merely untransformed ratios which we only most commonly explicitly use when refering to angles. I believe the abstract concept of "radians" is always there for ratios of quantities having the same classification, it's just that we only write them down on paper when working with angles since it's used for disambiguation with common transformations of ratios such as degrees. I know it's strange, but comparing radians to decibels I think is another good way to attempt to explain the standpoint. Decibels and bels and nepers are all dimensionless types which represent the ratio of two values in logarithmic scales. My system can represent them perfectly fine and in a way that I believe makes logical sense. They are related to radians and degrees since all of them are just ways of representing ratios, either transformed or untransformed, just like other quantities having an empty classification, and a conversion exists between them. Since they are just transformations of ratios, expressions such as my_decibel_quantity = length / length should work fine, since the result of the right-hand operation is just a ratio, and decibels are merely transformations of ratios -- exactly like the relationship of two units of another classification such as time, energy, etc. Raw ratios are convertible to decibels since they both have units of empty classification and a defined relationship exists between them. I believe that stating that ratios exist in the same classification as quantities with an empty classification, only with no units attached is a mistake. My stance is that the unit type is not "unitless", but that the ratio has untransformed units in that derived classification. This unit type happens to be analogous to radians only perhaps with a broader definition than most people use. I wonder if the name is all that we are arguing about, so call it what you want -- "untransformed ratio" or something else, as the name is unimportant, but I believe the abstraction definately exists which is why we have different unit types which describe ratios, such as decibels. Using raw values without units associated loses that abstraction. That natural form isn't unitless, it's just that we don't normally attach a name to it. Following with geometry, radians are untransformed ratios (note here I'm purposely stating that radians are untransformed ratios not that untransformed ratios are radians, since I apparently have hit a nerve with some of you). If you don't want to call all ratios radians, a conversion still definately exists between them -- that conversion happens to be an identity conversion, where you leave the value the same, which is why the length of an arc divided by the radius can be converted to radians without changing the value. If you want, then look at the relationship similar to that of kelvin vectors and celsius vectors -- conversion between them is to simply leave the values the same and is implicit. Both concepts have units and can be looked at logically differently, but they are represented exactly the same, and they can be converted between. -- -Matt Calabrese

Matt Calabrese wrote:
Also, you could look at the factorial as 3 radians * 2 radians, thus the term would be radians^3 / radians^2, which is again, just a radian.
-- -Matt Calabrese _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Sure. I could also say that the factorial is 3 radians^2 * 2 radians^2 and get yet something else as a result. I don't get it. You need to explain some mathematical principles underlying what you're doing and not just try to come up with something that seems to fit in this particular case. You have to explain not just sin(x), but log(x) and arcsin(x), too.

Yeah, you're right. I think I just got caught up trying to remove special cases and have a more general abstraction without fully thinking it through. I see that this was a mistake, now. The result is no longer radians, it's just an encapsulated ratio (encapsulated because all expressions are encapsulated, since they are represented as expression templates, and so that way operator usage is still performed through the provided policies). Conversion to the raw value is implicit, so you can use the result of such expressions intuitively. However, I would like some input on my talk of decibels, only now removing my foolish talk of radians with "untransformed ratios" (encapsulated raw numbers which when multiplied together result in another "untransformed ratio" just like "regular" numbers operations result in more "regular" numbers). I'm unsure if you were confused by my explanation of the relationship of decibels to regular numbers and how point decibels are convertible to regular number points yet not vectors and scalars, so I hope this clarifies, and I would appreciate some feedback. To explain this better I'll try to give some more examples relating bels to untransformed ratios. Firstly, think of bel points and points without no units (untransformed ratio units). Bels are just ratios represented with a base 10 logarithmic scale, so concerning point space, these would be the relationships (bels are approximated): Ratio: 1 = Bel: 0 Ratio: 2 = Bel: 0.301 Ratio: 3 = Bel: 0.477 Ratio: 4 = Bel: 0.602 Ratio: 5 = Bel: 0.699 ... Ratio: 10 = Bel: 1 ... etc. I'm sure you understand the above, but it is provided for clarity and a point of reference. Note that while the space between a ratio (encapsulated raw number) increases by the number 1 in each grouping, the value in bels increases more slowly the further away from 0 you get. You can convert a point ratio to a point bel no problem, since the mapping is done by just applying base 10 logarithm to the ratio. However, this relationship cannot be use with vectors and scalars! In other words, a bel vector can not be converted to a "ratio" vector (raw vector) and a bel scalar can not be converted to a regular scalar. This is because how a ratio vector or magnitude relates to a bel vector or magnitude depends on "where" in point space those quantities lie. Since vectors and scalars have no spacial location, the conversion is impossible. Firstly, say you have two bel vectors with a value of 1 and a bel vector with a value of 2. If you were to assume that bel vectors were convertible to ratios, you would think that you could convert those bel vectors with value 1 to ratios, add them together, then convert them back to bels to have a value of 2. As I said, the conversion wouldn't exist, but I'll follow through with the operation to show the results: 1 bel = 10 10 + 10 = 20 20 = 1.301 bels 1.301 bels != 2 bels Again, this is the case because what a translation of "1 bel" or magnitude of "1 bel" is as a raw number changes depending on spacial location, which vectors and scalars don't have. In actuality, converting a bel vector to a raw number vector isn't possible, even though you can convert a bel point to a raw point! This also means that given two vectors, one of bels and one as an untransformed ratio, you can't add the two together, since conversion from one to the other is impossible. Now, what about adding a raw point with a bel vector? The operation can be done and makes logical sense. Rather than converting the bel vector to a raw vector, which is impossible, you have to convert the raw point to a bel point. Now the operation can be performed and results in a bel point. This bel point can also be converted back to a raw point if needed. This relationship is the same for nepers and the richter scale, etc. making it perfectly fine to have such unit types in an environment as other units, given proper use of points, vectors, and scalars. -- -Matt Calabrese

Matt Calabrese wrote:
However, I would like some input on my talk of decibels, ...
(discussion of bels omitted)
To be honest, I don't really have anything intelligent to say about your efforts to handle bels properly, except that, as far as I can tell, it isn't particularly relevant to my needs. I would suggest that it will be difficult to find an effective universal approach to handling dimensionless quantities and that your initial efforts might be best devoted to the dimensioned quantities (i.e., vector and point quantities).

Matt Calabrese wrote:
On 10/13/05, Deane Yang <deane_yang@yahoo.com> wrote:
Given an angle x in radians,
sin(x) = x - x^3/3! + .....
Does your approach to radians work coherently with this formula? In other words, does it assign the right "units" to each term and to the "sin(x)"? I don't see how this can be done, because x^3/3! has to have the same units as x in order to allow the addition.
I would say yes. I describe radians as being untransformed ratios of two quantities of the same dimension, much like wikipedia. The value where factorial is being applied is an untranformed ratio (hense, as I believe, radians).
An analysis being:
"x in radians" - ( x^3 in radians^3 ) / ( 3 radians * 2 radians * 1 radian ) ... etc
Can you justify why the factors in the denominator should be in "radians"? Can you do a similar analysis for me for the arcsin function? If I understand your explanations, you would say that given an angle x in radians, then both x and sin(x) are in radians. So this means you would allow the expression "x + sin(x)" and "(sin(sin(x))". If you allow all this, how is this better than just using pure floats or doubles as Andy has suggested?

"Matt Calabrese" wrote
On 10/13/05, Deane Yang wrote:
Mathematically, I think Andy is entirely correct in what he says above. Once you take the ratio of two measurements of the same dimension (or quantity), you end up with a pure number that really can't be distinguished from other ratios or pure numbers.
I tend to disagree here. A ratio of two lengths, for example, is in fact a value in radians.
As an example take two people. Person1 has a height of 1 m . Person2 has a height of 2 m. Person 1 is 1/2 as high as person 2. That 1/2 is certainly not measured in radians. it is just a number. [cut]
Take this situation, for example, if one were to choose to make the result of length / length simply a raw value. What happens if you have:
arc_length / radius + quantity< degrees >( 90 );
If you choose to have the result of the first operation be a raw value as opposed to a radian value, then what do we do here? Andy states that the operation shouldn't be allowed, however, I believe it should, since arc_length / radius is in fact an angle.
(Not sure what I am meant to have stated ) Actually this calc is entirely possible in pqs (See examples/angles.cpp). pqs uses angles as value_types. A sample calculation might look like this: // the angle value_type of arc_length signifies an arc length length_<of_angle::rad>::m arc_length(of_angle::pi/2); //[2] // the implicit double value_type of radius signifies a straight length length::m radius(1); std::cout << arc_length / radius + of_angle::deg(90) << '\n'; Outputs 3.141593 rad (The type of len1 / len2 is radians. radians and degrees are addable .) However // meant to be an arc length length::m arc_len1( pi/2); // the implied double value_type signifies a straight length length::m len2(1); std::cout << arc_len1 / len2 + of_angle::deg(90) << '\n'; // no operator + for (double, degrees). It does work (You can also use degrees etc as the value_type) but the implicit conversion from radians to/from numeric is also available if user wishes to work in a simpler way. cheers Andy Little [note1] To get the implicit conversion behaviour in pqs-2-00-02 you need to define PQS_IMPLICIT_RADIANS_STRAIGHTENING. It was an experimental behaviour but as it seems to work ok I guess it should be the default. However implicit conversion of degrees(minutes,seconds etc) to a numeric type was found to be unsatisfactory. [note 2] I really should change l 'of_angle, to just 'angle;' It would make much more sense ;-)

On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
What I'm more interested in learning is how you handle "composite quantities", which are obtained by multiplying and dividing existing units (like "meters/second"), as well as raising to a rational power (like the standard unit of volatility in finance, "1/square_root(years)".
Rational powers are handled with power functions and metafunctions, as I showed in later replies. However, I would like much more information regarding "volatility in finance." Up until now, I have seen absolutely no cases where non-derived unit classifications raised to a non-integer powers makes sense and have even talked about such situations with mathematicians. Looking back to the archives, I see people talking about fractional-powered base units being possible and speak of examples from other threads, but I can't seem to find such examples. An exact link would be very helpful. Right now I support fractional powers, but not when the operation yields fractional-powered base units. For instance, I allow the expression power< 1, 2 >( your_meters_quantity * your_meters_quantity ) // where power< 1,2 > denotes a power of 1/2 However, I have chosen to disallow: power< 1, 2 >( your_meters ) since it does not seem to ever make sense -- for any base classification type, not just length. In an attempt to rationalize why this was the case, I noticed that a base classification raised to a power could be looked at as a hyper-volume in N-dimensional space, where N is the value of the exponent. Continuing with "length" as an example, your_meters^2 represents a hyper-volume in 2 dimensional space (area), and your_meters^3 represents a hyper-volume in 3 dimensional space (volume), and your_meters^-3 could be looked at as units per volume, etc. This model makes sense for all integer powers, yet not for rational powers for base units, as it would imply a concept of fractions of a dimension, which intuitively I do not believe exist, though I am admittedly not a mathematician and my model could be too specific. Keep in mind that rational powered derived-classifications are still perfectly fine, just so long as the resultant unit type does not have fractional powered base units in its make-up. Considering you apparently have an example where fractional-powered years is used (years being a base unit of time), I suppose my logic could be flawed, though I haven't heard of your example and googling around doesn't appear to be helping either. If you can, would you link to information regarding such fractional-powered base classifications? It's easy to go back and allow them in my library, as my restriction is mostly just superficial, but I won't do so until I see a place in practice where such operations actually make sense. Thanks in advance. -- -Matt Calabrese

On 10/11/05, Matt Calabrese <rivorus@gmail.com> wrote:
It's easy to go back and allow them in my library, as my restriction is mostly just superficial, but I won't do so until I see a place in practice where such operations actually make sense.
Nevermind, I found some info. Thanks for pointing this out. Prior to going further, are there any places where irrational powers make sense? -- -Matt Calabrese

Matt Calabrese wrote:
On 10/11/05, Matt Calabrese <rivorus@gmail.com> wrote:
It's easy to go back and allow them in my library, as my restriction is mostly just superficial, but I won't do so until I see a place in practice where such operations actually make sense.
Nevermind, I found some info. Thanks for pointing this out. Prior to going further, are there any places where irrational powers make sense?
I sure hope not. My recollection is that no one had any use case for irrational powers of units.

Matt Calabrese wrote:
On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
What I'm more interested in learning is how you handle "composite quantities", which are obtained by multiplying and dividing existing units (like "meters/second"), as well as raising to a rational power (like the standard unit of volatility in finance, "1/square_root(years)".
Rational powers are handled with power functions and metafunctions, as I showed in later replies. However, I would like much more information regarding "volatility in finance." Up until now, I have seen absolutely no cases where non-derived unit classifications raised to a non-integer powers makes sense and have even talked about such situations with mathematicians. Looking back to the archives, I see people talking about fractional-powered base units being possible and speak of examples from other threads, but I can't seem to find such examples. An exact link would be very helpful. Right now I support fractional powers, but not when the operation yields fractional-powered base units.
sqrt(Hz) arises occasionally; the unit of noise is seconds^{1/2} = 1/sqrt(Hz), the unit of magnetic field noise is Tesla per sqrt(Hz), and so on. In fact, this sounds entirely analagous to the financial application Deane mentioned (but do they really define the volatility as the reciprocal of the noise, or is it something different?). But it only occurs in a very narrow specialization. I have never seen fractional base units occur anywhere else. Links seem surprisingly hard to come by, but if you look at the Wikipedia article for SQUID (the superconducting version, not the animal ;), you will see the noise level mentioned in units of femto-Tesla/sqrt(Hz). http://en.wikipedia.org/wiki/SQUID HTH, Ian

The application is to Brownian motion (which of course originated in physics!), which, to oversimplify, can be viewed as a time-dependent Gaussian distribution whose variance grows linearly with time and therefore its standard deviation grows proportionally to the square root of time. The proportionality constant in the standard deviation is called the volatility, and the units for volatility are the units for the standard deviation (think of that as a spatial dimension) divided by the square root of time. To take another tack, Brownian motion is closely related to the heat equation (again, a physical thing) u_t = (v^2/2)u_xx, where v is a constant measuring how well heat conducts in the material (I'll let the physicists make this more precise). The quantity v is the volatility. You could say that we should be working with v^2 and not v itself, and I won't disagree. But I have to live with common usage and convention. As for why Brownian motion matters in finance, I'm going to plead "off-topic" here, but you could try to look for explanations of the Black-Scholes formula. (Terence Tao at math.ucla.edu has a terrific but very terse explanation) So indeed, things like (time_duration)^(-1/2) do arise and are needed. Sorry. Your hopes were entirely reasonable, but fractional powers of fundamental units are really needed. But couldn't this be done rather nicely using the MPL map type, using a compile-time rational number type? I'm not exactly sure how to contruct the derived unit type from the unit types of two factors, but I bet it could be done most easily using this approach. Matt Calabrese wrote:
On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
What I'm more interested in learning is how you handle "composite quantities", which are obtained by multiplying and dividing existing units (like "meters/second"), as well as raising to a rational power (like the standard unit of volatility in finance, "1/square_root(years)".
Rational powers are handled with power functions and metafunctions, as I showed in later replies. However, I would like much more information regarding "volatility in finance." Up until now, I have seen absolutely no cases where non-derived unit classifications raised to a non-integer powers makes sense and have even talked about such situations with mathematicians. Looking back to the archives, I see people talking about fractional-powered base units being possible and speak of examples from other threads, but I can't seem to find such examples. An exact link would be very helpful. Right now I support fractional powers, but not when the operation yields fractional-powered base units. For instance, I allow the expression
power< 1, 2 >( your_meters_quantity * your_meters_quantity ) // where power< 1,2 > denotes a power of 1/2
However, I have chosen to disallow:
power< 1, 2 >( your_meters )
since it does not seem to ever make sense -- for any base classification type, not just length. In an attempt to rationalize why this was the case, I noticed that a base classification raised to a power could be looked at as a hyper-volume in N-dimensional space, where N is the value of the exponent. Continuing with "length" as an example, your_meters^2 represents a hyper-volume in 2 dimensional space (area), and your_meters^3 represents a hyper-volume in 3 dimensional space (volume), and your_meters^-3 could be looked at as units per volume, etc. This model makes sense for all integer powers, yet not for rational powers for base units, as it would imply a concept of fractions of a dimension, which intuitively I do not believe exist, though I am admittedly not a mathematician and my model could be too specific.
Keep in mind that rational powered derived-classifications are still perfectly fine, just so long as the resultant unit type does not have fractional powered base units in its make-up. Considering you apparently have an example where fractional-powered years is used (years being a base unit of time), I suppose my logic could be flawed, though I haven't heard of your example and googling around doesn't appear to be helping either. If you can, would you link to information regarding such fractional-powered base classifications? It's easy to go back and allow them in my library, as my restriction is mostly just superficial, but I won't do so until I see a place in practice where such operations actually make sense.
Thanks in advance.
-- -Matt Calabrese _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
Useful info
Thanks, again. But couldn't this be done rather nicely using the MPL map type, using a
compile-time rational number type? I'm not exactly sure how to contruct the derived unit type from the unit types of two factors, but I bet it could be done most easily using this approach.
Yeah, in fact that's how I already work with types. The classifications and unit types internally have maps whose keys are the fundamental types which make up the derived type, and the mapped type is a group of information which also contains the power of each fundamental type. All have to do is use rationals, which I already have available, instead of integral types inside the mapped type. One thing I'll mention, in case anyone can think of something better, is that comparison of classifications and unit types takes either constant time or N*log(N) for a comparison resulting in true_, where N is the number of fundamental types which make up the derived type. This is due to the fact that the order of elements in a compile-time associative sequence in MPL is determined by how the sequence is created (and I see no simple way to make consistently ordered sequences of types at compile-time without requiring intrusive information, which is not an option in this case). So, in order to perform a proper comparison, I cycle through the fundamentals of one type and check the corresponding mapped type on the other type if an element with the same key exists. Hence, N*log(N) time for a comparison resulting in true_. Thankfully, due to the nature of templates, this time won't be needed in every check, since once the template is instantiated, the calculations won't have to be performed again with redundant instantiations. Aside from that, prior to doing the complex comparison described, I do a raw is_same check, which would run in constant time and is all that is required in the case that it yields true_, in the hope that in many situations the type will have been formed in a similar manner, meaning the complex check would not be required. Still, if anyone can think of a more efficient way of handling this without requiring a worst case scenario of N*log(N) time for comparisons yielding true_, I'm all ears. -- -Matt Calabrese

On 2005-10-12, Matt Calabrese <rivorus@gmail.com> wrote:
On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
But couldn't this be done rather nicely using the MPL map type, using a compile-time rational number type? I'm not exactly sure how to contruct the derived unit type from the unit types of two factors, but I bet it could be done most easily using this approach. Yeah, in fact that's how I already work with types. The classifications and unit types internally have maps whose keys are the fundamental types which make up the derived type, and the mapped type is a group of information which also contains the power of each fundamental type. All have to do is use rationals, which I already have available, instead of integral types inside the mapped type.
What are the "fundamental types" that are being referred to here? I'm guessing that it is the basis set for the dimensional analysis, and hence would be something like: length, time, mass, temperature, intensity, current, amount. Is this a fixed set, or can it be overridden (not just extended)? (This is what, if memory serves, was one of the major points of discussion back in 2003/2004.) What I mean be overridden is: Could I choose to use velocity, force, and pressure as the basis for my dimensional analysis (so rather than thinking of velocity as "length / time", length would be represented as "pressure^-1 force^1 velocity^-2") Personally, I think this level of flexibility is pointless and overcomplicates things, but I feel I have to ask given some of the discussions last time around... :-) If it can be expanded, can it be extended arbitrarily by any code anywhere, or is it possible to define a "family" of dimensions for specific use? In other words, if one part of my system is fiddling around with "traditional" dimensional analysis (the 7 ones listed above), and another part is interested in "bedknobs" and "broomsticks" dimensional analysis, could I do bedknobs(1) * mass(1) (or some such)? Or can I constrain what various parts of the code are doing so that that expression would be invalid because "physical quantities" do not have a "bedknobs" dimension? I went for the latter approach: This resulted in doing things like: struct SI : physical7_system<u::kilogram, u::meter, u::second, u::ampere, u::kelvin, u::candela, u::mole> {}; struct Imperial : physical7_system<u::pound, u::foot, u::second, u::ampere, u::fahrenheit, u::candela, u::mole> {}; When a quantity was defined, you could do: SI::length<double> meter(1.0) and you would get something that was in meters units, and stored as 1.0. (This is equivalent to something like: quantity<double, ...dimensionality in physical_system7..., SI> meter(1.0); Of course, there can be a raft of convenience typedef's to make things more usable/readable. ) and then: Imperial::length<double> foot(1.0) and you would get something that was in feet units, and stored as 1.0. You could then do: SI::length<double> footInMeters = convert_units<SI>(foot); which would store a value of 0.3048 in footInMeters (since the internal representation is in units of meters). Personally, I'm with Deane Yang: I don't like implicit conversions. If you then introduced: struct Silly : disney_system<u::bedknobs, u::broomsticks> {}; And did Silly::sleeping<double> s(1.0); this would *not* interact with, or convert to, anything in the physical7_system of dimensions. I've never actually needed this level of functionality, so I've never be inclined to wonder whether it was overly restrictive or not :-) Oh, and it did fractional powers and printing, too. And supported absolute (sorry, point) quantities. (Thanks to an approach suggested by Jan Langer, if I remember correctly.) I gave up trying to progress with boost-ing it because I couldn't see a path of consensus to what was actually wanted. There seemed to be a desire for more flexibility, and I couldn't see the point :-( (One of the few things I took from a brief flirtation with eXtreme Programming was YAGNI and "do the least amount that will work".) In fact, all I've ever needed is physical4_system (mass, length, time, temperature), and never need to convert units because we always insist on everything being in SI. phil -- change name before "@" to "phil" for email

Phil Richards wrote:
....
I gave up trying to progress with boost-ing it because I couldn't see a path of consensus to what was actually wanted. There seemed to be a desire for more flexibility, and I couldn't see the point :-( (One of the few things I took from a brief flirtation with eXtreme Programming was YAGNI and "do the least amount that will work".)
In fact, all I've ever needed is physical4_system (mass, length, time, temperature), and never need to convert units because we always insist on everything being in SI.
Yes, this was a major issue. Do we want a general dimensions library (without even predefining ANY dimensions at all) that I claim would have extremely broad applicability outside physics, or do we want a physical-dimensions-only library that predefines a standard or basic collection of physical dimensions.? I am strongly in favor of the former, I have also never understood why the latter couldn't be built using the former anyway, so the library could have two layers to it. The physicists could ignore the lower layer completely, and I could ignore the upper one.

On 2005-10-20, Deane Yang <deane_yang@yahoo.com> wrote:
Phil Richards wrote:
I gave up trying to progress with boost-ing it because I couldn't see a path of consensus to what was actually wanted. There seemed to be a desire for more flexibility, and I couldn't see the point :-( [...] In fact, all I've ever needed is physical4_system (mass, length, time, temperature), and never need to convert units because we always insist on everything being in SI. Yes, this was a major issue.
Do we want a general dimensions library (without even predefining ANY dimensions at all) that I claim would have extremely broad applicability outside physics, or do we want a physical-dimensions-only library that predefines a standard or basic collection of physical dimensions.?
The difficulty with not having some basics defined is that it makes things a lot more complicated :-) SI length is defined as having unit in meters. meters has dimensionality of length^1, in SI (and Imperial, for that matter). If you change your basis set for dimensional analysis, then length may not be a basis dimension in this new basis set. This different new (derived) definition of "length" dimensionality has to exist in a different namespace to SI length. And it *can't* interoperate with it particularly easily - you would have to specify the transformation of each basis dimension from one family to the other. Which, funnily enough, is where I got to with my "dimensionality family" stuff. I was never enormously convinced of my solution, it has to be said, but it works if all you want to do is define disjoint, non-interacting, dimensional analysis systems. (You can define any basis set you like, and call things in it anything you like (everything is partitioned either by class or namespace scopes) but it won't let you mix-and-match things of different families.)
I am strongly in favor of the former, I have also never understood why the latter couldn't be built using the former anyway, so the library could have two layers to it. The physicists could ignore the lower layer completely, and I could ignore the upper one.
Ok, give a few examples of different basis sets that may be wanted :-) The best thing to drive this forward are real use-cases for the library. Without them, we'll just go round in circles again. phil -- change name before "@" to "phil" for email

On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
If you change your basis set for dimensional analysis, then length may not be a basis dimension in this new basis set. This different new (derived) definition of "length" dimensionality has to exist in a different namespace to SI length. And it *can't* interoperate with it particularly easily - you would have to specify the transformation of each basis dimension from one family to the other.
Which, funnily enough, is where I got to with my "dimensionality family" stuff. I was never enormously convinced of my solution, it has to be said, but it works if all you want to do is define disjoint, non-interacting, dimensional analysis systems.
Again though, I question why you would ever want to do this. Whether a unit classification (dimension) you are using is fundamental on or not shouldn't affect how you use it in code. You can work with the units the same way whether they are fundamental or derived, so why would you want to make a system where "velocity" is fundamental? The only place where it would make a difference that I can think of at the moment is with type traits, but in that case you can just have separate traits defined for the same units, as opposed to making a whole new system of redundant unit types. I.E. you can do is_derived< SI, velocity > or is_derived< your_system, velocity >. This is a better solution, in my opinion, since it doesn't require making an entire new system of units and avoids all of the needs to have a way to convert between a fundamental velocity and a derived velocity, since now they are still just represented with the same type. This also succeeds at minimizing the number of types and templates which would need to be used. -- -Matt Calabrese

Phil Richards wrote:
If you change your basis set for dimensional analysis, then length may not be a basis dimension in this new basis set. This different new (derived) definition of "length" dimensionality has to exist in a different namespace to SI length. And it *can't* interoperate with it particularly easily - you would have to specify the transformation of each basis dimension from one family to the other.
I have no idea what all this means. Why would I change my "basis set" (I assume this means a base collection of dimensions) if I want to use SI dimensions? Why should it matter to you that someone else outside of physics might use the library with a completely set of dimensions that are completely disjoint from the dimensions you use? I don't understand why that causes any problems for you, especially if the library is kind enough to provide a layer that predefines the basic physical dimensions and corresponding SI units for you. And why should it matter to you if the library also allows me to use it without any predefined physical dimensions and SI units? Are you objecting to using an mpl map, because you think it'll substantially increase the compilation time? If that turns out to be true, I think you do have a case. Then I think we need two completely separate libraries, one designed specifically for standard physical dimensions and one for user-defined dimensions only.
I am strongly in favor of the former, I have also never understood why the latter couldn't be built using the former anyway, so the library could have two layers to it. The physicists could ignore the lower layer completely, and I could ignore the upper one.
Ok, give a few examples of different basis sets that may be wanted :-) The best thing to drive this forward are real use-cases for the library. Without them, we'll just go round in circles again.
In mathematical finance, the only essential dimensions are time and dimensions derived from time. Why do I want a library that lugs around all the other physical dimensions, too? A general dimension/units library is, I think safe to say, useful anywhere one is doing mathematical computations in a practical setting. Virtually any practical mathematical calculation uses well-defined dimensions and units, and such a library would help guard against incorrect formulas. But I don't have specific examples (my experience is just as limited as yours); I'll have to let others, if any, speak up. And, please, if I'm the only one expressing these extreme views, you're all welcome to ignore and dismiss me. It's clear that a pure physical dimensions library is still extremely useful for a lot of people. I hope that one of you (Phil, Matt, Andy) will find a way to submit something to boost, even if I don't like it at all.

Deane Yang wrote:
A general dimension/units library is, I think safe to say, useful anywhere one is doing mathematical computations in a practical setting. Virtually any practical mathematical calculation uses well-defined dimensions and units, and such a library would help guard against incorrect formulas. But I don't have specific examples (my experience is just as limited as yours); I'll have to let others, if any, speak up.
Here's the set of examples I bring up every time this discussion rears its head ... 1) Particle and nuclear physics use a "natural units" system in theoretical calculations where length and time have the same units, and energy, mass, and momentum have the same units, and the two units are just the inverse of each other. You would't WANT to use SI in this field, because the orders of magnitude aren't even close to useful. Additionally, your fundamental unit is energy, which is a derived unit in SI. 2) Cosmology and astrophysics are in a similar situation, but use a different set of natural units. 3) SI doesn't include things like currency, and doesn't admit the possibility that unit conversions change with time. SI is _A_ useful system of dimensions and units, but it is geared to physical measurements used in commerce, trade, and engineering. It is not in any way a statement about mathematics, and is often the wrong choice for a unit system in fields of basic science. -- ------------------------------------------------------------------------------- Kevin Lynch voice: (617) 353-6025 Physics Department Fax: (617) 353-9393 Boston University office: PRB-361 590 Commonwealth Ave. e-mail: krlynch@bu.edu Boston, MA 02215 USA http://budoe.bu.edu/~krlynch -------------------------------------------------------------------------------

On 2005-10-20, Kevin Lynch <krlynch@bu.edu> wrote: > Deane Yang wrote: > > A general dimension/units library is, I think safe to say, useful > > anywhere one is doing mathematical computations in a practical setting. > > Virtually any practical mathematical calculation uses well-defined > > dimensions and units, and such a library would help guard against > > incorrect formulas. But I don't have specific examples (my experience is > > just as limited as yours); I'll have to let others, if any, speak up. > Here's the set of examples I bring up every time this discussion rears > its head ... > 1) Particle and nuclear physics use a "natural units" system in > theoretical calculations where length and time have the same units, and > energy, mass, and momentum have the same units, and the two units are > just the inverse of each other. You would't WANT to use SI in this > field, because the orders of magnitude aren't even close to useful. > Additionally, your fundamental unit is energy, which is a derived unit > in SI. Can you give an example of an equation and explain what dimensional analysis is able to be performed? Off hand, it looks like there is only one dimension to keep track of - is that right? But, my original supposition stands: you wouldn't want dimensional analysis that was using SI stuff to interact with dimensional analysis at used in particle physics because they don't match. You would, in fact, want the library to prevent such operations, I would guess. [...snip...] > SI is _A_ useful system of dimensions and units, but it is geared to > physical measurements used in commerce, trade, and engineering. It is > not in any way a statement about mathematics, and is often the wrong > choice for a unit system in fields of basic science. I certainly don't disagree with that statement. But I only really have experience of dimensions and units that are compatible with the SI view of things, so it is practically impossible to design a library to support other modes without knowing more about how they operate... (That, I suspect, is true for all the people who've tried over the last couple of years.) phil -- change name before "@" to "phil" for email

"Phil Richards" wrote
I certainly don't disagree with that statement. But I only really have experience of dimensions and units that are compatible with the SI view of things, so it is practically impossible to design a library to support other modes without knowing more about how they operate... (That, I suspect, is true for all the people who've tried over the last couple of years.)
Not sure if youre include me in that. I believe that pqs is a great solution for SI quantities. The primary purpose of a physical quantity library is to cater for common practise, rather than being some sort of tool kit for ad-hoc unit systems to be created. Defining a unit system is a non-trivial task. The dimensional analysis part is trivial really. The difficult part is output and to be honest I havent seen a library apart form pqs that tackles this well. Output is messy even in the SI. I believe that users ( including myself) want simplicity. I dont want to have to spend time creating output facilities or making complex typedefs for commonly used SI quantities. The design of an SI quantity library is possible because they have published detailed definitions of their base units and the output format. pqs doesnt preclude anyone using the library for their own system, writing their own unit conversions and their own output format. but obviously it cant do that for them, unless some detailed definition of what these systems are is provided. Even then is there a common requirement there? regards Andy Little

Andy Little wrote: I believe that pqs is a great solution
for SI quantities. The primary purpose of a physical quantity library is to cater for common practise, rather than being some sort of tool kit for ad-hoc unit systems to be created. Defining a unit system is a non-trivial task. The dimensional analysis part is trivial really. The difficult part is output and to be honest I havent seen a library apart form pqs that tackles this well. Output is messy even in the SI. I believe that users ( including myself) want simplicity. I dont want to have to spend time creating output facilities or making complex typedefs for commonly used SI quantities. The design of an SI quantity library is possible because they have published detailed definitions of their base units and the output format.
Again, it's probably just me, but this all sounds backwards to me. I certainly agree that adding a "generalized dimensions" library as a layer over an SI quantities library is not a good idea. But wouldn't it make sense to develop a core dimensions/units library without any predefined dimensions in it and develop the SI quantities library as a layer above that? I am not proposing that the dimensions library should be distributed without predefined SI dimensions and units; that would of course be silly. I am just proposing that the underlying infrastructure of the library (I am assuming that the physical dimensions and units are not hardwired in the library from top to bottom) be exposed, so that someone like me can build our own customized dimension/units system (analogous to but different from the SI units). But it appears that the only people willing to devote effort to developing such a library are people who always use SI quantities and are not familiar with applications that don't use them. So I will now bow out of this discussion (until that indefinite time in the future when I can submit actual code for the kind of library I want), but I would encourage all of you to move ahead with the SI quantities library. It definitely sounds like a very useful library to me.

On 10/21/05, Deane Yang <deane_yang@yahoo.com> wrote:
But wouldn't it make sense to develop a core dimensions/units library without any predefined dimensions in it and develop the SI quantities library as a layer above that?
That's exactly what my library is. It's a general physical quantities library with SI just also provided as a set of classifications and units coupled with the library. Having only a fixed system would definately not be very much in the spirit of boost. The only reason I can see why one might want a fixed system would be for faster compile-times. Since a general library pretty much has to use compile-time sequences, compile-times tend to grow. For instance, right now I internally use MPL maps which still only get nlog(n) for unordered comparisons returning true, where n is the number of base classficiations of a given base or derived classification, with some cases resolving to constant time if the template for comparison with those arguments was already instantiated or if is_same reports true. A similar type of operation occurs for comparing unit types as well. Those operations generally have to be done for any binary operator expression having two quantities for operands, since it usually has to be determined if they are of the same classification first, and has to compare the unit types of each operand. Unfortunately, I see no way around this for a general library and am pretty sure that nlog(n) is the best we can do, which is unfortunate (which is why earlier I challenged someone to figure out a better way). How much this will actually impact compile-times in practice is still hard to tell at this point in development, since many of those operations will likely be redundant template instantiations, meaning you should only have that compile-time overhead once per set of arguments and then it's almost free after that. Exactly how often the same arguments happen to be passed is difficult to tell without using the library in practice, since the order of elements in compile-time associative sequences are dependent on the way in which the sequences are created and modified. Not only that, but nlog(n) isn't a terrible complexity anyway, especially considering most of the classifications will only have between 0 and 5 fundamental classifications or units which make them up. Still, it's obviously not better than being always performed in constant time, as if a fixed set were used. There is another solution I have come up with, though, which has the benefits of both approaches. If compile-times prove to be too long, an adaptor could be developed which takes a group of classifications created by the general library and converts them to a "system" such as those described earlier, where you can optionally only use units together from that system in certain contexts. Such a system could often have constant time classification comparisons as well as have other optimizations unavailable with a strictly general approach. This would probably be the ideal solution, since you still have the general library as the basis and are able to use all units with each other when needed, but you can also optionally pull a subset of any of the infinite number of classifications which could be created for that library into their own subset for situations which need better compile times or which you don't want to intermingle with other units. Not only that, but since the classifications of those systems come from the general library, an explicit conversion could easily be made to convert quantities back to a general representation to be used with any other units once calculations are done on them in the fixed system (not a good idea to have such a conversion implicit since it defeats the purpose of systems). This way, you can create systems for optimizations or just for logical groupings without impacting how general the rest of the library is, and it doesn't make the overall library much more complex either. I'm not going to think about creating such an adaptor just yet since I'm caught up with finishing the rest of the general library, but I'm tossing the idea up into the air for people to see. It should provide a way to have the best of both worlds without having to have two completely separate libraries, and it wouldn't be too difficult to implement once we get to that point in time. Opinions on such an approach would be nice now, though. On 10/21/05, David Abrahams <dave@boost-consulting.com> wrote:
Matt wasn't talking about that "feature." Note that the implicit conversion he mentioned is a widening one, which is always okay.
Thank you! Someone understands the point I was making. I was a little worried when everyone started talking about unrelated conversions after that post. -- -Matt Calabrese

| -----Original Message----- | [mailto:boost-bounces@lists.boost.org] On Behalf Of Matt Calabrese | Sent: 21 October 2005 18:53 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | | On 10/21/05, Deane Yang <deane_yang@yahoo.com> wrote: | | > But wouldn't it make sense to develop a core | dimensions/units library | > without any predefined dimensions in it and develop the SI | quantities | > library as a layer above that? | | | That's exactly what my library is. It's a general physical quantities | library with SI just also provided as a set of classifications and units | coupled with the library. I've read this discussion with renewed interest. This sounds like a good basis to work on, potentially meeting all the requirements from the feet-on-the-ground-SI group (almost certainly by far the largest) but not excluding the head-in-the-astronomicals group (whose distances overflow SI units!), nor excluding the monetarily-important finance groups, not to mention the ones we have yet to conceive. I worry that the compile times and complexity will outstrip both hardware and compilers, but the only way to find out is to try it. So I would encourage Matt to continue his efforts in this direction. Paul PS My gut instinct is to enforce explicit conversions - mainly as a matter of documenting intent, but I am just about persuaded that implicit can be OK, provided it is loseless. If we can have a way of highlighting when implicit conversion takes place, that could make everyone happier. Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

I just want to say that I agree with everything Paul says below. Paul A Bristow wrote:
| -----Original Message----- | [mailto:boost-bounces@lists.boost.org] On Behalf Of Matt Calabrese | Sent: 21 October 2005 18:53 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | | On 10/21/05, Deane Yang <deane_yang@yahoo.com> wrote: | | > But wouldn't it make sense to develop a core | dimensions/units library | > without any predefined dimensions in it and develop the SI | quantities | > library as a layer above that? | | | That's exactly what my library is. It's a general physical quantities | library with SI just also provided as a set of classifications and units | coupled with the library.
I've read this discussion with renewed interest.
This sounds like a good basis to work on, potentially meeting all the requirements from the feet-on-the-ground-SI group (almost certainly by far the largest) but not excluding the head-in-the-astronomicals group (whose distances overflow SI units!), nor excluding the monetarily-important finance groups, not to mention the ones we have yet to conceive.
I worry that the compile times and complexity will outstrip both hardware and compilers, but the only way to find out is to try it. So I would encourage Matt to continue his efforts in this direction.
Paul
PS My gut instinct is to enforce explicit conversions - mainly as a matter of documenting intent, but I am just about persuaded that implicit can be OK, provided it is loseless. If we can have a way of highlighting when implicit conversion takes place, that could make everyone happier.
Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Paul A Bristow wrote:
| -----Original Message----- | [mailto:boost-bounces@lists.boost.org] On Behalf Of Matt Calabrese | Sent: 21 October 2005 18:53 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | | On 10/21/05, Deane Yang <deane_yang@yahoo.com> wrote: | | > But wouldn't it make sense to develop a core | dimensions/units library | > without any predefined dimensions in it and develop the SI | quantities | > library as a layer above that? | | | That's exactly what my library is. It's a general physical quantities | library with SI just also provided as a set of classifications and units | coupled with the library.
I've read this discussion with renewed interest.
This sounds like a good basis to work on, potentially meeting all the requirements from the feet-on-the-ground-SI group (almost certainly by far ^ meters-on-the-ground ? :-D the largest) but not excluding the head-in-the-astronomicals group (whose distances overflow SI units!), nor excluding the monetarily-important finance groups, not to mention the ones we have yet to conceive.
Don't forget the particle/quantam guys! Their units under-flow SI doubles! (Or at least loose some serious accuracy)
I worry that the compile times and complexity will outstrip both hardware and compilers, but the only way to find out is to try it. So I would encourage Matt to continue his efforts in this direction.
A lot of time could be saved with good header design, I assume, but there really is no way around some overhead. Maybe some sort of explicit instatiation and static linking stategy (whether in user or library) could help.
Paul
PS My gut instinct is to enforce explicit conversions - mainly as a matter of documenting intent, but I am just about persuaded that implicit can be OK, provided it is loseless. If we can have a way of highlighting when implicit conversion takes place, that could make everyone happier.
Implicit lossy conversions are the worst curse a library can inflict on the user, IMAO. Lossless is better, but I am only comfortable with promotions, I don't even like int to double very much (as it loses the guarantee of integralness). So yes, explicit only. Try putting the line "-- " just before this, it marks this as a sig, so it won't be quoted in a lot of agents (AFAIK):
Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Simon Buchan | Sent: 26 October 2005 00:28 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | >... | not to mention the ones *I* had yet to conceive ;-) | | Don't forget the particle/quantam guys! Their units under-flow SI | doubles! (Or at least loose some serious accuracy) | > I worry that the compile times and complexity will outstrip | both hardware | > and compilers, but the only way to find out is to try it. | So I would | > encourage Matt to continue his efforts in this direction. | > | A lot of time could be saved with good header design, I assume, but | there really is no way around some overhead. Maybe some sort of | explicit instatiation and static linking stategy (whether in user or | library) could help. Some VERY fancy meta-coding is required but the compile time effect on real-life projects remains difficult to predict. | > Paul | > | > PS My gut instinct is to enforce explicit conversions - | mainly as a matter | > of documenting intent, but I am just about persuaded that | implicit can be | > OK, provided it is loseless. | > If we can have a way of highlighting when implicit | conversion takes place, | > that could make everyone happier. | > | Implicit lossy conversions are the worst curse a library can | inflict on | the user, IMAO. Lossless is better, but I am only comfortable with | promotions, I don't even like int to double very much (as it | loses the guarantee of integralness). | So yes, explicit only. We are talking about implicit conversions from feet to meters here - almost certainly lossless. You need to read Matt's quite complicated arguments for these. | Try putting the line "-- " just before this, it marks this as | a sig, so | it won't be quoted in a lot of agents (AFAIK): | > Paul A Bristow | > Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB | > Phone and SMS text +44 1539 561830, Mobile and SMS text +44 | 7714 330204 | > mailto: pbristow@hetp.u-net.com www.hetp.u-net.com Does this please you better? -- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

Paul A Bristow wrote: Sent: Wednesday, October 26, 2005 1:46 AM To: boost@lists.boost.org Subject: Re: [boost] Interest in dimension/unit-checking library?
We are talking about implicit conversions from feet to meters here - almost certainly lossless. You need to read Matt's quite complicated arguments for these.
Unless I'm mistaken, this is only a theoretically lossless operation. In the real world of precision issues and whatnot, a conversion back and forth might result in a slightly different answer. Given the fact that a number divided by 10 and then multiplied by 10 might not result in the original number, the feet-meter conversion certainly can't be made lossless. Even worse, although converting from feet to inches is lossless (excluding overflow considerations), converting from inches to feet is not lossless. I really hate floating point! -- Noah

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Noah Stein | Sent: 26 October 2005 15:39 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in dimension/unit-checking library? | | > Paul A Bristow wrote: | > Sent: Wednesday, October 26, 2005 1:46 AM | > To: boost@lists.boost.org | > Subject: Re: [boost] Interest in dimension/unit-checking library? | | | > We are talking about implicit conversions from feet to meters here - | > almost certainly lossless. | Unless I'm mistaken, this is only a theoretically lossless | operation. In | the real world of precision issues and whatnot, a conversion | back and forth | might result in a slightly different answer. Given the fact | that a number | divided by 10 and then multiplied by 10 might not result in | the original | number, the feet-meter conversion certainly can't be made | lossless. Even | worse, although converting from feet to inches is lossless (excluding | overflow considerations), converting from inches to feet is | not lossless. I really hate floating point! You are right - I could have chosen better words. But it is only a teeny-weeny loss compared to the catastrophic int to char, or even double to float, that people really, really hate! Paul -- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

On 10/26/05, Noah Stein <noah@acm.org> wrote:
Unless I'm mistaken, this is only a theoretically lossless operation. In the real world of precision issues and whatnot, a conversion back and forth might result in a slightly different answer.
Of course, but such is true for any operations you perform on floating point types, not just unit conversions. For instance, if you multiply two float values together, the result does not have perfect precision. a * b / a does not necessarily yield the same value as a, just like meters_a + feet_b - meters_a doesn't necessarily result in the same value as meters_a. These aren't problems with implicit casting of unit types, they are there with just about all floating point operations other than negation, and they exist because floating point types simply can't have infinite precision without taking up an infinitely large amount of memory. Forcing explicit casts on unit types does not solve this since the floating point operations you'd be using which would require casts would have limited precision regardless of whether or not unit conversion takes place. Aside from all of that, keep in mind that implicit conversions occur only where you'd be explicitly casting anyway, so really you're just making the user type more to perform simple operations. If for some reason you want to mark the conversion explictly with a unit cast, there is nothing stopping you, just like you can always explictly cast fundamental types in C++, however I don't see why that should be required. Really, the main place it's important to explicitly cast would be as the last operation of an entire unit expression, since you may want the end result to be in a particular unit type such as for output or to extract that raw value of a given quantity such that it can be used in more low-level operations. Other than situations like that, the choice for explicit casting should be left up to the user. The point of the library is to make working with units easy as well as potentially more optimized, not unecessarily complicated without gain. Especially in cases where the unit types of the operands may or may not be the same depending on template arguments, forcing explicit casts becomes horribly complex for no reason, and even makes the code harder to read and difficult to write correctly not to mention efficiently. Making necessary conversions automatic through non-explicit constructors solves all of those problems. -- -Matt Calabrese

On 10/26/05, Matt Calabrese <rivorus@gmail.com> wrote:
a * b / a does not necessarily yield the same value as a, just like meters_a + feet_b - meters_a doesn't necessarily result in the same value as meters_a
Forgive my typos there, that should read "same value as b" and "same value as feet_b" if you haven't already realized. -- -Matt Calabrese

On 2005-10-20, Deane Yang <deane_yang@yahoo.com> wrote:
Phil Richards wrote: [some stuff] I have no idea what all this means. Why would I change my "basis set" (I assume this means a base collection of dimensions) if I want to use SI dimensions?
You wouldn't. I wasn't saying that you would. I was saying that if you define a different set of dimensions as the ones you want to use in you equations, then it isn't going to interoperate with SI.
Why should it matter to you that someone else outside of physics might use the library with a completely set of dimensions that are completely disjoint from the dimensions you use?
It doesn't. The problem only comes in if you try and make the two sets of dimensions interact - because the result may not be well-formed. You can't combine SI-based quantities with quanties in which time and length have the same units because you have no guarantee that the resulting dimension makes sense. This is why I went down the path of insisting that you predefine what make up a well-formed set of dimensio You snipped out where I said:
Which, funnily enough, is where I got to with my "dimensionality family" stuff. I was never enormously convinced of my solution, it has to be said, but it works if all you want to do is define disjoint, non-interacting, dimensional analysis systems.
The key part is the "it works if all you want to do is define disjoint, non-interacting, dimensional analysis systems." Which, from what you are saying, is exactly how you would expect/want it to work. You see, the problem I have is that I can't understand now (or back a year or so ago) what else needed to be added to the stuff I've done. Since I can't understand what is missing, I can't add it.
Are you objecting to using an mpl map, because you think it'll substantially increase the compilation time?
No. Implementation isn't the issue. I converted to using MPL (admittedly, mpl::vector, but that's not really important - it just so happens that if you define your basis set of dimensions up front, you don't need to mess about with maps and the sorting and uniqifying that goes on as a result). I'm not happy with the performance when doing unit conversion and printing, but they are moderately rare in what I do...
In mathematical finance, the only essential dimensions are time and dimensions derived from time. Why do I want a library that lugs around all the other physical dimensions, too?
With what I did, you wouldn't have to. You would define your dimensional system to be struct Finance : finance_system<u::second> {}; (or some such). The only downside is that it would interoperate with SI::time, but that's not necessarily a problem from what you've said. If you want to track second, hour, day, year as separate dimensions, then just do: struct Finance : finance_4system<u::second, u::hour, u::day, u::year> {}; I'm guessing that I'm still missing something :-) phil -- change name before "@" to "phil" for email

On Oct 20, 2005, at 7:56 PM, Phil Richards wrote:
On 2005-10-20, Deane Yang <deane_yang@yahoo.com> wrote:
Phil Richards wrote:
I gave up trying to progress with boost-ing it because I couldn't see a path of consensus to what was actually wanted. There seemed to be a desire for more flexibility, and I couldn't see the point :-(
[...]
In fact, all I've ever needed is physical4_system (mass, length, time, temperature), and never need to convert units because we always insist on everything being in SI.
Yes, this was a major issue.
Do we want a general dimensions library (without even predefining ANY dimensions at all) that I claim would have extremely broad applicability outside physics, or do we want a physical- dimensions-only library that predefines a standard or basic collection of physical dimensions.?
The difficulty with not having some basics defined is that it makes things a lot more complicated :-)
SI length is defined as having unit in meters. meters has dimensionality of length^1, in SI (and Imperial, for that matter).
If you change your basis set for dimensional analysis, then length may not be a basis dimension in this new basis set. This different new (derived) definition of "length" dimensionality has to exist in a different namespace to SI length. And it *can't* interoperate with it particularly easily - you would have to specify the transformation of each basis dimension from one family to the other.
Which, funnily enough, is where I got to with my "dimensionality family" stuff. I was never enormously convinced of my solution, it has to be said, but it works if all you want to do is define disjoint, non-interacting, dimensional analysis systems.
(You can define any basis set you like, and call things in it anything you like (everything is partitioned either by class or namespace scopes) but it won't let you mix-and-match things of different families.)
I am strongly in favor of the former, I have also never understood why the latter couldn't be built using the former anyway, so the library could have two layers to it. The physicists could ignore the lower layer completely, and I could ignore the upper one.
Ok, give a few examples of different basis sets that may be wanted :-) The best thing to drive this forward are real use-cases for the library. Without them, we'll just go round in circles again.
Just one example: in Lorentz-invariant (relativistic) simulations I might set the speed of light c=1, and consider time and space to be the same unit. As a consequence also energy and mass then have the same units. Or in q quantum simulation I might set the Planck constant \hbar=1, with other consequences for the unit system. A general purpose system, that could be used to implement SI or totally alien unit systems --- even more alien than the US one :-) --- would be the best way to go. An SI unit system could then be easily built on top of it. Mattthias

On 2005-10-20, Matthias Troyer <troyer@itp.phys.ethz.ch> wrote: [...]
A general purpose system, that could be used to implement SI or totally alien unit systems --- even more alien than the US one :-) --- would be the best way to go. An SI unit system could then be easily built on top of it.
Well, SI wasn't a fundamental part of what I did - SI was an instantiation of a set of dimensions and units like so: struct SI : physical7_system<u::meter, ...> {}; You can define any system you like, and instantiate with any set of units you like. The point is, however, that SI (being derived from physical7_system<>) is only unit convertible to other instantiations of physical7_system. For example, it can convert to things from struct Imperial : physical7_system<u::foot, ...> {}; but not struct USDollar : currency_system<u::dollar> or struct UKPound : currency_system<u::sterling> (which USDollar and UKPound are inter-convertible) I'm obviously missing something. I can't see what more flexibility is needed :-( phil -- change name before "@" to "phil" for email

On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
What are the "fundamental types" that are being referred to here? I'm guessing that it is the basis set for the dimensional analysis, and hence would be something like: length, time, mass, temperature, intensity, current, amount.
Is this a fixed set, or can it be overridden (not just extended)? (This is what, if memory serves, was one of the major points of discussion back in 2003/2004.)
By fundamental types I meant base unit classifications such as length, etc. yes. You can add your own easily anywhere with one line anywhere in code. I posted the code to do so earlier in this thread already. You can use that classification with any other classifications, for instance, you can create "currency" and use currency/time. This is all covered already earlier in the thread. On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
What I mean be overridden is: Could I choose to use velocity, force, and pressure as the basis for my dimensional analysis (so rather than thinking of velocity as "length / time", length would be represented as "pressure^-1 force^1 velocity^-2")
You can do that as well by just creating your own "velocity" base classification separate from the one I define. This would be rather silly though as well as pointless. Currently you wouldn't be able to convert your base classification to the more natural derived classification implicitly. This could easily be added, but I don't think it is necessary. On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
can I constrain what various parts of the code are doing so that that expression would be invalid because "physical quantities" do not have a "bedknobs" dimension?
No. I don't really see the benefit of that. On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
SI::length<double> footInMeters = convert_units<SI>(foot); which would store a value of 0.3048 in footInMeters (since the internal representation is in units of meters). Personally, I'm with Deane Yang: I don't like implicit conversions.
Well, implicit conversions is how it will be at least for this version since it's already all in place. I still don't see why you would want to force all explicit conversions. Quantities in meters, centimeters, feet, inches, miles, etc. all represent the same concept and should be able to be converted between behind the scenes. Nothing logically bad ever comes from it at that level of abstraction. Even Deane's example of why he wanted the functionality seemed completely specific to the way his project worked. Adding years to months in his case isn't unnacceptable because they are different units, it's just that he chose to use years and months in two separate modules, and just in the case of that project, he wouldn't ever need to add what the represent together. It's not because it doesn't make sense to add the concept of years with months. Changing the example slightly to better explain, one could very well have two different modules only now both are using years, though you may not logically ever want to add them together. The fact that you don't want to add them together really has no direct link to the fact that they are different units or the that they are the same units, but because at a higher level in your project than the quantities themselves, you shouldn't have to be adding them together. This type of abstraction, in my opinion, has absolutely no reason for being expressed at the library level. If you want that functionality, again, it's because of restrictions at a higher level in code than just "quantities". In actuality, I'd say the better solution, even if explicit conversions were forced by the library, would be for you to make a type which encapsulates one concept and a different type which encapsulates the other concept, since that higher level abstraction is what disallows the conversion, not the fact that they are different units. At this moment, the only result I see from adding direct support for quantities all requiring explicit conversions to the library is uneccessary bloating since the restrictions you desire are better expressible with higher-level code than a quantities library should provide. On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
I've never actually needed this level of functionality, so I've never be inclined to wonder whether it was overly restrictive or not :-)
Neither do I. Length plus length is fine. Mass minus mass is fine. Time divided by time is fine. The underlying units used are merely implementation details. Restricting such operations merely because the underlying units of the dimensions are different does not make sense. They represent the same exact thing! Right now, the only exceptions to this rule that I see occur in abundance with dimensionless quantities, such as with radians and steradians, since implicit conversion between them doesn't make logical sense, despite the fact that they are of the same derived classification. Also, I wanted a version out for people to play with earlier this week, but with all of the discussion from last week and the amount of work I have to do this week, you'll have to wait a little bit longer; I'm just going to try to finish up getting expression rearrangement fully completed, as at the moment it's half-implemented. Toggles to turn individual optimizations off won't be implemented yet so that I can get it out earlier for people to use. -- -Matt Calabrese

Matt Calabrese wrote: (discussion about implicit versus explicit conversion of units omitted) It could be just me, but I'd like to be at least warned if I manage to write code that contained quantity_in_inches + quantity_in_meters or even quantity_in_millimeters - quantity_in_kilometers Both to me are signs that something went wrong. And if I recall correctly that was the problem with some space mission that went wrong. I just don't think implicit conversion of units would have been the right fix for that problem. Is it really sometimes necessary or desirable to write computation code that mixes different units for the same dimension? Is anyone patient and indulgent enough to explain to this naive mathematician why?

On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
And if I recall correctly that was the problem with some space mission that went wrong. I just don't think implicit conversion of units would have been the right fix for that problem.
There is nothing logically wrong with the expression at all. If such a mistake was made it wasn't because they mathematically shouldn't add inches and meters, it's because they forgot to convert the units or because they were adding together two unrelated values. If it was the former problem, this is already solved since the conversion is automatic. If it was the latter problem, it, again, has nothing to do with the fact that different units were used, it's because they were adding together the wrong values. Just as I described above, you can have the same problem if both quantities had the same units. The reason why you shouldn't add them together has nothing to do with the units used, it's because there is a higher level abstraction that isn't represented. You can either choose to encapsulate the two quantities with separate types to disallow the conversion, or you can just add quantities together only where you should in your particular project. Forcing explicit conversion does not "fix" any of this. Adding a length with another length always makes sense. It's a higher level of abstraction entirely specific to individual project which might make you believe otherwise. Forcing explicit conversions does not solve this. On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
Is it really sometimes necessary or desirable to write computation code that mixes different units for the same dimension? Is anyone patient and indulgent enough to explain to this naive mathematician why?
I am standing on a stool that is 3 feet high. I am 1.6 meters tall. Adding the heights together describes how high above the ground I reach when standing on the stool. The same applies to mass: my mass plus the mass of a bowling ball, or anything else you can think of. Units are merely implementation details to their dimension and should not directly affect the way expressions combining them are written. Special cases occur, especially in the "empty classification" (radians to steradians should not be convertible), however this is specific to individual unit types, not general to the entire system. Disallowing adding together two different lengths just results in exposing implementation details to high-level code. The point in having them be two different units of the same dimension is to show that they express the same thing just with a different representation. Since they represent the same exact same concept there is absolutely no reason why you shouldn't allow them to be used in the same manner. Again, all of the "problems" you describe have nothing to do with the units used, but rather occur because of an unrepresented abstraction in your specific project. Encapsulate the different types separately if you want that abstraction as it has no place in a units library as I see it. -- -Matt Calabrese

Matt Calabrese wrote:
Adding a length with another length always makes sense. It's a higher level of abstraction entirely specific to individual project which might make you believe otherwise. Forcing explicit conversions does not solve this.
I'm not arguing conceptual matters. Yes, I know adding lengths in inches to lengths in meters makes sense. But is it good, clean code? In some sense, I consider this to be analogous to the difference between the strong type checking of C++ and the "anything goes" approach of, say, Perl. Somehow, for me, automatic unit conversion seems like a good fit with Perl but not with C++.
On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
Is it really sometimes necessary or desirable to write computation code that mixes different units for the same dimension? Is anyone patient and indulgent enough to explain to this naive mathematician why?
I am standing on a stool that is 3 feet high. I am 1.6 meters tall. Adding the heights together describes how high above the ground I reach when standing on the stool. ..
I'm looking for an example of software design, not a toy textbook problem.
Again, all of the "problems" you describe have nothing to do with the units used, but rather occur because of an unrepresented abstraction in your specific project. Encapsulate the different types separately if you want that abstraction as it has no place in a units library as I see it.
But why? The underlying concepts of vector and point quantities apply just as well to my needs as it does to yours. The only difference is that you want to define a certain collection of dimensions, and I want to use a different collection. What's the difference?

On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
I'm not arguing conceptual matters. Yes, I know adding lengths in inches to lengths in meters makes sense. But is it good, clean code?
I don't see why not. Nothing bad happens from allowing the conversion and it prevents users from having to do it explicitly. On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
In some sense, I consider this to be analogous to the difference between the strong type checking of C++ and the "anything goes" approach of, say, Perl. Somehow, for me, automatic unit conversion seems like a good fit with Perl but not with C++.
I'd say it's much more analogous to conversions in C++ from a short unsigned int to an unsigned int being implicit. You don't lose any information in the conversion and the conversion makes perfectly logical sense. Forcing users to always be explicit is just making them write more unecessary code. On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
I'm looking for an example of software design, not a toy textbook problem.
They are one and the same. Such an example can occur in code in a physics simulation, for example, or anything else. On 10/20/05, Deane Yang <deane_yang@yahoo.com> wrote:
But why? The underlying concepts of vector and point quantities apply just as well to my needs as it does to yours. The only difference is that you want to define a certain collection of dimensions, and I want to use a different collection. What's the difference?
Because vectors, points, and scalars are concepts which all exist at the level of abstraction of a units library. The problems you describe exist at a higher-level in code and have absolutely nothing to do with units of different types in the same dimension, and really don't have anything to do with units at all. I'm not certain why you aren't seeing this. Again, the "problems" you describe occur even if you are using units of the SAME unit type in two different locations, not just if they are of a different unit type. Such problems exists even if you aren't using units at all. The only reason you want operations disallowed between them in your particular project is because the units are being used as details encapsulated in different high-level concepts which only exists in your code. This type of relationship is one that can only be expressed in your code. Forcing people to always explicitly convert doesn't solve even this type of problem, either. All it does is provide an artificial guard in your specific high-level code through an entirely unrelated and illogical restriction put in low-level code. The reason you don't want years to be convertible to months has nothing to do with them being of different unit types, it's because in your particular project, you are using months and years as implementation details of two different concepts that are not interchangeable. Those concepts could just as easily both be represented in months and it would not change the fact that you shouldn't add them together. As I said before, the reason why you can't add them is because of a reason specific to your project and is entirely unrelated to the units you are using. It is your responsibility to provide that abstraction through encapsulation or by other means as it is a restriction which exists at a higher level in code which doesn't even exist in a units library. Forcing all explicit conversions only happens to somewhat hide your particular type of "problem" in the case where those two different concepts happen to also be represented by different units in the same classification. -- -Matt Calabrese

On 10/20/05, Matt Calabrese <rivorus@gmail.com> wrote:
I'd say it's much more analogous to conversions in C++ from a short unsigned int to an unsigned int being implicit. You don't lose any information in the conversion and the conversion makes perfectly logical sense. Forcing users to always be explicit is just making them write more unecessary code.
Also, expanding on this analogy since I don't think you are understanding the point I'm trying to make -- one might have code which uses shorts and ints to represt two different high-level concepts in code. In that particular project, under your logic, you wouldn't want implicit conversion from short to int. This is literally exactly the same situation with units. The "problem" isn't because short to int conversions should be explicit, it's because you aren't representing the high-level concepts which actually use those types as implementation details in your code. You really should be encapsulating those values in two different types if that is the functionality you want. The same situation can occur if both values were represented with ints. The operation between the two ints still wouldn't make sense -- the problem is that you aren't representing the fact that they implementation details of higher level concepts in your code. Encapsulation is what you really want. Always making short int to int conversions be explicit is missing the point that the datatype isn't the reason why the two objects aren't addable. The reason is because there is a higher level of abstraction which you didn not represent. -- -Matt Calabrese

Matt Calabrese wrote:
I'd say it's much more analogous to conversions in C++ from a short unsigned int to an unsigned int being implicit. You don't lose any information in the conversion and the conversion makes perfectly logical sense. Forcing users to always be explicit is just making them write more unecessary code.
OK. I think I'll concede that it's my own fetish, bcause I think implicit casting of int to unsigned int and vice versa is one of the worst "features" of C++. I really, really wish they could make this a compiler option somehow. But even then I couldn't use it, because nothing in the standard library would compile.

On 2005-10-20, Deane Yang <deane_yang@yahoo.com> wrote:
Matt Calabrese wrote:
I'd say it's much more analogous to conversions in C++ from a short unsigned int to an unsigned int being implicit. You don't lose any information in the conversion and the conversion makes perfectly logical sense.
Yes, but C++ allows implicit conversion of int to float/short/char, too, so perhaps C++ isn't the best example to use...
Forcing users to always be explicit is just making them write more unecessary code. OK. I think I'll concede that it's my own fetish, bcause I think implicit casting of int to unsigned int and vice versa is one of the worst "features" of C++. I really, really wish they could make this a compiler option somehow. But even then I couldn't use it, because nothing in the standard library would compile.
It's not just your fetish. I agree with you completely (on all points). phil -- change name before "@" to "phil" for email

Deane Yang <deane_yang@yahoo.com> writes:
Matt Calabrese wrote:
I'd say it's much more analogous to conversions in C++ from a short unsigned int to an unsigned int being implicit. You don't lose any information in the conversion and the conversion makes perfectly logical sense. Forcing users to always be explicit is just making them write more unecessary code.
OK. I think I'll concede that it's my own fetish, bcause I think implicit casting of int to unsigned int and vice versa is one of the worst "features" of C++.
Matt wasn't talking about that "feature." Note that the implicit conversion he mentioned is a widening one, which is always okay. signed char -> short -> int -> long etc. Not vice-versa! -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Deane Yang" wrote
It could be just me, but I'd like to be at least warned if I manage to write code that contained
quantity_in_inches + quantity_in_meters
or even
quantity_in_millimeters - quantity_in_kilometers
Both to me are signs that something went wrong.
Actually I had just a problem the other day where the conversion came in handy. i wanted to find postage for an item to go on ebay. I had a kitchen scales that works in lb and oz, and which was also not adequte to weigh the item which was around 15 kg. in weight. So I got a plank of wood and put one end to the floor and the other to the scales. Then I put the ebay-item on some way down the wood so I didnt max out the scales. Then I did a quick C++ program with pqs library to get the result. It sure was easy not having to do all the conversions by hand. Heres the program: #include <pqs/pqs.hpp> int main() { pqs::length::m L1(1.57); // ebay_item disance along beam to scale pqs::length::m L2(.47); // ebay-item distance to beeam end on floor pqs::length::m L = L1 + L2; // total beam length pqs::mass::kg m1 = pqs::mass::lb(9) + pqs::mass::oz(6); // mass read by scales with item pqs::mass::kg m2 = pqs::mass::lb(2) + pqs::mass::oz(10); // mass of beam only pqs::mass::kg m = m1 - m2; // mass on scales to due ebay-item pqs::mass::kg result = m * L / L2; // scale by moment std::cout << result <<'\n'; } This also occurs with user input which often requires a conversion from e.g imperial units to S.I. units. cheers Andy Little

<jaw drops> If you really do use C++ to do this type of stuff, then I definitely concede the point. Implicit unit casting is definitely useful in your example. Andy Little wrote:
"Deane Yang" wrote
It could be just me, but I'd like to be at least warned if I manage to write code that contained
quantity_in_inches + quantity_in_meters
or even
quantity_in_millimeters - quantity_in_kilometers
Both to me are signs that something went wrong.
Actually I had just a problem the other day where the conversion came in handy. i wanted to find postage for an item to go on ebay. I had a kitchen scales that works in lb and oz, and which was also not adequte to weigh the item which was around 15 kg. in weight. So I got a plank of wood and put one end to the floor and the other to the scales. Then I put the ebay-item on some way down the wood so I didnt max out the scales. Then I did a quick C++ program with pqs library to get the result. It sure was easy not having to do all the conversions by hand. Heres the program:
#include <pqs/pqs.hpp> int main() { pqs::length::m L1(1.57); // ebay_item disance along beam to scale pqs::length::m L2(.47); // ebay-item distance to beeam end on floor pqs::length::m L = L1 + L2; // total beam length pqs::mass::kg m1 = pqs::mass::lb(9) + pqs::mass::oz(6); // mass read by scales with item pqs::mass::kg m2 = pqs::mass::lb(2) + pqs::mass::oz(10); // mass of beam only pqs::mass::kg m = m1 - m2; // mass on scales to due ebay-item pqs::mass::kg result = m * L / L2; // scale by moment std::cout << result <<'\n'; }
This also occurs with user input which often requires a conversion from e.g imperial units to S.I. units.
cheers Andy Little
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Deane Yang" wrote
<jaw drops>
If you really do use C++ to do this type of stuff, then I definitely concede the point. Implicit unit casting is definitely useful in your example.
I do when I find something I cant handle easily in say Excel :-) pqs has embedded in it all the conversion factors which I'd otherwise have to look up. I guess you could do it in another language but I dont think you could do it as neatly in another language. One raison-d'aitre of a units library is to show C++ off isnt it ? cheers Andy Little

On 2005-10-20, Matt Calabrese <rivorus@gmail.com> wrote:
What I mean be overridden is: Could I choose to use velocity, force, and pressure as the basis for my dimensional analysis (so rather than thinking of velocity as "length / time", length would be represented as "pressure^-1 force^1 velocity^-2") You can do that as well by just creating your own "velocity" base classification separate from the one I define. This would be rather silly
On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote: though as well as pointless. Currently you wouldn't be able to convert your base classification to the more natural derived classification implicitly. This could easily be added, but I don't think it is necessary.
Actually, it would be ill-formed - you would have introduced a mechanism for allowing two things of the same dimensionality to be represented in two different ways. I'm really not convinced that this is good for dimensional analysis...
Well, implicit conversions is how it will be at least for this version since it's already all in place. I still don't see why you would want to force all explicit conversions. Quantities in meters, centimeters, feet, inches, miles, etc. all represent the same concept and should be able to be converted between behind the scenes. Nothing logically bad ever comes from it at that level of abstraction.
Repeated transformation of values is not something that I've ever found particularly good when doing numerical algorithms. It is generally better to encourage up-front conversion and do everything internally in a consistent set of units. And explicit conversion forces you to think about what operations are going on. If I saw an equation written using mixed units I'd run a mile - I'd wonder why the person hadn't normalised all the values first :-) In fact, if I was implementing it, I would normalise the values first - using explicit conversions to make it absolutely clear what was going...
At this moment, the only result I see from adding direct support for quantities all requiring explicit conversions to the library is uneccessary bloating since the restrictions you desire are better expressible with higher-level code than a quantities library should provide.
Erm, there is little difference in forcing explicit or implicit unit conversions in terms of coding. I would, off-the-top-of-my-head, expect implicit unit conversion to be ever so slightly messier to do right - as demonstrated by you expresssion rearrangement example. Anyway, I'll agree to disagree with you on this one. phil -- change name before "@" to "phil" for email

On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
Actually, it would be ill-formed - you would have introduced a mechanism for allowing two things of the same dimensionality to be represented in two different ways. I'm really not convinced that this is good for dimensional analysis...
Actually, that's exactly what I said but in different words. Again, though, read my other reply to understand why you wouldn't ever have to do this (the one refering to type traits). On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
Repeated transformation of values is not something that I've ever found particularly good when doing numerical algorithms. It is generally better to encourage up-front conversion and do everything internally in a consistent set of units.
Why do you think repeated transformations occur with implicit conversion? In fact, with automatic expression rearrangement, the amount of transformations can be minimized even more-so. Remember, if you WANT to force conversions, there's nothing stopping you from explicitly casting where you choose, it's just that you aren't forced to do so since there is no logical reason why the operation can't do it automatically. However, the expression templates can potentially do just as good of a job as you, and often can do even better since they may have more information about the individual objects in a complex expression (i.e. concerning parameters to function template instantations, where the best order of conversion can change depending on the unit types of the objects passed). Objects of length dimension represent the same concept even though the unit details may vary. Forcing explicit conversions also forces those implementation details to high-level code. Having automatic conversions while supplying explicit casts operations keeps details hidden by default, as they should be, and also allows for low-level toggling where it is necessary. I don't see why you would want to always explictly cast, and the "problems" in the examples provided, again, occur if the objects were of the same unit type as well. The problems described were because a higher level of abstraction was missed in the user's code, which isn't even solved by always forcing explicit conversions, it is just hidden in a subset of some of those cases where the two types just happen to be using different units of the same dimension. On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
And explicit conversion forces you to think about what operations are going on. If I saw an equation written using mixed units I'd run a mile - I'd wonder why the person hadn't normalised all the values first :-)
...because the library does it automatically and provides a more concise way of representing the expression in code. Forcing the user to be explicit only requires more code and doesn't add anything. You can be explicit where you want to be, but usually you're just being redundant since the library figures out the best way to handle the conversions anyway. On 10/20/05, Phil Richards <news@derived-software.ltd.uk> wrote:
Erm, there is little difference in forcing explicit or implicit unit conversions in terms of coding. I would, off-the-top-of-my-head, expect implicit unit conversion to be ever so slightly messier to do right - as demonstrated by you expresssion rearrangement example. Anyway, I'll agree to disagree with you on this one.
Added complexity for me to write as the library programmer means less complexity for the user of the library. Sure it's more complex to for me to code in the library how to automatically figure out the best order of conversions and how to properly organize an expression to produce the best code, but so what? Me doing it once now solves it for everyone else later, and since it's done programmatically at compile-time, it produces just as good, and often better results than if a user were to do it explicitly, and it has no runtime overhead. It's win-win with just a small sacrifice of a week or two of my time. -- -Matt Calabrese

Deane Yang wrote:
The application is to Brownian motion (which of course originated in physics!), which, to oversimplify, can be viewed as a time-dependent Gaussian distribution whose variance grows linearly with time and therefore its standard deviation grows proportionally to the square root of time. The proportionality constant in the standard deviation is called the volatility, and the units for volatility are the units for the standard deviation (think of that as a spatial dimension) divided by the square root of time.
To take another tack, Brownian motion is closely related to the heat equation (again, a physical thing)
u_t = (v^2/2)u_xx,
where v is a constant measuring how well heat conducts in the material (I'll let the physicists make this more precise). The quantity v is the volatility.
Yes, and also used all over the place in geophysics and seismicity, not to mention elsewhere, across the broad spectrum of physical sciences, and as already mentioned by others, economics. ...You can go further, and see applications in gridded FFT work, and data compression techniques. ... no one seemingly want's to mention the F-word, but we're talking about Fractals, for purposes of statistical measure. In short, the fractal dimension in physical sciences is commonly used to measure the "distance" that "particles" need to travel/flow between two points in (generally), some hyper-volume. A readable paper on the subject - from an earth sciences point of view, can be got from here: http://www.seismo.unr.edu/ftp/web/htdocs/students/MELA/thesis/geophysics9816...
You could say that we should be working with v^2 and not v itself, and I won't disagree. But I have to live with common usage and convention.
As for why Brownian motion matters in finance, I'm going to plead "off-topic" here, but you could try to look for explanations of the Black-Scholes formula. (Terence Tao at math.ucla.edu has a terrific but very terse explanation)
So indeed, things like (time_duration)^(-1/2) do arise and are needed. Sorry. Your hopes were entirely reasonable, but fractional powers of fundamental units are really needed.
This touches on the volitility of timeseries in financial domains, and fractional powers, but for the less technically minded. -Again the concept of distance of travel applies here too. http://econwpa.wustl.edu/eps/em/papers/0308/0308002.pdf
But couldn't this be done rather nicely using the MPL map type, using a compile-time rational number type? I'm not exactly sure how to contruct the derived unit type from the unit types of two factors, but I bet it could be done most easily using this approach.
Matt Calabrese wrote:
On 10/11/05, Deane Yang <deane_yang@yahoo.com> wrote:
Cheers, -- Manfred Doudar MetOcean Engineers www.metoceanengineers.com

On 10/10/05 4:12 PM, "Matt Calabrese" <rivorus@gmail.com> wrote:
Also note that just like with points and vectors, it generally doesn't make sense to add together two absolute temperatures, whereas it does make sense to subtract two. As well, it even makes sense to add the result of the subtraction to an absolute temperature, and the same goes for all other standard point and vector operations. Finally, just like in geometry, there are a few places where the rules can be broken regarding adding points, such as with barycentric combinations. With temperatures, a barycentric combination could be used to find the average temperature of the day. Just like with temperatures, the geometric representation applies to all other unit types. If users find it difficult to understand, most can get away with just using scalar quantities all of the time, though the more advanced users would recognize the benefits of using points and vectors.
If I recall my physics correctly, your use of temperature as a model is a bad one. It _actually_ does make sense to add temperatures, just like two lengths. That's because zero temperature is an actual zero point, just like zero length. You can't use degrees Celsius or degrees Fahrenheit because they have a built-in offset. You have to use an absolute scale, like Kelvin[1]. Back when thermometers were invented, no one knew enough thermodynamics to realize the existence of an absolute zero, let alone have any technology that can generate temperatures close to that point. If you want a better example, look no further than the main language of this list. (Think "pointers," "offsets," and "array segments.") [1] The "degree" was dropped from "Kelvin" because it's an absolute unit, so math with it works just like "meters" or "kilograms". -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

On 10/27/05, Daryle Walker <darylew@hotmail.com> wrote:
You have to use an absolute scale, like Kelvin[1]. Back when thermometers were invented, no one knew enough thermodynamics to realize the existence of an absolute zero, let alone have any technology that can generate temperatures close to that point.
It doesn't matter that Kelvin is based around 0. The concept of points, vectors, and scalars still exists, just like they do for lengths, which are usually based around 0, as well as any other unit type. You can have length points too, and in fact those are extremely common as well (length points are points in space, which are used all of the time). Just because Kelvin, like most lengths, is based around 0, does not change that fact. It still does not mean that it makes sense to add the temperature at the beginning of the day with the temperature at the end of the day whether it's kelvin, celsius, or otherwise. You still have the the distinct concepts of points (absolute locations), vectors (translations), and scalars (magnitudes). A celsius vector is convertible to a Kelvin vector. A fahrenheit point is convertible to a Kelvin point. The logical difference is always there, just like with lengths and all other units. You are just confused since usually you don't usually explicitly state "vector", "point", or "scalar". If you find this hard to understand, you can often get away with just always using scalars, but in many cases this will cause you problems (such as with temperatures). -- -Matt Calabrese

"Geoffrey Romer" <geoff.romer@gmail.com> wrote
Would there be any interest in a library for attaching units (physical or otherwise) to numeric variables, so that the type system could enforce dimension- and unit-consistency in all calculations, and convert semi-automatically between compatible units?
To make this a little more concrete, here's a sketch of the kind of code such a library could enable:
--- quantity<meters, double> distance(1.0); quantity<newtons, double> force(5.0);
quantity<joules, double> work = distance * force; quantity<calories, double> work_cal = unit_cast<calories>(work); work_cal = work; //Compile error or implicit conversion, // possibly depending on compiler flag quantity<watts, double> power = work; //Compile error- incompatible types
In pqs http://www.servocomm.freeserve.co.uk/Cpp/physical_quantity/index.html it would look like this: pqs::length::m distance(1.); pqs::force::N force(5.); pqs::energy::J work = distance * force; // note: you would need to add calories of which according to the SI there are I // think 6 varieties //I opted to make automatic conversions between units... pqs::energy::cal work_cal = work; //pqs::power::W power = work ; //Compile error- incompatible types pqs::power::W power = work / pqs::time::s(1); //ok
I know there's been a lot of discussion of units for a GUI library, so I'm especially interested in what people involved in that thread think of this idea- I want to make something sufficiently powerful to be useful in a context like that.
The problem with using physical units for a GUI is that they can make the code rather inflexible. It is possible to template functions on the unit parameter but this will cause code bloat. Far better to set a notional unit somewhere and then have the ability to change the unit easily at runtime. That said some applications can work only with one set of units because the domain is fixed. e.g PCB design . In these cases it is helpful to users to provide a set of user units(micrometers, millimeters, centimeters, inches) that can be converted to-from a standard unit for use by the application( probably millimeters in the case of PCBs.) regards Andy Little
participants (18)
-
Andy Little
-
Daryle Walker
-
David Abrahams
-
Deane Yang
-
Eric Niebler
-
Geoffrey Romer
-
Ian McCulloch
-
Jeff Flinn
-
Jeff Garland
-
Jonathan Turkanis
-
Kevin Lynch
-
Manfred Doudar
-
Matt Calabrese
-
Matthias Troyer
-
Noah Stein
-
Paul A Bristow
-
Phil Richards
-
Simon Buchan