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

Applying numpy.cbrt (cubic root) loses quantity #807

Closed
omtee opened this issue May 14, 2019 · 3 comments · Fixed by #965
Closed

Applying numpy.cbrt (cubic root) loses quantity #807

omtee opened this issue May 14, 2019 · 3 comments · Fixed by #965

Comments

@omtee
Copy link

omtee commented May 14, 2019

pint.__version__
'0.9'
a = ur.Quantity(100, "m ** 3")
print(a)
100 meter ** 3
print(np.sqrt(a))
10.0 meter ** 1.5
print(np.cbrt(a))
4.641588833612779

@hgrecco
Copy link
Owner

hgrecco commented May 16, 2019

Yes. This happens because sqrt is handled by pint. I hope that we the recent addition to numpy all these quirks will be removed.

@sxie22
Copy link

sxie22 commented Sep 11, 2019

When trying to find a workaround, I found that adding another dictionary entry "cbrt" : 1/3 here in quantity.py seems to work.

'sqrt': .5, 'square': 2, 'reciprocal': -1}

from pint import UnitRegistry
ur = UnitRegistry()
a = ur.Quantity(100, "m ** 3")
print(a)
100 meter ** 3
print(np.sqrt(a))
10.0 meter ** 1.5
print(np.cbrt(a))
4.641588833612778 meter

Could you look into this as a hotfix?

@jthielen
Copy link
Contributor

This was not added in #905 (even though it likely would have been easy to do so in retrospect). However, this should be an easy addition by defining a new unit operation in

pint/pint/numpy_func.py

Lines 94 to 152 in 43fbae2

def get_op_output_unit(unit_op, first_input_units, all_args=[], size=None):
"""Determine resulting unit from given operation.
Options for `unit_op`:
- "sum": `first_input_units`, unless non-multiplicative, which raises
OffsetUnitCalculusError
- "mul": product of all units in `all_args`
- "delta": `first_input_units`, unless non-multiplicative, which uses delta version
- "delta,div": like "delta", but divided by all units in `all_args` except the first
- "div": unit of first argument in `all_args` (or dimensionless if not a Quantity) divided
by all following units
- "variance": square of `first_input_units`, unless non-multiplicative, which raises
OffsetUnitCalculusError
- "square": square of `first_input_units`
- "sqrt": square root of `first_input_units`
- "reciprocal": reciprocal of `first_input_units`
- "size": `first_input_units` raised to the power of `size`
"""
if unit_op == "sum":
result_unit = (1 * first_input_units + 1 * first_input_units).units
elif unit_op == "mul":
product = first_input_units._REGISTRY.parse_units('')
for x in all_args:
if hasattr(x, 'units'):
product *= x.units
result_unit = product
elif unit_op == "delta":
result_unit = (1 * first_input_units - 1 * first_input_units).units
elif unit_op == "delta,div":
product = (1 * first_input_units - 1 * first_input_units).units
for x in all_args[1:]:
if hasattr(x, 'units'):
product /= x.units
result_unit = product
elif unit_op == "div":
# Start with first arg in numerator, all others in denominator
product = getattr(all_args[0], 'units', first_input_units._REGISTRY.parse_units(''))
for x in all_args[1:]:
if hasattr(x, 'units'):
product /= x.units
result_unit = product
elif unit_op == "variance":
result_unit = ((1 * first_input_units + 1 * first_input_units)**2).units
elif unit_op == "square":
result_unit = first_input_units**2
elif unit_op == "sqrt":
result_unit = first_input_units**0.5
elif unit_op == "reciprocal":
result_unit = first_input_units**-1
elif unit_op == "size":
if size is None:
raise ValueError('size argument must be given when unit_op=="size"')
result_unit = first_input_units**size
else:
raise ValueError('Output unit method {} not understood'.format(unit_op))
return result_unit

and adding the appropriate entry in:

pint/pint/numpy_func.py

Lines 266 to 269 in 43fbae2

op_units_output_ufuncs = {'var': 'square', 'prod': 'size', 'multiply': 'mul',
'true_divide': 'div', 'divide': 'div', 'floor_divide': 'div',
'sqrt': 'sqrt', 'square': 'square', 'reciprocal': 'reciprocal',
'std': 'sum', 'sum': 'sum', 'cumsum': 'sum', 'matmul': 'mul'}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants