mpusz / mp-units

The quantities and units library for C++
https://mpusz.github.io/mp-units/
MIT License
1.07k stars 85 forks source link

Vector quantities with units #439

Open correaa opened 1 year ago

correaa commented 1 year ago

Do you have any strategy or plans to support units for vectors? (Let's say non-dynamically sized vectors.) For example, I have a position in 3D space that can be in Angstroms or Bohr units (or meters and inches).

Have you put some thought into it?

I know the question is tricky because it is not the vector components or the vector as a whole that carries the units but the "metric tensor", but still.

I find the approach in https://www.youtube.com/watch?v=J6H9CwzynoQ [Daniel Withopf - Physical Units for Matrices] overly complicated, but perhaps it is unavoidable to do it that way.

dwith-ts commented 1 year ago

If you want to use uniform vectors where each entry has the same physical unit then there are easier solutions, the V1 doc contained code examples for this, not sure if they are still part of the documentation.

mpusz commented 1 year ago

As @dwith-ts mentioned, in cases where all quantities in the vector/matrix store the same type, then it works nicely already. See https://mpusz.github.io/units/use_cases/linear_algebra.html. It gets tricky when you want to use various types in a matrix (i.e. kalman filters), but this is a limitation of the LA library and not mp-units. In such cases, an additional level of abstraction will be needed as mentioned by Daniel Withopf in his talk.

mpusz commented 1 year ago

I also plan to provide examples with BLAS-based LA and SIMD which both were proposed for standardization recently.

correaa commented 1 year ago

Yes, I think you can get away with components-as-quantities for vectors, (which might also imply "cartesian", BTW). But for matrices (and higher rank tensors) it is not possible to use this trick, I think.

Also, I am hesitant about the implicit equivalency (ambiguity?) between components-as-quantities and vector-as-quantity: e.g. {1*meter, 2*meter}[0] == ({1,2}*meter)[0] (I know that the RHS probably doesn't compile, but you get the point, even this issue of indexing opens a can of worms).

I have my own library for arrays (dynamic, arbitrary static dimension), https://gitlab.com/correaa/boost-multi. I wonder how I have to generalize my container class to support some kind of units. Since I purposely left linear algebra out, I think I probably shouldn't do anything, because, after all, any implicit connection between arrays and units is "through" linear algebra.

Any feedback is welcome, BTW.

In any case, I expect it to be used as a backend (representation) of linear algebra, I want it to be compatible with linear algebra applications (and also with units). On these lines, I gave some feedback to the linear algebra proposal already based on the experience with my library, https://github.com/BobSteagall/wg21/issues/74.

mpusz commented 1 year ago

Also, I am hesitant about the implicit equivalency (ambiguity?) between components-as-quantities and vector-as-quantity: e.g. {1meter, 2meter}[0] == ({1,2}*meter)[0].

I think we might support such an equivalency. Please note that ISO 80000-2 explicitly states:

Instead of treating each coordinate of a vector as a physical quantity value (i.e. a number multiplied by a unit), the vector could be written as a numerical vector multiplied by a unit. All units are scalars.

EXAMPLE Force acting on a given particle, e.g. in Cartesian components (Fx; Fy; Fz) = (−31,5; 43,2; 17,0) N.

correaa commented 1 year ago

I think we might support such an equivalency.

That would be a bold move, indeed.

It probably makes sense because, in linear algebra, indexing can be seen as a linear operator. Same logic as why units pertain to multiplication and addition, and now indexing(?).

I tried to hack Boost.Units to make that work, but I think I gave up.

I hope it goes well. ... and that it doesn't open a can of worms (e.g., what if operator[] is not semantically indexing or not an "orthogonal" decomposition?, or should operator() be supported? :) , (cos*meter)(1.2) == cos(1.2)*meter :clown_face: )

Please note that ISO 80000-2 explicitly states:

You are taking this seriously. :+1: Nice to see that.

Instead of treating each coordinate of a vector as a physical quantity value (i.e., a number multiplied by a unit), the vector could be written as a numerical vector multiplied by a unit. All units are scalars.

EXAMPLE Force acting on a given particle, e.g., in Cartesian components (Fx; Fy; Fz) = (−31,5; 43,2; 17,0) N.

Interesting, I do that all the time, of course, but I didn't know I was allowed by ISO. (Indeed, using units over vectors/components implies cartesian components, in contrast to components on a non-orthogonal basis.)

I guess it is risky to take ISO as a source of mathematical knowledge (mathematics by committee?), but it does point in a reasonable direction in this case.

dwith-ts commented 1 year ago

The equivalency only makes sense for uniform vectors. As soon as we have non-uniformity it will no longer work.

This also shows that this is not a mathematical relationship in the general case, it is merely a notational convenience for this special case.