Skip to content

Commit

Permalink
Fix #1184 to_reduced with ndarray of int
Browse files Browse the repository at this point in the history
Do not use ito with to_reduced function
  • Loading branch information
jules-ch committed Nov 23, 2021
1 parent 79a0db2 commit 28f1cb7
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Pint Changelog

- Upgrade min version of uncertainties to 3.1.4
- Fix setting options of the application registry (Issue #1403).
- Fix casting error when using to_reduced_units with array of int.
(Issue #1184)


0.18 (2021-10-26)
Expand Down
46 changes: 28 additions & 18 deletions pint/quantity.py
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,21 @@ def to_base_units(self) -> Quantity[_MagnitudeType]:

return self.__class__(magnitude, other)

def _get_reduced_units(self, units):
# loop through individual units and compare to each other unit
# can we do better than a nested loop here?
for unit1, exp in units.items():
# make sure it wasn't already reduced to zero exponent on prior pass
if unit1 not in units:
continue
for unit2 in units:
if unit1 != unit2:
power = self._REGISTRY._get_dimensionality_ratio(unit1, unit2)
if power:
units = units.add(unit2, exp / power).remove([unit1])
break
return units

def ito_reduced_units(self) -> None:
"""Return Quantity scaled in place to reduced units, i.e. one unit per
dimension. This will not reduce compound units (e.g., 'J/kg' will not
Expand All @@ -775,32 +790,27 @@ def ito_reduced_units(self) -> None:
if len(self._units) == 1:
return None

newunits = self._units.copy()
# loop through individual units and compare to each other unit
# can we do better than a nested loop here?
for unit1, exp in self._units.items():
# make sure it wasn't already reduced to zero exponent on prior pass
if unit1 not in newunits:
continue
for unit2 in newunits:
if unit1 != unit2:
power = self._REGISTRY._get_dimensionality_ratio(unit1, unit2)
if power:
newunits = newunits.add(unit2, exp / power).remove([unit1])
break
units = self._units.copy()
new_units = self._get_reduced_units(units)

return self.ito(newunits)
return self.ito(new_units)

def to_reduced_units(self) -> Quantity[_MagnitudeType]:
"""Return Quantity scaled in place to reduced units, i.e. one unit per
dimension. This will not reduce compound units (intentionally), nor
can it make use of contexts at this time.
"""

# can we make this more efficient?
newq = copy.copy(self)
newq.ito_reduced_units()
return newq
# shortcuts in case we're dimensionless or only a single unit
if self.dimensionless:
return self.ito({})
if len(self._units) == 1:
return None

units = self._units.copy()
new_units = self._get_reduced_units(units)

return self.to(new_units)

def to_compact(self, unit=None) -> Quantity[_MagnitudeType]:
""" "Return Quantity rescaled to compact, human-readable units.
Expand Down
7 changes: 7 additions & 0 deletions pint/testsuite/test_quantity.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,13 @@ def test_upcast_type_rejection_on_creation(self):
self.Q_(FakeWrapper(42), "m")
assert FakeWrapper(self.Q_(42, "m")).q == self.Q_(42, "m")

@helpers.requires_numpy
def test_to_reduced_units(self):
q = self.Q_([3, 4], "s * ms")
helpers.assert_quantity_equal(
q.to_reduced_units(), self.Q_([3000.0, 4000.0], "ms**2")
)


class TestQuantityToCompact(QuantityTestCase):
def assertQuantityAlmostIdentical(self, q1, q2):
Expand Down

0 comments on commit 28f1cb7

Please sign in to comment.