-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quantity points arithmetics #668
Comments
@burnpanck, you always cared for quantity points and had good ideas on how to support those. Your feedback is welcomed here. |
I usually understand 'height' and 'width' as quantities of different (spatial) dimensions. Only if the points are defined in a common (vector) space, you can determine (vector) distances or offset them with (vector) distances of this space. However, one might be tempted to interpret the 'length' in the expression implicitly as 'belonging to' in each case: |
Yes, this is why I submitted this issue. I think that we need to fix a few things.
Right. quantity_point{isq::height(1 * m)} + 1 * m == quantity_point{isq::height(2 * m)}; A bit more interesting may be the following cases: quantity_point{1 * m} + isq::height(1 * m) == ???; // point of isq::height or any length ?
quantity_point{isq::height(1 * m)} - quantity_point{1 * m} == ???; // quantity<isq::height[m]> ? |
So it seems that This is yet another reason to consider a redesign of the |
I do care a lot about quantity points. However, in my opinion, the concept of quantity types is quite orthogonal. For me, the benefit of what we call "quantity type" (I still struggle a bit with that name) are a scheme of incrementally narrowing down the applicability. I think it should not matter here if we are talking about points or distances - if we decide that two related quantity specs are "compatible" then this also applies to their points, and vice versa. Now what should be compatible with each other? I think we have some choice here. We want to disallow obviously wrong things. We want to allow practically useful things if they are unambiguous. If you want to know the boundary length of a rectangle, you end up summing height and width. There is only one way to do that, it is unambiguous. It is, because you are adding the length of those things. (That said, the last time I participated in the discussion about quantity types, we were still classifying "sibling types" like those as incompatible). I don't think that |
@burnpanck, it is good to hear from you again 😃
It depends on what you mean by incompatible. We can't convert from
I have a hard time imagining what it means to subtract a point of |
BTW @burnpanck, you still have a few PRs open. Will you have some time to finish them soon? |
I thought about this a bit more. Let's analyze such a simple tree: flowchart TD
parent["parent (e.g., length)"]
parent --- child["child (e.g., height)"]
parent --- other_child["other_child (e.g., radius)"]
Delta (
|
I can agree with the proposed rules for mixed
But for operations between two Finally, if |
Ohh, I forgot to write about this as well. Yes, I think that converting between points should also not be enabled as they may describe different spaces. However, I might be wrong. In such a case, please do let me know. I would prefer to be conservative here and extend the design if compelling use cases emerge. |
If they were, then that reasoning should also apply to deltas. After all, we claim that deltas are differences between points in the same space. If we say |
Yeah, I'm trying to wrap my head around this. My mental model is that, for example, for 1-D lengths, points represent an axis that can't be rotated, and we can only move back and forth through it. For example, altitude has a vertical axis. If we want to add a delta diameter to points on the altitude axis, we first need to "rotate" the diameter to align with the altitude axis. As a result, we end up with another altitude. As you wrote, points are strictly "stronger" than deltas. Now, if you have a vertical axis for altitude and another for horizontal length, trying to subtract or convert between points on those two is impossible. Also, a parent quantity is a more generic quantity that, again, may be an "unspelled" horizontal length or an axis in any other direction. Deltas are different. They express the exact amount and can be "rotated" to align to any other quantity. However, they lose their character after rotation, and we look for a common, more generic quantity that describes both of them. Of course, my mental model might be wrong, and please let me know in such a case. |
This seems reasonable to me too, at least as far as the quantity category goes. But I wanted to clarify that this is not true for the units: rather, all the usual rules for "common unit" must apply. So, for the example of a point of altitude and a delta of diameter: if the point-of-altitude is measured in meters, and the delta-of-diameter in cm, then we should get a point-of-altitude measured in cm. I think this is pretty uncontroversial, but I wanted to lay it out explicitly. |
I absolutely agree. But:
I'm not so sure there in general. The semantics of an actual physical quantity are completely transparent to the unit. The unit is "accidental" in that it is required to be able to represent the physical quantity through a number and a specification of some universally understood reference quantity. Instead, I would want to specify the library behaviour with respect to range and precision. These concepts are not part of the semantics of the physical quantity itself, but how we represent quantities as C++ object, with the necessary compromise between range, precision, storage and computation. In particular, the choice of the "greatest common divisor" of all input units as the output units is bad IMHO, because it may expose the use to unexpected risks around the range of the number representation. Even for floating-point types, you quickly reach the point where the apparent "exact" conversion to the smaller unit becomes an illusion due to the finite number of significant digits. I know that you @chiphogg prefer to see the |
Well stated: I completely agree.
Representing range and precision explicitly in the quantity type system sounds like a very intriguing and appealing idea. I hope you (or someone else) is able to show what this would look like in practice, so we can find out whether it works, and whether there are any meaningful downsides. I'd really like to see this explored further! One interesting question will be what we mean by "precision": will we support absolute, relative, or both? Currently, the integer reps (and fixed-point) give us something more like absolute precision, while floating point reps give us relative precision. So perhaps the precision "category" (i.e., relative vs. absolute) won't be fully independent from the rep. It'll be especially interesting to see what the rules are for deducing the output precision, range, and rep from the inputs of a mathematical operation.
I wouldn't say that it's "bad"; I'd just say that it has risks, such as this one that you've pointed out. I think this risk can be effectively mitigated with an adaptive overflow safety surface, which does a good job in practice of permitting many safe operations, and forbidding many risky ones. It isn't perfect, but it's a huge leap forward IMO compared to the previous state of the art (which was, essentially, "use GCD, and users are on their own for overflow risks"). As for floating point: you are right on the money. No libraries, including Au and mp-units, have advanced at all (AFAIK) beyond the
It's a great point that individual values rarely come from exact sources. If we could take that uncertainty into account in the ways you suggest, it could make a lot of things nicer. (Here's an example that resonates with me: we measure our timestamps with integer nanosecond precision, and this means Absent a robust framework for handling those precisions, at least I'd like to avoid adding to the error. So we use the common unit for mixed-unit operations, and trust in the safety surface to mitigate risk. It's pretty satisfying overall. One principle I do want to see a range/precision approach respect is symmetry in the arguments. For example, the unit of the result of adding or subtracting two quantities should never change when we swap the order. I also think that unit should never directly depend on the rep (although the precision might conceivably have an effect, and the rep might not be independent of the precision). But these are just abstract ideas until we have a real set of range/precision based quantity APIs to see how they work in practice. |
I think that this discussion derailed a bit from the quantity point arithmetic subject, but I will add one more thing to it 😉 We have had the following issue open for a long time: #464. Proper modeling of measurement uncertainties will allow us to model IAU units and many other things mentioned above. The problem is that implementing an |
For quantities, we allow arithmetic between different quantity types:
We had something similar for quantity points, but I am starting to think, if that is correct.
For example, for lengths, quantities represent a distance/delta between two points. Adding such deltas of length measured in different ways/dimensions makes sense and is required by the ISO 80000. Quantity points of length represent a distinct point in, for example, 3D space. The same point may have many representations from different origins in this 3D space, but they all still describe exactly the same point.
Subtracting two points of
width
gives a delta ofwidth
. However, what does it mean to subtract points ofheight
andwidth
or add a delta ofwidth
to the point ofheight
?I start to think that the above should not compile. Do you agree?
The above examples contained quantities from different branches of the length hierarchy tree. What about the same branch?
A similar question to the above might be if it should be possible to define a point of
height
with the origin being a point oflength
or vice versa?Please let me know your thoughts.
The text was updated successfully, but these errors were encountered: