Repository: OpenMined/PySyft

Issue:
Implement Default remainder Functionality for Base Tensor Type
**User Story A:** As a Data Scientist using Syft's Base Tensor type, I want to leverage a default method for computing operations on a Tensor of arbitrary type. For this ticket to be complete, remainder() should return a new tensor, but remainder_() should operate inline. For a reference on the operation this performs check out [PyTorch](http://pytorch.org/docs/master/tensors.html)'s documentation.

**Acceptance Criteria:**
- If the Base Tensor type's attribute "encrypted" is set to True, it should return a NotImplemented error.
- a unit test demonstrating the correct operation on the Base Tensor type implemented over int and float Tensors.
- inline documentation in the python code. For inspiration on inline documentation, please check out [PyTorch](http://pytorch.org/docs/master/tensors.html)'s documentation for this operator.

Discussion:

Patch:
diff --git a/syft/tensor.py b/syft/tensor.py
index 553420c417..8c97892ea3 100644
--- a/syft/tensor.py
+++ b/syft/tensor.py
@@ -1160,6 +1160,37 @@ class TensorBase(object):
     def deserialize(b):
         return pickle.loads(b)
 
+    def remainder(self, divisor):
+        """
+        Computes the element-wise remainder of division.
+        The divisor and dividend may contain both for integer and floating point numbers.
+        The remainder has the same sign as the divisor.
+        When ``divisor`` is a Tensor, the shapes of ``self`` and ``divisor`` must be broadcastable.
+        :param divisor:  The divisor. This may be either a number or a tensor.
+        :return: result tensor
+        """
+        if self.encrypted:
+            return NotImplemented
+        if not np.isscalar(divisor):
+            divisor = _ensure_tensorbase(divisor)
+        return TensorBase(np.remainder(self.data, divisor))
+
+    def remainder_(self, divisor):
+        """
+        Computes the element-wise remainder of division.
+        The divisor and dividend may contain both for integer and floating point numbers.
+        The remainder has the same sign as the divisor.
+        When ``divisor`` is a Tensor, the shapes of ``self`` and ``divisor`` must be broadcastable.
+        :param divisor:  The divisor. This may be either a number or a tensor.
+        :return: self
+        """
+        if self.encrypted:
+            return NotImplemented
+        if not np.isscalar(divisor):
+            divisor = _ensure_tensorbase(divisor)
+        self.data = np.remainder(self.data, divisor)
+        return self
+
     def index_select(self, dim, index):
         """
         Returns a new Tensor which indexes the ``input`` Tensor along


Test patch:
diff --git a/tests/test_tensor.py b/tests/test_tensor.py
index e8429080be..9eaf6c42c6 100644
--- a/tests/test_tensor.py
+++ b/tests/test_tensor.py
@@ -873,6 +873,23 @@ class scatterTests(unittest.TestCase):
             t.scatter_(dim=dim, index=idx, src=src)
 
 
+class remainderTests(unittest.TestCase):
+    def testRemainder(self):
+        t = TensorBase([[-2, -3], [4, 1]])
+        result = t.remainder(1.5)
+        self.assertTrue(np.array_equal(result.data, np.array([[1, 0], [1, 1]])))
+
+    def testRemainder_broadcasting(self):
+        t = TensorBase([[-2, -3], [4, 1]])
+        result = t.remainder([2, -3])
+        self.assertTrue(np.array_equal(result.data, np.array([[0, 0], [0, -2]])))
+
+    def testRemainder_(self):
+        t = TensorBase([[-2, -3], [4, 1]])
+        t.remainder_(2)
+        self.assertTrue(np.array_equal(t.data, np.array([[0, 1], [0, 1]])))
+
+
 class testMv(unittest.TestCase):
     def mvTest(self):
         mat = TensorBase([[1, 2, 3], [2, 3, 4], [4, 5, 6]])