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

Implemented Quantity-aware wrapper for assert_allclose #3273

Merged
merged 3 commits into from Jan 15, 2015

Conversation

astrofrog
Copy link
Member

This is a replacement for #2402. It seems there is general resistance against having quantity-aware wrappers for many Numpy functions, but the one here is one that is needed in various packages so it makes sense to make it available as a helper.

Not a full feature, just part of the infrastructure, so I figured this would be ok for 1.0?

@astrofrog astrofrog added this to the v1.0.0 milestone Jan 6, 2015
@astrofrog astrofrog self-assigned this Jan 6, 2015
@Cadair
Copy link
Member

Cadair commented Jan 6, 2015

👍

@mhvk
Copy link
Contributor

mhvk commented Jan 6, 2015

My resistance is due mostly to the fact that I feel this is a bug in numpy, and it would be good to try to improve numpy rather than work around it. Specifically, assert_allclose would become fine if one had at least the option to allow subclasses in numpy.core.numeric._allclose_points (https://github.com/numpy/numpy/blob/master/numpy/core/numeric.py#L2205 and two further instances down from there).

Could you perhaps raise a wishlist issue with numpy about that?

But having written many tests with allclose and being annoyed, I do see the point of having the wrapper now. Comments on the implementation will be inline.

import numpy as np
from ..units import Quantity

if isinstance(actual, Quantity) and isinstance(desired, Quantity):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this is excessive testing of inputs! Elsewhere, anything not a Quantity is treated as dimensionless, and I would just do that here too, raising UnitsError if necessary. So, I would do:

actual = Quantity(actual, subok=True, copy=False)
desired = Quantity(desired, subok=True, copy=False).to(actual.unit)
atol = Quantity(atol, subok=True, copy=False).to(actual.unit)
rtol=  Quantity(rtol, subok=True, copy=False).to(u.dimensionless_unscaled)
np.testing.assert_allclose(actual.value, desired.value,
                           rtol=rtol.value, atol=atol.value, err_msg=err_msg, verbose=verbose)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind, but if we do this, the error messages will be less explicit than they currently are. What do others think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But very similar to the error messages you get generally from working with quantities...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @mhvk that this may be a call to try to get more explicit error messages in Quantity itself... But I think there's no harm in leaving this in to make reading of test results easier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I have implemented this, but I override the exceptions if any are raised, which I think is a good compromise

@embray
Copy link
Member

embray commented Jan 12, 2015

Certainly for testing purposes I see no problem with having this.


def assert_quantity_allclose(actual, desired, rtol=1.e-7, atol=0, err_msg='', verbose=True):
"""
Raise an assertion if two objects are not equal up to desired tolerance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably note in the docstring here that the definition of atol is set by the unit of actual, not desired (because desired gets converted to actual.units). Or even go a bit further and change the name of atol to atol_actualunit or something like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it doesn't matter: atol has to be specified as a quantity to work so the units have to be explicit anyway (and can be different from actual.unit. The only reason it doesn't have units by default is because for zero it's unambiguous and doesn't matter what the units are. But you can do:

assert_quantity_allclose([1,2] * u.m, [100,200] * u.cm, atol=2 * u.cm)

and that should work. In fact, if atol is non-zero, you have to give units.

@eteq
Copy link
Member

eteq commented Jan 13, 2015

Aside from the minor comments, I'm 👍 to this, @astrofrog

raise u.UnitsError("Units for 'desired' ({0}) and 'actual' ({1}) are not convertible".format(desired.unit, actual.unit))

if atol == 0:
atol = u.Quantity(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny really, but somehow this feels slightly confusing. How about writing

# we take 0 to be convertible to any unit
atol = u.Quantity(0, actual.unit)

You could also consider making the default atol=None and then test for that, i.e.,

if atol is None:
    # by default, we assume an absolute tolerance of 0
    atol = u.Quantity(0, actual.unit)
else:
    ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@mhvk
Copy link
Contributor

mhvk commented Jan 13, 2015

@astrofrog - yes, I'm fine with catching the Quantity exceptions. As @embray noted, perhaps the fact that you feel it is helpful to do so is a signal that the exceptions raised by Quantity itself need clarification...

Note my tiny comment -- implement it if you wish -- happy either way.

astrofrog added a commit that referenced this pull request Jan 15, 2015
Implemented Quantity-aware wrapper for assert_allclose
@astrofrog astrofrog merged commit 6ca6ac4 into astropy:master Jan 15, 2015
@astrofrog astrofrog deleted the quantity-test-helpers branch July 5, 2016 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants