Skip to content

Commit

Permalink
Fix division float over scalar and float over array
Browse files Browse the repository at this point in the history
BARRIL-15

Add floor division support

Add changelog

Using CreateEmpty
  • Loading branch information
arthursoprana committed Oct 10, 2019
1 parent fbcfac0 commit 69b7798
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 12 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ UNRELEASED
* ``_foundation`` has been renamed to ``_util``, and a lot of functions which were not being
used anymore have been removed.
* Add new unit category mass temperature per mol (``kg.K/mol``).
* Fix division `1.0 / a` where `a` is a `Scalar` or `Array` and also add support for floor
division, i.e., operations like ``a // b`` where `a` and `b` are `Scalar` or `Array`
(and combinations with `float` or `int`).

1.7.1 (2019-10-03)
------------------
Expand Down
11 changes: 10 additions & 1 deletion src/barril/units/_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from oop_ext.interface._interface import ImplementsInterface

from ._abstractvaluewithquantity import AbstractValueWithQuantityObject
from .interfaces import IArray
from ._quantity import Quantity
from .interfaces import IArray

__all__ = ["Array"]

Expand Down Expand Up @@ -246,6 +246,9 @@ def __iter__(self):
def __truediv__(self, other):
return self._DoOperation(self, other, "Divide")

def __floordiv__(self, other):
return self._DoOperation(self, other, "FloorDivide")

def __mul__(self, other):
return self._DoOperation(self, other, "Multiply")

Expand All @@ -256,6 +259,12 @@ def __sub__(self, other):
return self._DoOperation(self, other, "Subtract")

# Right-Basic operators ------------------------------------------------------------------------
def __rtruediv__(self, other):
return self._DoOperation(other, self, "Divide")

def __rfloordiv__(self, other):
return self._DoOperation(other, self, "FloorDivide")

def __rdiv__(self, other):
return self._DoOperation(other, self, "Divide")

Expand Down
26 changes: 20 additions & 6 deletions src/barril/units/_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from oop_ext.interface._interface import ImplementsInterface

from ._abstractvaluewithquantity import AbstractValueWithQuantityObject
from .interfaces import IQuantity, IScalar
from ._quantity import ObtainQuantity, Quantity
from .interfaces import IQuantity, IScalar
from .unit_database import UnitDatabase

__all__ = ["Scalar"]
Expand Down Expand Up @@ -269,7 +269,8 @@ def __lt__(self, other):
def __rtruediv__(self, other):
return self._DoOperation(other, self, "Divide", lambda a, b: a / b)

__rfloordiv__ = __rtruediv__
def __rfloordiv__(self, other):
return self._DoOperation(other, self, "FloorDivide", lambda a, b: a // b)

def __rmul__(self, other):
return self._DoOperation(other, self, "Multiply", lambda a, b: a * b)
Expand All @@ -284,7 +285,8 @@ def __radd__(self, other):
def __truediv__(self, other):
return self._DoOperation(self, other, "Divide", lambda a, b: a / b)

__floordiv__ = __truediv__
def __floordiv__(self, other):
return self._DoOperation(self, other, "FloorDivide", lambda a, b: a // b)

def __mul__(self, other):
return self._DoOperation(self, other, "Multiply", lambda a, b: a * b)
Expand All @@ -302,7 +304,8 @@ def __pow__(self, exponent):
return result

def _DoOperation(self, p1, p2, operation, callback_operation):
if IsNumber(p1):
p1_is_number = IsNumber(p1)
if p1_is_number and operation not in ["Divide", "FloorDivide"]:
return self.__class__.CreateWithQuantity(
self._quantity, callback_operation(p1, self._value)
)
Expand All @@ -313,8 +316,19 @@ def _DoOperation(self, p1, p2, operation, callback_operation):
)

unit_database = self._unit_database
operation = getattr(unit_database, operation)
q, v = operation(p1.GetQuantity(), p2.GetQuantity(), self._value, p2.value)
operation_func = getattr(unit_database, operation)
if p1_is_number:
assert operation in [
"Divide",
"FloorDivide",
], "Only operation Divide and FloorDivide allowed here!"
q, v = operation_func(
Quantity.CreateEmpty(), p2.GetQuantity(), p1, p2.value
)
else:
q, v = operation_func(
p1.GetQuantity(), p2.GetQuantity(), self._value, p2.value
)
return self.__class__.CreateWithQuantity(q, v)

def __reduce__(self):
Expand Down
21 changes: 19 additions & 2 deletions src/barril/units/_tests/test_array.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import pytest
from pytest import approx

from collections import OrderedDict
from barril import units
from barril.units import Array, InvalidUnitError, ObtainQuantity, Quantity
from pytest import approx


def testEmptyArray():
Expand Down Expand Up @@ -215,6 +214,24 @@ def testDivision(unit_database_len_time):
assert calculated1 == s1 / s2


def testFloorDivision():
a = Array([3.5, 4.2], "m")
b = Array([100.0, 100.0], "cm")
assert approx((a // b).GetValues()) == [3.0, 4.0]
assert approx((350 // b).GetValues("1/cm")) == [3.0, 3.0]
assert approx((a // 1.0).GetValues("m")) == [3.0, 4.0]


def testNumberOverArray():
a = Array([2.0, 2.0], "m")
b = Array([3.0, 3.0], "m")
c = 1.0 / a

assert approx(c.GetValues("1/m")) == [0.5, 0.5]
assert approx((3.0 / a).GetValues("1/m")) == [1.5, 1.5]
assert b / a == b * 1 / a == b * (1 / a)


def testNumberInteractions(unit_database_len_time):
import numpy

Expand Down
3 changes: 3 additions & 0 deletions src/barril/units/_tests/test_derived_quantities.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ def testConvertionWithDerivedUnits(unit_database_len_time):
# check division with cancelling units (and different categories)
assert (empty, 1) == unit_database.Divide(m, m_city, 1, 1)

# floor division
assert (m, 3.0) == unit_database.FloorDivide(cat_mix_m2, km_city, 3.5, 0.001)

# sum
assert (m, 1 + 0.01) == unit_database.Sum(m, cm, 1, 1)
assert (m, 2) == unit_database.Sum(m, m_city, 1, 1)
Expand Down
21 changes: 18 additions & 3 deletions src/barril/units/_tests/test_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
"""

import pytest
from pytest import approx

from collections import OrderedDict
from barril import units
from barril.units import (
ChangeScalars,
InvalidOperationError,
InvalidUnitError,
ObtainQuantity,
Quantity,
Scalar,
ChangeScalars,
)
from pytest import approx


def testScalarInterface(unit_database_well_length):
Expand Down Expand Up @@ -319,6 +318,22 @@ def testDivision(unit_database_len_time):
assert calculated1 == s1 / s2


def testFloorDivision():
a = Scalar(3.5, "m")
b = Scalar(100.0, "cm")
assert (a // b).GetValueAndUnit() == (3.0, "")
assert (350 // b).GetValueAndUnit() == (3.0, "1/cm")
assert (a // 1.0).GetValueAndUnit() == (3.0, "m")


def testNumberOverScalar():
a = Scalar(2.0, "m")
b = Scalar(3.0, "m")
assert (1.0 / a).GetValueAndUnit() == (0.5, "1/m")
assert (3.0 / a).GetValueAndUnit() == (1.5, "1/m")
assert b / a == b * 1 / a == b * (1.0 / a)


def testPow(unit_database_len_time):
s = Scalar(2, "s", "Time")
spow = s ** 3
Expand Down
10 changes: 10 additions & 0 deletions src/barril/units/unit_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,16 @@ def Divide(self, quantity1, quantity2, value1, value2):
quantity1, quantity2, value1, value2, lambda a, b: a - b, lambda a, b: a / b
)

def FloorDivide(self, quantity1, quantity2, value1, value2):
return self._DoOperationResultingInNewQuantity(
quantity1,
quantity2,
value1,
value2,
lambda a, b: a - b,
lambda a, b: a // b,
)

def Multiply(self, quantity1, quantity2, value1, value2):
"""
Multiplication with different quantities.
Expand Down

0 comments on commit 69b7798

Please sign in to comment.