Commit 1db8640d authored by Peter Eastman's avatar Peter Eastman
Browse files

Further optimizations to units code

parent ee78f1e7
...@@ -261,6 +261,8 @@ class Quantity(object): ...@@ -261,6 +261,8 @@ class Quantity(object):
def __lt__(self, other): def __lt__(self, other):
return self._value < (other.value_in_unit(self.unit)) return self._value < (other.value_in_unit(self.unit))
_reduce_cache = {}
def reduce_unit(self, guide_unit=None): def reduce_unit(self, guide_unit=None):
""" """
Combine similar component units and scale, to form an Combine similar component units and scale, to form an
...@@ -268,6 +270,10 @@ class Quantity(object): ...@@ -268,6 +270,10 @@ class Quantity(object):
Returns underlying value type if unit is dimensionless. Returns underlying value type if unit is dimensionless.
""" """
key = (self.unit, guide_unit)
if key in Quantity._reduce_cache:
(unit, value_factor) = Quantity._reduce_cache[key]
else:
value_factor = 1.0 value_factor = 1.0
canonical_units = {} # dict of dimensionTuple: (Base/ScaledUnit, exponent) canonical_units = {} # dict of dimensionTuple: (Base/ScaledUnit, exponent)
# Bias result toward guide units # Bias result toward guide units
...@@ -303,6 +309,7 @@ class Quantity(object): ...@@ -303,6 +309,7 @@ class Quantity(object):
value_factor *= unit_factor value_factor *= unit_factor
# print "value_factor = %s" % value_factor # print "value_factor = %s" % value_factor
unit = dimensionless unit = dimensionless
Quantity._reduce_cache[key] = (unit, value_factor)
# Create Quantity, then scale (in case value is a container) # Create Quantity, then scale (in case value is a container)
# That's why we don't just scale the value. # That's why we don't just scale the value.
result = Quantity(self._value, unit) result = Quantity(self._value, unit)
......
...@@ -144,19 +144,7 @@ class Unit(object): ...@@ -144,19 +144,7 @@ class Unit(object):
def __eq__(self, other): def __eq__(self, other):
if not is_unit(other): if not is_unit(other):
return False return False
if self._all_base_units == other._all_base_units and self._scaled_units == other._scaled_units: return self.get_name() == other.get_name()
return True
if hash(self) != hash(other):
return False
factor = 1.0
factor *= self.get_conversion_factor_to_base_units()
factor /= other.get_conversion_factor_to_base_units()
for (base1, exp1), (base2, exp2) in zip(self.iter_all_base_units(), other.iter_all_base_units()):
if base1.dimension != base2.dimension or exp1 != exp2:
return False
if base1 != base2:
factor *= base1.conversion_factor_to(base2)**exp1
return factor == 1.0
def __ne__(self, other): def __ne__(self, other):
return not self.__eq__(other) return not self.__eq__(other)
...@@ -181,10 +169,7 @@ class Unit(object): ...@@ -181,10 +169,7 @@ class Unit(object):
return self._hash return self._hash
except AttributeError: except AttributeError:
pass pass
description = "" self._hash = hash(self.get_name())
for unit, power in self.iter_all_base_units():
description += unit.name + str(power)
self._hash = hash(description)
return self._hash return self._hash
# def __mul__(self, other): # def __mul__(self, other):
...@@ -204,15 +189,24 @@ class Unit(object): ...@@ -204,15 +189,24 @@ class Unit(object):
# def __rdiv__(self, other): # def __rdiv__(self, other):
# Because rdiv returns a Quantity, look in quantity.py for definition of Unit.__rdiv__ # Because rdiv returns a Quantity, look in quantity.py for definition of Unit.__rdiv__
_pow_cache = {}
def __pow__(self, exponent): def __pow__(self, exponent):
"""Raise a Unit to a power. """Raise a Unit to a power.
Returns a new Unit with different exponents on the BaseUnits. Returns a new Unit with different exponents on the BaseUnits.
""" """
if self in Unit._pow_cache:
if exponent in Unit._pow_cache[self]:
return Unit._pow_cache[self][exponent]
else:
Unit._pow_cache[self] = {}
result = {} # dictionary of unit: exponent result = {} # dictionary of unit: exponent
for unit, exponent2 in self.iter_base_or_scaled_units(): for unit, exponent2 in self.iter_base_or_scaled_units():
result[unit] = exponent2 * exponent result[unit] = exponent2 * exponent
return Unit(result) new_unit = Unit(result)
Unit._pow_cache[self][exponent] = new_unit
return new_unit
def sqrt(self): def sqrt(self):
""" """
...@@ -419,6 +413,10 @@ class Unit(object): ...@@ -419,6 +413,10 @@ class Unit(object):
Returns a unit name (string) for this Unit, composed of its various Returns a unit name (string) for this Unit, composed of its various
BaseUnit symbols. e.g. 'kilogram meter**2 secon**-1'. BaseUnit symbols. e.g. 'kilogram meter**2 secon**-1'.
""" """
try:
return self._name
except AttributeError:
pass
# emit positive exponents first # emit positive exponents first
pos = "" pos = ""
pos_count = 0 pos_count = 0
...@@ -456,6 +454,7 @@ class Unit(object): ...@@ -456,6 +454,7 @@ class Unit(object):
name = "dimensionless" name = "dimensionless"
else: else:
name = "%s%s" % (pos_string, neg_string) name = "%s%s" % (pos_string, neg_string)
self._name = name
return name return name
......
...@@ -61,6 +61,11 @@ def _unit_class_mul(self, other): ...@@ -61,6 +61,11 @@ def _unit_class_mul(self, other):
of the Quantity is returned. of the Quantity is returned.
""" """
if is_unit(other): if is_unit(other):
if self in Unit._multiplication_cache:
if other in Unit._multiplication_cache[self]:
return Unit._multiplication_cache[self][other]
else:
Unit._multiplication_cache[self] = {}
# print "unit * unit" # print "unit * unit"
result1 = {} # dictionary of dimensionTuple: (BaseOrScaledUnit, exponent) result1 = {} # dictionary of dimensionTuple: (BaseOrScaledUnit, exponent)
for unit, exponent in self.iter_base_or_scaled_units(): for unit, exponent in self.iter_base_or_scaled_units():
...@@ -83,7 +88,9 @@ def _unit_class_mul(self, other): ...@@ -83,7 +88,9 @@ def _unit_class_mul(self, other):
if exponent != 0: if exponent != 0:
assert unit not in result2 assert unit not in result2
result2[unit] = exponent result2[unit] = exponent
return Unit(result2) new_unit = Unit(result2)
Unit._multiplication_cache[self][other] = new_unit
return new_unit
elif is_quantity(other): elif is_quantity(other):
# print "unit * quantity" # print "unit * quantity"
value = other._value value = other._value
...@@ -99,6 +106,7 @@ def _unit_class_mul(self, other): ...@@ -99,6 +106,7 @@ def _unit_class_mul(self, other):
Unit.__mul__ = _unit_class_mul Unit.__mul__ = _unit_class_mul
Unit.__rmul__ = Unit.__mul__ Unit.__rmul__ = Unit.__mul__
Unit._multiplication_cache = {}
# run module directly for testing # run module directly for testing
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment