From d95e400f5c3edea6548467143a8b7c60cb3d7d79 Mon Sep 17 00:00:00 2001 From: Tiago Freitas Pereira Date: Tue, 3 Mar 2015 19:32:33 +0100 Subject: [PATCH] Added more checks in the bindings --- bob/learn/em/MAP_gmm_trainer.cpp | 18 ++++ bob/learn/em/ML_gmm_trainer.cpp | 16 +++ bob/learn/em/gmm_machine.cpp | 2 - bob/learn/em/gmm_stats.cpp | 75 +++++++++++--- bob/learn/em/isv_base.cpp | 50 ++++++++-- bob/learn/em/isv_machine.cpp | 75 +++++++++++++- bob/learn/em/isv_trainer.cpp | 51 ++++++++-- bob/learn/em/jfa_base.cpp | 76 +++++++++++--- bob/learn/em/jfa_machine.cpp | 102 +++++++++++++++++-- bob/learn/em/jfa_trainer.cpp | 166 +++++++++++++++++++++++++------ bob/learn/em/kmeans_machine.cpp | 108 +++++++++++++++++++- bob/learn/em/kmeans_trainer.cpp | 31 ++++++ 12 files changed, 680 insertions(+), 90 deletions(-) diff --git a/bob/learn/em/MAP_gmm_trainer.cpp b/bob/learn/em/MAP_gmm_trainer.cpp index 437e277..4594673 100644 --- a/bob/learn/em/MAP_gmm_trainer.cpp +++ b/bob/learn/em/MAP_gmm_trainer.cpp @@ -305,6 +305,24 @@ static PyObject* PyBobLearnEMMAPGMMTrainer_eStep(PyBobLearnEMMAPGMMTrainerObject &PyBlitzArray_Converter, &data)) return 0; auto data_ = make_safe(data); + + // perform check on the input + if (data->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, eStep.name()); + return 0; + } + + if (data->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, eStep.name()); + return 0; + } + + if (data->shape[1] != (Py_ssize_t)gmm_machine->cxx->getNInputs() ) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, gmm_machine->cxx->getNInputs(), data->shape[1], eStep.name()); + return 0; + } + + self->cxx->eStep(*gmm_machine->cxx, *PyBlitzArrayCxx_AsBlitz(data)); BOB_CATCH_MEMBER("cannot perform the eStep method", 0) diff --git a/bob/learn/em/ML_gmm_trainer.cpp b/bob/learn/em/ML_gmm_trainer.cpp index 6b5b271..c125bd4 100644 --- a/bob/learn/em/ML_gmm_trainer.cpp +++ b/bob/learn/em/ML_gmm_trainer.cpp @@ -204,7 +204,23 @@ static PyObject* PyBobLearnEMMLGMMTrainer_eStep(PyBobLearnEMMLGMMTrainerObject* if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, &PyBlitzArray_Converter, &data)) return 0; auto data_ = make_safe(data); + + // perform check on the input + if (data->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, eStep.name()); + return 0; + } + + if (data->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, eStep.name()); + return 0; + } + if (data->shape[1] != (Py_ssize_t)gmm_machine->cxx->getNInputs() ) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, gmm_machine->cxx->getNInputs(), data->shape[1], eStep.name()); + return 0; + } + self->cxx->eStep(*gmm_machine->cxx, *PyBlitzArrayCxx_AsBlitz(data)); BOB_CATCH_MEMBER("cannot perform the eStep method", 0) diff --git a/bob/learn/em/gmm_machine.cpp b/bob/learn/em/gmm_machine.cpp index 55ce47b..6c84d98 100644 --- a/bob/learn/em/gmm_machine.cpp +++ b/bob/learn/em/gmm_machine.cpp @@ -221,8 +221,6 @@ int PyBobLearnEMGMMMachine_setMeans(PyBobLearnEMGMMMachineObject* self, PyObject return -1; } - - auto b = PyBlitzArrayCxx_AsBlitz(input, "means"); if (!b) return -1; self->cxx->setMeans(*b); diff --git a/bob/learn/em/gmm_stats.cpp b/bob/learn/em/gmm_stats.cpp index dd05a86..c38a674 100644 --- a/bob/learn/em/gmm_stats.cpp +++ b/bob/learn/em/gmm_stats.cpp @@ -187,13 +187,30 @@ PyObject* PyBobLearnEMGMMStats_getN(PyBobLearnEMGMMStatsObject* self, void*){ } int PyBobLearnEMGMMStats_setN(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, n.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "n"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, n.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, n.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->n.extent(0)){ + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->n.extent(0), input->shape[0], n.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "n"); if (!b) return -1; self->cxx->n = *b; return 0; @@ -214,13 +231,30 @@ PyObject* PyBobLearnEMGMMStats_getSum_px(PyBobLearnEMGMMStatsObject* self, void* } int PyBobLearnEMGMMStats_setSum_px(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, sum_px.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "sum_px"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, sum_px.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, sum_px.name()); + return -1; + } + + if (input->shape[1] != (Py_ssize_t)self->cxx->sumPx.extent(1) && input->shape[0] != (Py_ssize_t)self->cxx->sumPx.extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->sumPx.extent(1), (Py_ssize_t)self->cxx->sumPx.extent(0), (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[0], sum_px.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "sum_px"); if (!b) return -1; self->cxx->sumPx = *b; return 0; @@ -241,13 +275,30 @@ PyObject* PyBobLearnEMGMMStats_getSum_pxx(PyBobLearnEMGMMStatsObject* self, void } int PyBobLearnEMGMMStats_setSum_pxx(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, sum_pxx.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "sum_pxx"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, sum_pxx.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, sum_pxx.name()); + return -1; + } + + if (input->shape[1] != (Py_ssize_t)self->cxx->sumPxx.extent(1) && input->shape[0] != (Py_ssize_t)self->cxx->sumPxx.extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->sumPxx.extent(1), (Py_ssize_t)self->cxx->sumPxx.extent(0), (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[0], sum_pxx.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "sum_pxx"); if (!b) return -1; self->cxx->sumPxx = *b; return 0; diff --git a/bob/learn/em/isv_base.cpp b/bob/learn/em/isv_base.cpp index 850fc3f..e1b8c0b 100644 --- a/bob/learn/em/isv_base.cpp +++ b/bob/learn/em/isv_base.cpp @@ -209,13 +209,30 @@ PyObject* PyBobLearnEMISVBase_getU(PyBobLearnEMISVBaseObject* self, void*){ } int PyBobLearnEMISVBase_setU(PyBobLearnEMISVBaseObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, U.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "u"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, U.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, U.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getU().extent(0) && input->shape[1] != self->cxx->getU().extent(1)) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getU().extent(0), (Py_ssize_t)self->cxx->getU().extent(1), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], U.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "u"); if (!b) return -1; self->cxx->setU(*b); return 0; @@ -237,13 +254,30 @@ PyObject* PyBobLearnEMISVBase_getD(PyBobLearnEMISVBaseObject* self, void*){ } int PyBobLearnEMISVBase_setD(PyBobLearnEMISVBaseObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, D.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "d"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, D.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, D.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getD().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getU().extent(0), (Py_ssize_t)input->shape[0], D.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "d"); if (!b) return -1; self->cxx->setD(*b); return 0; diff --git a/bob/learn/em/isv_machine.cpp b/bob/learn/em/isv_machine.cpp index 6de1fe0..e4f4f62 100644 --- a/bob/learn/em/isv_machine.cpp +++ b/bob/learn/em/isv_machine.cpp @@ -197,13 +197,30 @@ PyObject* PyBobLearnEMISVMachine_getZ(PyBobLearnEMISVMachineObject* self, void*) } int PyBobLearnEMISVMachine_setZ(PyBobLearnEMISVMachineObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, Z.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "z"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, Z.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, Z.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getZ().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getZ().extent(0), (Py_ssize_t)input->shape[0], Z.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "z"); if (!b) return -1; self->cxx->setZ(*b); return 0; @@ -424,6 +441,23 @@ static PyObject* PyBobLearnEMISVMachine_estimateX(PyBobLearnEMISVMachineObject* //protects acquired resources through this scope auto input_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); + return 0; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); + return 0; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), (Py_ssize_t)input->shape[0], estimate_x.name()); + return 0; + } + self->cxx->estimateX(*stats->cxx, *PyBlitzArrayCxx_AsBlitz(input)); BOB_CATCH_MEMBER("cannot estimate X", 0) @@ -455,6 +489,23 @@ static PyObject* PyBobLearnEMISVMachine_estimateUx(PyBobLearnEMISVMachineObject* //protects acquired resources through this scope auto input_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); + return 0; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); + return 0; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs()*(Py_ssize_t)self->cxx->getNGaussians(), (Py_ssize_t)input->shape[0], estimate_ux.name()); + return 0; + } + self->cxx->estimateUx(*stats->cxx, *PyBlitzArrayCxx_AsBlitz(input)); BOB_CATCH_MEMBER("cannot estimate Ux", 0) @@ -486,6 +537,22 @@ static PyObject* PyBobLearnEMISVMachine_ForwardUx(PyBobLearnEMISVMachineObject* //protects acquired resources through this scope auto ux_input_ = make_safe(ux_input); + + // perform check on the input + if (ux_input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); + return 0; + } + + if (ux_input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); + return 0; + } + + if (ux_input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs(), (Py_ssize_t)ux_input->shape[0], forward_ux.name()); + return 0; + } double score = self->cxx->forward(*stats->cxx, *PyBlitzArrayCxx_AsBlitz(ux_input)); return Py_BuildValue("d", score); diff --git a/bob/learn/em/isv_trainer.cpp b/bob/learn/em/isv_trainer.cpp index 1d594a1..2bafaf8 100644 --- a/bob/learn/em/isv_trainer.cpp +++ b/bob/learn/em/isv_trainer.cpp @@ -224,13 +224,31 @@ PyObject* PyBobLearnEMISVTrainer_get_acc_u_a1(PyBobLearnEMISVTrainerObject* self } int PyBobLearnEMISVTrainer_set_acc_u_a1(PyBobLearnEMISVTrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_u_a1.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_u_a1"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); + return -1; + } + + if (input->ndim != 3){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 3D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA1().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA1().extent(1) && input->shape[2] != (Py_ssize_t)self->cxx->getAccUA1().extent(2)) { + PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA1().extent(0), (Py_ssize_t)self->cxx->getAccUA1().extent(1), (Py_ssize_t)self->cxx->getAccUA1().extent(2), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[2], acc_u_a1.name()); + return -1; + } + + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_u_a1"); if (!b) return -1; self->cxx->setAccUA1(*b); return 0; @@ -251,13 +269,30 @@ PyObject* PyBobLearnEMISVTrainer_get_acc_u_a2(PyBobLearnEMISVTrainerObject* self } int PyBobLearnEMISVTrainer_set_acc_u_a2(PyBobLearnEMISVTrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_u_a2.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_u_a2"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA2().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA2().extent(1)) { + PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA2().extent(0), (Py_ssize_t)self->cxx->getAccUA2().extent(1), input->shape[0], input->shape[1], acc_u_a2.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_u_a2"); if (!b) return -1; self->cxx->setAccUA2(*b); return 0; diff --git a/bob/learn/em/jfa_base.cpp b/bob/learn/em/jfa_base.cpp index 27c7136..a93da2a 100644 --- a/bob/learn/em/jfa_base.cpp +++ b/bob/learn/em/jfa_base.cpp @@ -216,13 +216,31 @@ PyObject* PyBobLearnEMJFABase_getU(PyBobLearnEMJFABaseObject* self, void*){ } int PyBobLearnEMJFABase_setU(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, U.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "u"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, U.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, U.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getU().extent(0) && input->shape[1] != self->cxx->getU().extent(1)) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getU().extent(0), (Py_ssize_t)self->cxx->getU().extent(1), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], U.name()); + return -1; + } + + + auto b = PyBlitzArrayCxx_AsBlitz(input, "u"); if (!b) return -1; self->cxx->setU(*b); return 0; @@ -243,13 +261,30 @@ PyObject* PyBobLearnEMJFABase_getV(PyBobLearnEMJFABaseObject* self, void*){ } int PyBobLearnEMJFABase_setV(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, V.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "v"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, V.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, V.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getV().extent(0) && input->shape[1] != self->cxx->getV().extent(1)) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getV().extent(0), (Py_ssize_t)self->cxx->getV().extent(1), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], V.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "v"); if (!b) return -1; self->cxx->setV(*b); return 0; @@ -271,13 +306,30 @@ PyObject* PyBobLearnEMJFABase_getD(PyBobLearnEMJFABaseObject* self, void*){ } int PyBobLearnEMJFABase_setD(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, D.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "d"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, D.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, D.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getD().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not [%" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getD().extent(0), (Py_ssize_t)input->shape[0], D.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "d"); if (!b) return -1; self->cxx->setD(*b); return 0; diff --git a/bob/learn/em/jfa_machine.cpp b/bob/learn/em/jfa_machine.cpp index d2f9476..9f1f7e3 100644 --- a/bob/learn/em/jfa_machine.cpp +++ b/bob/learn/em/jfa_machine.cpp @@ -198,13 +198,31 @@ PyObject* PyBobLearnEMJFAMachine_getY(PyBobLearnEMJFAMachineObject* self, void*) } int PyBobLearnEMJFAMachine_setY(PyBobLearnEMJFAMachineObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, Y.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "y"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, Y.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, Y.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getY().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getY().extent(0), (Py_ssize_t)input->shape[0], Y.name()); + return -1; + } + + + auto b = PyBlitzArrayCxx_AsBlitz(input, "y"); if (!b) return -1; self->cxx->setY(*b); return 0; @@ -226,13 +244,30 @@ PyObject* PyBobLearnEMJFAMachine_getZ(PyBobLearnEMJFAMachineObject* self, void*) } int PyBobLearnEMJFAMachine_setZ(PyBobLearnEMJFAMachineObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, Z.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "z"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, Z.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, Z.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getZ().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getZ().extent(0), (Py_ssize_t)input->shape[0], Z.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "z"); if (!b) return -1; self->cxx->setZ(*b); return 0; @@ -461,6 +496,23 @@ static PyObject* PyBobLearnEMJFAMachine_estimateX(PyBobLearnEMJFAMachineObject* //protects acquired resources through this scope auto input_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); + return 0; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); + return 0; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), (Py_ssize_t)input->shape[0], estimate_x.name()); + return 0; + } + self->cxx->estimateX(*stats->cxx, *PyBlitzArrayCxx_AsBlitz(input)); BOB_CATCH_MEMBER("cannot estimate X", 0) @@ -492,6 +544,23 @@ static PyObject* PyBobLearnEMJFAMachine_estimateUx(PyBobLearnEMJFAMachineObject* //protects acquired resources through this scope auto input_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); + return 0; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); + return 0; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs()*(Py_ssize_t)self->cxx->getNGaussians(), (Py_ssize_t)input->shape[0], estimate_ux.name()); + return 0; + } + self->cxx->estimateUx(*stats->cxx, *PyBlitzArrayCxx_AsBlitz(input)); BOB_CATCH_MEMBER("cannot estimate Ux", 0) @@ -523,6 +592,23 @@ static PyObject* PyBobLearnEMJFAMachine_ForwardUx(PyBobLearnEMJFAMachineObject* //protects acquired resources through this scope auto ux_input_ = make_safe(ux_input); + + // perform check on the input + if (ux_input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); + return 0; + } + + if (ux_input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); + return 0; + } + + if (ux_input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs(), (Py_ssize_t)ux_input->shape[0], forward_ux.name()); + return 0; + } + double score = self->cxx->forward(*stats->cxx, *PyBlitzArrayCxx_AsBlitz(ux_input)); return Py_BuildValue("d", score); diff --git a/bob/learn/em/jfa_trainer.cpp b/bob/learn/em/jfa_trainer.cpp index 1ec3782..60c7010 100644 --- a/bob/learn/em/jfa_trainer.cpp +++ b/bob/learn/em/jfa_trainer.cpp @@ -189,13 +189,30 @@ PyObject* PyBobLearnEMJFATrainer_get_acc_v_a1(PyBobLearnEMJFATrainerObject* self } int PyBobLearnEMJFATrainer_set_acc_v_a1(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_v_a1.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_v_a1"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_v_a1.name()); + return -1; + } + + if (input->ndim != 3){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 3D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_v_a1.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccVA1().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccVA1().extent(1) && input->shape[2] != (Py_ssize_t)self->cxx->getAccVA1().extent(2)) { + PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccVA1().extent(0), (Py_ssize_t)self->cxx->getAccVA1().extent(1), (Py_ssize_t)self->cxx->getAccVA1().extent(2), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[2], acc_v_a1.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_v_a1"); if (!b) return -1; self->cxx->setAccVA1(*b); return 0; @@ -216,13 +233,31 @@ PyObject* PyBobLearnEMJFATrainer_get_acc_v_a2(PyBobLearnEMJFATrainerObject* self } int PyBobLearnEMJFATrainer_set_acc_v_a2(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_v_a2.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_v_a2"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_v_a2.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_v_a2.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccVA2().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccVA2().extent(1)) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccVA2().extent(0), (Py_ssize_t)self->cxx->getAccVA2().extent(1), input->shape[0], input->shape[1], acc_v_a2.name()); + return -1; + } + + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_v_a2"); if (!b) return -1; self->cxx->setAccVA2(*b); return 0; @@ -243,13 +278,30 @@ PyObject* PyBobLearnEMJFATrainer_get_acc_u_a1(PyBobLearnEMJFATrainerObject* self } int PyBobLearnEMJFATrainer_set_acc_u_a1(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_u_a1.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_u_a1"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); + return -1; + } + + if (input->ndim != 3){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 3D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA1().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA1().extent(1) && input->shape[2] != (Py_ssize_t)self->cxx->getAccUA1().extent(2)) { + PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA1().extent(0), (Py_ssize_t)self->cxx->getAccUA1().extent(1), (Py_ssize_t)self->cxx->getAccUA1().extent(2), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[2], acc_u_a1.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_u_a1"); if (!b) return -1; self->cxx->setAccUA1(*b); return 0; @@ -270,13 +322,30 @@ PyObject* PyBobLearnEMJFATrainer_get_acc_u_a2(PyBobLearnEMJFATrainerObject* self } int PyBobLearnEMJFATrainer_set_acc_u_a2(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_u_a2.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_u_a2"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); + return -1; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA2().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA2().extent(1)) { + PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA2().extent(0), (Py_ssize_t)self->cxx->getAccUA2().extent(1), input->shape[0], input->shape[1], acc_u_a2.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_u_a2"); if (!b) return -1; self->cxx->setAccUA2(*b); return 0; @@ -297,13 +366,31 @@ PyObject* PyBobLearnEMJFATrainer_get_acc_d_a1(PyBobLearnEMJFATrainerObject* self } int PyBobLearnEMJFATrainer_set_acc_d_a1(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, acc_d_a1.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_d_a1"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_d_a1.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_d_a1.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccDA1().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccDA1().extent(0), input->shape[0], acc_d_a1.name()); + return -1; + } + + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_d_a1"); if (!b) return -1; self->cxx->setAccDA1(*b); return 0; @@ -324,13 +411,30 @@ PyObject* PyBobLearnEMJFATrainer_get_acc_d_a2(PyBobLearnEMJFATrainerObject* self } int PyBobLearnEMJFATrainer_set_acc_d_a2(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, acc_d_a2.name()); + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ + PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, acc_d_a1.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "acc_d_a2"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_d_a2.name()); + return -1; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_d_a2.name()); + return -1; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getAccDA2().extent(0)) { + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccDA2().extent(0), input->shape[0], acc_d_a2.name()); + return -1; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "acc_d_a2"); if (!b) return -1; self->cxx->setAccDA2(*b); return 0; @@ -435,42 +539,42 @@ static PyGetSetDef PyBobLearnEMJFATrainer_getseters[] = { { acc_v_a1.name(), (getter)PyBobLearnEMJFATrainer_get_acc_v_a1, - (setter)PyBobLearnEMJFATrainer_get_acc_v_a1, + (setter)PyBobLearnEMJFATrainer_set_acc_v_a1, acc_v_a1.doc(), 0 }, { acc_v_a2.name(), (getter)PyBobLearnEMJFATrainer_get_acc_v_a2, - (setter)PyBobLearnEMJFATrainer_get_acc_v_a2, + (setter)PyBobLearnEMJFATrainer_set_acc_v_a2, acc_v_a2.doc(), 0 }, { acc_u_a1.name(), (getter)PyBobLearnEMJFATrainer_get_acc_u_a1, - (setter)PyBobLearnEMJFATrainer_get_acc_u_a1, + (setter)PyBobLearnEMJFATrainer_set_acc_u_a1, acc_u_a1.doc(), 0 }, { acc_u_a2.name(), (getter)PyBobLearnEMJFATrainer_get_acc_u_a2, - (setter)PyBobLearnEMJFATrainer_get_acc_u_a2, + (setter)PyBobLearnEMJFATrainer_set_acc_u_a2, acc_u_a2.doc(), 0 }, { acc_d_a1.name(), (getter)PyBobLearnEMJFATrainer_get_acc_d_a1, - (setter)PyBobLearnEMJFATrainer_get_acc_d_a1, + (setter)PyBobLearnEMJFATrainer_set_acc_d_a1, acc_d_a1.doc(), 0 }, { acc_d_a2.name(), (getter)PyBobLearnEMJFATrainer_get_acc_d_a2, - (setter)PyBobLearnEMJFATrainer_get_acc_d_a2, + (setter)PyBobLearnEMJFATrainer_set_acc_d_a2, acc_d_a2.doc(), 0 }, diff --git a/bob/learn/em/kmeans_machine.cpp b/bob/learn/em/kmeans_machine.cpp index a7bca52..e00d40a 100644 --- a/bob/learn/em/kmeans_machine.cpp +++ b/bob/learn/em/kmeans_machine.cpp @@ -198,13 +198,30 @@ PyObject* PyBobLearnEMKMeansMachine_getMeans(PyBobLearnEMKMeansMachineObject* se } int PyBobLearnEMKMeansMachine_setMeans(PyBobLearnEMKMeansMachineObject* self, PyObject* value, void*){ BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ + PyBlitzArrayObject* input; + if (!PyBlitzArray_Converter(value, &input)){ PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, means.name()); return -1; } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz(o, "means"); + auto o_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, means.name()); + return 0; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, means.name()); + return 0; + } + + if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs()) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], means.name()); + return 0; + } + + auto b = PyBlitzArrayCxx_AsBlitz(input, "means"); if (!b) return -1; self->cxx->setMeans(*b); return 0; @@ -405,6 +422,22 @@ static PyObject* PyBobLearnEMKMeansMachine_set_mean(PyBobLearnEMKMeansMachineObj //protects acquired resources through this scope auto mean_ = make_safe(mean); + // perform check on the input + if (mean->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, set_mean.name()); + return 0; + } + + if (mean->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, set_mean.name()); + return 0; + } + + if (mean->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), mean->shape[0], set_mean.name()); + return 0; + } + //setting the mean self->cxx->setMean(i, *PyBlitzArrayCxx_AsBlitz(mean)); @@ -439,7 +472,23 @@ static PyObject* PyBobLearnEMKMeansMachine_get_distance_from_mean(PyBobLearnEMKM //protects acquired resources through this scope auto input_ = make_safe(input); + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_distance_from_mean.name()); + return 0; + } + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_distance_from_mean.name()); + return 0; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], get_distance_from_mean.name()); + return 0; + } + double output = self->cxx->getDistanceFromMean(*PyBlitzArrayCxx_AsBlitz(input),i); return Py_BuildValue("d", output); @@ -470,6 +519,23 @@ static PyObject* PyBobLearnEMKMeansMachine_get_closest_mean(PyBobLearnEMKMeansMa size_t closest_mean = 0; double min_distance = -1; + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_closest_mean.name()); + return 0; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_closest_mean.name()); + return 0; + } + + if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], get_closest_mean.name()); + return 0; + } + self->cxx->getClosestMean(*PyBlitzArrayCxx_AsBlitz(input), closest_mean, min_distance); return Py_BuildValue("(i,d)", closest_mean, min_distance); @@ -498,8 +564,24 @@ static PyObject* PyBobLearnEMKMeansMachine_get_min_distance(PyBobLearnEMKMeansMa //protects acquired resources through this scope auto input_ = make_safe(input); + double min_distance = 0; + + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_min_distance.name()); + return 0; + } + + if (input->ndim != 1){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_min_distance.name()); + return 0; + } - double min_distance = 0; + if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ + PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], get_min_distance.name()); + return 0; + } + min_distance = self->cxx->getMinDistance(*PyBlitzArrayCxx_AsBlitz(input)); return Py_BuildValue("d", min_distance); @@ -530,6 +612,22 @@ static PyObject* PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cl //protects acquired resources through this scope auto input_ = make_safe(input); + // perform check on the input + if (input->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_variances_and_weights_for_each_cluster.name()); + return 0; + } + + if (input->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_variances_and_weights_for_each_cluster.name()); + return 0; + } + + if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs() ) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[1], get_variances_and_weights_for_each_cluster.name()); + return 0; + } + blitz::Array variances(self->cxx->getNMeans(),self->cxx->getNInputs()); blitz::Array weights(self->cxx->getNMeans()); diff --git a/bob/learn/em/kmeans_trainer.cpp b/bob/learn/em/kmeans_trainer.cpp index 13833e0..a55ee12 100644 --- a/bob/learn/em/kmeans_trainer.cpp +++ b/bob/learn/em/kmeans_trainer.cpp @@ -329,6 +329,22 @@ static PyObject* PyBobLearnEMKMeansTrainer_initialize(PyBobLearnEMKMeansTrainerO &PyBlitzArray_Converter, &data, &PyBoostMt19937_Type, &rng)) return 0; auto data_ = make_safe(data); + + // perform check on the input + if (data->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, initialize.name()); + return 0; + } + + if (data->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, initialize.name()); + return 0; + } + + if (data->shape[1] != (Py_ssize_t)kmeans_machine->cxx->getNInputs() ) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, kmeans_machine->cxx->getNInputs(), data->shape[1], initialize.name()); + return 0; + } if(rng){ boost::shared_ptr rng_cpy = (boost::shared_ptr)new boost::mt19937(*rng->rng); @@ -367,6 +383,21 @@ static PyObject* PyBobLearnEMKMeansTrainer_eStep(PyBobLearnEMKMeansTrainerObject &PyBlitzArray_Converter, &data)) return 0; auto data_ = make_safe(data); + if (data->type_num != NPY_FLOAT64){ + PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, eStep.name()); + return 0; + } + + if (data->ndim != 2){ + PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, eStep.name()); + return 0; + } + + if (data->shape[1] != (Py_ssize_t)kmeans_machine->cxx->getNInputs() ) { + PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, kmeans_machine->cxx->getNInputs(), data->shape[1], eStep.name()); + return 0; + } + self->cxx->eStep(*kmeans_machine->cxx, *PyBlitzArrayCxx_AsBlitz(data));