mpusz / mp-units

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

Clarify concepts and casting rules of quantity kinds and types #567

Closed burnpanck closed 1 month ago

burnpanck commented 1 month ago

I'm finally refactoring our production code to units v2. Unfortunately, I have lost track of the previous discussion over interconvertibility of quantity kinds. There were concepts "quantity kind" and "quantity type", and potential hierarchies of those, but I currently fail to understand to what rules the library has settled.

The specific case where I was wondering this was here: In our code, we mostly use untyped quantities, with the exception of two custom quantity types. One of them is an inverse duration (dimension T^-1). Our embedded system measures statistical properties of the separatioon of events happening repeatedly (not related to radionucleides), and so we invented a new quantity type for quantities related to the "frequency" of those events - as in the statistician's sense of frequency, not the one from the ISQ. However, now I'm struggling to properly cast the measured values based on a real ISQ frequency and a count to that custom quantity-type: quantity_cast refuses the cast because hertz is associated with a quantity-type of it's own, but not related to our own event "frequency" type. So basically it seems that quantity_cast currently prohibits "horizontal casts". Is this intended?

I had declared that "frequency" type to be of inverse duration, rather than a refinement of frequency, because it seems that the library currently disallows restricting units to anything else than the "root of a kind-tree" (?). It is not entirely clear to me what that would be, or why there would be a need for such a restriction. If that restriction weren't there, then those casts would be "vertical".

mpusz commented 1 month ago

@burnpanck, it is great to hear that you are moving to V2.

Unfortunately, it is hard for me to understand your use case without a concrete code example, so maybe you could provide a simplified example in the Compiler Explorer? Also, maybe this example will help you: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3045r0.html#user-defined-quantities-and-units.

mpusz commented 1 month ago

Regarding Hz, here is the rationale for constraining it to frequency:

https://mpusz.github.io/mp-units/latest/users_guide/framework_basics/systems_of_units/#constraining-a-derived-unit-to-work-only-with-a-specific-derived-quantity

Although, indeed, "periodic phenomena" might not necessarily imply frequency. However, there is no "periodic phenomena" quantity type in ISQ.

burnpanck commented 1 month ago

I'm fine with the current choice and rationale of constraining Hz to frequency. In our use-case, we have something similar to the quantity type Tempo in P3045 example (let's call it BeatRate for this discussion), with a corresponding bpm unit. The P3045 example defines Tempo in terms of a custom kind Beat, whereas we defined it directly as a custom kind of inverse time (exactly by QUANTITY_SPEC(BeatRate, inverse(duration)). I believe the difference is immaterial (though I may be wrong). Ultimately, what failed is quantity_cast<BeatRate>(q), where q is expressed in Hz. I was further suggesting that the cast would have passed through if we had done QUANTITY_SPEC(BeatRate, frequency) instead, but then the unit definition fails, apparently because BeatRate isn't "at the root of a kind hierarchy" (?):

inline constexpr struct BeatsPerMinute : named_unit<"bpm", one/minute, kind_of<BeatRate>> {} BeatsPerMinute;

As I write this however I notice the is_kind in your example's definition of Beat, which most likely is absent from our QUANTITY_SPEC(BeatRate,...).

So ultimately, I think the library users would benefit from rigorous description of the concept of "kind". Can we now use a mental model of a hierarchy of quantity types? What does the is_kind in a quantity specification do exactly in terms of that hierarchy? Which nodes of the hierarchy are allowed as an argument of kind_of<...> inside a unit definition?

mpusz commented 1 month ago

https://mpusz.github.io/mp-units/latest/users_guide/framework_basics/dimensionless_quantities/#nested-quantity-kinds ;-)

mpusz commented 1 month ago

@burnpanck, do you need any more support here, or can we close that one?

burnpanck commented 1 month ago

I am good, thanks!