From 86424e696cf19d4d44c9a01ab68ea4c028daaf42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20Bla=C3=9F?= <michael.blass@uni-hamburg.de>
Date: Sat, 2 Mar 2019 10:26:11 +0100
Subject: [PATCH] Finished

---
 hmm/hmm_module.bckp.c | 161 ------------------------------------------
 hmm/hmm_module.c      | 105 ++++++++++-----------------
 include/hmm_module.h  |  18 +++++
 test.py               |  12 ++--
 4 files changed, 62 insertions(+), 234 deletions(-)
 delete mode 100644 hmm/hmm_module.bckp.c

diff --git a/hmm/hmm_module.bckp.c b/hmm/hmm_module.bckp.c
deleted file mode 100644
index bf53d68..0000000
--- a/hmm/hmm_module.bckp.c
+++ /dev/null
@@ -1,161 +0,0 @@
-#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
-
-#include "hmm_module.h"
-
-
-static PyObject *
-hmm_poisson_fit(PyObject* self, PyObject* args)
-{
-	/* 1. alloc alpha, beta, pprob
-	 * 2. call fwbw
-	 * 3. wrap alpha, beta, pprob in arrays
-	 * 4. return the arrays  */
-	Py_RETURN_NONE;
-}
-
-
-static PyObject *
-hmm_poisson_EM(PyObject* self, PyObject* args)
-{
-	PyArrayObject	*x		= NULL;
-	PyArrayObject	*_lambda= NULL;
-	PyArrayObject	*_gamma	= NULL;
-	PyArrayObject	*_delta	= NULL;
-	npy_intp		max_iter= 0;
-	double			tol		= 0;
-
-	if (!PyArg_ParseTuple(args, "OOOOld", &x, &_lambda, &_gamma,
-		&_delta, &max_iter, &tol)) return NULL;
-
-	npy_intp n = PyArray_SIZE(x);
-	npy_intp m = PyArray_SIZE(_lambda);
-
-	PoissonHMM *hmm	= NewPoissonHMM( m,
-						PyArray_DATA(_lambda),
-						PyArray_DATA(_gamma),
-						PyArray_DATA(_delta),
-						(size_t) max_iter, (scalar) tol);
-
-	int success = poisson_expectation_maximization(PyArray_DATA(x),
-												   (size_t) n, hmm);
-
-	if (success == 1)
-	{
-		npy_intp	dims_1d[]	= { m };
-		npy_intp	dims_2d[]	= { m, m };
-		size_t		v_size		= (size_t) m * sizeof(scalar);
-		size_t		m_size		= (size_t) m * v_size;
-
-		PyArrayObject *lambda_	= Apollon_NewPyArray1d(dims_1d);
-		PyArrayObject *gamma_	= Apollon_NewPyArray2d(dims_2d);
-		PyArrayObject *delta_	= Apollon_NewPyArray1d(dims_1d);
-
-		scalar *data = PyArray_DATA(lambda_);
-		memcpy (PyArray_DATA(lambda_), hmm->lambda_, v_size);	
-		memcpy (PyArray_DATA(gamma_), hmm->gamma_,  m_size);	
-		memcpy (PyArray_DATA(delta_), hmm->delta_, v_size);
-
-		for (npy_intp i = 0; i < m; i++)
-			fprintf(stdout, "%Lf\t", data[i]);
-
-		hmm->aic = compute_aic(hmm->nll, m,  n);
-		hmm->bic = compute_bic(hmm->nll, m,  n);
-
-		PyObject *out = PyTuple_Pack(7, lambda_, gamma_, delta_, 
-						   PyFloat_FromDouble(hmm->aic), PyFloat_FromDouble(hmm->bic),
-						   PyFloat_FromDouble(hmm->nll), PyLong_FromSize_t(hmm->n_iter));
-
-		Py_INCREF(out);
-		DeletePoissonHMM(hmm);
-		return out;
-	}
-	else
-	{
-		DeletePoissonHMM(hmm);
-		PyErr_SetString(PyExc_ValueError, "Training failed.");
-		Py_RETURN_NONE;
-	}
-}
-
-
-static PyObject *
-hmm_poisson_fwbw(PyObject* self, PyObject* args)
-{
-	PyArrayObject	*x		= NULL;
-	PyArrayObject	*lambda_= NULL;
-	PyArrayObject	*gamma_	= NULL;
-	PyArrayObject	*delta_	= NULL;
-
-	if (!PyArg_ParseTuple(args, "OOOO", &x, &lambda_, &gamma_, &delta_))
-		return NULL;
-
-	npy_intp 	n 		= PyArray_SIZE(x);
-	npy_intp	m 		= PyArray_SIZE(lambda_);
-	npy_intp	dims[]	= { n, m };
-
-	PyArrayObject *alpha	= Apollon_NewPyArray2d(dims);
-	PyArrayObject *beta		= Apollon_NewPyArray2d(dims);
-	PyArrayObject *lp_prob	= Apollon_NewPyArray2d(dims);
-							  
-	int success = log_poisson_forward_backward (PyArray_DATA(x),
-												(size_t) n, (size_t) m,
-						    					PyArray_DATA(lambda_),
-												PyArray_DATA(gamma_),
-												PyArray_DATA(delta_),
-						    					PyArray_DATA(alpha),
-												PyArray_DATA(beta),
-												PyArray_DATA(lp_prob));
-
-	if (success == 1)
-	{
-		PyObject *out = PyTuple_Pack(3, alpha, beta, lp_prob);
-		Py_INCREF(out);
-		return out;
-	}
-	else
-	{
-		PyErr_SetString(PyExc_RuntimeError, "Training failed.");
-		Py_RETURN_NONE;
-	}
-}
-
-
-static PyObject *
-hmm_poisson_viterbi(PyObject* self, PyObject* args)
-{
-	Py_RETURN_NONE;
-}
-
-static PyMethodDef
-HMM_Methods[] = {
-    {"hmm_poisson_fit", hmm_poisson_fit, METH_VARARGS, 
-	 "hmm_poisson_fit(x, m, _lambda, _gamma, _delta, max_iter, tol)"},
-	
-	{"hmm_poisson_EM", hmm_poisson_EM, METH_VARARGS,
-	 "docstring"},
-
-	{"hmm_poisson_fwbw", hmm_poisson_fwbw, METH_VARARGS,
-	 "docstring"},
-
-	{"hmm_poisson_viterbi", hmm_poisson_viterbi, METH_VARARGS,
-	 "docstring"},
-
-    {NULL, NULL, 0, NULL}
-};
-
-static struct PyModuleDef
-hmm_module = {
-    PyModuleDef_HEAD_INIT,
-    "hmm",
-    NULL,
-    -1,
-	HMM_Methods
-};
-
-PyMODINIT_FUNC
-PyInit_hmm(void)
-{
-    import_array();
-    return PyModule_Create (&hmm_module);
-}
-
diff --git a/hmm/hmm_module.c b/hmm/hmm_module.c
index 045177f..96a63f3 100644
--- a/hmm/hmm_module.c
+++ b/hmm/hmm_module.c
@@ -4,42 +4,32 @@
 
 
 static PyObject *
-hmm_poisson_fit(PyObject* self, PyObject* args)
+hmm_poisson_fit_em (PyObject *self, PyObject *args)
 {
-    /* 1. alloc alpha, beta, pprob
-     * 2. call fwbw
-     * 3. wrap alpha, beta, pprob in arrays
-     * 4. return the arrays  */
-    Py_RETURN_NONE;
-}
-
-
-static PyObject *
-hmm_poisson_EM(PyObject* self, PyObject* args)
-{
-    PyObject *py_X      = NULL;
+    PyObject *py_Xtrain = NULL;
     PyObject *py_lambda = NULL;
     PyObject *py_gamma  = NULL;
     PyObject *py_delta  = NULL;
+    npy_intp m_states   = 0;
     npy_intp max_iter   = 0;
     double   tol        = 0.0;
 
-    PyArrayObject *X       = NULL;
+    PyArrayObject *X_t     = NULL;
     PyArrayObject *_lambda = NULL;
     PyArrayObject *_gamma  = NULL;
     PyArrayObject *_delta  = NULL;
 
-    if (!PyArg_ParseTuple(args, "OOOOld", &py_X, &py_lambda, &py_gamma,
+    if (!PyArg_ParseTuple(args, "OlOOOld", &py_Xtrain, &m_states, &py_lambda, &py_gamma,
         &py_delta, &max_iter, &tol)) return NULL;
 
-    X       = (PyArrayObject *) PyArray_FROM_OTF(py_X, NPY_LONG, NPY_ARRAY_IN_ARRAY);
+    X_t     = (PyArrayObject *) PyArray_FROM_OTF(py_Xtrain, NPY_LONG,       NPY_ARRAY_IN_ARRAY);
     _lambda = (PyArrayObject *) PyArray_FROM_OTF(py_lambda, NPY_LONGDOUBLE, NPY_ARRAY_IN_ARRAY);
-    _gamma  = (PyArrayObject *) PyArray_FROM_OTF(py_gamma, NPY_LONGDOUBLE, NPY_ARRAY_IN_ARRAY);
-    _delta  = (PyArrayObject *) PyArray_FROM_OTF(py_delta, NPY_LONGDOUBLE, NPY_ARRAY_IN_ARRAY);
+    _gamma  = (PyArrayObject *) PyArray_FROM_OTF(py_gamma,  NPY_LONGDOUBLE, NPY_ARRAY_IN_ARRAY);
+    _delta  = (PyArrayObject *) PyArray_FROM_OTF(py_delta,  NPY_LONGDOUBLE, NPY_ARRAY_IN_ARRAY);
 
-    if (X == NULL || _lambda == NULL || _gamma == NULL || _delta == NULL)
+    if (X_t == NULL || _lambda == NULL || _gamma == NULL || _delta == NULL)
     {
-        Py_XDECREF (X);
+        Py_XDECREF (X_t);
         Py_XDECREF (_lambda);
         Py_XDECREF (_gamma);
         Py_XDECREF (_delta);
@@ -47,16 +37,15 @@ hmm_poisson_EM(PyObject* self, PyObject* args)
         Py_RETURN_NONE;
     }
 
-    npy_intp m = PyArray_SIZE (_lambda);
-
-    PoisHmm *ph = PoisHmm_FromData ((size_t) m,
+    PoisHmm *ph = PoisHmm_FromData ((size_t) m_states,
                             PyArray_DATA (_lambda),
                             PyArray_DATA (_gamma),
                             PyArray_DATA (_delta),
                             (size_t) max_iter, (scalar) tol);
+
     if (ph == NULL)
     {
-        Py_XDECREF (X);
+        Py_XDECREF (X_t);
         Py_XDECREF (_lambda);
         Py_XDECREF (_gamma);
         Py_XDECREF (_delta);
@@ -64,15 +53,15 @@ hmm_poisson_EM(PyObject* self, PyObject* args)
         Py_RETURN_NONE;
     }
 
-    DataSet X_train = {PyArray_DATA (X), (size_t) PyArray_SIZE (X)};
+    DataSet X_train = {PyArray_DATA (X_t), (size_t) PyArray_SIZE (X_t)};
 
-    int success = PoisHmm_EM (&X_train, ph); 
+    int success = PoisHmm_EM (&X_train, ph);
 
     {
-        npy_intp dims_1d[] = { m };
-        npy_intp dims_2d[] = { m, m };
-        size_t   vector_s  = (size_t) m * sizeof (scalar);
-        size_t   matrix_s  = (size_t) m * vector_s;
+        npy_intp dims_1d[] = { m_states };
+        npy_intp dims_2d[] = { m_states, m_states };
+        size_t   vector_s  = (size_t) m_states * sizeof (scalar);
+        size_t   matrix_s  = (size_t) m_states * vector_s;
 
         PyArrayObject *lambda_ = Apollon_NewPyArray1d (dims_1d);
         PyArrayObject *gamma_  = Apollon_NewPyArray2d (dims_2d);
@@ -86,11 +75,11 @@ hmm_poisson_EM(PyObject* self, PyObject* args)
         ph->bic = compute_bic(ph->nll, ph->m,  X_train.size);
 
         PyObject *out = NULL;
-        out = Py_BuildValue("iNNNdddk", success, lambda_, gamma_, delta_, 
+        out = Py_BuildValue("iNNNdddk", success, lambda_, gamma_, delta_,
                             (double) ph->aic, (double) ph->bic,
                             (double) ph->nll, ph->n_iter);
 
-        Py_DECREF (X);
+        Py_DECREF (X_t);
         Py_DECREF (_lambda);
         Py_DECREF (_gamma);
         Py_DECREF (_delta);
@@ -104,56 +93,38 @@ hmm_poisson_EM(PyObject* self, PyObject* args)
 static PyObject *
 hmm_poisson_fwbw(PyObject *self, PyObject *args)
 {
-    PyArrayObject *x        = NULL;
-    PyArrayObject *lambda_  = NULL;
-    PyArrayObject *gamma_   = NULL;
-    PyArrayObject *delta_   = NULL;
-
-    if (!PyArg_ParseTuple(args, "OOOO", &x, &lambda_, &gamma_, &delta_))
-        return NULL;
-
-    npy_intp    n       = PyArray_SIZE (x);
-    npy_intp    m       = PyArray_SIZE (lambda_);
-    npy_intp    dims[]  = { n, m };
-
-    PyArrayObject *alpha    = Apollon_NewPyArray2d (dims);
-    PyArrayObject *beta     = Apollon_NewPyArray2d (dims);
-    PyArrayObject *pois_pr  = Apollon_NewPyArray2d (dims);
-    
-    /*
-    if (success == 1)
-    {
-        PyObject *out = PyTuple_Pack(3, alpha, beta, lp_prob);
-        Py_INCREF(out);
-        return out;
-    }
-    else
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Training failed.");
-        Py_RETURN_NONE;
-    }
-    */
+    PyErr_SetString (PyExc_NotImplementedError, "");
+    Py_RETURN_NONE;
+}
+
+
+static PyObject *
+hmm_poisson_em (PyObject *self, PyObject *args)
+{
+    PyErr_SetString (PyExc_NotImplementedError, "");
     Py_RETURN_NONE;
 }
 
 
 static PyObject *
-hmm_poisson_viterbi(PyObject* self, PyObject* args)
+hmm_poisson_viterbi (PyObject *self, PyObject *args)
 {
+    PyErr_SetString (PyExc_NotImplementedError, "");
     Py_RETURN_NONE;
 }
 
+
 static PyMethodDef
 HMM_Methods[] = {
-    {"hmm_poisson_fit", hmm_poisson_fit, METH_VARARGS, 
-     "hmm_poisson_fit(x, m, _lambda, _gamma, _delta, max_iter, tol)"},
-    
-    {"hmm_poisson_EM", hmm_poisson_EM, METH_VARARGS,
-     "docstring"},
+    {"hmm_poisson_fit_em", hmm_poisson_fit_em, METH_VARARGS,
+     "hmm_poisson_fit_em (x, m, _lambda, _gamma, _delta, max_iter, tol)"},
 
     {"hmm_poisson_fwbw", hmm_poisson_fwbw, METH_VARARGS,
      "docstring"},
 
+    {"hmm_poisson_em", hmm_poisson_em, METH_VARARGS,
+     "docstring"},
+
     {"hmm_poisson_viterbi", hmm_poisson_viterbi, METH_VARARGS,
      "docstring"},
 
diff --git a/include/hmm_module.h b/include/hmm_module.h
index de3ff10..d07097a 100644
--- a/include/hmm_module.h
+++ b/include/hmm_module.h
@@ -23,4 +23,22 @@
                 2, shape, NULL, NULL, 0, NULL));
 
 
+/** Perform EM for given parameters. Return only fitted params. */
+static PyObject *hmm_poisson_em (PyObject* self, PyObject* args);
+
+
+/** Fit HMM for given parameters using EM. Return all params 
+ * and quality measures. 
+ */
+static PyObject *hmm_poisson_fit_em (PyObject* self, PyObject* args);
+
+
+/** Return forward backward, and state-dependent probabilites. */
+static PyObject *hmm_poisson_fwbw (PyObject *self, PyObject *args);
+
+
+/** Calculate viterbi path given HMM. */
+static PyObject *hmm_poisson_viterbi (PyObject *self, PyObject *args);
+
+
 #endif  /* hmm_module_h */
diff --git a/test.py b/test.py
index bfdb69f..e338101 100644
--- a/test.py
+++ b/test.py
@@ -2,17 +2,17 @@ import numpy as np
 import hmm
 
 x = np.random.randint(0, 500, 1000)
-
+m = 3
 l = np.array([10, 250, 450])
 g = np.array([[.8, .1, .1], [.1, .8, .1], [.1, .1, .8]])
 d = np.array([.3, .3, .3])
 
 
-(s, l_, g_, d_, aic, bic, nll, niter) = hmm.hmm_poisson_EM(x, l, g, d, 1000, 1e-6)
-print(s, aic, bic, nll, niter)
+(success, lambda_, gamma_, delta_, aic, bic, nll, niter) = hmm.hmm_poisson_fit_em(x, m, l, g, d, 1000, 1e-6)
+print(success, aic, bic, nll, niter)
 
-print(l_)
+print(lambda_)
 print("\n")
-print(g_)
+print(gamma_)
 print("\n")
-print(d_)
+print(delta_)
-- 
GitLab