-
Notifications
You must be signed in to change notification settings - Fork 44
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
Allow NaN values to pass floating point bounds check. #167
Conversation
Math should only be imported for messages with floating point fields in order for it to pass the linter |
Signed-off-by: Øystein Sture <os@skarvtech.com>
Updated the pull request. Inverted the bounds check instead of calling math.isnan. This works since NaN always evaluates to false in comparisons. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the ticket and PR!
Would you be willing to update it to do two more things?
- Modify the comparison logic to allow positive and negative infinity (
-float('inf')
andfloat('inf')
) - Add tests for NaN, -inf, and inf for float32 and float64 types in test_basic_types and test_arrays
Playground script for myself when I re-review
import math
bound = 3.402823e+38
def old_float_check(value):
return value >= -bound and value <= bound
def float_check(value):
return not (value < -bound or value > bound)
def float_array_check(value):
return not any(val < -bound or val > bound for val in value)
def alt_check(value):
return (not (value < -bound or value > bound)) or math.isinf(value)
def alt_array_check(array_value):
return all((not (value < -bound or value > bound)) or math.isinf(value) for value in array_value)
test_values = [
float('nan'),
float('inf'),
-float('inf'),
0,
float(0),
-float(0),
3.14,
-3.14,
]
print("New check")
for v in test_values:
print(f'{float_check(v)} - {repr(v)}')
print(f'{repr(test_values)} - {float_array_check(test_values)}')
print ("Old check")
for v in test_values:
print(f'{old_float_check(v)} - {repr(v)}')
print ("Alternative check")
for v in test_values:
print(f'{alt_check(v)} - {repr(v)}')
print(f'{repr(test_values)} - {alt_array_check(test_values)}')
In that case, the bounds check for float64 can be removed, as all numbers pass through it, unless I'm misunderstanding something about the representation of the values. Assigning a larger number than 1.7976931348623157e+308 to a regular python float or numpy.float64 automatically turns it into inf. The bounds check may still make sense for float32, since there is no python builtin type, and may exceed the C/C++ float type. Question is if it should be converted to -inf/inf instead of throwing a bounds error, since this is the behavior for float64. |
Just my opinion here, I think silent overflow to inf makes sense for float32, if we do not have type-checking to validate that the user is actually providing a np.float32. |
I agree. And that seems to be the behavior in IEEE 754 as far as I can tell. Honestly, I'm in favor of removing the entire bounds check for floating point numbers. I don't see what problem it solves. |
Yes it looks like IEEE 754 specifies this behavior Maybe @clalancette could weigh in on why the original PR was merged and then we can figure out whether the bounds check should be kept? |
The idea behind the checks using Letting the conversion to from rclpy.serialization import serialize_message, deserialize_message
from test_msgs.msg import BasicTypes
def float32_value(self):
return self._float32_value
def float32_value_setter(self, value):
self._float32_value = value
BasicTypes.float32_value = property(float32_value, float32_value_setter)
if __name__ == '__main__':
b = BasicTypes()
b.float32_value = -3.402823e+40
b_prime = deserialize_message(serialize_message(b), BasicTypes)
print('b == b_prime?', b == b_prime) # prints False because b_prime.float32_value is inf As for |
I agree that this is undesirable. If the corresponding numpy type or python.ctypes type had been used in python, this would not be the case.
That would mean that python is running on hardware that is not IEEE 754 compliant, or compiled with flags that disable conformance mode, but yes it can happen. What if the floating point bounds checks are kept, but variables explicitly set to Inf/NaN are allowed through? How does that sound? |
That sounds great to me |
Signed-off-by: Øystein Sture <os@skarvtech.com>
Signed-off-by: Øystein Sture <os@skarvtech.com>
I think the tests are failing because the assigned value gets rounded to inf and passes the bounds check, but I'll need to have a closer look at why it's happening. I won't have time to look at this again for a few days |
Signed-off-by: Øystein Sture <os@skarvtech.com>
Signed-off-by: Øystein Sture <os@skarvtech.com>
Signed-off-by: Øystein Sture <os@skarvtech.com>
Signed-off-by: Øystein Sture <os@skarvtech.com>
Signed-off-by: Øystein Sture <os@skarvtech.com>
I've updated the pull request, and it seems to pass the checks now. The float64 bounds check test is only executed if sys.float_info.max exceeds 1.7976931348623157e+308. Otherwise, the python float is converted silently to inf, which passes the bounds check without triggering the assertion error. The out or range tests are performed in test_arrays(), test_bounded_sequences(), and test_unbounded_sequences(). I've added the new tests for all of them. Perhaps these can be cleaned up in a separate PR. |
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
…l_python into pr_167
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with green CI!
CI (repos file build: |
CI LGTM! Thank you for the PR and for iterating! |
Hi, is there any plan when and if this PR will be merged into current Humble release? |
I'm cautious about backporting a behavior change to a low level package like this. If it is backported, then #182 must be backported with it. |
thanks for the quick answer. In my eyes, this behaviour in Humble is a regression from Galactic, hence worth porting back into Humble. I actually wonder why this has not impeded more users. Our system relies on setting some message contents to |
+1 This is affecting our system as well. We would like to upgrade to Humble but need this PR backported first. Thanks. |
@mergify backport humble |
❌ Command disallowed due to command restrictions in the Mergify configuration.
|
https://github.com/Mergifyio backport humble |
@Mergifyio backport humble |
❌ Command disallowed due to command restrictions in the Mergify configuration.
|
1 similar comment
❌ Command disallowed due to command restrictions in the Mergify configuration.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clalancette @sloretz i think this can backport to humble, what do you think? (I do not have permission to manage backport though.)
* Invert bounds check in order to permit floating point NaN values Signed-off-by: Øystein Sture <os@skarvtech.com> * Allow floating point numbers set to Inf to pass bounds check Signed-off-by: Øystein Sture <os@skarvtech.com> * Add float/double NaN/Inf tests Signed-off-by: Øystein Sture <os@skarvtech.com> * Increase precision of float32 bounds Signed-off-by: Øystein Sture <os@skarvtech.com> * Only perform float64 bounds check on non-compliant IEEE 754 systems Signed-off-by: Øystein Sture <os@skarvtech.com> * Disable bounds test for float64 on IEEE 754 compatible systems Signed-off-by: Øystein Sture <os@skarvtech.com> * Disable bounds test for float64 on IEEE 754 compatible systems Signed-off-by: Øystein Sture <os@skarvtech.com> * Resolve failing nan/inf test by comparing the same types Signed-off-by: Øystein Sture <os@skarvtech.com> * Change decode error mode to replace (#176) Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com> * Replace rosidl_cmake imports with rosidl_pycommon (#177) Signed-off-by: Jacob Perron <jacob@openrobotics.org> * Delete trailing whitespace Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> * Split fail case array check tests into two Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> Signed-off-by: Øystein Sture <os@skarvtech.com> Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com> Signed-off-by: Jacob Perron <jacob@openrobotics.org> Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com> Co-authored-by: Jacob Perron <jacob@openrobotics.org> Co-authored-by: Shane Loretz <sloretz@osrfoundation.org>
* Allow NaN values to pass floating point bounds check. (#167) * Invert bounds check in order to permit floating point NaN values Signed-off-by: Øystein Sture <os@skarvtech.com> * Allow floating point numbers set to Inf to pass bounds check Signed-off-by: Øystein Sture <os@skarvtech.com> * Add float/double NaN/Inf tests Signed-off-by: Øystein Sture <os@skarvtech.com> * Increase precision of float32 bounds Signed-off-by: Øystein Sture <os@skarvtech.com> * Only perform float64 bounds check on non-compliant IEEE 754 systems Signed-off-by: Øystein Sture <os@skarvtech.com> * Disable bounds test for float64 on IEEE 754 compatible systems Signed-off-by: Øystein Sture <os@skarvtech.com> * Disable bounds test for float64 on IEEE 754 compatible systems Signed-off-by: Øystein Sture <os@skarvtech.com> * Resolve failing nan/inf test by comparing the same types Signed-off-by: Øystein Sture <os@skarvtech.com> * Change decode error mode to replace (#176) Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com> * Replace rosidl_cmake imports with rosidl_pycommon (#177) Signed-off-by: Jacob Perron <jacob@openrobotics.org> * Delete trailing whitespace Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> * Split fail case array check tests into two Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> Signed-off-by: Øystein Sture <os@skarvtech.com> Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com> Signed-off-by: Jacob Perron <jacob@openrobotics.org> Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com> Co-authored-by: Jacob Perron <jacob@openrobotics.org> Co-authored-by: Shane Loretz <sloretz@osrfoundation.org> * 👨🌾 Fix NaN values bound numpy windows version (#182) * Replaced equal_nan for numpy<1.19 Signed-off-by: Crola1702 <cristobal.arroyo@ekumenlabs.com> * Remove stray numpy import (#185) NumPy was being imported in the template code (not the template output) for apparently no reason. This was causing problems when cross-compiling, where NumPy is only available for the target platform. Signed-off-by: Ben Wolsieffer <benwolsieffer@gmail.com> Signed-off-by: Øystein Sture <os@skarvtech.com> Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com> Signed-off-by: Jacob Perron <jacob@openrobotics.org> Signed-off-by: Shane Loretz <sloretz@osrfoundation.org> Signed-off-by: Crola1702 <cristobal.arroyo@ekumenlabs.com> Signed-off-by: Ben Wolsieffer <benwolsieffer@gmail.com> Co-authored-by: Øystein Sture <oysstu@users.noreply.github.com> Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com> Co-authored-by: Jacob Perron <jacob@openrobotics.org> Co-authored-by: Shane Loretz <sloretz@osrfoundation.org> Co-authored-by: Cristóbal Arroyo <69475004+Crola1702@users.noreply.github.com> Co-authored-by: Ben Wolsieffer <benwolsieffer@gmail.com>
This pull request resolves the issue #162 by explicitly adding NaN values to the floating point bounds check.
Signed-off-by: Oystein Sture os@skarvtech.com
Fixes #169
Fixes #162