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

more trouble with force_ndarray_like=True #1327

Closed
keewis opened this issue Jun 3, 2021 · 3 comments · Fixed by #1328
Closed

more trouble with force_ndarray_like=True #1327

keewis opened this issue Jun 3, 2021 · 3 comments · Fixed by #1328

Comments

@keewis
Copy link
Contributor

keewis commented Jun 3, 2021

Apparently, force_ndarray_like=True results in q._units containing numpy scalar values, which causes unit conversions to fail:

In [1]: import pint
   ...: 
   ...: ureg = pint.UnitRegistry(force_ndarray_like=True)
   ...: q = ureg.Quantity(1, "1 / hours") ** 2
   ...: display({k: type(v) for k, v in q._units.items()})
   ...: q.to("1 / s ** 2")
{'hour': numpy.int64}
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-fd499ff53bb2> in <module>
      3 ureg = pint.UnitRegistry(force_ndarray_like=True)
      4 q = 1 / ureg.Quantity(1, "hours") ** 2
----> 5 q.to("1 / s ** 2")

.../pint/quantity.py in to(self, other, *contexts, **ctx_kwargs)
    655         other = to_units_container(other, self._REGISTRY)
    656 
--> 657         magnitude = self._convert_magnitude_not_inplace(other, *contexts, **ctx_kwargs)
    658 
    659         return self.__class__(magnitude, other)

.../pint/quantity.py in _convert_magnitude_not_inplace(self, other, *contexts, **ctx_kwargs)
    604                 return self._REGISTRY.convert(self._magnitude, self._units, other)
    605 
--> 606         return self._REGISTRY.convert(self._magnitude, self._units, other)
    607 
    608     def _convert_magnitude(self, other, *contexts, **ctx_kwargs):

.../pint/registry.py in convert(self, value, src, dst, inplace)
    945             return value
    946 
--> 947         return self._convert(value, src, dst, inplace)
    948 
    949     def _convert(self, value, src, dst, inplace=False, check_dimensionality=True):

.../pint/registry.py in _convert(self, value, src, dst, inplace)
   1828                 value, src = src._magnitude, src._units
   1829 
-> 1830         return super()._convert(value, src, dst, inplace)
   1831 
   1832     def _get_compatible_units(self, input_units, group_or_system):

.../pint/registry.py in _convert(self, value, src, dst, inplace)
   1431 
   1432         if not (src_offset_unit or dst_offset_unit):
-> 1433             return super()._convert(value, src, dst, inplace)
   1434 
   1435         src_dim = self._get_dimensionality(src)

.../pint/registry.py in _convert(self, value, src, dst, inplace, check_dimensionality)
    982         # Here src and dst have only multiplicative units left. Thus we can
    983         # convert with a factor.
--> 984         factor, _ = self._get_root_units(src / dst)
    985 
    986         # factor is type float and if our magnitude is type Decimal then

.../pint/registry.py in _get_root_units(self, input_units, check_nonmult)
    822 
    823         accumulators = [1, defaultdict(int)]
--> 824         self._get_root_units_recurse(input_units, 1, accumulators)
    825 
    826         factor = accumulators[0]

.../pint/registry.py in _get_root_units_recurse(self, ref, exp, accumulators)
    871                 accumulators[1][key] += exp2
    872             else:
--> 873                 accumulators[0] *= reg._converter.scale ** exp2
    874                 if reg.reference is not None:
    875                     self._get_root_units_recurse(reg.reference, exp2, accumulators)

ValueError: Integers to negative integer powers are not allowed.

In [2]: q._units = pint.util.to_units_container({k: getattr(v, "item", lambda: v)() for k, v in q._units.items()})
   ...: print(q.to("1 / s ** 2"))
7.71604938271605e-08 / second ** 2

I'm pretty sure this is unrelated to #1301 (although they share a common cause: numpy.int64(1) ** -2 raises) because this also fails if I go back to the release commit of 0.17.

@keewis
Copy link
Contributor Author

keewis commented Jun 3, 2021

this can be fixed by:

diff --git a/pint/quantity.py b/pint/quantity.py
index cbe181f..8704971 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -1486,7 +1486,7 @@ class Quantity(PrettyIPython, SharedRegistryObject):
                     raise DimensionalityError(other._units, "dimensionless")
                 else:
                     exponent = _to_magnitude(
-                        other, self.force_ndarray, self.force_ndarray_like
+                        other, force_ndarray=False, force_ndarray_like=False
                     )
                     units = new_self._units ** exponent

not sure if I'm missing something? The test suite at least doesn't fail.

@jules-ch
Copy link
Collaborator

jules-ch commented Jun 3, 2021

Good catch.
Seems like the right thing to do.

Following my comment #60 (comment), IMO I think we need to constraint exponent type in UnitContainers

@keewis
Copy link
Contributor Author

keewis commented Jun 3, 2021

I would support that, but we have to make sure not to break the numpy support (does ureg.Quantity([0, 1], "m") ** Fraction("1.5") work?)

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

Successfully merging a pull request may close this issue.

2 participants