Repository: OpenMined/PySyft
Pull request #172 (2017-08-22 07:40:43)

Implemented transpose functionality
✨ Implemented:

1. Transpose function in math.py
2. Tranpose functions for TensorBase
3. T Functions for TensorBase
4. Respective unit tests


Patch:
diff --git a/syft/__init__.py b/syft/__init__.py
index 13a92d338a..e0bfb04721 100644
--- a/syft/__init__.py
+++ b/syft/__init__.py
@@ -3,7 +3,7 @@ from syft import nn
 
 from syft.tensor import equal, TensorBase
 from syft.math import cumprod, cumsum, ceil, dot, matmul, addmm, addcmul
-from syft.math import addcdiv, addmv, addbmm, baddbmm
+from syft.math import addcdiv, addmv, addbmm, baddbmm, transpose
 from syft.math import unsqueeze
 
 s = str(he)
@@ -12,4 +12,5 @@ s += str(nn)
 s += str(equal) + str(TensorBase) + str(cumprod) + str(cumsum) + str(ceil)
 s += str(dot) + str(matmul) + str(addmm) + str(addcmul) + str(addcdiv)
 s += str(addmv) + str(addbmm) + str(baddbmm)
+s += str(transpose)
 s += str(unsqueeze)
diff --git a/syft/math.py b/syft/math.py
index 0f8cf7c93c..db629cfe62 100644
--- a/syft/math.py
+++ b/syft/math.py
@@ -264,6 +264,27 @@ def baddbmm(tensor1, tensor2, mat, beta=1, alpha=1):
         return TensorBase(out)
 
 
+def transpose(tensor1, dim0, dim1):
+    """
+    Performs tensor transpose operation, tranposing dim0 and dim1.
+    Returns a tranposed TensorBase.
+    """
+    tensor1 = _ensure_tensorbase(tensor1)
+    num_dims = len(tensor1.data.shape)
+    axes = list(range(num_dims))
+
+    if dim0 >= num_dims:
+        print("dimension 0 out of range")
+    elif dim1 >= num_dims:
+        print("dimension 1 out of range")
+    elif tensor1.encrypted:
+        raise NotImplemented
+    else:
+        axes[dim0] = dim1
+        axes[dim1] = dim0
+        return TensorBase(np.transpose(tensor1.data, axes=axes))
+
+
 def unsqueeze(tensor1, dim):
     """
     Performs 'unsqueeze' operation, returning a new tensor with a dimension
diff --git a/syft/tensor.py b/syft/tensor.py
index 84c243c5dd..f5bf716aa4 100644
--- a/syft/tensor.py
+++ b/syft/tensor.py
@@ -424,6 +424,42 @@ class TensorBase(object):
             self.data += (mat.data * beta)
             return self
 
+    def transpose(self, dim0, dim1):
+        """
+        Returns the transpose along the dimensions in a new Tensor.
+        """
+        return syft.transpose(self.data, dim0, dim1)
+
+    def transpose_(self, dim0, dim1):
+        """
+        Replaces the Tensor with its transpose along the dimensions.
+        """
+        num_dims = len(self.data.shape)
+        axes = list(range(num_dims))
+
+        if dim0 >= num_dims:
+            print("dimension 0 out of range")
+        elif dim1 >= num_dims:
+            print("dimension 1 out of range")
+        elif self.encrypted:
+            raise NotImplemented
+        else:
+            axes[dim0] = dim1
+            axes[dim1] = dim0
+            self.data = np.transpose(self.data, axes=tuple(axes))
+
+    def t(self):
+        """
+        Returns the transpose along dimensions 0, 1 in a new Tensor.
+        """
+        return self.transpose(0, 1)
+
+    def t_(self):
+        """
+        Replaces the Tensor with its transpose along dimensions 0, 1.
+        """
+        self.transpose_(0, 1)
+
     def unsqueeze(self, dim):
         """
         Returns expanded Tensor. An additional dimension of size one is added


