515:  … r=hgrecco
See #500 

BaseRegistry.auto_reduce_dimensions was added to configure whether to automatically reduce dimensionality. The reduction was implemented using decorators, one for inplace and one for not. The only operations wrapped were multiplication and division. Is this correct?
This commit is contained in:
bors[bot]
2017-05-23 20:59:52 +00:00
3 changed files with 68 additions and 3 deletions

View File

@@ -44,6 +44,25 @@ class _Exception(Exception): # pragma: no cover
self.internal = internal
def reduce_dimensions(f):
def wrapped(self, *args, **kwargs):
result = f(self, *args, **kwargs)
if result._REGISTRY.auto_reduce_dimensions:
return result.to_root_units()
else:
return result
return wrapped
def ireduce_dimensions(f):
def wrapped(self, *args, **kwargs):
result = f(self, *args, **kwargs)
if result._REGISTRY.auto_reduce_dimensions:
result.ito_root_units()
return result
return wrapped
@fix_str_conversions
class _Quantity(SharedRegistryObject):
"""Implements a class to describe a physical quantity:
@@ -657,6 +676,7 @@ class _Quantity(SharedRegistryObject):
def __rsub__(self, other):
return -self._add_sub(other, operator.sub)
@ireduce_dimensions
def _imul_div(self, other, magnitude_op, units_op=None):
"""Perform multiplication or division operation in-place and return the
result.
@@ -714,6 +734,7 @@ class _Quantity(SharedRegistryObject):
return self
@reduce_dimensions
def _mul_div(self, other, magnitude_op, units_op=None):
"""Perform multiplication or division operation and return the result.

View File

@@ -96,6 +96,7 @@ class BaseRegistry(meta.with_metaclass(_Meta)):
:param on_redefinition: action to take in case a unit is redefined.
'warn', 'raise', 'ignore'
:type on_redefinition: str
:param auto_reduce_dimensions: If True, reduce dimensionality on appropriate operations.
"""
#: Map context prefix to function
@@ -111,7 +112,7 @@ class BaseRegistry(meta.with_metaclass(_Meta)):
'parse_unit_name', 'parse_units', 'parse_expression',
'convert']
def __init__(self, filename='', force_ndarray=False, on_redefinition='warn'):
def __init__(self, filename='', force_ndarray=False, on_redefinition='warn', auto_reduce_dimensions=False):
self._register_parsers()
@@ -129,6 +130,9 @@ class BaseRegistry(meta.with_metaclass(_Meta)):
#: Action to take in case a unit is redefined. 'warn', 'raise', 'ignore'
self._on_redefinition = on_redefinition
#: Determines if dimensionality should be reduced on appropriate operations.
self.auto_reduce_dimensions = auto_reduce_dimensions
#: Map between name (string) and value (string) of defaults stored in the definitions file.
self._defaults = {}
@@ -1435,17 +1439,20 @@ class UnitRegistry(SystemRegistry, ContextRegistry, NonMultiplicativeRegistry):
:param on_redefinition: action to take in case a unit is redefined.
'warn', 'raise', 'ignore'
:type on_redefinition: str
:param auto_reduce_dimensions: If True, reduce dimensionality on appropriate operations.
"""
def __init__(self, filename='', force_ndarray=False, default_as_delta=True,
autoconvert_offset_to_baseunit=False,
on_redefinition='warn', system=None):
on_redefinition='warn', system=None,
auto_reduce_dimensions=False):
super(UnitRegistry, self).__init__(filename=filename, force_ndarray=force_ndarray,
on_redefinition=on_redefinition,
default_as_delta=default_as_delta,
autoconvert_offset_to_baseunit=autoconvert_offset_to_baseunit,
system=system)
system=system,
auto_reduce_dimensions=auto_reduce_dimensions)
def pi_theorem(self, quantities):
"""Builds dimensionless quantities using the Buckingham π theorem

View File

@@ -1168,3 +1168,40 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase):
in1_cp = copy.copy(in1)
self.assertQuantityAlmostEqual(op.ipow(in1_cp, in2), expected)
class TestDimensionReduction(QuantityTestCase):
def _calc_mass(self, ureg):
density = 3 * ureg.g / ureg.L
volume = 32 * ureg.milliliter
return density * volume
def _icalc_mass(self, ureg):
res = ureg.Quantity(3.0, 'gram/liter')
res *= ureg.Quantity(32.0, 'milliliter')
return res
def test_mul_and_div_reduction(self):
ureg = UnitRegistry(auto_reduce_dimensions=True)
mass = self._calc_mass(ureg)
self.assertEqual(mass.units, ureg.g)
ureg = UnitRegistry(auto_reduce_dimensions=False)
mass = self._calc_mass(ureg)
self.assertEqual(mass.units, ureg.g / ureg.L * ureg.milliliter)
@helpers.requires_numpy()
def test_imul_and_div_reduction(self):
ureg = UnitRegistry(auto_reduce_dimensions=True, force_ndarray=True)
mass = self._icalc_mass(ureg)
self.assertEqual(mass.units, ureg.g)
ureg = UnitRegistry(auto_reduce_dimensions=False, force_ndarray=True)
mass = self._icalc_mass(ureg)
self.assertEqual(mass.units, ureg.g / ureg.L * ureg.milliliter)
def test_reduction_to_dimensionless(self):
ureg = UnitRegistry(auto_reduce_dimensions=True)
x = (10 * ureg.feet) / (3 * ureg.inches)
self.assertEqual(x.units, UnitsContainer({}))
ureg = UnitRegistry(auto_reduce_dimensions=False)
x = (10 * ureg.feet) / (3 * ureg.inches)
self.assertEqual(x.units, ureg.feet / ureg.inches)