1 /**
2  * Author: Damian Eads
3  * Date:   September 22, 2007 (moved to new file on June 8, 2008)
4  * Adapted for incorporation into Scipy, April 9, 2008.
5  *
6  * Copyright (c) 2007, Damian Eads. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *   - Redistributions of source code must retain the above
12  *     copyright notice, this list of conditions and the
13  *     following disclaimer.
14  *   - Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer
16  *     in the documentation and/or other materials provided with the
17  *     distribution.
18  *   - Neither the name of the author nor the names of its
19  *     contributors may be used to endorse or promote products derived
20  *     from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #if !defined(__clang__) && defined(__GNUC__) && defined(__GNUC_MINOR__)
36 #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
37 /* enable auto-vectorizer */
38 #pragma GCC optimize("tree-vectorize")
39 /* float associativity required to vectorize reductions */
40 #pragma GCC optimize("unsafe-math-optimizations")
41 /* maybe 5% gain, manual unrolling with more accumulators would be better */
42 #pragma GCC optimize("unroll-loops")
43 #endif
44 #endif
45 #include <stdio.h>
46 #include <math.h>
47 #include <stdlib.h>
48 #include <Python.h>
49 #include <numpy/arrayobject.h>
50 #include <numpy/npy_math.h>
51 
52 #include "distance_impl.h"
53 
54 #define DEFINE_WRAP_CDIST(name, type)                                   \
55     static PyObject *                                                   \
56     cdist_ ## name ## _ ## type ## _wrap(PyObject *self, PyObject *args)\
57     {                                                                   \
58         PyArrayObject *XA_, *XB_, *dm_;                                 \
59         Py_ssize_t mA, mB, n;                                           \
60         double *dm;                                                     \
61         const type *XA, *XB;                                            \
62         if (!PyArg_ParseTuple(args, "O!O!O!",                           \
63                               &PyArray_Type, &XA_, &PyArray_Type, &XB_, \
64                               &PyArray_Type, &dm_)) {                   \
65             return NULL;                                                \
66         }                                                               \
67         else {                                                          \
68             NPY_BEGIN_ALLOW_THREADS;                                    \
69             XA = (const type *)XA_->data;                               \
70             XB = (const type *)XB_->data;                               \
71             dm = (double *)dm_->data;                                   \
72             mA = XA_->dimensions[0];                                    \
73             mB = XB_->dimensions[0];                                    \
74             n = XA_->dimensions[1];                                     \
75             cdist_ ## name ## _ ## type(XA, XB, dm, mA, mB, n);         \
76             NPY_END_ALLOW_THREADS;                                      \
77         }                                                               \
78         return Py_BuildValue("d", 0.);                                  \
79     }
80 
DEFINE_WRAP_CDIST(bray_curtis,double)81 DEFINE_WRAP_CDIST(bray_curtis, double)
82 DEFINE_WRAP_CDIST(canberra, double)
83 DEFINE_WRAP_CDIST(chebyshev, double)
84 DEFINE_WRAP_CDIST(city_block, double)
85 DEFINE_WRAP_CDIST(euclidean, double)
86 DEFINE_WRAP_CDIST(jaccard, double)
87 DEFINE_WRAP_CDIST(jensenshannon, double)
88 DEFINE_WRAP_CDIST(sqeuclidean, double)
89 
90 DEFINE_WRAP_CDIST(dice, char)
91 DEFINE_WRAP_CDIST(jaccard, char)
92 DEFINE_WRAP_CDIST(kulsinski, char)
93 DEFINE_WRAP_CDIST(rogerstanimoto, char)
94 DEFINE_WRAP_CDIST(russellrao, char)
95 DEFINE_WRAP_CDIST(sokalmichener, char)
96 DEFINE_WRAP_CDIST(sokalsneath, char)
97 DEFINE_WRAP_CDIST(yule, char)
98 
99 static PyObject *cdist_hamming_double_wrap(
100                             PyObject *self, PyObject *args, PyObject *kwargs)
101 {
102   PyArrayObject *XA_, *XB_, *dm_, *w_;
103   int mA, mB, n;
104   double *dm;
105   const double *XA, *XB, *w;
106   static char *kwlist[] = {"XA", "XB", "dm", "w", NULL};
107   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
108             "O!O!O!O!:cdist_hamming_double_wrap", kwlist,
109             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
110             &PyArray_Type, &dm_,
111             &PyArray_Type, &w_)) {
112     return 0;
113   }
114   else {
115     NPY_BEGIN_ALLOW_THREADS;
116     XA = (const double*)XA_->data;
117     XB = (const double*)XB_->data;
118     w = (const double*)w_->data;
119     dm = (double*)dm_->data;
120     mA = XA_->dimensions[0];
121     mB = XB_->dimensions[0];
122     n = XA_->dimensions[1];
123     cdist_hamming_double(XA, XB, dm, mA, mB, n, w);
124     NPY_END_ALLOW_THREADS;
125   }
126   return Py_BuildValue("d", 0.0);
127 }
128 
cdist_hamming_char_wrap(PyObject * self,PyObject * args,PyObject * kwargs)129 static PyObject *cdist_hamming_char_wrap(
130                             PyObject *self, PyObject *args, PyObject *kwargs)
131 {
132   PyArrayObject *XA_, *XB_, *dm_, *w_;
133   int mA, mB, n;
134   double *dm;
135   const char *XA, *XB;
136   const double *w;
137   static char *kwlist[] = {"XA", "XB", "dm", "w", NULL};
138   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
139             "O!O!O!O!:cdist_hamming_char_wrap", kwlist,
140             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
141             &PyArray_Type, &dm_,
142             &PyArray_Type, &w_)) {
143     return 0;
144   }
145   else {
146     NPY_BEGIN_ALLOW_THREADS;
147     XA = (const char*)XA_->data;
148     XB = (const char*)XB_->data;
149     w = (const double*)w_->data;
150     dm = (double*)dm_->data;
151     mA = XA_->dimensions[0];
152     mB = XB_->dimensions[0];
153     n = XA_->dimensions[1];
154     cdist_hamming_char(XA, XB, dm, mA, mB, n, w);
155     NPY_END_ALLOW_THREADS;
156   }
157   return Py_BuildValue("d", 0.0);
158 }
159 
cdist_cosine_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)160 static PyObject *cdist_cosine_double_wrap(PyObject *self, PyObject *args,
161                                                PyObject *kwargs) {
162   PyArrayObject *XA_, *XB_, *dm_;
163   int mA, mB, n, status;
164   double *dm;
165   const double *XA, *XB;
166   static char *kwlist[] = {"XA", "XB", "dm", NULL};
167   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
168             "O!O!O!:cdist_cosine_double_wrap", kwlist,
169             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
170             &PyArray_Type, &dm_))
171   {
172     return 0;
173   }
174   else {
175     NPY_BEGIN_THREADS_DEF;
176     NPY_BEGIN_THREADS;
177     XA = (const double*)XA_->data;
178     XB = (const double*)XB_->data;
179     dm = (double*)dm_->data;
180     mA = XA_->dimensions[0];
181     mB = XB_->dimensions[0];
182     n = XA_->dimensions[1];
183 
184     status = cdist_cosine(XA, XB, dm, mA, mB, n);
185     NPY_END_THREADS;
186     if(status < 0)
187         return PyErr_NoMemory();
188   }
189   return Py_BuildValue("d", 0.0);
190 }
191 
cdist_mahalanobis_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)192 static PyObject *cdist_mahalanobis_double_wrap(PyObject *self, PyObject *args,
193                                                PyObject *kwargs) {
194   PyArrayObject *XA_, *XB_, *covinv_, *dm_;
195   int mA, mB, n, status;
196   double *dm;
197   const double *XA, *XB;
198   const double *covinv;
199   static char *kwlist[] = {"XA", "XB", "dm", "VI", NULL};
200   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
201             "O!O!O!O!:cdist_mahalanobis_double_wrap", kwlist,
202             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
203             &PyArray_Type, &dm_, &PyArray_Type, &covinv_))
204   {
205     return 0;
206   }
207   else {
208     NPY_BEGIN_THREADS_DEF;
209     NPY_BEGIN_THREADS;
210     XA = (const double*)XA_->data;
211     XB = (const double*)XB_->data;
212     covinv = (const double*)covinv_->data;
213     dm = (double*)dm_->data;
214     mA = XA_->dimensions[0];
215     mB = XB_->dimensions[0];
216     n = XA_->dimensions[1];
217 
218     status = cdist_mahalanobis(XA, XB, dm, mA, mB, n, covinv);
219     NPY_END_THREADS;
220     if(status < 0)
221         return PyErr_NoMemory();
222   }
223   return Py_BuildValue("d", 0.0);
224 }
225 
cdist_minkowski_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)226 static PyObject *cdist_minkowski_double_wrap(PyObject *self, PyObject *args,
227                                              PyObject *kwargs)
228 {
229   PyArrayObject *XA_, *XB_, *dm_;
230   int mA, mB, n;
231   double *dm;
232   const double *XA, *XB;
233   double p;
234   static char *kwlist[] = {"XA", "XB", "dm", "p", NULL};
235   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
236             "O!O!O!d:cdist_minkowski_double_wrap", kwlist,
237             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
238             &PyArray_Type, &dm_,
239             &p)) {
240     return 0;
241   }
242   else {
243     NPY_BEGIN_ALLOW_THREADS;
244     XA = (const double*)XA_->data;
245     XB = (const double*)XB_->data;
246     dm = (double*)dm_->data;
247     mA = XA_->dimensions[0];
248     mB = XB_->dimensions[0];
249     n = XA_->dimensions[1];
250     cdist_minkowski(XA, XB, dm, mA, mB, n, p);
251     NPY_END_ALLOW_THREADS;
252   }
253   return Py_BuildValue("d", 0.0);
254 }
255 
cdist_seuclidean_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)256 static PyObject *cdist_seuclidean_double_wrap(PyObject *self, PyObject *args,
257                                               PyObject *kwargs)
258 {
259   PyArrayObject *XA_, *XB_, *dm_, *var_;
260   int mA, mB, n;
261   double *dm;
262   const double *XA, *XB, *var;
263   static char *kwlist[] = {"XA", "XB", "dm", "V", NULL};
264   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
265             "O!O!O!O!:cdist_seuclidean_double_wrap", kwlist,
266             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
267             &PyArray_Type, &dm_, &PyArray_Type, &var_)) {
268     return 0;
269   }
270   else {
271     NPY_BEGIN_ALLOW_THREADS;
272     XA = (const double*)XA_->data;
273     XB = (const double*)XB_->data;
274     dm = (double*)dm_->data;
275     var = (double*)var_->data;
276     mA = XA_->dimensions[0];
277     mB = XB_->dimensions[0];
278     n = XA_->dimensions[1];
279 
280     cdist_seuclidean(XA, XB, var, dm, mA, mB, n);
281     NPY_END_ALLOW_THREADS;
282   }
283   return Py_BuildValue("d", 0.0);
284 }
285 
cdist_weighted_chebyshev_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)286 static PyObject *cdist_weighted_chebyshev_double_wrap(
287     PyObject *self, PyObject *args, PyObject *kwargs)
288 {
289   PyArrayObject *XA_, *XB_, *dm_, *w_;
290   int mA, mB, n;
291   double *dm;
292   const double *XA, *XB, *w;
293   static char *kwlist[] = {"XA", "XB", "dm", "w", NULL};
294   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
295             "O!O!O!O!:cdist_weighted_chebyshev_double_wrap", kwlist,
296             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
297             &PyArray_Type, &dm_,
298             &PyArray_Type, &w_)) {
299     return 0;
300   }
301   else {
302     NPY_BEGIN_ALLOW_THREADS;
303     XA = (const double*)XA_->data;
304     XB = (const double*)XB_->data;
305     w = (const double*)w_->data;
306     dm = (double*)dm_->data;
307     mA = XA_->dimensions[0];
308     mB = XB_->dimensions[0];
309     n = XA_->dimensions[1];
310     cdist_weighted_chebyshev(XA, XB, dm, mA, mB, n, w);
311     NPY_END_ALLOW_THREADS;
312   }
313   return Py_BuildValue("d", 0.0);
314 }
315 
cdist_old_weighted_minkowski_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)316 static PyObject *cdist_old_weighted_minkowski_double_wrap(
317   PyObject *self, PyObject *args, PyObject *kwargs)
318 {
319   PyArrayObject *XA_, *XB_, *dm_, *w_;
320   int mA, mB, n;
321   double *dm;
322   const double *XA, *XB, *w;
323   double p;
324   static char *kwlist[] = {"XA", "XB", "dm", "p", "w", NULL};
325   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
326                                    "O!O!O!dO!:cdist_old_weighted_minkowski_double_wrap", kwlist,
327                                    &PyArray_Type, &XA_, &PyArray_Type, &XB_,
328                                    &PyArray_Type, &dm_,
329                                    &p,
330                                    &PyArray_Type, &w_)) {
331     return 0;
332   }
333   else {
334     int res;
335     NPY_BEGIN_ALLOW_THREADS;
336     XA = (const double*)XA_->data;
337     XB = (const double*)XB_->data;
338     w = (const double*)w_->data;
339     dm = (double*)dm_->data;
340     mA = XA_->dimensions[0];
341     mB = XB_->dimensions[0];
342     n = XA_->dimensions[1];
343     res = cdist_old_weighted_minkowski(XA, XB, dm, mA, mB, n, p, w);
344     NPY_END_ALLOW_THREADS;
345 
346     if (res) {
347       return PyErr_NoMemory();
348     }
349   }
350   return Py_BuildValue("d", 0.0);
351 }
352 
cdist_weighted_minkowski_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)353 static PyObject *cdist_weighted_minkowski_double_wrap(
354                             PyObject *self, PyObject *args, PyObject *kwargs)
355 {
356   PyArrayObject *XA_, *XB_, *dm_, *w_;
357   int mA, mB, n;
358   double *dm;
359   const double *XA, *XB, *w;
360   double p;
361   static char *kwlist[] = {"XA", "XB", "dm", "p", "w", NULL};
362   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
363             "O!O!O!dO!:cdist_weighted_minkowski_double_wrap", kwlist,
364             &PyArray_Type, &XA_, &PyArray_Type, &XB_,
365             &PyArray_Type, &dm_,
366             &p,
367             &PyArray_Type, &w_)) {
368     return 0;
369   }
370   else {
371     NPY_BEGIN_ALLOW_THREADS;
372     XA = (const double*)XA_->data;
373     XB = (const double*)XB_->data;
374     w = (const double*)w_->data;
375     dm = (double*)dm_->data;
376     mA = XA_->dimensions[0];
377     mB = XB_->dimensions[0];
378     n = XA_->dimensions[1];
379     cdist_weighted_minkowski(XA, XB, dm, mA, mB, n, p, w);
380     NPY_END_ALLOW_THREADS;
381   }
382   return Py_BuildValue("d", 0.0);
383 }
384 
385 /***************************** pdist ***/
386 
387 #define DEFINE_WRAP_PDIST(name, type)                                   \
388     static PyObject *                                                   \
389     pdist_ ## name ## _ ## type ## _wrap(PyObject *self, PyObject *args)\
390     {                                                                   \
391         PyArrayObject *X_, *dm_;                                        \
392         Py_ssize_t m, n;                                                \
393         double *dm;                                                     \
394         const type *X;                                                  \
395         if (!PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &X_,         \
396                                             &PyArray_Type, &dm_)) {     \
397             return NULL;                                                \
398         }                                                               \
399         else {                                                          \
400             NPY_BEGIN_ALLOW_THREADS;                                    \
401             X = (const type *)X_->data;                                 \
402             dm = (double *)dm_->data;                                   \
403             m = X_->dimensions[0];                                      \
404             n = X_->dimensions[1];                                      \
405             pdist_ ## name ## _ ## type(X, dm, m, n);                   \
406             NPY_END_ALLOW_THREADS;                                      \
407         }                                                               \
408         return Py_BuildValue("d", 0.);                                  \
409     }
410 
DEFINE_WRAP_PDIST(bray_curtis,double)411 DEFINE_WRAP_PDIST(bray_curtis, double)
412 DEFINE_WRAP_PDIST(canberra, double)
413 DEFINE_WRAP_PDIST(chebyshev, double)
414 DEFINE_WRAP_PDIST(city_block, double)
415 DEFINE_WRAP_PDIST(euclidean, double)
416 DEFINE_WRAP_PDIST(jaccard, double)
417 DEFINE_WRAP_PDIST(jensenshannon, double)
418 DEFINE_WRAP_PDIST(sqeuclidean, double)
419 
420 DEFINE_WRAP_PDIST(dice, char)
421 DEFINE_WRAP_PDIST(kulsinski, char)
422 DEFINE_WRAP_PDIST(jaccard, char)
423 DEFINE_WRAP_PDIST(rogerstanimoto, char)
424 DEFINE_WRAP_PDIST(russellrao, char)
425 DEFINE_WRAP_PDIST(sokalmichener, char)
426 DEFINE_WRAP_PDIST(sokalsneath, char)
427 DEFINE_WRAP_PDIST(yule, char)
428 
429 static PyObject *pdist_hamming_double_wrap(
430                             PyObject *self, PyObject *args, PyObject *kwargs)
431 {
432   PyArrayObject *X_, *dm_, *w_;
433   int m, n;
434   double *dm;
435   const double *X, *w;
436   static char *kwlist[] = {"X", "dm", "w", NULL};
437   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
438             "O!O!O!:pdist_hamming_double_wrap", kwlist,
439             &PyArray_Type, &X_,
440             &PyArray_Type, &dm_,
441             &PyArray_Type, &w_)) {
442     return 0;
443   }
444   else {
445     NPY_BEGIN_ALLOW_THREADS;
446     X = (const double*)X_->data;
447     dm = (double*)dm_->data;
448     w = (const double*)w_->data;
449     m = X_->dimensions[0];
450     n = X_->dimensions[1];
451 
452     pdist_hamming_double(X, dm, m, n, w);
453     NPY_END_ALLOW_THREADS;
454   }
455   return Py_BuildValue("d", 0.0);
456 }
457 
pdist_hamming_char_wrap(PyObject * self,PyObject * args,PyObject * kwargs)458 static PyObject *pdist_hamming_char_wrap(
459                             PyObject *self, PyObject *args, PyObject *kwargs)
460 {
461   PyArrayObject *X_, *dm_, *w_;
462   int m, n;
463   const char *X;
464   const double *w;
465   double *dm;
466   static char *kwlist[] = {"X", "dm", "w", NULL};
467   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
468             "O!O!O!:pdist_hamming_char_wrap", kwlist,
469             &PyArray_Type, &X_,
470             &PyArray_Type, &dm_,
471             &PyArray_Type, &w_)) {
472     return 0;
473   }
474   else {
475     NPY_BEGIN_ALLOW_THREADS;
476     X = (const char*)X_->data;
477     dm = (double*)dm_->data;
478     w = (const double*)w_->data;
479     m = X_->dimensions[0];
480     n = X_->dimensions[1];
481 
482     pdist_hamming_char(X, dm, m, n, w);
483     NPY_END_ALLOW_THREADS;
484   }
485   return Py_BuildValue("d", 0.0);
486 }
487 
pdist_cosine_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)488 static PyObject *pdist_cosine_double_wrap(PyObject *self, PyObject *args,
489                                           PyObject *kwargs)
490 {
491   PyArrayObject *X_, *dm_;
492   int m, n, status;
493   double *dm;
494   const double *X;
495   static char *kwlist[] = {"X", "dm", NULL};
496   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
497             "O!O!:pdist_cosine_double_wrap", kwlist,
498             &PyArray_Type, &X_,
499             &PyArray_Type, &dm_)) {
500     return 0;
501   }
502   else {
503     NPY_BEGIN_THREADS_DEF;
504     NPY_BEGIN_THREADS;
505     X = (const double*)X_->data;
506     dm = (double*)dm_->data;
507     m = X_->dimensions[0];
508     n = X_->dimensions[1];
509 
510     status = pdist_cosine(X, dm, m, n);
511     NPY_END_THREADS;
512     if(status < 0)
513         return PyErr_NoMemory();
514   }
515   return Py_BuildValue("d", 0.0);
516 }
517 
pdist_mahalanobis_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)518 static PyObject *pdist_mahalanobis_double_wrap(PyObject *self, PyObject *args,
519                                                PyObject *kwargs) {
520   PyArrayObject *X_, *covinv_, *dm_;
521   int m, n, status;
522   double *dm;
523   const double *X;
524   const double *covinv;
525   static char *kwlist[] = {"X", "dm", "VI", NULL};
526   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
527             "O!O!O!:pdist_mahalanobis_double_wrap", kwlist,
528             &PyArray_Type, &X_,
529             &PyArray_Type, &dm_,
530             &PyArray_Type, &covinv_)) {
531     return 0;
532   }
533   else {
534     NPY_BEGIN_THREADS_DEF;
535     NPY_BEGIN_THREADS;
536     X = (const double*)X_->data;
537     covinv = (const double*)covinv_->data;
538     dm = (double*)dm_->data;
539     m = X_->dimensions[0];
540     n = X_->dimensions[1];
541 
542     status = pdist_mahalanobis(X, dm, m, n, covinv);
543     NPY_END_THREADS;
544     if(status < 0)
545         return PyErr_NoMemory();
546   }
547   return Py_BuildValue("d", 0.0);
548 }
549 
pdist_minkowski_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)550 static PyObject *pdist_minkowski_double_wrap(PyObject *self, PyObject *args,
551                                              PyObject *kwargs)
552 {
553   PyArrayObject *X_, *dm_;
554   int m, n;
555   double *dm, *X;
556   double p;
557   static char *kwlist[] = {"X", "dm", "p", NULL};
558   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
559             "O!O!d:pdist_minkowski_double_wrap", kwlist,
560             &PyArray_Type, &X_,
561             &PyArray_Type, &dm_,
562             &p)) {
563     return 0;
564   }
565   else {
566     NPY_BEGIN_ALLOW_THREADS;
567     X = (double*)X_->data;
568     dm = (double*)dm_->data;
569     m = X_->dimensions[0];
570     n = X_->dimensions[1];
571 
572     pdist_minkowski(X, dm, m, n, p);
573     NPY_END_ALLOW_THREADS;
574   }
575   return Py_BuildValue("d", 0.0);
576 }
577 
pdist_seuclidean_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)578 static PyObject *pdist_seuclidean_double_wrap(PyObject *self, PyObject *args,
579                                               PyObject *kwargs)
580 {
581   PyArrayObject *X_, *dm_, *var_;
582   int m, n;
583   double *dm;
584   const double *X, *var;
585   static char *kwlist[] = {"X", "dm", "V", NULL};
586   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
587             "O!O!O!:pdist_seuclidean_double_wrap", kwlist,
588             &PyArray_Type, &X_,
589             &PyArray_Type, &dm_,
590             &PyArray_Type, &var_)) {
591     return 0;
592   }
593   else {
594     NPY_BEGIN_ALLOW_THREADS;
595     X = (double*)X_->data;
596     dm = (double*)dm_->data;
597     var = (double*)var_->data;
598     m = X_->dimensions[0];
599     n = X_->dimensions[1];
600 
601     pdist_seuclidean(X, var, dm, m, n);
602     NPY_END_ALLOW_THREADS;
603   }
604   return Py_BuildValue("d", 0.0);
605 }
606 
pdist_weighted_chebyshev_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)607 static PyObject *pdist_weighted_chebyshev_double_wrap(
608   PyObject *self, PyObject *args, PyObject *kwargs)
609 {
610   PyArrayObject *X_, *dm_, *w_;
611   int m, n;
612   double *dm, *X, *w;
613   static char *kwlist[] = {"X", "dm", "w", NULL};
614   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
615                                    "O!O!O!:pdist_weighted_minkowski_double_wrap", kwlist,
616                                    &PyArray_Type, &X_,
617                                    &PyArray_Type, &dm_,
618                                    &PyArray_Type, &w_)) {
619     return 0;
620   }
621   else {
622     NPY_BEGIN_ALLOW_THREADS;
623     X = (double*)X_->data;
624     dm = (double*)dm_->data;
625     w = (double*)w_->data;
626     m = X_->dimensions[0];
627     n = X_->dimensions[1];
628 
629     pdist_weighted_chebyshev(X, dm, m, n, w);
630     NPY_END_ALLOW_THREADS;
631   }
632   return Py_BuildValue("d", 0.0);
633 }
634 
pdist_old_weighted_minkowski_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)635 static PyObject *pdist_old_weighted_minkowski_double_wrap(
636   PyObject *self, PyObject *args, PyObject *kwargs)
637 {
638   PyArrayObject *X_, *dm_, *w_;
639   int m, n;
640   double *dm, *X, *w;
641   double p;
642   static char *kwlist[] = {"X", "dm", "p", "w", NULL};
643   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
644                                    "O!O!dO!:pdist_weighted_minkowski_double_wrap", kwlist,
645                                    &PyArray_Type, &X_,
646                                    &PyArray_Type, &dm_,
647                                    &p,
648                                    &PyArray_Type, &w_)) {
649     return 0;
650   }
651   else {
652     int res;
653     NPY_BEGIN_ALLOW_THREADS;
654     X = (double*)X_->data;
655     dm = (double*)dm_->data;
656     w = (double*)w_->data;
657     m = X_->dimensions[0];
658     n = X_->dimensions[1];
659 
660     res = pdist_old_weighted_minkowski(X, dm, m, n, p, w);
661     NPY_END_ALLOW_THREADS;
662     if (res) {
663       return PyErr_NoMemory();
664     }
665   }
666   return Py_BuildValue("d", 0.0);
667 }
668 
pdist_weighted_minkowski_double_wrap(PyObject * self,PyObject * args,PyObject * kwargs)669 static PyObject *pdist_weighted_minkowski_double_wrap(
670                             PyObject *self, PyObject *args, PyObject *kwargs)
671 {
672   PyArrayObject *X_, *dm_, *w_;
673   int m, n;
674   double *dm, *X, *w;
675   double p;
676   static char *kwlist[] = {"X", "dm", "p", "w", NULL};
677   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
678             "O!O!dO!:pdist_weighted_minkowski_double_wrap", kwlist,
679             &PyArray_Type, &X_,
680             &PyArray_Type, &dm_,
681             &p,
682             &PyArray_Type, &w_)) {
683     return 0;
684   }
685   else {
686     NPY_BEGIN_ALLOW_THREADS;
687     X = (double*)X_->data;
688     dm = (double*)dm_->data;
689     w = (double*)w_->data;
690     m = X_->dimensions[0];
691     n = X_->dimensions[1];
692 
693     pdist_weighted_minkowski(X, dm, m, n, p, w);
694     NPY_END_ALLOW_THREADS;
695   }
696   return Py_BuildValue("d", 0.0);
697 }
698 
699 
to_squareform_from_vector_wrap(PyObject * self,PyObject * args)700 static PyObject *to_squareform_from_vector_wrap(PyObject *self, PyObject *args)
701 {
702   PyArrayObject *M_, *v_;
703   int n, elsize;
704   if (!PyArg_ParseTuple(args, "O!O!",
705             &PyArray_Type, &M_,
706             &PyArray_Type, &v_)) {
707     return 0;
708   }
709   NPY_BEGIN_ALLOW_THREADS;
710   n = M_->dimensions[0];
711   elsize = M_->descr->elsize;
712   if (elsize == 8) {
713     dist_to_squareform_from_vector_double(
714         (double*)M_->data, (const double*)v_->data, n);
715   } else {
716     dist_to_squareform_from_vector_generic(
717         (char*)M_->data, (const char*)v_->data, n, elsize);
718   }
719   NPY_END_ALLOW_THREADS;
720   return Py_BuildValue("");
721 }
722 
to_vector_from_squareform_wrap(PyObject * self,PyObject * args)723 static PyObject *to_vector_from_squareform_wrap(PyObject *self, PyObject *args)
724 {
725   PyArrayObject *M_, *v_;
726   int n, s;
727   char *v;
728   const char *M;
729   if (!PyArg_ParseTuple(args, "O!O!",
730             &PyArray_Type, &M_,
731             &PyArray_Type, &v_)) {
732     return 0;
733   }
734   else {
735     NPY_BEGIN_ALLOW_THREADS;
736     M = (const char*)M_->data;
737     v = (char*)v_->data;
738     n = M_->dimensions[0];
739     s = M_->descr->elsize;
740     dist_to_vector_from_squareform(M, v, n, s);
741     NPY_END_ALLOW_THREADS;
742   }
743   return Py_BuildValue("");
744 }
745 
746 
747 static PyMethodDef _distanceWrapMethods[] = {
748   {"cdist_braycurtis_double_wrap",
749    cdist_bray_curtis_double_wrap,
750    METH_VARARGS},
751   {"cdist_canberra_double_wrap",
752    cdist_canberra_double_wrap,
753    METH_VARARGS},
754   {"cdist_chebyshev_double_wrap",
755    cdist_chebyshev_double_wrap,
756    METH_VARARGS},
757   {"cdist_cityblock_double_wrap",
758    cdist_city_block_double_wrap,
759    METH_VARARGS},
760   {"cdist_cosine_double_wrap",
761    (PyCFunction) cdist_cosine_double_wrap,
762    METH_VARARGS | METH_KEYWORDS},
763   {"cdist_dice_bool_wrap",
764    cdist_dice_char_wrap,
765    METH_VARARGS},
766   {"cdist_euclidean_double_wrap",
767    cdist_euclidean_double_wrap,
768    METH_VARARGS},
769   {"cdist_sqeuclidean_double_wrap",
770    cdist_sqeuclidean_double_wrap,
771    METH_VARARGS},
772   {"cdist_hamming_double_wrap",
773    (PyCFunction) cdist_hamming_double_wrap,
774    METH_VARARGS | METH_KEYWORDS},
775   {"cdist_hamming_bool_wrap",
776    (PyCFunction) cdist_hamming_char_wrap,
777    METH_VARARGS | METH_KEYWORDS},
778   {"cdist_jaccard_double_wrap",
779    cdist_jaccard_double_wrap,
780    METH_VARARGS},
781   {"cdist_jaccard_bool_wrap",
782    cdist_jaccard_char_wrap,
783    METH_VARARGS},
784   {"cdist_jensenshannon_double_wrap",
785    cdist_jensenshannon_double_wrap,
786    METH_VARARGS},
787   {"cdist_kulsinski_bool_wrap",
788    cdist_kulsinski_char_wrap,
789    METH_VARARGS},
790   {"cdist_mahalanobis_double_wrap",
791    (PyCFunction) cdist_mahalanobis_double_wrap,
792    METH_VARARGS | METH_KEYWORDS},
793   {"cdist_minkowski_double_wrap",
794    (PyCFunction) cdist_minkowski_double_wrap,
795    METH_VARARGS | METH_KEYWORDS},
796   {"cdist_weighted_chebyshev_double_wrap",
797    (PyCFunction) cdist_weighted_chebyshev_double_wrap,
798    METH_VARARGS | METH_KEYWORDS},
799   {"cdist_old_weighted_minkowski_double_wrap",
800    (PyCFunction) cdist_old_weighted_minkowski_double_wrap,
801    METH_VARARGS | METH_KEYWORDS},
802   {"cdist_weighted_minkowski_double_wrap",
803    (PyCFunction) cdist_weighted_minkowski_double_wrap,
804    METH_VARARGS | METH_KEYWORDS},
805   {"cdist_rogerstanimoto_bool_wrap",
806    cdist_rogerstanimoto_char_wrap,
807    METH_VARARGS},
808   {"cdist_russellrao_bool_wrap",
809    cdist_russellrao_char_wrap,
810    METH_VARARGS},
811   {"cdist_seuclidean_double_wrap",
812    (PyCFunction) cdist_seuclidean_double_wrap,
813    METH_VARARGS | METH_KEYWORDS},
814   {"cdist_sokalmichener_bool_wrap",
815    cdist_sokalmichener_char_wrap,
816    METH_VARARGS},
817   {"cdist_sokalsneath_bool_wrap",
818    cdist_sokalsneath_char_wrap,
819    METH_VARARGS},
820   {"cdist_yule_bool_wrap",
821    cdist_yule_char_wrap,
822    METH_VARARGS},
823   {"pdist_braycurtis_double_wrap",
824    pdist_bray_curtis_double_wrap,
825    METH_VARARGS},
826   {"pdist_canberra_double_wrap",
827    pdist_canberra_double_wrap,
828    METH_VARARGS},
829   {"pdist_chebyshev_double_wrap",
830    pdist_chebyshev_double_wrap,
831    METH_VARARGS},
832   {"pdist_cityblock_double_wrap",
833    pdist_city_block_double_wrap,
834    METH_VARARGS},
835   {"pdist_cosine_double_wrap",
836    (PyCFunction) pdist_cosine_double_wrap,
837    METH_VARARGS | METH_KEYWORDS},
838   {"pdist_dice_bool_wrap",
839    pdist_dice_char_wrap,
840    METH_VARARGS},
841   {"pdist_euclidean_double_wrap",
842    pdist_euclidean_double_wrap,
843    METH_VARARGS},
844   {"pdist_sqeuclidean_double_wrap",
845    pdist_sqeuclidean_double_wrap,
846    METH_VARARGS},
847   {"pdist_hamming_double_wrap",
848    (PyCFunction) pdist_hamming_double_wrap,
849    METH_VARARGS | METH_KEYWORDS},
850   {"pdist_hamming_bool_wrap",
851    (PyCFunction) pdist_hamming_char_wrap,
852    METH_VARARGS | METH_KEYWORDS},
853   {"pdist_jaccard_double_wrap",
854    pdist_jaccard_double_wrap,
855    METH_VARARGS},
856   {"pdist_jaccard_bool_wrap",
857    pdist_jaccard_char_wrap,
858    METH_VARARGS},
859   {"pdist_jensenshannon_double_wrap",
860    pdist_jensenshannon_double_wrap,
861    METH_VARARGS},
862   {"pdist_kulsinski_bool_wrap",
863    pdist_kulsinski_char_wrap,
864    METH_VARARGS},
865   {"pdist_mahalanobis_double_wrap",
866    (PyCFunction) pdist_mahalanobis_double_wrap,
867    METH_VARARGS | METH_KEYWORDS},
868   {"pdist_minkowski_double_wrap",
869    (PyCFunction) pdist_minkowski_double_wrap,
870    METH_VARARGS | METH_KEYWORDS},
871   {"pdist_weighted_chebyshev_double_wrap",
872    (PyCFunction) pdist_weighted_chebyshev_double_wrap,
873    METH_VARARGS | METH_KEYWORDS},
874   {"pdist_old_weighted_minkowski_double_wrap",
875    (PyCFunction) pdist_old_weighted_minkowski_double_wrap,
876    METH_VARARGS | METH_KEYWORDS},
877   {"pdist_weighted_minkowski_double_wrap",
878    (PyCFunction) pdist_weighted_minkowski_double_wrap,
879    METH_VARARGS | METH_KEYWORDS},
880   {"pdist_rogerstanimoto_bool_wrap",
881    pdist_rogerstanimoto_char_wrap,
882    METH_VARARGS},
883   {"pdist_russellrao_bool_wrap",
884    pdist_russellrao_char_wrap,
885    METH_VARARGS},
886   {"pdist_seuclidean_double_wrap",
887    (PyCFunction) pdist_seuclidean_double_wrap,
888    METH_VARARGS | METH_KEYWORDS},
889   {"pdist_sokalmichener_bool_wrap",
890    pdist_sokalmichener_char_wrap,
891    METH_VARARGS},
892   {"pdist_sokalsneath_bool_wrap",
893    pdist_sokalsneath_char_wrap,
894    METH_VARARGS},
895   {"pdist_yule_bool_wrap",
896    pdist_yule_char_wrap,
897    METH_VARARGS},
898   {"to_squareform_from_vector_wrap",
899    to_squareform_from_vector_wrap,
900    METH_VARARGS},
901   {"to_vector_from_squareform_wrap",
902    to_vector_from_squareform_wrap,
903    METH_VARARGS},
904   {NULL, NULL}     /* Sentinel - marks the end of this structure */
905 };
906 
907 static struct PyModuleDef moduledef = {
908     PyModuleDef_HEAD_INIT,
909     "_distance_wrap",
910     NULL,
911     -1,
912     _distanceWrapMethods,
913     NULL,
914     NULL,
915     NULL,
916     NULL
917 };
918 
PyInit__distance_wrap(void)919 PyObject *PyInit__distance_wrap(void)
920 {
921     PyObject *m;
922 
923     m = PyModule_Create(&moduledef);
924     import_array();
925 
926     return m;
927 }
928