diff --git a/bob/math/cpp/svd.cpp b/bob/math/cpp/svd.cpp
index 1fbf99cacf78f210b2ab5bdee97476d2aa695a45..854cd47328f134cabab3c4f28040c879243ab409 100644
--- a/bob/math/cpp/svd.cpp
+++ b/bob/math/cpp/svd.cpp
@@ -79,6 +79,19 @@ static void svd_lapack( const char jobz, const int M, const int N,
     if (info != 0)
       throw std::runtime_error("The LAPACK dgesdd function returned a non-zero value. You may consider using LAPACK dgsevd instead (see #171) by enabling the 'safe' option.");
   }
+  
+  // Defining the sign of the eigenvectors
+  // Approch extracted from page 8 - http://prod.sandia.gov/techlib/access-control.cgi/2007/076422.pdf  
+  if(U[0] < 0){    
+    int ucol=0; ucol= (jobz=='A')? M : std::min(M,N);
+    for (int i=0; i<ldu*ucol; i++){
+      U[i] = -1*U[i];
+    }
+
+    for (int i=0; i<ldvt*N; i++){
+      VT[i] = -1*VT[i];
+    }
+  }
 }
 
 void bob::math::svd(const blitz::Array<double,2>& A, blitz::Array<double,2>& U,
@@ -148,7 +161,8 @@ void bob::math::svd_(const blitz::Array<double,2>& A, blitz::Array<double,2>& U,
 
   // Call the LAPACK function
   svd_lapack(jobz, N, M, A_lapack, lda, S_lapack, U_lapack, ldu,
-    VT_lapack, ldvt, safe);
+    VT_lapack, ldvt, safe);  
+
 
   // Copy singular vectors back to U, V and sigma if required
   if (!U_direct_use)  Vt = U_blitz_lapack;
diff --git a/bob/math/gsvd.cpp b/bob/math/gsvd.cpp
index aa20a8156b06b67c1e39b8fa278d5230640ab81d..8d80eafce2bb89ab4ebec2f45aef45312011a990 100644
--- a/bob/math/gsvd.cpp
+++ b/bob/math/gsvd.cpp
@@ -9,6 +9,8 @@
 #include <bob.blitz/cppapi.h>
 #include <bob.blitz/cleanup.h>
 #include <bob.math/gsvd.h>
+#include <bob.math/svd.h>
+#include <bob.math/linear.h>
 
 PyObject* py_gsvd (PyObject*, PyObject* args, PyObject* kwds) {
 
@@ -41,9 +43,9 @@ PyObject* py_gsvd (PyObject*, PyObject* args, PyObject* kwds) {
   auto A_bz = PyBlitzArrayCxx_AsBlitz<double,2>(A);
   auto B_bz = PyBlitzArrayCxx_AsBlitz<double,2>(B);
 
- const int M = A_bz->extent(0);
- const int N = A_bz->extent(1);
- const int P = B_bz->extent(0);
+  const int M = A_bz->extent(0);
+  const int N = A_bz->extent(1);
+  const int P = B_bz->extent(0);
 
   // Creating the output matrices
   blitz::Array<double,2> U(M, M); U=0;
@@ -75,3 +77,73 @@ PyObject* py_gsvd (PyObject*, PyObject* args, PyObject* kwds) {
   return 0;
 
 }
+
+
+PyObject* py_svd (PyObject*, PyObject* args, PyObject* kwds) {
+
+  /* Parses input arguments in a single shot */
+  static const char* const_kwlist[] = { "A",  0 /* Sentinel */ };
+  static char** kwlist = const_cast<char**>(const_kwlist);
+
+  PyBlitzArrayObject* A = 0;
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, 
+                                   &PyBlitzArray_Converter, &A
+      ))
+      return 0;
+
+   auto A_ = make_safe(A);
+
+  if (A->ndim != 2 || A->type_num != NPY_FLOAT64) {
+    PyErr_Format(PyExc_TypeError, "`A` matrix only supports 2D 64-bit float array");
+    return 0;
+  }
+
+
+  auto A_bz = PyBlitzArrayCxx_AsBlitz<double,2>(A);
+
+  int M = A_bz->extent(0);
+  int N = A_bz->extent(1); 
+
+  // Creating the output matrices
+  // Prepares to call LAPACK function:
+  // We recall that FORTRAN/LAPACK is column-major order whereas blitz arrays
+  // are row-major order by default.
+  // If A = U.S.V^T, then A^T = V.S.U^T
+
+  blitz::Array<double,2> V(M, M); V=0;
+  blitz::Array<double,1> S(std::min(M,N)); S=0;  
+  blitz::Array<double,2> U(N, N); U=0;   
+  
+
+  try {
+    bob::math::svd(*A_bz,V,S,U);
+
+    // S for the python output.
+    // LAPACK returns an 1d matrix of size n.
+    // In order to nicelly fit A = U S V,
+    // I need to create a matrix S_output of size MxN and fits the diagonal of S (NxN) on it.    
+    blitz::Array<double,2> S_output(M, N); S_output=0;
+    blitz::Array<double,2> S_diag(N, N); S_diag=0;
+    bob::math::diag(S, S_diag);
+    S_output(blitz::Range(0,N-1), blitz::Range(0,N-1)) = S_diag;
+    //bob::math::diag(S, (reinterpret_cast<blitz::Array<double,2>>)S_output(blitz::Range(0,N-1), blitz::Range(0,N-1)));    
+    return Py_BuildValue("NNN",
+                         PyBlitzArrayCxx_AsConstNumpy(U),
+                         PyBlitzArrayCxx_AsConstNumpy(S_output),
+                         PyBlitzArrayCxx_AsConstNumpy(V));
+  }
+  catch (std::exception& e) {
+    PyErr_SetString(PyExc_RuntimeError, e.what());
+  }
+  catch (...) {
+    PyErr_SetString(PyExc_RuntimeError, "norminv failed: unknown exception caught");
+  }
+
+
+  return 0;
+
+}
+
+
+
diff --git a/bob/math/gsvd.h b/bob/math/gsvd.h
index cc38f9fc38360e041536a83cca82c2e6ad3f33e8..1465400ec974636041915128499d0eb9c22de182 100644
--- a/bob/math/gsvd.h
+++ b/bob/math/gsvd.h
@@ -8,3 +8,4 @@
 #include <Python.h>
 
 PyObject* py_gsvd(PyObject*, PyObject* args, PyObject* kwds);
+PyObject* py_svd(PyObject*, PyObject* args, PyObject* kwds);
diff --git a/bob/math/main.cpp b/bob/math/main.cpp
index e78fe28de0135d7fdf1e9a78f94f803175404202..97886907b22fade0c9afd98dd54cd842071db4a5 100644
--- a/bob/math/main.cpp
+++ b/bob/math/main.cpp
@@ -376,6 +376,22 @@ static bob::extension::FunctionDoc s_gsvd = bob::extension::FunctionDoc(
 ;
 
 
+static bob::extension::FunctionDoc s_svd = bob::extension::FunctionDoc(
+  "svd",
+  "Computes the SVD",
+  "Computes the SVD (Singular Value Decomposition).\n"
+  "[U,S,V] = svd(A) returns :math:`U`, :math:`S` and :math:`V` such that ` \n\n"
+  ".. math:: A=U S V\n"
+  )
+  .add_prototype("A", "")
+  .add_parameter("A", "[array_like (float, 2D)]", "Must be :math:`m \\times n`")
+  .add_return("U", "[array_like (float, 2D)]", "The :math:`U` matrix of left singular vectors (size :math:`m \\times m`)")
+  .add_return("S", "[array_like (float, 2D)]", "The matrix of singular values :math:`S` of size :math:`m \\times n`")
+  .add_return("V", "[array_like (float, 2D)]", "The :math:`V^{T}` matrix of right singular vectors (size :math:`n \\times n`)")
+;
+
+
+
 static PyMethodDef module_methods[] = {
     {
       s_histogram_intersection.name(),
@@ -497,6 +513,12 @@ static PyMethodDef module_methods[] = {
       METH_VARARGS|METH_KEYWORDS,
       s_gsvd.doc()
     },
+    {
+      s_svd.name(),
+      (PyCFunction)py_svd,
+      METH_VARARGS|METH_KEYWORDS,
+      s_svd.doc()
+    },
 
     {0}  /* Sentinel */
 };
diff --git a/bob/math/test_gsvd.py b/bob/math/test_gsvd.py
index 804203e0740ea8c58ed0a37057ac17d54bebff15..eac76a011776c66bbc7c3f743bb73550aca251eb 100644
--- a/bob/math/test_gsvd.py
+++ b/bob/math/test_gsvd.py
@@ -20,6 +20,7 @@ import bob.math
 import numpy
 import nose.tools
 numpy.random.seed(10)
+import pkg_resources
 
 
 def gsvd_relations(A,B):
@@ -39,12 +40,17 @@ def gsvd_relations(A,B):
   nose.tools.eq_( (abs(B-B_check) < 1e-10).all(), True )
 
 
+def svd_relations(A):
+
+  [U, S, V] = bob.math.svd(A)  
+  A_check = numpy.dot(numpy.dot(V,S), U)
+  nose.tools.eq_( (abs(A-A_check) < 1e-10).all(), True )
+
 
 def test_first_case():
-  """
-  Testing the first scenario of gsvd:
-  M-K-L >= 0 (check http://www.netlib.org/lapack/explore-html/d1/d7e/group__double_g_esing_ga4a187519e5c71da3b3f67c85e9baf0f2.html#ga4a187519e5c71da3b3f67c85e9baf0f2)  
-  """
+  
+  #Testing the first scenario of gsvd:
+  #M-K-L >= 0 (check http://www.netlib.org/lapack/explore-html/d1/d7e/group__double_g_esing_ga4a187519e5c71da3b3f67c85e9baf0f2.html#ga4a187519e5c71da3b3f67c85e9baf0f2)  
 
   A = numpy.random.rand(10,10)
   B = numpy.random.rand(790,10)
@@ -53,10 +59,10 @@ def test_first_case():
 
 
 def test_second_case():
-  """
-  Testing the second scenario of gsvd:
-  M-K-L < 0 (check http://www.netlib.org/lapack/explore-html/d1/d7e/group__double_g_esing_ga4a187519e5c71da3b3f67c85e9baf0f2.html#ga4a187519e5c71da3b3f67c85e9baf0f2)  
-  """
+  
+  #Testing the second scenario of gsvd:
+  #M-K-L < 0 (check http://www.netlib.org/lapack/explore-html/d1/d7e/group__double_g_esing_ga4a187519e5c71da3b3f67c85e9baf0f2.html#ga4a187519e5c71da3b3f67c85e9baf0f2)  
+
 
   A = numpy.random.rand(4,5)
   B = numpy.random.rand(11,5)
@@ -65,10 +71,9 @@ def test_second_case():
 
 
 def test_corner_case():
-  """
-  Testing when P <= N.
-    
-  """
+
+  #Testing when P <= N.
+
 
   A = numpy.random.rand(25, 25)
   B = numpy.random.rand(25, 25)
@@ -76,3 +81,56 @@ def test_corner_case():
 
 
 
+def test_svd_relation():
+
+  ##Testing SVD
+
+  A = numpy.random.rand(25, 25)
+  svd_relations(A)
+
+  #A = numpy.random.rand(20, 25)
+  #svd_relations(A)
+
+  A = numpy.random.rand(30, 25)
+  svd_relations(A)
+
+
+
+def test_svd_signal():
+
+  ##Testing SVD signal
+  ##This test was imported from bob.learn.linear  
+
+  A = numpy.array([[3,-3,100], [4,-4,50], [3.5,-3.5,-50], [3.8,-3.7,-100]], dtype='float64')
+
+  U_ref = numpy.array([[  2.20825004e-03,  -1.80819459e-03,  -9.99995927e-01],
+                       [  7.09549949e-01,  -7.04649416e-01,   2.84101853e-03],
+                       [ -7.04651683e-01,  -7.09553332e-01,  -2.73037723e-04]])
+  
+  [U,S,V] = bob.math.svd(A)
+  nose.tools.eq_((abs(U-U_ref) < 1e-8).all(), True)
+  svd_relations(A)
+  
+
+  
+def test_svd_signal_book_example():
+
+  ## Reference copied from here http://prod.sandia.gov/techlib/access-control.cgi/2007/076422.pdf  
+
+  A = numpy.array([[2.5, 63.5, 40.1, 78, 61.1],
+                   [0.9, 58.0, 25.1, 78, 94.1],
+                   [1.7, 46.0, 65.0, 78, 106.4],
+                   [1.2, 15.7, 102.1, 78, 173.0],
+                   [1.5, 12.2, 100.0, 77, 199.7],
+                   [2.0, 8.9, 87.8, 76, 176.0],
+                   [3.8, 2.7, 17.1, 69, 373.6],
+                   [1.0, 1.7, 140.0, 73, 283.7],
+                   [2.1, 1.0, 55.0, 79, 34.7],
+                   [0.8, 0.2, 50.4, 73, 36.4]])
+
+  [U,S,V] = bob.math.svd(A)
+  assert U[0,0] > 0
+  svd_relations(A)
+  
+  
+
diff --git a/doc/py_api.rst b/doc/py_api.rst
index 252233d3e0a009b637dd39cf2de4cc17448f1c99..7e63d97495da91b843e56fa886879b8909c0c054 100644
--- a/doc/py_api.rst
+++ b/doc/py_api.rst
@@ -16,6 +16,7 @@ Summary
   bob.math.LPInteriorPointShortstep
   bob.math.LPInteriorPointLongstep
   bob.math.chi_square
+  bob.math.svd
   bob.math.gsvd
   bob.math.histogram_intersection
   bob.math.kullback_leibler