1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Python Wrapper
3  * Title:        cmsismodule.h
4  * Description:  C code for the CMSIS-DSP Python wrapper
5  *
6  * $Date:        27 April 2021
7  * $Revision:    V1.0
8  *
9  * Target Processor: Cortex-M cores
10  * -------------------------------------------------------------------- */
11 /*
12  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the License); you may
17  * not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  * www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  */
28 
29 #define MODNAME "cmsisdsp_distance"
30 #define MODINITNAME cmsisdsp_distance
31 
32 #include "cmsisdsp_module.h"
33 MATRIXFROMNUMPY(f32,float32_t,double,NPY_DOUBLE);
34 CREATEMATRIX(f32,float32_t);
35 NUMPYARRAYFROMMATRIX(f32,NPY_FLOAT);
36 
37 MATRIXFROMNUMPY(q7,q7_t,int8_t,NPY_BYTE);
38 CREATEMATRIX(q7,q7_t);
39 NUMPYARRAYFROMMATRIX(q7,NPY_BYTE);
40 
41 
42 NUMPYVECTORFROMBUFFER(f32,float32_t,NPY_FLOAT);
43 
44 
typeRegistration(PyObject * module)45 void typeRegistration(PyObject *module) {
46 
47 
48 }
49 
50 #define FLOATDIST(NAME)                                                \
51 static PyObject *                                                      \
52 cmsis_arm_##NAME##_f32(PyObject *obj, PyObject *args)                  \
53 {                                                                      \
54                                                                        \
55   PyObject *pSrcA=NULL;                                                \
56   float32_t *pSrcA_converted=NULL;                                     \
57   PyObject *pSrcB=NULL;                                                \
58   float32_t *pSrcB_converted=NULL;                                     \
59   uint32_t blockSize;                                                  \
60   float32_t result;                                               \
61                                                                        \
62   if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB))                       \
63   {                                                                    \
64                                                                        \
65     GETARGUMENT(pSrcA,NPY_DOUBLE,double,float32_t);                    \
66     GETARGUMENT(pSrcB,NPY_DOUBLE,double,float32_t);                    \
67     blockSize = arraySizepSrcA ;                                       \
68                                                                        \
69                                                                        \
70                                                                        \
71     result=arm_##NAME##_f32(pSrcA_converted,pSrcB_converted,blockSize);\
72     PyObject* resultOBJ=Py_BuildValue("f",result);                     \
73                                                                        \
74     PyObject *pythonResult = Py_BuildValue("O",resultOBJ);             \
75                                                                        \
76     FREEARGUMENT(pSrcA_converted);                                     \
77     FREEARGUMENT(pSrcB_converted);                                     \
78     Py_DECREF(resultOBJ);                                              \
79     return(pythonResult);                                              \
80                                                                        \
81   }                                                                    \
82   return(NULL);                                                        \
83 }
84 
85 #define FLOAT64DIST(NAME)                                                \
86 static PyObject *                                                      \
87 cmsis_arm_##NAME##_f64(PyObject *obj, PyObject *args)                  \
88 {                                                                      \
89                                                                        \
90   PyObject *pSrcA=NULL;                                                \
91   float64_t *pSrcA_converted=NULL;                                     \
92   PyObject *pSrcB=NULL;                                                \
93   float64_t *pSrcB_converted=NULL;                                     \
94   uint32_t blockSize;                                                  \
95   float64_t result;                                               \
96                                                                        \
97   if (PyArg_ParseTuple(args,"OO",&pSrcA,&pSrcB))                       \
98   {                                                                    \
99                                                                        \
100     GETARGUMENT(pSrcA,NPY_DOUBLE,double,float64_t);                    \
101     GETARGUMENT(pSrcB,NPY_DOUBLE,double,float64_t);                    \
102     blockSize = arraySizepSrcA ;                                       \
103                                                                        \
104                                                                        \
105                                                                        \
106     result=arm_##NAME##_f64(pSrcA_converted,pSrcB_converted,blockSize);\
107     PyObject* resultOBJ=Py_BuildValue("d",result);                     \
108                                                                        \
109     PyObject *pythonResult = Py_BuildValue("O",resultOBJ);             \
110                                                                        \
111     FREEARGUMENT(pSrcA_converted);                                     \
112     FREEARGUMENT(pSrcB_converted);                                     \
113     Py_DECREF(resultOBJ);                                              \
114     return(pythonResult);                                              \
115                                                                        \
116   }                                                                    \
117   return(NULL);                                                        \
118 }
119 
120 FLOAT64DIST(chebyshev_distance);
121 FLOAT64DIST(cityblock_distance);
122 FLOAT64DIST(cosine_distance);
123 FLOAT64DIST(euclidean_distance);
124 
125 
126 FLOATDIST(braycurtis_distance);
127 FLOATDIST(canberra_distance);
128 FLOATDIST(chebyshev_distance);
129 FLOATDIST(cityblock_distance);
130 FLOATDIST(correlation_distance);
131 FLOATDIST(cosine_distance);
132 FLOATDIST(euclidean_distance);
133 FLOATDIST(jensenshannon_distance);
134 
135 static PyObject *
cmsis_arm_minkowski_distance_f32(PyObject * obj,PyObject * args)136 cmsis_arm_minkowski_distance_f32(PyObject *obj, PyObject *args)
137 {
138 
139   PyObject *pSrcA=NULL;
140   float32_t *pSrcA_converted=NULL;
141   PyObject *pSrcB=NULL;
142   float32_t *pSrcB_converted=NULL;
143   int32_t w;
144   uint32_t blockSize;
145   float32_t result;
146 
147   if (PyArg_ParseTuple(args,"OOi",&pSrcA,&pSrcB,&w))
148   {
149 
150     GETARGUMENT(pSrcA,NPY_DOUBLE,double,float32_t);
151     GETARGUMENT(pSrcB,NPY_DOUBLE,double,float32_t);
152 
153     blockSize = arraySizepSrcA ;
154 
155 
156 
157     result=arm_minkowski_distance_f32(pSrcA_converted,pSrcB_converted,w,blockSize);
158     PyObject* resultOBJ=Py_BuildValue("f",result);
159 
160     PyObject *pythonResult = Py_BuildValue("O",resultOBJ);
161 
162     FREEARGUMENT(pSrcA_converted);
163     FREEARGUMENT(pSrcB_converted);
164 
165     Py_DECREF(resultOBJ);
166     return(pythonResult);
167 
168   }
169   return(NULL);
170 }
171 
172 
173 #define INTDIST(NAME)                                               \
174 static PyObject *                                                   \
175 cmsis_arm_##NAME (PyObject *obj, PyObject *args)                   \
176 {                                                                   \
177                                                                     \
178   PyObject *pSrcA=NULL;                                             \
179   uint32_t *pSrcA_converted=NULL;                                   \
180   PyObject *pSrcB=NULL;                                             \
181   uint32_t *pSrcB_converted=NULL;                                   \
182   uint32_t blockSize;                                               \
183   float32_t result;                                            \
184                                                                     \
185                                                                     \
186   if (PyArg_ParseTuple(args,"OOi",&pSrcA,&pSrcB,&blockSize))        \
187   {                                                                 \
188                                                                     \
189     GETARGUMENT(pSrcA,NPY_UINT32,uint32_t,uint32_t);                \
190     GETARGUMENT(pSrcB,NPY_UINT32,uint32_t,uint32_t);                \
191                                                                     \
192                                                                     \
193                                                                     \
194     result=arm_##NAME (pSrcA_converted,pSrcB_converted,blockSize); \
195     PyObject* resultOBJ=Py_BuildValue("f",result);                  \
196                                                                     \
197     PyObject *pythonResult = Py_BuildValue("O",resultOBJ);          \
198                                                                     \
199     FREEARGUMENT(pSrcA_converted);                                  \
200     FREEARGUMENT(pSrcB_converted);                                  \
201     Py_DECREF(resultOBJ);                                           \
202     return(pythonResult);                                           \
203                                                                     \
204   }                                                                 \
205   return(NULL);                                                     \
206 }
207 
208 
209 INTDIST(dice_distance);
210 INTDIST(hamming_distance);
211 INTDIST(jaccard_distance);
212 INTDIST(kulsinski_distance);
213 INTDIST(rogerstanimoto_distance);
214 INTDIST(russellrao_distance);
215 INTDIST(sokalmichener_distance);
216 INTDIST(sokalsneath_distance);
217 INTDIST(yule_distance);
218 
219 static PyObject *
cmsis_arm_dtw_init_window_q7(PyObject * obj,PyObject * args)220 cmsis_arm_dtw_init_window_q7(PyObject *obj,
221                              PyObject *args)
222 {
223 
224   PyObject *pSrc=NULL; // input
225   int32_t winType;
226   int32_t winSize;
227   arm_matrix_instance_q7 pSrc_converted; // input
228 
229 
230   if (PyArg_ParseTuple(args,"iiO",&winType,&winSize,&pSrc))
231   {
232 
233     q7MatrixFromNumpy(&pSrc_converted,pSrc);
234     uint32_t row = pSrc_converted.numCols ;
235     uint32_t column = pSrc_converted.numRows ;
236 
237     arm_status returnValue =
238     arm_dtw_init_window_q7(winType,
239                            winSize,
240                            &pSrc_converted
241                            );
242     PyObject* theReturnOBJ=Py_BuildValue("i",returnValue);
243     PyObject* dstOBJ=NumpyArrayFromq7Matrix(&pSrc_converted);
244 
245     PyObject *pythonResult = Py_BuildValue("OO",theReturnOBJ,dstOBJ);
246 
247     Py_DECREF(theReturnOBJ);
248     Py_DECREF(dstOBJ);
249     return(pythonResult);
250 
251   }
252   Py_RETURN_NONE;
253 }
254 
255 static PyObject *
cmsis_arm_dtw_distance_f32(PyObject * obj,PyObject * args)256 cmsis_arm_dtw_distance_f32(PyObject *obj,
257                     PyObject *args)
258 {
259 
260   PyObject *pDist=NULL; // input
261   arm_matrix_instance_f32 pDist_converted; // input
262 
263   PyObject *pWin=NULL; // input
264   arm_matrix_instance_q7 pWin_converted; // input
265   arm_matrix_instance_q7 *pWinMatrix;
266 
267   arm_matrix_instance_f32 dtw_converted;
268 
269 
270   if (PyArg_ParseTuple(args,"OO",&pDist,&pWin))
271   {
272 
273     f32MatrixFromNumpy(&pDist_converted,pDist);
274     if (pWin != Py_None)
275     {
276        q7MatrixFromNumpy(&pWin_converted,pWin);
277        pWinMatrix = &pWin_converted;
278     }
279     else
280     {
281         pWinMatrix = NULL;
282     }
283 
284     uint32_t column = pDist_converted.numCols ;
285     uint32_t row = pDist_converted.numRows ;
286     createf32Matrix(&dtw_converted,row,column);
287     float32_t distance;
288 
289     arm_status returnValue =
290     arm_dtw_distance_f32(&pDist_converted,
291                          pWinMatrix,
292                          &dtw_converted,
293                          &distance
294                          );
295 
296 
297     PyObject* theReturnOBJ=Py_BuildValue("i",returnValue);
298     PyObject* distOBJ=Py_BuildValue("f",distance);
299 
300     PyObject* dstOBJ=NumpyArrayFromf32Matrix(&dtw_converted);
301 
302 
303     PyObject *pythonResult = Py_BuildValue("OOO",theReturnOBJ,distOBJ,dstOBJ);
304 
305     Py_DECREF(theReturnOBJ);
306     Py_DECREF(distOBJ);
307 
308     FREEMATRIX(&pDist_converted);
309     if (pWinMatrix)
310     {
311         FREEMATRIX(pWinMatrix);
312     }
313     Py_DECREF(dstOBJ);
314 
315     return(pythonResult);
316 
317   }
318   Py_RETURN_NONE;
319 }
320 
321 static PyObject *
cmsis_arm_dtw_path_f32(PyObject * obj,PyObject * args)322 cmsis_arm_dtw_path_f32(PyObject *obj,
323                        PyObject *args)
324 {
325   PyObject *pCost=NULL; // input
326   arm_matrix_instance_f32 pCost_converted; // input
327   int16_t *pDst=NULL; // output
328 
329   if (PyArg_ParseTuple(args,"O",&pCost))
330   {
331      f32MatrixFromNumpy(&pCost_converted,pCost);
332 
333      uint32_t pathLength;
334      int32_t blockSize;
335      blockSize=2*(pCost_converted.numRows+pCost_converted.numCols);
336      pDst=PyMem_Malloc(sizeof(int16_t)*blockSize);
337 
338 
339      arm_dtw_path_f32(&pCost_converted,
340                       pDst,
341                       &pathLength);
342 
343      INT16ARRAY1(pDstOBJ,2*pathLength,pDst);
344 
345      PyObject *pythonResult = Py_BuildValue("O",pDstOBJ);
346 
347      FREEMATRIX(&pCost_converted);
348      Py_DECREF(pDstOBJ);
349      return(pythonResult);
350   }
351   Py_RETURN_NONE;
352 }
353 
354 static PyMethodDef CMSISDSPMethods[] = {
355 
356     {"arm_braycurtis_distance_f32",  cmsis_arm_braycurtis_distance_f32, METH_VARARGS,""},
357     {"arm_canberra_distance_f32"  ,  cmsis_arm_canberra_distance_f32, METH_VARARGS,""},
358     {"arm_chebyshev_distance_f32" ,  cmsis_arm_chebyshev_distance_f32, METH_VARARGS,""},
359     {"arm_chebyshev_distance_f64" ,  cmsis_arm_chebyshev_distance_f64, METH_VARARGS,""},
360 
361     {"arm_cityblock_distance_f32",  cmsis_arm_cityblock_distance_f32, METH_VARARGS,""},
362     {"arm_cityblock_distance_f64",  cmsis_arm_cityblock_distance_f64, METH_VARARGS,""},
363 
364     {"arm_correlation_distance_f32",  cmsis_arm_correlation_distance_f32, METH_VARARGS,""},
365 
366     {"arm_cosine_distance_f32",  cmsis_arm_cosine_distance_f32, METH_VARARGS,""},
367     {"arm_cosine_distance_f64",  cmsis_arm_cosine_distance_f64, METH_VARARGS,""},
368 
369     {"arm_euclidean_distance_f32",  cmsis_arm_euclidean_distance_f32, METH_VARARGS,""},
370     {"arm_euclidean_distance_f64",  cmsis_arm_euclidean_distance_f64, METH_VARARGS,""},
371 
372     {"arm_jensenshannon_distance_f32",  cmsis_arm_jensenshannon_distance_f32, METH_VARARGS,""},
373     {"arm_minkowski_distance_f32",  cmsis_arm_minkowski_distance_f32, METH_VARARGS,""},
374 
375     {"arm_dice_distance",cmsis_arm_dice_distance, METH_VARARGS,""},
376     {"arm_hamming_distance",cmsis_arm_hamming_distance, METH_VARARGS,""},
377     {"arm_jaccard_distance",cmsis_arm_jaccard_distance, METH_VARARGS,""},
378     {"arm_kulsinski_distance",cmsis_arm_kulsinski_distance, METH_VARARGS,""},
379     {"arm_rogerstanimoto_distance",cmsis_arm_rogerstanimoto_distance, METH_VARARGS,""},
380     {"arm_russellrao_distance",cmsis_arm_russellrao_distance, METH_VARARGS,""},
381     {"arm_sokalmichener_distance",cmsis_arm_sokalmichener_distance, METH_VARARGS,""},
382     {"arm_sokalsneath_distance",cmsis_arm_sokalsneath_distance, METH_VARARGS,""},
383     {"arm_yule_distance",cmsis_arm_yule_distance, METH_VARARGS,""},
384 
385     {"arm_dtw_init_window_q7",  cmsis_arm_dtw_init_window_q7, METH_VARARGS,""},
386     {"arm_dtw_distance_f32",  cmsis_arm_dtw_distance_f32, METH_VARARGS,""},
387     {"arm_dtw_path_f32",  cmsis_arm_dtw_path_f32, METH_VARARGS,""},
388 
389     {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
390     {NULL, NULL, 0, NULL}        /* Sentinel */
391 };
392 
393 #ifdef IS_PY3K
cmsisdsp_traverse(PyObject * m,visitproc visit,void * arg)394 static int cmsisdsp_traverse(PyObject *m, visitproc visit, void *arg) {
395     Py_VISIT(GETSTATE(m)->error);
396     return 0;
397 }
398 
cmsisdsp_clear(PyObject * m)399 static int cmsisdsp_clear(PyObject *m) {
400     Py_CLEAR(GETSTATE(m)->error);
401     return 0;
402 }
403 
404 
405 static struct PyModuleDef moduledef = {
406         PyModuleDef_HEAD_INIT,
407         MODNAME,
408         NULL,
409         sizeof(struct module_state),
410         CMSISDSPMethods,
411         NULL,
412         cmsisdsp_traverse,
413         cmsisdsp_clear,
414         NULL
415 };
416 
417 #define INITERROR return NULL
418 
419 PyMODINIT_FUNC
CAT(PyInit_,MODINITNAME)420 CAT(PyInit_,MODINITNAME)(void)
421 
422 
423 #else
424 #define INITERROR return
425 
426 void CAT(init,MODINITNAME)(void)
427 #endif
428 {
429     import_array();
430 
431   #ifdef IS_PY3K
432     PyObject *module = PyModule_Create(&moduledef);
433   #else
434     PyObject *module = Py_InitModule(MODNAME, CMSISDSPMethods);
435   #endif
436 
437   if (module == NULL)
438       INITERROR;
439   struct module_state *st = GETSTATE(module);
440 
441   st->error = PyErr_NewException(MODNAME".Error", NULL, NULL);
442   if (st->error == NULL) {
443       Py_DECREF(module);
444       INITERROR;
445   }
446 
447 
448   typeRegistration(module);
449 
450   #ifdef IS_PY3K
451     return module;
452   #endif
453 }
454