Dimensioned 0.6: compile-time dimensional analysis, much nicer than before


#1

I have updated dimensioned and it is much improved! Read about it here:

http://paholg.com/2017/03/03/dimensioned_0.6/

Feedback welcome!


#2

Note for people like me:
“compile-time dimensional analysis” == “using types to represent measurement units (meters, seconds, …)”


#3

Awesome, thanks!
I will try it out, it looks much better than my crate simple_units :wink:


#4

I don’t understand what do you mean by “dimensional analysis”, by I understand very well what is “using types to represent measurement units”. Some years ago I wrote a C++ library to that purpose and I published it here: https://github.com/carlomilanesi/cpp-measures
You may be interested in looking at it.
In addition to represent units of measurement and their conversions, it represents absolute and relative measures, bi-dimensional and three-dimensional measures and transformations, and three different types of absolute angles.


#5

For the context, dimensional analysis predates the modern concept of computers and is used to quickly check if given physical equation makes sense (if you’ve got mismatching dimensions, it probably has no meaning). In some sense it is a human-directed type system and it makes much sense to make it available to programming languages where possible :smiley:


#6

Ah OK. But then I don’t think a library doing only dimensional analysis is much useful. For example, it can check that if you divide miles by hours you get a speed, but usually you also have to distinguish hours from seconds, and optionally convert between them, you should distinguish absolute celsius degrees from relative celsius degrees, you should compute dot product and cross product between vector measures, you should apply linear or affine transformations in plane or in space, you should compute angles modulo one revolution. I wonder if that library does all that, or if there is another library that does that.


#7

For example, it can check that if you divide miles by hours you get a speed, but usually you also have to distinguish hours from seconds, and optionally convert between them

This is covered in two different ways. Dimensioned works by defining a unit system and then working in that system, so all values are stored in terms of some combination of the base units. Say you’re working in SI, there’s a constant for hours, HR. So, you can do:

let t = 5.0 * si::HR;

and t will have type Second<f64> and value 300.0. Say you want to print it in hours, you can do

println!("t: {} hr", t / si::HR);

Instead of t / si::HR, you could do *(t / si::HR) or (t / si::HR).value(). Each of these extracts the value (as an f64 in this case), but they are only defined for dimensionless quantities, so it ensures that what you have is time.

Alternatively, you could create a unit system that has hours as a base unit, and convert between them using std::convert::From and Into, but this requires more setup.

you should distinguish absolute celsius degrees from relative celsius degrees

I have left this to a user. If one wants to work in celsius, then it would be easy enough for them to make to_celsius() and from_celsius() functions. Celsius isn’t a real unit, so doesn’t belong in a unit system.

you should compute dot product and cross product between vector measures, you should apply linear or affine transformations in plane or in space, you should compute angles modulo one revolution.

This is beyond the scope of dimensioned, and I think it should be. But there’s no reason you can’t use dimensioned with a linear algebra library. The idea is for it to act as a primitive replacer, but there are some caveats. I cover this in this fairly long example.

For example, this is how I define a cross product for a 3d vector:

pub trait Cross<Rhs = Self> {
    type Output;
    fn cross(self, rhs: Rhs) -> Self::Output;
}

impl<T, U> Cross<Vector3d<U>> for Vector3d<T>
    where T: Mul<U> + Copy,
          U: Copy,
          Prod<T, U>: Sub<Output = Prod<T, U>>
{
    type Output = Vector3d<Prod<T, U>>;
    fn cross(self, rhs: Vector3d<U>) -> Self::Output {
        Vector3d::new(self.y * rhs.z - self.z * rhs.y,
                      self.z * rhs.x - self.x * rhs.z,
                      self.x * rhs.y - self.y * rhs.x)
    }
}

There is no reason that linear algebra libraries couldn’t do this, but I think none that exist today provide this level of genericity (note that the parametrized types are allowed to be different and to change under multiplication). I plan to talk to linear algebra library authors and see how open they are to pull requests to this effect.