Skip to content
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

Open
mpusz opened this issue Jan 23, 2025 · 7 comments
Open

Quantity points arithmetics #668

mpusz opened this issue Jan 23, 2025 · 7 comments
Milestone

Comments

@mpusz
Copy link
Owner

mpusz commented Jan 23, 2025

For quantities, we allow arithmetic between different quantity types:

quantity q = isq::height(1 * m) + isq::width(1 * m);    // results with `isq::length(2 * m)`

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 of width. However, what does it mean to subtract points of height and width or add a delta of width to the point of height?

quantity q1 = quantity_point{isq::height(1 * m)} - quantity_point{isq::width(1 * m)};    // results with ????
quantity_point qp1 = quantity_point{isq::height(1 * m)} + isq::width(1 * m);    // results with ????

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?

quantity q2 = quantity_point{isq::height(1 * m)} - quantity_point{isq::length(1 * m)};    // results with ????
quantity q3 = quantity_point{isq::length(1 * m)} - quantity_point{isq::height(1 * m)};    // results with ????
quantity_point qp2 = quantity_point{isq::height(1 * m)} + isq::length(1 * m);    // results with ????
quantity_point qp3 = quantity_point{isq::length(1 * m)} + isq::height(1 * m);    // results with ????

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 of length or vice versa?

inline constexpr struct zero_length final : mp_units::absolute_point_origin<mp_units::isq::length> {} zero_length;
inline constexpr struct zero_height final : mp_units::absolute_point_origin<mp_units::isq::height> {} zero_height;

quantity_point qp4 = zero_length + isq::height(1 * m);
quantity_point qp5 = zero_height + isq::length(1 * m);

Please let me know your thoughts.

@mpusz
Copy link
Owner Author

mpusz commented Jan 23, 2025

@burnpanck, you always cared for quantity points and had good ideas on how to support those. Your feedback is welcomed here.

@Spammed
Copy link

Spammed commented Jan 23, 2025

I usually understand 'height' and 'width' as quantities of different (spatial) dimensions.
Therefore, my answer would be 'no, not allowed' both times.

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:
quantity_point{isq::height(1 * m)} + isq::length(1 * m) == quantity_point{isq::height(2 * m)};
I suspect that would not be a good idea.

@mpusz
Copy link
Owner Author

mpusz commented Jan 24, 2025

Therefore, my answer would be 'no, not allowed' both times.

Yes, this is why I submitted this issue. I think that we need to fix a few things.

I suspect that would not be a good idea.

Right. isq::length represents a generic/unspecified length but not any length. We represent any length with kind_of<QS> (or just a unit), and I think the below should work:

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]> ?

@mpusz
Copy link
Owner Author

mpusz commented Jan 24, 2025

So it seems that isq::height and isq::width should have a common type, compare with each other, be convertible, and be possible to add or subtract only in case of quantities but not points.

This is yet another reason to consider a redesign of the quantity_point that I mentioned in my last blog article.

@burnpanck
Copy link
Contributor

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 quantity_point{isq::height(1 * m)} + isq::width(2*m) -> quantity_point{3*m} is any more surprising than than isq::height(1 * m) + isq::width(2 * m) -> isq::length(3 * m).

@mpusz
Copy link
Owner Author

mpusz commented Jan 27, 2025

@burnpanck, it is good to hear from you again 😃

(That said, the last time I participated in the discussion about quantity types, we were still classifying "sibling types" like those as incompatible)

It depends on what you mean by incompatible. We can't convert from isq::width to isq::height, but we can add them and the result will be isq::length.

if we decide that two related quantity specs are "compatible" then this also applies to their points, and vice versa

I have a hard time imagining what it means to subtract a point of isq::height from a point of isq::width 😕

@mpusz
Copy link
Owner Author

mpusz commented Jan 27, 2025

BTW @burnpanck, you still have a few PRs open. Will you have some time to finish them soon?

@mpusz mpusz added this to the v2.5.0 milestone Jan 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants