diff --git a/bob/learn/misc/__init__.py b/bob/learn/misc/__init__.py
index 4692c864bd6c1eb1c8a8a167f5d434a47868c6c1..4f39609df8e4a73433f3fda1aba17dcbcad3635b 100644
--- a/bob/learn/misc/__init__.py
+++ b/bob/learn/misc/__init__.py
@@ -17,6 +17,7 @@ from .__MAP_gmm_trainer__ import *
 from .__jfa_trainer__ import *
 from .__isv_trainer__ import *
 from .__ivector_trainer__ import *
+from .__plda_trainer__ import *
 
 
 def ztnorm_same_value(vect_a, vect_b):
diff --git a/bob/learn/misc/__plda_trainer__.py b/bob/learn/misc/__plda_trainer__.py
new file mode 100644
index 0000000000000000000000000000000000000000..a48e92cbdf20b487ced56289e50a31ede1e79e94
--- /dev/null
+++ b/bob/learn/misc/__plda_trainer__.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# vim: set fileencoding=utf-8 :
+# Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
+# Mon Fev 02 21:40:10 2015 +0200
+#
+# Copyright (C) 2011-2015 Idiap Research Institute, Martigny, Switzerland
+
+from ._library import _PLDATrainer
+import numpy
+
+# define the class
+class PLDATrainer (_PLDATrainer):
+
+  def __init__(self, max_iterations=10, use_sum_second_order=True):
+    """
+    :py:class:`bob.learn.misc.PLDATrainer` constructor
+
+    Keyword Parameters:
+      max_iterations
+        Number of maximum iterations
+    """
+    _PLDATrainer.__init__(self, use_sum_second_order)
+    self._max_iterations         = max_iterations
+
+
+  def train(self, plda_base, data):
+    """
+    Train the :py:class:`bob.learn.misc.PLDABase` using data
+
+    Keyword Parameters:
+      jfa_base
+        The `:py:class:bob.learn.misc.PLDABase` class
+      data
+        The data to be trained
+    """
+
+    #Initialization
+    self.initialize(plda_base, data);
+      
+    for i in range(self._max_iterations):
+      #eStep
+      self.eStep(plda_base, data);
+      #mStep
+      self.mStep(plda_base);
+    self.finalize(plda_base);
+
+
+
+# copy the documentation from the base class
+__doc__ = _PLDATrainer.__doc__
diff --git a/bob/learn/misc/main.cpp b/bob/learn/misc/main.cpp
index c2171ab782e95eba70c04fad2b97f94d572e6b0c..c16df1ec197a334a829ad052ff3c2675f7ca5df3 100644
--- a/bob/learn/misc/main.cpp
+++ b/bob/learn/misc/main.cpp
@@ -81,7 +81,8 @@ static PyObject* create_module (void) {
   if (!init_BobLearnMiscIVectorTrainer(module)) return 0;
     
   if (!init_BobLearnMiscPLDABase(module)) return 0;
-  if (!init_BobLearnMiscPLDAMachine(module)) return 0; 
+  if (!init_BobLearnMiscPLDAMachine(module)) return 0;
+  if (!init_BobLearnMiscPLDATrainer(module)) return 0; 
 
   if (!init_BobLearnMiscEMPCATrainer(module)) return 0;  
 
diff --git a/bob/learn/misc/plda_trainer.cpp b/bob/learn/misc/plda_trainer.cpp
index 80010d1288656e56aced4b84c5b3df29a0557fe8..902d42898726d9c28621f2bee89bf9803144316f 100644
--- a/bob/learn/misc/plda_trainer.cpp
+++ b/bob/learn/misc/plda_trainer.cpp
@@ -33,11 +33,25 @@ int list_as_vector(PyObject* list, std::vector<blitz::Array<double,N> >& vec)
 }
 
 
+template <int N>
+static PyObject* vector_as_list(const std::vector<blitz::Array<double,N> >& vec)
+{
+  PyObject* list = PyList_New(vec.size());
+  for(size_t i=0; i<vec.size(); i++){
+    blitz::Array<double,N> numpy_array = vec[i];
+    PyObject* numpy_py_object = PyBlitzArrayCxx_AsNumpy(numpy_array);
+    PyList_SET_ITEM(list, i, numpy_py_object);
+  }
+  return list;
+}
+
+
 static auto PLDATrainer_doc = bob::extension::ClassDoc(
   BOB_EXT_MODULE_PREFIX ".PLDATrainer",
   "This class can be used to train the :math:`$F$`, :math:`$G$ and "
-  " :math:`$\\Sigma$` matrices and the mean vector :math:`$\\mu$` of a PLDA model.",
+  " :math:`$\\Sigma$` matrices and the mean vector :math:`$\\mu$` of a PLDA model."
   "References: [ElShafey2014,PrinceElder2007,LiFu2012]",
+  ""
 ).add_constructor(
   bob::extension::FunctionDoc(
     "__init__",
@@ -89,35 +103,29 @@ static int PyBobLearnMiscPLDATrainer_init(PyBobLearnMiscPLDATrainerObject* self,
   // get the number of command line arguments
   int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0);
 
-  switch(nargs){
-    case 0:{
-      self->cxx.reset(new bob::learn::misc::PLDATrainer());
-      return 0;
+  if(nargs==1){
+    //Reading the input argument
+    PyObject* arg = 0;
+    if (PyTuple_Size(args))
+      arg = PyTuple_GET_ITEM(args, 0);
+    else {
+      PyObject* tmp = PyDict_Values(kwargs);
+      auto tmp_ = make_safe(tmp);
+      arg = PyList_GET_ITEM(tmp, 0);
     }
-    case 1:{
-      //Reading the input argument
-      PyObject* arg = 0;
-      if (PyTuple_Size(args))
-        arg = PyTuple_GET_ITEM(args, 0);
-      else {
-        PyObject* tmp = PyDict_Values(kwargs);
-        auto tmp_ = make_safe(tmp);
-        arg = PyList_GET_ITEM(tmp, 0);
-      }
       
-      if(PyBobLearnMiscPLDATrainer_Check(arg))
-        // If the constructor input is PLDATrainer object
-        return PyBobLearnMiscPLDATrainer_init_copy(self, args, kwargs);
-      else
-        return PyBobLearnMiscPLDATrainer_init_bool(self, args, kwargs);
-
-    }
-    default:{
-      PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 0 or 1 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs);
-      PLDATrainer_doc.print_usage();
-      return -1;
-    }
+    if(PyBobLearnMiscPLDATrainer_Check(arg))
+      // If the constructor input is PLDATrainer object
+      return PyBobLearnMiscPLDATrainer_init_copy(self, args, kwargs);
+    else
+      return PyBobLearnMiscPLDATrainer_init_bool(self, args, kwargs);
+  }
+  else{
+    PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 0 or 1 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs);
+    PLDATrainer_doc.print_usage();
+    return -1;
   }
+
   BOB_CATCH_MEMBER("cannot create PLDATrainer", 0)
   return 0;
 }
@@ -167,7 +175,8 @@ static auto z_second_order = bob::extension::VariableDoc(
 );
 PyObject* PyBobLearnMiscPLDATrainer_get_z_second_order(PyBobLearnMiscPLDATrainerObject* self, void*){
   BOB_TRY
-  return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZSecondOrder());
+  //return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZSecondOrder());
+  return vector_as_list(self->cxx->getZSecondOrder());
   BOB_CATCH_MEMBER("z_second_order could not be read", 0)
 }
 
@@ -193,7 +202,8 @@ static auto z_first_order = bob::extension::VariableDoc(
 );
 PyObject* PyBobLearnMiscPLDATrainer_get_z_first_order(PyBobLearnMiscPLDATrainerObject* self, void*){
   BOB_TRY
-  return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZFirstOrder());
+  //return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZFirstOrder());
+  return vector_as_list(self->cxx->getZFirstOrder());
   BOB_CATCH_MEMBER("z_first_order could not be read", 0)
 }
 
@@ -255,7 +265,7 @@ static PyObject* PyBobLearnMiscPLDATrainer_initialize(PyBobLearnMiscPLDATrainerO
 
   std::vector<blitz::Array<double,2> > data_vector;
   if(list_as_vector(data ,data_vector)==0)
-    self->cxx->initialize(*plda_machine->cxx, data_vector);
+    self->cxx->initialize(*plda_base->cxx, data_vector);
 
   BOB_CATCH_MEMBER("cannot perform the initialize method", 0)
 
@@ -287,7 +297,7 @@ static PyObject* PyBobLearnMiscPLDATrainer_e_step(PyBobLearnMiscPLDATrainerObjec
 
   std::vector<blitz::Array<double,2> > data_vector;
   if(list_as_vector(data ,data_vector)==0)
-    self->cxx->e_step(*plda_machine->cxx, data_vector);
+    self->cxx->eStep(*plda_base->cxx, data_vector);
 
   BOB_CATCH_MEMBER("cannot perform the e_step method", 0)
 
@@ -319,7 +329,7 @@ static PyObject* PyBobLearnMiscPLDATrainer_m_step(PyBobLearnMiscPLDATrainerObjec
 
   std::vector<blitz::Array<double,2> > data_vector;
   if(list_as_vector(data ,data_vector)==0)
-    self->cxx->m_step(*plda_machine->cxx, data_vector);
+    self->cxx->mStep(*plda_base->cxx, data_vector);
 
   BOB_CATCH_MEMBER("cannot perform the m_step method", 0)
 
@@ -351,7 +361,7 @@ static PyObject* PyBobLearnMiscPLDATrainer_finalize(PyBobLearnMiscPLDATrainerObj
 
   std::vector<blitz::Array<double,2> > data_vector;
   if(list_as_vector(data ,data_vector)==0)
-    self->cxx->finalize(*plda_machine->cxx, data_vector);
+    self->cxx->finalize(*plda_base->cxx, data_vector);
 
   BOB_CATCH_MEMBER("cannot perform the finalize method", 0)
 
@@ -370,7 +380,7 @@ static auto enrol = bob::extension::FunctionDoc(
 .add_prototype("plda_machine,data")
 .add_parameter("plda_machine", ":py:class:`bob.learn.misc.PLDAMachine`", "PLDAMachine Object")
 .add_parameter("data", "list", "");
-static PyObject* PyBobLearnMiscPLDATrainer_finalize(PyBobLearnMiscPLDATrainerObject* self, PyObject* args, PyObject* kwargs) {
+static PyObject* PyBobLearnMiscPLDATrainer_enrol(PyBobLearnMiscPLDATrainerObject* self, PyObject* args, PyObject* kwargs) {
   BOB_TRY
 
   /* Parses input arguments in a single shot */
diff --git a/bob/learn/misc/test_plda_trainer.py b/bob/learn/misc/test_plda_trainer.py
index b0c6a04504ad37dbbd28e71e3ff66530724d7424..f18fe33c742551ff63f0976698381aaa6c98fec2 100644
--- a/bob/learn/misc/test_plda_trainer.py
+++ b/bob/learn/misc/test_plda_trainer.py
@@ -77,8 +77,8 @@ class PythonPLDATrainer():
 
   def __init_f__(self, machine, data):
     n_ids = len(data)
-    S = numpy.zeros(shape=(machine.dim_d, n_ids), dtype=numpy.float64)
-    Si_sum = numpy.zeros(shape=(machine.dim_d,), dtype=numpy.float64)
+    S = numpy.zeros(shape=(machine.shape[0], n_ids), dtype=numpy.float64)
+    Si_sum = numpy.zeros(shape=(machine.shape[0],), dtype=numpy.float64)
     for i in range(n_ids):
       Si = S[:,i]
       data_i = data[i]
@@ -88,7 +88,7 @@ class PythonPLDATrainer():
       Si_sum += Si
     Si_sum /= n_ids
 
-    S = S - numpy.tile(Si_sum.reshape([machine.dim_d,1]), [1,n_ids])
+    S = S - numpy.tile(Si_sum.reshape([machine.shape[0],1]), [1,n_ids])
     U, sigma, S_ = numpy.linalg.svd(S, full_matrices=False)
     U_slice = U[:,0:self.m_dim_f]
     sigma_slice = sigma[0:self.m_dim_f]
@@ -99,9 +99,9 @@ class PythonPLDATrainer():
     n_samples = 0
     for v in data:
       n_samples += v.shape[0]
-    S = numpy.zeros(shape=(machine.dim_d, n_samples), dtype=numpy.float64)
-    Si_sum = numpy.zeros(shape=(machine.dim_d,), dtype=numpy.float64)
-    cache = numpy.zeros(shape=(machine.dim_d,), dtype=numpy.float64)
+    S = numpy.zeros(shape=(machine.shape[0], n_samples), dtype=numpy.float64)
+    Si_sum = numpy.zeros(shape=(machine.shape[0],), dtype=numpy.float64)
+    cache = numpy.zeros(shape=(machine.shape[0],), dtype=numpy.float64)
     c = 0
     for i in range(len(data)):
       cache = 0
@@ -115,7 +115,7 @@ class PythonPLDATrainer():
         c += 1
     Si_sum /= n_samples
 
-    S = S - numpy.tile(Si_sum.reshape([machine.dim_d,1]), [1,n_samples])
+    S = S - numpy.tile(Si_sum.reshape([machine.shape[0],1]), [1,n_samples])
     U, sigma, S_ = numpy.linalg.svd(S, full_matrices=False)
     U_slice = U[:,0:self.m_dim_g]
     sigma_slice_sqrt = numpy.sqrt(sigma[0:self.m_dim_g])