Boost logo

Boost :

From: Matthias Schabel (boost_at_[hidden])
Date: 2007-01-18 14:03:18


Hi Ben,

> I do think it would be great to distinguish between affine and
> vector spaces
> in a library like this, but in practical terms it seems like there
> are three
> levels of commitment that users might have to dimensional analysis:
> 1. Type of dimension (length versus temperature).
> 2. Units of measure (meters versus feet).
> 3. Absolute versus relative quantities (°C = K+273.15 versus °C = K).

The way I've developed the abstractions for this library is similar
to the way you describe :

1) "raw" dimensional analysis as demonstrated in unit_example_1.cpp.
This is purely
compile-time metaprogramming, and is a little messy because of that.
However, I suspect
that this will be a relatively rare use case for end users of the
library. Furthermore, if it
turned out to be useful, it would certainly be possible to add some
metaprogramming
and/or preprocessor support to simplify the syntax and handling of
dimensional analysis
typelists.

2) units, defined as you do, a type of dimension with an associated
unit system but no
numeric value : SI::length, SI::energy, SI::power, etc...

3) quantities, defined as a quantity of a specified unit :
1.5*meters, (1.5+0.2*i)*ohms, etc...

Quantities need to implement two algebras : the compile-time
dimensional analysis algebra
and the algebra for the underlying value_type. This is where handling
of the difference
between absolute and relative quantities would happen. The advantage
of this is that I
have already implemented quantity algebra in such a way that the
value_type algebra should
just delegate to the value_type itself (this requires typeof support
or manual specialization
of operator helpers for heterogeneous algebras), so the dimensional
analysis is completely
decoupled from the value_type algebra.

> I'm thinking usage like this:
> // First: type of dimension
> quantity<double, distance> x1 = 42.0 * distance;

As it stands, the library assumes that quantities are values
associated with a specific unit system.
That being said, you can easily implement a unit system for
"abstract" dimensioned quantities so
you would write

quantity<double,abstract::length> x1 = 42.0*abstract::length;

> // Second: units of measure
> quantity<double, meters> x2 = 20.0 * meters;

This is basically identical to the existing SI system as implemented.

> // Casting to explicitly add units of measure to unitless
> quantities.
> x2 = quantity_cast<quantity<double, meters> >(x1); // The user
> claims x1
> is in meters.

This will hopefully be implemented for the next release.

> // Allow casting a reference or pointer, too (important for
> interfacing
> with numerical solvers).
> quantity<double, meters>& xref = quantity_cast<quantity<double,
> meters>&>(x1);
> quantity<double, meters>* xptr = quantity_cast<quantity<double,
> meters>*>(x1);

This is a good idea; of course, since it involves pointers and
references, I'm sure the actual
implementation will be ugly to get constness and everything else
right...

> // Third, since most people won't want to get into this, let
> quantity be
> what
> // most would expect (i.e., a linear space) but add absolute_ and
> relative_ to be clear.
> absolute_quantity<double, temperature> t1 = 1000.0 * temperature; //
> Unspecified temperature type.
> absolute_quantity<double, temperature> t2 = 1010.0 * temperature;
>
> relative_quantity<double, temperature> tdiff = t2 - t1; // tdiff
> is now 10
> temperature units.

[snip]

The way I'd propose to do this within the existing framework is to
implement two different
value_types:

template<class Y> class absolute_measure;
template<class Y> class difference_measure;

with the appropriate algebra defined within and between the two
classes (don't quote me
on this - I'd need to think carefully about the exact algebra):

absoute_measure - absolute_measure = difference_measure
absolute_measure +- difference_measure = absolute_measure
absolute_measure +*/ absolute_measure = error
absolute_measure */ scalar = absolute_measure (?)

difference_measure -> normal quantity algebra, implicitly convertible
to value_type (Y)

Then you would have

quantity<absolute_measure<double>,SI::temperature> t1 =
1000.0*SI::kelvin,
                                                                                                        t2 = 1010.0*SI::kelvin;
quantity<difference_measure<double>,SI::temperature> tdiff = t2-t1;

quantity_casts would just work by delegating to the appropriate
value_type constructor when
converting explicitly between absolute_measure and relative_measure...

> PS
> Temperature is particularly odd in that absolute temperature it is
> (almost)
> a linear space even though temperature differences are in a
> different linear
> space. That is,
> 0°C × 2 = 273.15K × 2 = 546.3K = 273.15°C.
> (I say "almost" because there's no negative absolute temperature,
> so it
> can't really be a linear space.)

I'm not sure I follow the significance here...

> PPS
> Where can I find the code under discussion?

It's in the Boost Vault :

http://www.boost-consulting.com/vault/index.php?
&direction=0&order=&directory=Units

file is mcs_units_v0.5.4.zip

Thanks for the feedback.

Matthias


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk