From 530db51caf6f2da918fb5c3a0e7136660f64734c Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 1 Apr 2019 17:17:22 +0200 Subject: [PATCH 1/7] added right hand side operands for commutative operations --- heat/core/tensor.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/heat/core/tensor.py b/heat/core/tensor.py index bcc7ed9b2f..f56ee2e169 100644 --- a/heat/core/tensor.py +++ b/heat/core/tensor.py @@ -1287,6 +1287,26 @@ def __setitem__(self, key, value): raise NotImplementedError( 'Not implemented for {}'.format(value.__class__.__name__)) + """ + This ensures that commutative arithmetic operations work no matter on which side the heat-tensor is placed. + + Examples + -------- + >>> import heat as ht + >>> T = ht.float32([[1., 2.], [3., 4.,]]) + >>> T + 1 + tensor([[2., 3.], + [4., 5.]]) + >>> 1 + T + tensor([[2., 3.], + [4., 5.]]) + + + Make sure to uncomment the correct line when a new method of the left hand side operations has been implemented. + """ + __radd__ = __add__ + __rmul__ = __mul__ + def __factory(shape, dtype, split, local_factory, device, comm): """ From 0c2c7c1ec309969b790b8e7678e685005f6dde7c Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 1 Apr 2019 17:27:25 +0200 Subject: [PATCH 2/7] added tests and right hand side operands that need to be implemented --- heat/core/tensor.py | 9 ++++++--- heat/core/tests/test_tensor.py | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/heat/core/tensor.py b/heat/core/tensor.py index f56ee2e169..483060b082 100644 --- a/heat/core/tensor.py +++ b/heat/core/tensor.py @@ -1300,13 +1300,16 @@ def __setitem__(self, key, value): >>> 1 + T tensor([[2., 3.], [4., 5.]]) - - - Make sure to uncomment the correct line when a new method of the left hand side operations has been implemented. """ __radd__ = __add__ __rmul__ = __mul__ + # __rtruediv__ = __truediv__ + # __rfloordiv__ = __floordiv__ + # __rmod__ = __mod__ + # __rpow__ = __pow__ + # __rsub__ = __sub__ + def __factory(shape, dtype, split, local_factory, device, comm): """ diff --git a/heat/core/tests/test_tensor.py b/heat/core/tests/test_tensor.py index a73d8af7f0..3e39ddce7b 100644 --- a/heat/core/tests/test_tensor.py +++ b/heat/core/tests/test_tensor.py @@ -1,3 +1,5 @@ +import operator + import torch import unittest @@ -686,3 +688,37 @@ def test_empty_like(self): ht.empty_like(ones, dtype='abc') with self.assertRaises(TypeError): ht.empty_like(ones, split='axis') + + def test_right_hand_side_operations(self): + """ + This test ensures that for each arithmetic operation (e.g. +, -, *, ...) that is implemented in the tensor + class, it works both ways. + + Examples + -------- + >>> import heat as ht + >>> T = ht.float32([[1., 2.], [3., 4.]]) + >>> assert T * 3 == 3 * T + + """ + operators = ( + ('__add__', operator.add, True), + ('__sub__', operator.sub, False), + ('__mul__', operator.mul, True), + ('__truediv__', operator.truediv, False), + ('__floordiv__', operator.floordiv, False), + ('__mod__', operator.mod, False), + ('__pow__', operator.pow, False) + ) + tensor = ht.float32([[1, 4], [2, 3]]) + num = 3 + for (attr, op, commutative) in operators: + try: + func = tensor.__getattribute__(attr) + except AttributeError: + continue + self.assertTrue(callable(func)) + res_1 = op(tensor, num) + res_2 = op(num, tensor) + if commutative: + self.assertTrue(ht.equal(res_1, res_2)) From c79c112a5b2ba9245551da04b8256081d4b49310 Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 4 Apr 2019 17:43:47 +0200 Subject: [PATCH 3/7] added non-commutative right-hand-side-operations and documentation --- heat/core/tensor.py | 169 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 135 insertions(+), 34 deletions(-) diff --git a/heat/core/tensor.py b/heat/core/tensor.py index e49fc1f406..522d7deb55 100644 --- a/heat/core/tensor.py +++ b/heat/core/tensor.py @@ -451,41 +451,93 @@ def __truediv__(self, other): """ return arithmetics.div(self, other) + def __rtruediv__(self, other): + """ + Element-wise true division (i.e. result is floating point value rather than rounded int (floor)) + of the not-heat-type parameter by another tensor. Takes the first tensor by which it divides the second + not-heat-typed-parameter. + + Parameters + ---------- + other: scalar or unknown data-type + this will be divided by the self-tensor + + Returns + ------- + result: ht.tensor + A tensor containing the results of element-wise division. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.float32([2,3]) + >>> 2 / T + tensor([1.0000, 0.6667]) + """ + return arithmetics.div(other, self) + def __mod__(self, other): """ - Element-wise division remainder of values of self by values of operand other (i.e. self % other), not commutative. - Takes the two operands (scalar or tensor) whose elements are to be divided (operand 1 by operand 2) - as arguments. + Element-wise division remainder of values of self by values of operand other (i.e. self % other), not commutative. + Takes the two operands (scalar or tensor) whose elements are to be divided (operand 1 by operand 2) + as arguments. - Parameters - ---------- - other: tensor or scalar - The second operand by whose values it self to be divided. + Parameters + ---------- + other: tensor or scalar + The second operand by whose values it self to be divided. - Returns - ------- - result: ht.tensor - A tensor containing the remainder of the element-wise division of self by other. - - Examples: - --------- - >>> import heat as ht - >>> ht.mod(2, 2) - tensor([0]) - - >>> T1 = ht.int32([[1, 2], [3, 4]]) - >>> T2 = ht.int32([[2, 2], [2, 2]]) - >>> T1 % T2 - tensor([[1, 0], - [1, 0]], dtype=torch.int32) - - >>> s = ht.int32([2]) - >>> s % T1 - tensor([[0, 0] - [2, 2]], dtype=torch.int32) - """ + Returns + ------- + result: ht.tensor + A tensor containing the remainder of the element-wise division of self by other. + + Examples: + --------- + >>> import heat as ht + >>> ht.mod(2, 2) + tensor([0]) + + >>> T1 = ht.int32([[1, 2], [3, 4]]) + >>> T2 = ht.int32([[2, 2], [2, 2]]) + >>> T1 % T2 + tensor([[1, 0], + [1, 0]], dtype=torch.int32) + + >>> s = ht.int32([2]) + >>> s % T1 + tensor([[0, 0] + [2, 2]], dtype=torch.int32) + """ return arithmetics.mod(self, other) + def __rmod__(self, other): + """ + Element-wise division remainder of values of other by values of operand self (i.e. other % self), + not commutative. + Takes the two operands (scalar or tensor) whose elements are to be divided (operand 2 by operand 1) + as arguments. + + Parameters + ---------- + other: scalar or unknown data-type + The second operand which values will be divided by self. + + Returns + ------- + result: ht.tensor + A tensor containing the remainder of the element-wise division of other by self. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.int32([1, 3]) + >>> 2 % T + tensor([0, 2], dtype=torch.int32) + + """ + return arithmetics.mod(other, self) + def __eq__(self, other): """ Element-wise rich comparison of equality with values from second operand (scalar or tensor) @@ -1014,6 +1066,33 @@ def __pow__(self, other): """ return arithmetics.pow(self, other) + def __rpow__(self, other): + """ + Element-wise exponential function of second operand (not-heat-typed) with values from first operand (tensor). + Takes the first operand (tensor) whose values are the exponent to be applied to the second + scalar or unknown data-type as argument. + + Parameters + ---------- + other: scalar or unknown data-type + The value(s) in the base (element-wise) + + Returns + ------- + result: ht.tensor + A tensor containing the results of element-wise exponential operation. + + Examples: + --------- + >>> import heat as ht + + >>> T = ht.float32([[1, 2], [3, 4]]) + >>> 3 ** T + tensor([[ 3., 9.], + [27., 81.]]) + """ + return arithmetics.pow(other, self) + def resplit(self, axis=None): """ In-place redistribution of the content of the tensor. Allows to "unsplit" (i.e. gather) all values from all @@ -1285,6 +1364,32 @@ def __sub__(self, other): """ return arithmetics.sub(self, other) + def __rsub__(self, other): + """ + Element-wise subtraction of another tensor or a scalar from the tensor. + Takes the first operand (tensor) whose elements are to be subtracted from the second argument + (scalar or unknown data-type). + + Parameters + ---------- + other: scalar or unknown data-type + The value(s) from which the self-tensor will be element wise subtracted. + + Returns + ------- + result: ht.tensor + A tensor containing the results of element-wise subtraction. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.float32([[1, 2], [3, 4]]) + >>> 5 - T + tensor([[4., 3.], + [2., 1.]]) + """ + return arithmetics.sub(other, self) + def sum(self, axis=None, out=None): # TODO: Allow also list of axes """ @@ -1501,11 +1606,7 @@ def __setitem__(self, key, value): __radd__ = __add__ __rmul__ = __mul__ - # __rtruediv__ = __truediv__ - # __rfloordiv__ = __floordiv__ - # __rmod__ = __mod__ - # __rpow__ = __pow__ - # __rsub__ = __sub__ + # __rfloordiv__ = __floordiv__ // TODO: Implement me when implementing __floordiv__ def __factory(shape, dtype, split, local_factory, device, comm): From 6bac4a2a039f08080f229aca8e8967eae0192cc0 Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 4 Apr 2019 17:46:03 +0200 Subject: [PATCH 4/7] changed a todo --- heat/core/tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heat/core/tensor.py b/heat/core/tensor.py index 522d7deb55..25024bd967 100644 --- a/heat/core/tensor.py +++ b/heat/core/tensor.py @@ -1606,7 +1606,7 @@ def __setitem__(self, key, value): __radd__ = __add__ __rmul__ = __mul__ - # __rfloordiv__ = __floordiv__ // TODO: Implement me when implementing __floordiv__ + # __rfloordiv__ // TODO: Implement me when implementing __floordiv__ def __factory(shape, dtype, split, local_factory, device, comm): From 66f4fe33e04af329c79f71dbc42a2e7005613450 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 9 Apr 2019 15:48:50 +0200 Subject: [PATCH 5/7] added implementation and documentation for floordiv and rfloordiv --- heat/core/arithmetics.py | 33 +++++++++++++++++++++++ heat/core/tensor.py | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/heat/core/arithmetics.py b/heat/core/arithmetics.py index 49aee43dd7..07fdde02d7 100644 --- a/heat/core/arithmetics.py +++ b/heat/core/arithmetics.py @@ -7,6 +7,7 @@ __all__ = [ 'add', 'div', + 'floordiv', 'fmod', 'mod', 'mul', @@ -94,6 +95,38 @@ def div(t1, t2): return binary_op(torch.div, t1, t2) +def floordiv(t1, t2): + """ + Element-wise floor division of value of operand t1 by values of operands t2 (i.e. t1 // t2), not commutative. + Takes the two operands (scalar or tensor) whose elements are to be divided (operand 1 by operand 2) as argument. + + Parameters + ---------- + t1: tensor or scalar + The first operand whose values are divided + t2: tensor or scalar + The second operand by whose values is divided + + Return + ------ + result: ht.tensor + A tensor containing the results of element-wise floor division (integer values) of t1 by t2. + + Examples: + --------- + >>> import heat as ht + >>> T1 = ht.float32([[1.7, 2.0], [1.9, 4.2]]) + >>> ht.floordiv(T1, 1) + tensor([[1., 2.], + [1., 4.]]) + >>> T2 = ht.float32([1.5, 2.5]) + >>> ht.floordiv(T1, T2) + tensor([[1., 0.], + [1., 1.]]) + """ + return binary_op(lambda a, b: torch.div(a, b).floor(), t1, t2) + + def mod(t1, t2): """ Element-wise division remainder of values of operand t1 by values of operand t2 (i.e. t1 % t2), not commutative. diff --git a/heat/core/tensor.py b/heat/core/tensor.py index ea2553f891..43a2ca697a 100644 --- a/heat/core/tensor.py +++ b/heat/core/tensor.py @@ -476,6 +476,62 @@ def __rtruediv__(self, other): """ return arithmetics.div(other, self) + def __floordiv__(self, other): + """ + Element-wise floor division (i.e. result is rounded int (floor)) + of the tensor by another tensor or scalar. Takes the first tensor by which it divides the second + not-heat-typed-parameter. + + Parameters + ---------- + other: tensor or scalar + The second operand by whose values is divided + + Return + ------ + result: ht.tensor + A tensor containing the results of element-wise floor division (integer values) of t1 by t2. + + Examples: + --------- + >>> import heat as ht + >>> T1 = ht.float32([[1.7, 2.0], [1.9, 4.2]]) + >>> T1 // 1 + tensor([[1., 2.], + [1., 4.]]) + >>> T2 = ht.float32([1.5, 2.5]) + >>> T1 // T2 + tensor([[1., 0.], + [1., 1.]]) + """ + return arithmetics.floordiv(self, other) + + def __rfloordiv__(self, other): + """ + Element-wise floor division (i.e. result is rounded int (floor)) + of the not-heat-typed parameter by another tensor. Takes the first operand (scalar or tensor) by which to divide + as argument. + + Parameters + ---------- + other: scalar or unknown data-type + this will be divided by the self-tensor + + Return + ------ + result: ht.tensor + A tensor containing the results of element-wise floor division (integer values) of t1 by t2. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.float32([[1.7, 2.0], [1.9, 4.2]]) + >>> 5 // T + tensor([[2., 2.], + [2., 1.]]) + """ + return arithmetics.floordiv(other, self) + def __mod__(self, other): """ Element-wise division remainder of values of self by values of operand other (i.e. self % other), not commutative. From f538455cd9290185d439dd09d9e6d1927818aa6e Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 7 May 2019 08:05:27 +0200 Subject: [PATCH 6/7] merged with the master and ordered functions alphabetically --- heat/core/dndarray.py | 362 +++++++++++----------------- heat/core/tests/test_arithmetics.py | 36 +++ 2 files changed, 182 insertions(+), 216 deletions(-) diff --git a/heat/core/dndarray.py b/heat/core/dndarray.py index 38445d0913..6d89e98cf1 100644 --- a/heat/core/dndarray.py +++ b/heat/core/dndarray.py @@ -553,66 +553,6 @@ def cpu(self): self.__array = self.__array.cpu() return self - def __truediv__(self, other): - """ - Element-wise true division (i.e. result is floating point value rather than rounded int (floor)) - of the tensor by another tensor or scalar. Takes the second operand (scalar or tensor) by which to divide - as argument. - - Parameters - ---------- - other: tensor or scalar - The value(s) by which to divide the tensor (element-wise) - - Returns - ------- - result: ht.DNDarray - A tensor containing the results of element-wise division. - - Examples: - --------- - >>> import heat as ht - >>> ht.div(2.0, 2.0) - tensor([1.]) - - >>> T1 = ht.float32([[1, 2],[3, 4]]) - >>> T2 = ht.float32([[2, 2], [2, 2]]) - >>> T1.__div__(T2) - tensor([[0.5000, 1.0000], - [1.5000, 2.0000]]) - - >>> s = 2.0 - >>> T1.__div__(s) - tensor([[0.5000, 1.0000], - [1.5, 2.0000]]) - """ - return arithmetics.div(self, other) - - def __rtruediv__(self, other): - """ - Element-wise true division (i.e. result is floating point value rather than rounded int (floor)) - of the not-heat-type parameter by another tensor. Takes the first tensor by which it divides the second - not-heat-typed-parameter. - - Parameters - ---------- - other: scalar or unknown data-type - this will be divided by the self-tensor - - Returns - ------- - result: ht.DNDarray - A tensor containing the results of element-wise division. - - Examples: - --------- - >>> import heat as ht - >>> T = ht.float32([2,3]) - >>> 2 / T - tensor([1.0000, 0.6667]) - """ - return arithmetics.div(other, self) - def __floordiv__(self, other): """ Element-wise floor division (i.e. result is rounded int (floor)) @@ -643,94 +583,6 @@ def __floordiv__(self, other): """ return arithmetics.floordiv(self, other) - def __rfloordiv__(self, other): - """ - Element-wise floor division (i.e. result is rounded int (floor)) - of the not-heat-typed parameter by another tensor. Takes the first operand (scalar or tensor) by which to divide - as argument. - - Parameters - ---------- - other: scalar or unknown data-type - this will be divided by the self-tensor - - Return - ------ - result: ht.tensor - A tensor containing the results of element-wise floor division (integer values) of t1 by t2. - - Examples: - --------- - >>> import heat as ht - >>> T = ht.float32([[1.7, 2.0], [1.9, 4.2]]) - >>> 5 // T - tensor([[2., 2.], - [2., 1.]]) - """ - return arithmetics.floordiv(other, self) - - def __mod__(self, other): - """ - Element-wise division remainder of values of self by values of operand other (i.e. self % other), not commutative. - Takes the two operands (scalar or tensor) whose elements are to be divided (operand 1 by operand 2) - as arguments. - - Parameters - ---------- - other: tensor or scalar - The second operand by whose values it self to be divided. - - Returns - ------- - result: ht.tensor - A tensor containing the remainder of the element-wise division of self by other. - - Examples: - --------- - >>> import heat as ht - >>> ht.mod(2, 2) - tensor([0]) - - >>> T1 = ht.int32([[1, 2], [3, 4]]) - >>> T2 = ht.int32([[2, 2], [2, 2]]) - >>> T1 % T2 - tensor([[1, 0], - [1, 0]], dtype=torch.int32) - - >>> s = ht.int32([2]) - >>> s % T1 - tensor([[0, 0] - [2, 2]], dtype=torch.int32) - """ - return arithmetics.mod(self, other) - - def __rmod__(self, other): - """ - Element-wise division remainder of values of other by values of operand self (i.e. other % self), - not commutative. - Takes the two operands (scalar or tensor) whose elements are to be divided (operand 2 by operand 1) - as arguments. - - Parameters - ---------- - other: scalar or unknown data-type - The second operand which values will be divided by self. - - Returns - ------- - result: ht.tensor - A tensor containing the remainder of the element-wise division of other by self. - - Examples: - --------- - >>> import heat as ht - >>> T = ht.int32([1, 3]) - >>> 2 % T - tensor([0, 2], dtype=torch.int32) - - """ - return arithmetics.mod(other, self) - def __eq__(self, other): """ Element-wise rich comparison of equality with values from second operand (scalar or tensor) @@ -1442,33 +1294,6 @@ def __repr__(self, *args): # TODO: generate none-PyTorch repr return self.__array.__repr__(*args) - def __rpow__(self, other): - """ - Element-wise exponential function of second operand (not-heat-typed) with values from first operand (tensor). - Takes the first operand (tensor) whose values are the exponent to be applied to the second - scalar or unknown data-type as argument. - - Parameters - ---------- - other: scalar or unknown data-type - The value(s) in the base (element-wise) - - Returns - ------- - result: ht.NDNarray - A tensor containing the results of element-wise exponential operation. - - Examples: - --------- - >>> import heat as ht - - >>> T = ht.float32([[1, 2], [3, 4]]) - >>> 3 ** T - tensor([[ 3., 9.], - [27., 81.]]) - """ - return arithmetics.pow(other, self) - def resplit(self, axis=None): """ In-place redistribution of the content of the tensor. Allows to "unsplit" (i.e. gather) all values from all @@ -1553,6 +1378,137 @@ def resplit(self, axis=None): return self + def __rfloordiv__(self, other): + """ + Element-wise floor division (i.e. result is rounded int (floor)) + of the not-heat-typed parameter by another tensor. Takes the first operand (scalar or tensor) by which to divide + as argument. + + Parameters + ---------- + other: scalar or unknown data-type + this will be divided by the self-tensor + + Return + ------ + result: ht.tensor + A tensor containing the results of element-wise floor division (integer values) of t1 by t2. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.float32([[1.7, 2.0], [1.9, 4.2]]) + >>> 5 // T + tensor([[2., 2.], + [2., 1.]]) + """ + return arithmetics.floordiv(other, self) + + def __rmod__(self, other): + """ + Element-wise division remainder of values of other by values of operand self (i.e. other % self), + not commutative. + Takes the two operands (scalar or tensor) whose elements are to be divided (operand 2 by operand 1) + as arguments. + + Parameters + ---------- + other: scalar or unknown data-type + The second operand which values will be divided by self. + + Returns + ------- + result: ht.tensor + A tensor containing the remainder of the element-wise division of other by self. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.int32([1, 3]) + >>> 2 % T + tensor([0, 2], dtype=torch.int32) + + """ + return arithmetics.mod(other, self) + + def __rpow__(self, other): + """ + Element-wise exponential function of second operand (not-heat-typed) with values from first operand (tensor). + Takes the first operand (tensor) whose values are the exponent to be applied to the second + scalar or unknown data-type as argument. + + Parameters + ---------- + other: scalar or unknown data-type + The value(s) in the base (element-wise) + + Returns + ------- + result: ht.NDNarray + A tensor containing the results of element-wise exponential operation. + + Examples: + --------- + >>> import heat as ht + + >>> T = ht.float32([[1, 2], [3, 4]]) + >>> 3 ** T + tensor([[ 3., 9.], + [27., 81.]]) + """ + return arithmetics.pow(other, self) + + def __rsub__(self, other): + """ + Element-wise subtraction of another tensor or a scalar from the tensor. + Takes the first operand (tensor) whose elements are to be subtracted from the second argument + (scalar or unknown data-type). + + Parameters + ---------- + other: scalar or unknown data-type + The value(s) from which the self-tensor will be element wise subtracted. + + Returns + ------- + result: ht.DNDarray + A tensor containing the results of element-wise subtraction. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.float32([[1, 2], [3, 4]]) + >>> 5 - T + tensor([[4., 3.], + [2., 1.]]) + """ + return arithmetics.sub(other, self) + + def __rtruediv__(self, other): + """ + Element-wise true division (i.e. result is floating point value rather than rounded int (floor)) + of the not-heat-type parameter by another tensor. Takes the first tensor by which it divides the second + not-heat-typed-parameter. + + Parameters + ---------- + other: scalar or unknown data-type + this will be divided by the self-tensor + + Returns + ------- + result: ht.DNDarray + A tensor containing the results of element-wise division. + + Examples: + --------- + >>> import heat as ht + >>> T = ht.float32([2,3]) + >>> 2 / T + tensor([1.0000, 0.6667]) + """ + return arithmetics.div(other, self) + def save(self, path, *args, **kwargs): """ Save the tensor's data to disk. Attempts to auto-detect the file format by determining the extension. @@ -1834,32 +1790,6 @@ def __sub__(self, other): """ return arithmetics.sub(self, other) - def __rsub__(self, other): - """ - Element-wise subtraction of another tensor or a scalar from the tensor. - Takes the first operand (tensor) whose elements are to be subtracted from the second argument - (scalar or unknown data-type). - - Parameters - ---------- - other: scalar or unknown data-type - The value(s) from which the self-tensor will be element wise subtracted. - - Returns - ------- - result: ht.DNDarray - A tensor containing the results of element-wise subtraction. - - Examples: - --------- - >>> import heat as ht - >>> T = ht.float32([[1, 2], [3, 4]]) - >>> 5 - T - tensor([[4., 3.], - [2., 1.]]) - """ - return arithmetics.sub(other, self) - def sum(self, axis=None, out=None, keepdim=None): """ Sum of array elements over a given axis. @@ -2060,19 +1990,19 @@ def __truediv__(self, other): """ return arithmetics.div(self, other) - """ - This ensures that commutative arithmetic operations work no matter on which side the heat-tensor is placed. - - Examples - -------- - >>> import heat as ht - >>> T = ht.float32([[1., 2.], [3., 4.,]]) - >>> T + 1 - tensor([[2., 3.], - [4., 5.]]) - >>> 1 + T - tensor([[2., 3.], + """ + This ensures that commutative arithmetic operations work no matter on which side the heat-tensor is placed. + + Examples + -------- + >>> import heat as ht + >>> T = ht.float32([[1., 2.], [3., 4.,]]) + >>> T + 1 + tensor([[2., 3.], [4., 5.]]) - """ - __radd__ = __add__ - __rmul__ = __mul__ \ No newline at end of file + >>> 1 + T + tensor([[2., 3.], + [4., 5.]]) + """ + __radd__ = __add__ + __rmul__ = __mul__ diff --git a/heat/core/tests/test_arithmetics.py b/heat/core/tests/test_arithmetics.py index 51c0c3456c..3d07de3376 100644 --- a/heat/core/tests/test_arithmetics.py +++ b/heat/core/tests/test_arithmetics.py @@ -1,3 +1,5 @@ +import operator + import torch import unittest @@ -316,3 +318,37 @@ def test_sum(self): ht.ones((4, 4)).sum(axis=0, out=out_noaxis) with self.assertRaises(TypeError): ht.ones(array_len).sum(axis='bad_axis_type') + + def test_right_hand_side_operations(self): + """ + This test ensures that for each arithmetic operation (e.g. +, -, *, ...) that is implemented in the tensor + class, it works both ways. + + Examples + -------- + >>> import heat as ht + >>> T = ht.float32([[1., 2.], [3., 4.]]) + >>> assert T * 3 == 3 * T + + """ + operators = ( + ('__add__', operator.add, True), + ('__sub__', operator.sub, False), + ('__mul__', operator.mul, True), + ('__truediv__', operator.truediv, False), + ('__floordiv__', operator.floordiv, False), + ('__mod__', operator.mod, False), + ('__pow__', operator.pow, False) + ) + tensor = ht.float32([[1, 4], [2, 3]]) + num = 3 + for (attr, op, commutative) in operators: + try: + func = tensor.__getattribute__(attr) + except AttributeError: + continue + self.assertTrue(callable(func)) + res_1 = op(tensor, num) + res_2 = op(num, tensor) + if commutative: + self.assertTrue(ht.equal(res_1, res_2)) From a1f4a8f1e22df0dad9da5f1feccb513b9c07d7c8 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 7 May 2019 08:07:49 +0200 Subject: [PATCH 7/7] added todo for testing with split tensors --- heat/core/tests/test_arithmetics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/heat/core/tests/test_arithmetics.py b/heat/core/tests/test_arithmetics.py index 3d07de3376..59ed28d353 100644 --- a/heat/core/tests/test_arithmetics.py +++ b/heat/core/tests/test_arithmetics.py @@ -352,3 +352,4 @@ def test_right_hand_side_operations(self): res_2 = op(num, tensor) if commutative: self.assertTrue(ht.equal(res_1, res_2)) + # TODO: Test with split tensors when binary operations are working properly for split tensors