Test patch:
diff --git a/tests/test_math.py b/tests/test_math.py
index 011bcfeb88..ec0b82be4f 100644
--- a/tests/test_math.py
+++ b/tests/test_math.py
@@ -169,6 +169,20 @@ class baddbmmTests(unittest.TestCase):
                                                   [[122, 184], [28, 42]]]))
 
 
+class transposeTests(unittest.TestCase):
+    def testTranspose(self):
+        t1 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        out1 = syft.transpose(t1, 0, 1)
+        self.assertTrue(np.array_equal(out1.data, np.array([[[3, 4], [7, 8]],
+                                                            [[5, 6], [1, 2]]])))
+        out2 = syft.transpose(t1, 0, 2)
+        self.assertTrue(np.array_equal(out2.data, np.array([[[3, 7], [5, 1]],
+                                                            [[4, 8], [6, 2]]])))
+        out3 = syft.transpose(t1, 1, 2)
+        self.assertTrue(np.array_equal(out3.data, np.array([[[3, 5], [4, 6]],
+                                                            [[7, 1], [8, 2]]])))
+
+
 class unsqueezeTests(unittest.TestCase):
     def testUnsqueeze(self):
         t1 = TensorBase(np.arange(3 * 4 * 5).reshape((3, 4, 5)))
@@ -176,4 +190,5 @@ class unsqueezeTests(unittest.TestCase):
             out = syft.unsqueeze(t1, i)
             expected_shape = list(t1.data.shape)
             expected_shape.insert(i, 1)
+
             self.assertTrue(np.array_equal(out.data.shape, expected_shape))
diff --git a/tests/test_tensor.py b/tests/test_tensor.py
index b121177577..5b9eb12f5b 100644
--- a/tests/test_tensor.py
+++ b/tests/test_tensor.py
@@ -307,6 +307,46 @@ class baddbmmTests(unittest.TestCase):
                                                  [[122, 184], [28, 42]]]))
 
 
+class transposeTests(unittest.TestCase):
+    def testTranspose(self):
+        t1 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        out1 = t1.transpose(0, 1)
+        self.assertTrue(np.array_equal(out1.data, [[[3, 4], [7, 8]],
+                                                   [[5, 6], [1, 2]]]))
+        out2 = t1.transpose(0, 2)
+        self.assertTrue(np.array_equal(out2.data, [[[3, 7], [5, 1]],
+                                                   [[4, 8], [6, 2]]]))
+        out3 = t1.transpose(1, 2)
+        self.assertTrue(np.array_equal(out3.data, [[[3, 5], [4, 6]],
+                                                   [[7, 1], [8, 2]]]))
+
+    def testTranspose_(self):
+        t1 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        t1.transpose_(0, 1)
+        self.assertTrue(np.array_equal(t1.data, [[[3, 4], [7, 8]],
+                                                 [[5, 6], [1, 2]]]))
+        t2 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        t2.transpose_(0, 2)
+        self.assertTrue(np.array_equal(t2.data, [[[3, 7], [5, 1]],
+                                                 [[4, 8], [6, 2]]]))
+        t3 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        t3.transpose_(1, 2)
+        self.assertTrue(np.array_equal(t3.data, [[[3, 5], [4, 6]],
+                                                 [[7, 1], [8, 2]]]))
+
+    def testT(self):
+        t1 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        out1 = t1.t()
+        self.assertTrue(np.array_equal(out1.data, [[[3, 4], [7, 8]],
+                                                   [[5, 6], [1, 2]]]))
+
+    def testT_(self):
+        t1 = TensorBase(np.array([[[3, 4], [5, 6]], [[7, 8], [1, 2]]]))
+        t1.transpose_(0, 1)
+        self.assertTrue(np.array_equal(t1.data, [[[3, 4], [7, 8]],
+                                                 [[5, 6], [1, 2]]]))
+
+
 class unsqueezeTests(unittest.TestCase):
     def testUnsqueeze(self):
         t1 = TensorBase(np.arange(3 * 4 * 5).reshape((3, 4, 5)))