-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing right hand side operations #204
Changes from 6 commits
530db51
0c2c7c1
7d8d4a0
c79c112
6bac4a2
d0a3226
66f4fe3
615c851
f538455
a1f4a8f
f6a9b29
83d3886
c70b11d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
""" | ||
|
@@ -1484,6 +1589,25 @@ 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.]]) | ||
""" | ||
__radd__ = __add__ | ||
__rmul__ = __mul__ | ||
|
||
# __rfloordiv__ // TODO: Implement me when implementing __floordiv__ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide both implementations (regular and right-hand side floor-div). Straight forward by adapting div (torch supports truediv as well) |
||
|
||
|
||
def __factory(shape, dtype, split, local_factory, device, comm): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import operator | ||
|
||
import torch | ||
import unittest | ||
|
||
|
@@ -735,6 +737,40 @@ def test_empty_like(self): | |
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]]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need test cases here for split tensors There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is related to #167, which needs to be fixed first |
||
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)) | ||
|
||
def test_eye(self): | ||
|
||
def get_offset(tensor_array): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a technicality, but shouldn't the functions be sorted alphabetically? (at least for the operators before it is the case)
EDIT: This goes for all the operators below