-
Notifications
You must be signed in to change notification settings - Fork 18
/
dpcore_py.c
138 lines (115 loc) · 3.84 KB
/
dpcore_py.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* dpcore_py.c - calculate dynamic programming inner loop
* Python extension version
* 2014-05-30 Dan Ellis [email protected]
*/
/* see http://wiki.scipy.org/Cookbook/C_Extensions/NumPy_arrays */
#include <Python.h>
#include <numpy/arrayobject.h>
#include <math.h>
#include <numpy/npy_math.h>
static void calc_dpcore(
double *pM, /* input scores */
int rows, /* size of arrays */
int cols,
double pen, /* nondiagonal penalty score */
double *pD, /* output best-cost matrix */
int *pP /* output traceback matrix */
)
{
/* Data is passed in as pointers to contiguous, row-first memory
blocks for each array, that we interpret appropriately here */
int i, j, k, tb;
double d1, d2, d3, v;
double *costs;
int *steps;
int ncosts;
/* setup cost matrix */
int ii;
ncosts = 3;
costs = (double *)malloc(ncosts*sizeof(double));
steps = (int *)malloc(ncosts*2*sizeof(int));
steps[0] = 1; steps[1] = 1; costs[0] = 0.0;
steps[2] = 0; steps[3] = 1; costs[1] = pen;
steps[4] = 1; steps[5] = 0; costs[2] = pen;
/* do dp */
v = pM[0];
tb = 0; /* value to use for 0,0 */
for (j = 0; j < cols; ++j) {
for (i = 0; i < rows; ++i) {
d1 = pM[i*cols + j];
for (k = 0; k < ncosts; ++k) {
if ( i >= steps[2*k] && j >= steps[2*k+1] ) {
d2 = d1 + costs[k] + pD[(i-steps[2*k])*cols + (j-steps[2*k+1])];
if (d2 < v) {
v = d2;
tb = k;
}
}
}
pD[i*cols + j] = v;
pP[i*cols + j] = tb;
v = NPY_INFINITY;
}
}
free((void *)costs);
free((void *)steps);
}
//////////////////////////// python extension wrapper /////////////////////
/* ==== Check that PyArrayObject is a double (Float) type and a matrix ==========
return 1 if an error and raise exception */
int not_doublematrix(PyArrayObject *mat) {
if (mat->descr->type_num != NPY_DOUBLE || mat->nd != 2) {
PyErr_SetString(PyExc_ValueError,
"In not_doublematrix: array must be of type Float and 2 dimensional (n x m).");
return 1; }
return 0;
}
static PyObject *
dpcore_py_dpcore(PyObject *self, PyObject *args)
{
PyArrayObject *Sin, *Dout, *Pout;
double pen;
double *Sptr, *Dptr;
int *Pptr;
int nrows, ncols;
npy_intp dims[2];
/* parse input args */
if (!PyArg_ParseTuple(args, "O!d",
&PyArray_Type, &Sin, &pen))
return NULL;
if (Sin == NULL) return NULL;
/* Check that object input is 'double' type and a matrix
Not needed if python wrapper function checks before call to this routine */
if (not_doublematrix(Sin)) return NULL;
/* Get the dimension of the input */
nrows = Sin->dimensions[0];
ncols = Sin->dimensions[1];
/* Set up output matrices */
dims[0] = nrows;
dims[1] = ncols;
Dout = (PyArrayObject *)PyArray_SimpleNew(2, dims, NPY_DOUBLE);
Pout = (PyArrayObject *)PyArray_SimpleNew(2, dims, NPY_INT);
/* Change contiguous arrays into C *arrays */
Sptr = (double *)Sin->data;
Dptr = (double *)Dout->data;
Pptr = (int *)Pout->data;
/* run calculation */
calc_dpcore(Sptr, nrows, ncols, pen, Dptr, Pptr);
/* return the result */
PyObject *tupleresult = PyTuple_New(2);
PyTuple_SetItem(tupleresult, 0, PyArray_Return(Dout));
PyTuple_SetItem(tupleresult, 1, PyArray_Return(Pout));
return tupleresult;
}
/* standard hooks to Python, per http://docs.python.org/2/extending/extending.html */
static PyMethodDef DpcoreMethods[] = {
{"dpcore", dpcore_py_dpcore, METH_VARARGS},
{NULL, NULL} /* Sentinel */
};
/* ==== Initialize the C_test functions ====================== */
// Module name must be _dpcoremodule in compile and linked
void init_dpcore_py() {
(void) Py_InitModule("_dpcore_py", DpcoreMethods);
import_array(); // Must be present for NumPy. Called first after above line.
}