Skip to content

Commit

Permalink
Merge pull request #1417 from jules-ch/fix-1184
Browse files Browse the repository at this point in the history
Fix to_reduced_units
  • Loading branch information
jules-ch authored Jan 15, 2022
2 parents 09546b5 + 6d6acc9 commit befdffb
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 18 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Pint Changelog
- Fix setting options of the application registry (Issue #1403).
- Fix Quantity & Unit `is_compatible_with` with registry active contexts (Issue #1424).
- Allow Quantity to parse 'NaN' and 'inf(inity)', case insensitive
- 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 @@ -635,6 +635,13 @@ def test_nan(self, nan_str, has_unit):
assert math.isnan(test.magnitude)
assert ref != test

@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 befdffb

Please sign in to comment.