source: orange/source/statc/statc.cpp @ 10494:b92eb3f86d16

Revision 10494:b92eb3f86d16, 43.6 KB checked in by Ales Erjavec <ales.erjavec@…>, 2 years ago (diff)

Raise an error if less the two unique points.

Line 
1/*
2    This file is part of Orange.
3   
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20 
21
22#ifdef _MSC_VER
23  #define NOMINMAX
24  #define WIN32_LEAN_AND_MEAN       // Exclude rarely-used stuff from Windows headers
25  #include <windows.h>
26#endif
27
28#include "statc.hpp"
29#include "pywrapper.hpp"
30#include "stat.hpp"
31#include "stladdon.hpp"
32//#include <algorithm>
33#include <string>
34using namespace std;
35
36/* *********** EXCEPTION CATCHING ETC. ************/
37
38 
39#undef min
40#undef max
41 
42#define PyTRY try {
43 
44#define PYNULL ((PyObject *)NULL)
45#define PyCATCH   PyCATCH_r(PYNULL)
46#define PyCATCH_1 PyCATCH_r(-1)
47 
48#define PyCATCH_r(r) \
49  } \
50catch (pyexception& err)   { err.restore(); return r; } \
51catch (exception& err) { PYERROR(PyExc_StatcKernel, err.what(), r); }
52
53PyObject *PyExc_StatcKernel;
54PyObject *PyExc_StatcWarning;
55
56/* *********** MODULE INITIALIZATION ************/
57
58STATC_API void initstatc()
59{ if (   ((PyExc_StatcKernel = makeExceptionClass("statc.KernelException", "an error occurred in statc's C++ code")) == NULL)
60      || ((PyExc_StatcWarning = makeExceptionClass("statc.Warning", "statc warning", PyExc_Warning)) == NULL))
61    return;
62
63  PyObject *me = Py_InitModule("statc", statc_functions);
64
65  PyObject *pdm = PyModule_New("pointDistribution");
66  PyModule_AddObject(pdm, "Minimal", PyInt_FromLong(DISTRIBUTE_MINIMAL));
67  PyModule_AddObject(pdm, "Factor", PyInt_FromLong(DISTRIBUTE_FACTOR));
68  PyModule_AddObject(pdm, "Fixed", PyInt_FromLong(DISTRIBUTE_FIXED));
69  PyModule_AddObject(pdm, "Uniform", PyInt_FromLong(DISTRIBUTE_UNIFORM));
70  PyModule_AddObject(pdm, "Maximal", PyInt_FromLong(DISTRIBUTE_MAXIMAL));
71
72  PyModule_AddObject(me, "pointDistribution", pdm);
73}
74
75
76#ifdef _MSC_VER
77BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
78{ switch (ul_reason_for_call)
79    { case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break; }
80  return TRUE;
81}
82#endif
83
84/* *********** CONVERSION TO AND FROM PYTHON ************/
85
86
87bool py2double(PyObject *pyo, double &dd)
88{ 
89  PyObject *pyn=PyNumber_Float(pyo);
90  if (!pyn)
91    PYERROR(PyExc_TypeError, "invalid number", false);
92  dd=PyFloat_AsDouble(pyn);
93  Py_DECREF(pyn);
94  return true;
95}
96
97bool py2int(PyObject *pyo, int &dd)
98{ PyObject *pyn=PyNumber_Int(pyo);
99  if (!pyn)
100    PYERROR(PyExc_TypeError, "invalid number", false);
101  dd=int(PyInt_AsLong(pyn));
102  Py_DECREF(pyn);
103  return true;
104}
105
106
107bool PyList2flist(PyObject *pylist, vector<double> &flist)
108{ int len=PyList_Size(pylist);
109  flist=vector<double>(len);
110  for(int i=0; i<len; i++) {
111    PyObject *item=PyList_GetItem(pylist, i);
112    PyObject *number=PyNumber_Float(item);
113    if (!number)
114      PYERROR(PyExc_AttributeError, "invalid number in list", false);
115    flist[i]=PyFloat_AsDouble(number);
116    Py_DECREF(number);
117  }
118  return true;
119}
120
121
122bool PyList2flist2d(PyObject *pylist, vector<vector<double> > &flist)
123{ int len=PyList_Size(pylist);
124  flist=vector<vector<double> >(len);
125  for(int i=0; i<len; i++) {
126    PyObject *slist=PyList_GetItem(pylist, i);
127    if (!PyList_Check(slist))
128      PYERROR(PyExc_TypeError, "list expected", false);
129    if (!PyList2flist(slist, flist[i]))
130      return false;
131  }
132
133  return true;
134}
135
136
137bool args2flist(PyObject *args, vector<double> &flist)
138{ PyObject *pylist;
139  if (   !PyArg_ParseTuple(args, "O", &pylist)
140      || !PyList_Check(pylist))
141    PYERROR(PyExc_AttributeError, "list expected", false)
142
143  return PyList2flist(pylist, flist);
144}
145
146
147bool args2flist2d(PyObject *args, vector<vector<double> > &flist)
148{ PyObject *pylist;
149  if (   !PyArg_ParseTuple(args, "O", &pylist)
150      || !PyList_Check(pylist))
151    PYERROR(PyExc_AttributeError, "list expected", false)
152
153  return PyList2flist2d(pylist, flist);
154}
155
156bool args22lists(PyObject *args, vector<double> &flist1, vector<double> &flist2)
157{ PyObject *pylist1, *pylist2;
158  if (   !PyArg_ParseTuple(args, "OO", &pylist1, &pylist2)
159      || !PyList_Check(pylist1)
160      || !PyList_Check(pylist2)
161      || (PyList_Size(pylist1)!=PyList_Size(pylist2)))
162    PYERROR(PyExc_AttributeError, "two lists of equal sizes expected", false)
163
164  return PyList2flist(pylist1, flist1) && PyList2flist(pylist2, flist2);
165}
166
167bool args22listsne(PyObject *args, vector<double> &flist1, vector<double> &flist2)
168{ PyObject *pylist1, *pylist2;
169  if (   !PyArg_ParseTuple(args, "OO", &pylist1, &pylist2)
170      || !PyList_Check(pylist1)
171      || !PyList_Check(pylist2))
172    PYERROR(PyExc_AttributeError, "two lists expected", false)
173
174  return PyList2flist(pylist1, flist1) && PyList2flist(pylist2, flist2);
175}
176
177
178PyObject *flist2PyList(const vector<double> &flist)
179{ PyObject *pylist=PyList_New(flist.size());
180  int i=0;
181  const_ITERATE(vector<double>, fi, flist)
182    PyList_SetItem(pylist, i++, PyFloat_FromDouble(*fi));
183  return pylist;
184}
185
186
187PyObject *ilist2PyList(const vector<int> &ilist)
188{ PyObject *pylist=PyList_New(ilist.size());
189  int i=0;
190  const_ITERATE(vector<int>, fi, ilist)
191    PyList_SetItem(pylist, i++, PyInt_FromLong(*fi));
192  return pylist;
193}
194
195
196
197bool PyList2wlist(PyObject *pylist, vector<PyWrapper> &wlist)
198{ int len=PyList_Size(pylist);
199  wlist=vector<PyWrapper>();
200  wlist.reserve(len);
201  for(int i=0; i<len; i++)
202    wlist.push_back(PyWrapper(PyList_GetItem(pylist, i)));
203  return true;
204}
205
206
207bool PyList2wlist2d(PyObject *pylist, vector<vector<PyWrapper> > &flist)
208{ int len=PyList_Size(pylist);
209  flist=vector<vector<PyWrapper> >(len);
210  for(int i=0; i<len; i++) {
211    PyObject *slist=PyList_GetItem(pylist, i);
212    if (!PyList_Check(slist))
213      PYERROR(PyExc_TypeError, "list expected", false);
214    if (!PyList2wlist(slist, flist[i]))
215      return false;
216  }
217
218  return true;
219}
220
221
222bool args2wlist2d(PyObject *args, vector<vector<PyWrapper> > &wlist)
223{ PyObject *pylist;
224  if (   !PyArg_ParseTuple(args, "O", &pylist)
225      || !PyList_Check(pylist))
226    PYERROR(PyExc_AttributeError, "list expected", false)
227
228  return PyList2wlist2d(pylist, wlist);
229}
230
231
232bool args2wlist(PyObject *args, vector<PyWrapper> &wlist)
233{ PyObject *pylist;
234  if (   !PyArg_ParseTuple(args, "O", &pylist)
235      || !PyList_Check(pylist))
236    PYERROR(PyExc_AttributeError, "list expected", false)
237
238  return PyList2wlist(pylist, wlist);
239}
240
241
242bool args22wlists(PyObject *args, vector<PyWrapper> &flist1, vector<PyWrapper> &flist2)
243{ PyObject *pylist1, *pylist2;
244  if (   !PyArg_ParseTuple(args, "OO", &pylist1, &pylist2)
245      || !PyList_Check(pylist1)
246      || !PyList_Check(pylist2)
247      || (PyList_Size(pylist1)!=PyList_Size(pylist2)))
248    PYERROR(PyExc_AttributeError, "two lists of equal sizes expected", false)
249
250  return PyList2wlist(pylist1, flist1) && PyList2wlist(pylist2, flist2);
251}
252
253
254bool args22wlistsne(PyObject *args, vector<PyWrapper> &flist1, vector<PyWrapper> &flist2)
255{ PyObject *pylist1, *pylist2;
256  if (   !PyArg_ParseTuple(args, "OO", &pylist1, &pylist2)
257      || !PyList_Check(pylist1)
258      || !PyList_Check(pylist2))
259    PYERROR(PyExc_AttributeError, "two lists expected", false)
260
261  return PyList2wlist(pylist1, flist1) && PyList2wlist(pylist2, flist2);
262}
263
264
265PyObject *wlist2PyList(const vector<PyWrapper> &flist)
266{ PyObject *pylist=PyList_New(flist.size());
267  int i=0;
268  const_ITERATE(vector<PyWrapper>, fi, flist)
269    PyList_SetItem(pylist, i++, *fi);
270  return pylist;
271}
272
273
274/* *********** MACROS FOR GENERAL FUNCTION DEFINITIONS ************/
275
276#define T_FROM_LIST(name) \
277PyObject *py_##name(PyObject *, PyObject *args) \
278{ PyTRY \
279    vector<double> flist; \
280    if (args2flist(args, flist)) \
281      return PyFloat_FromDouble(name(flist)); \
282    \
283    PyErr_Clear(); \
284    \
285    vector<PyWrapper> wlist; \
286    if (args2wlist(args, wlist)) \
287      return name(wlist); \
288    \
289    return PYNULL; \
290  PyCATCH \
291}
292
293
294#define T_FROM_LIST_optT(name) \
295PyObject *py_##name(PyObject *, PyObject *args) \
296{ PyTRY \
297    PyObject *pylist; \
298    vector<double> flist; \
299    double init=0.0; \
300    if (   PyArg_ParseTuple(args, "O|d", &pylist, &init) \
301        && PyList2flist(pylist, flist)) \
302      return PyFloat_FromDouble(name(flist, init)); \
303    \
304    PyErr_Clear(); \
305    \
306    vector<PyWrapper> wlist; \
307    PyObject *pyinit=NULL; \
308    if (   PyArg_ParseTuple(args, "O|O", &pylist, &pyinit) \
309        && PyList2wlist(pylist, wlist)) \
310      return (PyObject *)(name(wlist, PyWrapper(pyinit))); \
311    \
312    return PYNULL; \
313  PyCATCH \
314}
315
316
317#define T_FROM_LIST_LIST(name) \
318PyObject *py_##name(PyObject *, PyObject *args) \
319{ PyTRY \
320    vector<double> x, y; \
321    if (args22lists(args, x, y)) \
322      return PyFloat_FromDouble(name(x, y)); \
323    \
324    PyErr_Clear(); \
325    \
326    vector<PyWrapper> wx, wy; \
327    if (args22wlists(args, wx, wy)) \
328      return name(wx, wy); \
329    \
330    PYERROR(PyExc_AttributeError, #name": two lists expected", PYNULL); \
331  PyCATCH \
332}
333
334
335#define T_FROM_LIST_LIST_optT(name) \
336PyObject *py_##name(PyObject *, PyObject *args) \
337{ PyTRY \
338    PyObject *pyx, *pyy; \
339    vector<double> x, y; \
340    double init=0.0; \
341    if (   PyArg_ParseTuple(args, "OO|d", &pyx, &pyy, &init) \
342        && PyList2flist(pyx, x)  \
343        && PyList2flist(pyy, y)) \
344      return PyFloat_FromDouble(name(x, y, init)); \
345    \
346    PyErr_Clear(); \
347    \
348    vector<PyWrapper> wx, wy; \
349    PyObject *pyinit=NULL; \
350    if (   PyArg_ParseTuple(args, "OO|d", &pyx, &pyy, &pyinit) \
351        && PyList2wlist(pyx, wx)  \
352        && PyList2wlist(pyy, wy)) \
353      return (PyObject *)(name(wx, wy, PyWrapper(pyinit))); \
354    \
355    return PYNULL; \
356  PyCATCH \
357}
358
359
360
361#define LIST_FROM_LIST(name) \
362PyObject *py_##name(PyObject *, PyObject *args) \
363{ PyTRY \
364    vector<double> x, res; \
365    if (args2flist(args, x)) \
366      name(x, res); \
367      return flist2PyList(res); \
368    \
369    PyErr_Clear(); \
370    \
371    vector<PyWrapper> w, wres; \
372    if (args2wlist(args, w)) \
373      name(w, wres); \
374      return wlist2PyList(wres); \
375    \
376    PYERROR(PyExc_AttributeError, #name": list expected", PYNULL); \
377  PyCATCH \
378}
379
380
381
382#define LIST_FROM_LIST_optT(name) \
383PyObject *py_##name(PyObject *, PyObject *args) \
384{ PyTRY \
385    PyObject *pylist; \
386    vector<double> flist, res; \
387    double init=0.0; \
388    if (   PyArg_ParseTuple(args, "O|d", &pylist, &init) \
389        && PyList2flist(pylist, flist)) {\
390      name(flist, res); \
391      return flist2PyList(res); \
392    } \
393    \
394    PyErr_Clear(); \
395    \
396    vector<PyWrapper> wlist, wres; \
397    PyObject *pyinit=NULL; \
398    if (   PyArg_ParseTuple(args, "O|O", &pylist, &pyinit) \
399        && PyList2wlist(pylist, wlist)) { \
400      name(wlist, wres); \
401      return wlist2PyList(wlist); \
402    } \
403    \
404    return PYNULL; \
405  PyCATCH \
406}
407
408
409#define T_FROM_LIST_T(name) \
410PyObject *py_##name(PyObject *, PyObject *args) \
411{ PyTRY \
412    PyObject *pylist; \
413    double mom; \
414    vector<double> flist; \
415    if (   PyArg_ParseTuple(args, "Od", &pylist, &mom) \
416        && PyList2flist(pylist, flist)) \
417          return PyFloat_FromDouble(name(flist, mom)); \
418    \
419    PyErr_Clear(); \
420    \
421    vector<PyWrapper> wlist; \
422    PyObject *wmom; \
423    if (   PyArg_ParseTuple(args, "OO", &pylist, &wmom)  \
424        && PyList2wlist(pylist, wlist)) \
425          return name(wlist, PyWrapper(wmom)); \
426    \
427    PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
428  PyCATCH \
429}
430
431
432#define T_FROM_LIST_plus(name, type, pys) \
433PyObject *py_##name(PyObject *, PyObject *args) \
434{ PyTRY \
435    PyObject *pylist; \
436    type mom; \
437    if (   PyArg_ParseTuple(args, pys, &pylist, &mom)) {\
438      vector<double> flist; \
439      if (PyList2flist(pylist, flist)) \
440        return PyFloat_FromDouble(name(flist, mom)); \
441      \
442      PyErr_Clear(); \
443      \
444      vector<PyWrapper> wlist; \
445      if (PyList2wlist(pylist, wlist)) \
446        return name(wlist, mom); \
447    } \
448    PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
449  PyCATCH \
450}
451
452#define T_FROM_LIST_INT(name) T_FROM_LIST_plus(name, int, "Oi")
453#define T_FROM_LIST_DOUBLE(name) T_FROM_LIST_plus(name, double, "Od")
454
455
456
457#define LIST_FROM_LIST_plus(name, type, pys) \
458PyObject *py_##name(PyObject *, PyObject *args) \
459{ PyTRY \
460    PyObject *pylist; \
461    type mom; \
462    if (   PyArg_ParseTuple(args, pys, &pylist, &mom)) {\
463      vector<double> flist; \
464      if (PyList2flist(pylist, flist)) { \
465        vector<double> fres; \
466        name(flist, mom, fres); \
467        return flist2PyList(fres); \
468      } \
469      \
470      PyErr_Clear(); \
471      \
472      vector<PyWrapper> wlist; \
473      if (PyList2wlist(pylist, wlist)) { \
474        vector<PyWrapper> wres; \
475        name(wlist, mom, wres); \
476        return wlist2PyList(wres); \
477      } \
478    } \
479    PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
480  PyCATCH \
481}
482
483#define LIST_FROM_LIST_INT(name) LIST_FROM_LIST_plus(name, int, "Oi")
484#define LIST_FROM_LIST_DOUBLE(name) LIST_FROM_LIST_plus(name, double, "Od")
485
486
487#define DOUBLE_DOUBLE_FROM_LIST_LIST(name) \
488PyObject *py_##name(PyObject *, PyObject *args) \
489{ PyTRY \
490    vector<double> x, y; \
491    double res1, res2; \
492    if (args22lists(args, x, y)) {\
493      res1=name(x, y, res2); \
494      return Py_BuildValue("dd", res1, res2); \
495    } \
496    \
497    PyErr_Clear(); \
498    \
499    vector<PyWrapper> wx, wy; \
500    if (args22wlists(args, wx, wy)) {\
501      res1=name(wx, wy, res2); \
502      return Py_BuildValue("dd", res1, res2); \
503    } \
504    \
505    PYERROR(PyExc_AttributeError, #name": two lists of equal size expected", PYNULL); \
506  PyCATCH \
507}
508
509
510#define T_T_FROM_LIST_LIST(name) \
511PyObject *py_##name(PyObject *, PyObject *args) \
512{ PyTRY \
513    vector<double> x, y; \
514    if (args22lists(args, x, y)) { \
515      double res1, res2; \
516      res1=name(x, y, res2); \
517      return Py_BuildValue("dd", res1, res2); \
518    } \
519    \
520    PyErr_Clear(); \
521    \
522    vector<PyWrapper> wx, wy; \
523    if (args22wlists(args, wx, wy)) { \
524      PyWrapper res1, res2; \
525      res1=name(wx, wy, res2); \
526      return Py_BuildValue("NN", (PyObject *)res1, (PyObject *)res2); \
527    } \
528    \
529    PYERROR(PyExc_AttributeError, #name": two lists of equal size expected", PYNULL); \
530  PyCATCH \
531}
532
533
534#define T_T_FROM_LIST(name) \
535PyObject *py_##name(PyObject *, PyObject *args) \
536{ PyTRY \
537    vector<double> flist; \
538    if (!args2flist(args, flist)) \
539      return NULL; \
540\
541      double res1, res2; \
542      res1 = name(flist, res2); \
543      return Py_BuildValue("dd", res1, res2); \
544  PyCATCH \
545}
546
547
548#define T_T_FROM_LIST_plus(name, type, pys) \
549PyObject *py_##name(PyObject *, PyObject *args) \
550{ PyTRY \
551    PyObject *pylist; \
552    type mom; \
553    if (   PyArg_ParseTuple(args, pys, &pylist, &mom)) {\
554      vector<double> flist; \
555      if (PyList2flist(pylist, flist)) \
556        double res1, res2; \
557        res1=name(flist, mom, res2); \
558        return PyBuildValue("dd", res1, res2); \
559      \
560      PyErr_Clear(); \
561      \
562      vector<PyWrapper> wlist; \
563      if (PyList2wlist(pylist, wlist)) \
564        PyWrapper res1, res2; \
565        res1=name(wlist, mom, res2); \
566        return PyBuildValue("OO", (PyObject *)res1, (PyObject *)res2); \
567    } \
568    PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
569  PyCATCH \
570}
571
572#define T_T_FROM_LIST_INT(name) T_T_FROM_LIST_plus(name, int, "Oi")
573#define T_T_FROM_LIST_DOUBLE(name) T_T_FROM_LIST_plus(name, double, "Od")
574
575
576
577#define DOUBLE_DOUBLE_FROM_LIST_plus(name, type, pys) \
578PyObject *py_##name(PyObject *, PyObject *args) \
579{ PyTRY \
580    PyObject *pylist; \
581    double res1, res2; \
582    type mom; \
583    if (   PyArg_ParseTuple(args, pys, &pylist, &mom)) {\
584      vector<double> flist; \
585      if (PyList2flist(pylist, flist)) \
586        res1=name(flist, mom, res2); \
587      \
588      PyErr_Clear(); \
589      \
590      vector<PyWrapper> wlist; \
591      if (PyList2wlist(pylist, wlist)) \
592        res1=name(wlist, mom, res2); \
593      \
594      else PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
595      \
596      return PyBuildValue("dd", res1, res2); \
597    } \
598    PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
599  PyCATCH \
600}
601
602#define DOUBLE_DOUBLE_FROM_LIST_INT(name) DOUBLE_DOUBLE_FROM_LIST_plus(name, int, "Oi")
603#define DOUBLE_DOUBLE_FROM_LIST_DOUBLE(name) DOUBLE_DOUBLE_FROM_LIST_plus(name, double, "Od")
604
605
606#define T_T_FROM_LIST_T(name) \
607PyObject *py_##name(PyObject *, PyObject *args) \
608{ PyTRY \
609    PyObject *pylist; \
610    double mom; \
611    vector<double> flist; \
612    if (   PyArg_ParseTuple(args, "Od", &pylist, &mom)\
613        && (PyList2flist(pylist, flist))) {\
614        double res1, res2; \
615        res1=name(flist, mom, res2); \
616        return Py_BuildValue("dd", res1, res2); \
617      } \
618      \
619      PyErr_Clear(); \
620      \
621    PyObject *wmom; \
622    vector<PyWrapper> wlist; \
623    if (   PyArg_ParseTuple(args, "OO", &pylist, &wmom)\
624        && (PyList2wlist(pylist, wlist))) {\
625        PyWrapper res1, res2; \
626        res1=name(wlist, PyWrapper(mom), res2); \
627        return Py_BuildValue("NN", (PyObject *)res1, (PyObject *)res2); \
628    } \
629    PYERROR(PyExc_AttributeError, #name": invalid arguments", PYNULL); \
630  PyCATCH \
631}
632
633
634#define T_FROM_T(name) \
635PyObject *py_##name(PyObject *, PyObject *args) \
636{ PyTRY \
637    double x; \
638    if (PyArg_ParseTuple(args, "d", &x)) \
639      return PyFloat_FromDouble(name(x)); \
640\
641    PyErr_Clear(); \
642\
643    PyObject *pyx; \
644    if (PyArg_ParseTuple(args, "O", &pyx)) \
645      return (PyObject *)(name(PyWrapper(pyx))); \
646\
647    return PYNULL; \
648  PyCATCH \
649}
650
651
652#define T_FROM_T_T_T(name) \
653PyObject *py_##name(PyObject *, PyObject *args) \
654{ PyTRY \
655    double x, y, z; \
656    if (PyArg_ParseTuple(args, "ddd", &x, &y, &z)) \
657      return PyFloat_FromDouble(name(x, y, z)); \
658\
659    PyErr_Clear(); \
660\
661    PyObject *pyx, *pyy, *pyz; \
662    if (PyArg_ParseTuple(args, "OOO", &pyx, &pyy, &pyz)) \
663      return (PyObject *)(name(PyWrapper(pyx), PyWrapper(pyy), PyWrapper(pyz))); \
664\
665    return PYNULL; \
666  PyCATCH \
667}
668
669
670#define T_FROM_T_T(name) \
671PyObject *py_##name(PyObject *, PyObject *args) \
672{ PyTRY \
673    double x, y; \
674    if (PyArg_ParseTuple(args, "dd", &x, &y)) \
675      return PyFloat_FromDouble(name(x, y)); \
676\
677    PyErr_Clear(); \
678\
679    PyObject *pyx, *pyy; \
680    if (PyArg_ParseTuple(args, "OO", &pyx, &pyy)) \
681      return (PyObject *)(name(PyWrapper(pyx), PyWrapper(pyy))); \
682\
683    return PYNULL; \
684  PyCATCH \
685}
686
687
688#define T_FROM_INT_INT_T(name) \
689PyObject *py_##name(PyObject *, PyObject *args) \
690{ PyTRY \
691    double x; \
692    int i1, i2; \
693    if (PyArg_ParseTuple(args, "iid", &i1, &i2, &x)) \
694      return PyFloat_FromDouble(name(i1, i2, x)); \
695\
696    PyErr_Clear(); \
697\
698    PyObject *pyx; \
699    if (PyArg_ParseTuple(args, "iiO", &i1, &i2, &pyx)) \
700      return (PyObject *)(name(i1, i2, PyWrapper(pyx))); \
701\
702    return PYNULL; \
703  PyCATCH \
704}
705
706
707/* *********** AUXILIARY FUNCTIONS ************/
708
709
710class Callback {
711public:
712  PyObject *callback;
713
714  Callback(PyObject *cb)
715    : callback(cb)
716  { if (cb)
717      if (cb==Py_None)
718        callback=PYNULL;
719      else {
720        if (!PyCallable_Check(cb))
721          throw StatException("Callback: non-callable callback function");
722
723        Py_XINCREF(callback);
724      }
725  }
726
727  ~Callback()
728  { Py_XDECREF(callback); }
729
730  Callback(const Callback &other)
731   : callback(other.callback)
732   { Py_XINCREF(callback); }
733
734  void operator = (const Callback &other)
735   { Py_XINCREF(other.callback);
736     Py_XDECREF(callback);
737     callback=other.callback;
738   }
739};
740
741
742class BoolUnaryCallback : public Callback {
743public:
744  BoolUnaryCallback(PyObject *cb)
745    : Callback(cb)
746    {}
747
748  bool operator ()(const PyWrapper &x) const
749  { if (!x.pyobject)
750      throw StatException("BoolUnaryCallable: invalid object");
751
752    PyObject *args=Py_BuildValue("(O)", x.pyobject);
753    PyObject *res=PyEval_CallObject(callback, args);
754    Py_DECREF(args);
755
756    PyWrapper::checkForError();
757
758    return PyObject_IsTrue(res)!=0;
759  }
760};
761
762
763class BoolBinaryCallback : public Callback {
764public:
765  typedef PyWrapper first_argument_type;
766  typedef PyWrapper second_argument_type;
767  typedef bool result_type;
768
769  BoolBinaryCallback(PyObject *cb)
770    : Callback(cb)
771    {}
772
773  bool operator ()(const PyWrapper &x, const PyWrapper &y) const
774  { if (!x.pyobject || !y.pyobject)
775      throw StatException("BoolBinaryCallable: invalid objects");
776
777    PyObject *args=Py_BuildValue("OO", x.pyobject, y.pyobject);
778    PyObject *res=PyEval_CallObject(callback, args);
779    Py_DECREF(args);
780
781    PyWrapper::checkForError();
782
783    return PyObject_IsTrue(res)!=0;
784  }
785};
786
787class IsTrueCallback : public BoolUnaryCallback {
788public:
789    IsTrueCallback(PyObject *cb=NULL)
790      : BoolUnaryCallback(cb)
791      {}
792
793    bool operator()(const PyWrapper &x) const
794    { if (!x.pyobject)
795        throw StatException("IsTrueCallback: invalid object");
796
797      return callback ? BoolUnaryCallback::operator ()(x) : (PyObject_IsTrue(x.pyobject)!=0);
798    }
799};
800
801
802class LessThanCallback : public BoolBinaryCallback {
803public:
804    LessThanCallback(PyObject *o=NULL)
805      : BoolBinaryCallback(o)
806      {}
807
808    bool operator()(const PyWrapper &x, const PyWrapper &y) const
809    { if (!x.pyobject || !y.pyobject)
810        throw StatException("CompareCallback: invalid objects");
811      return callback ? BoolBinaryCallback::operator ()(x, y) : (x<y);
812    }
813};
814
815
816
817/* *********** CENTRAL TENDENCY ************/
818
819
820T_FROM_LIST(geometricmean)
821T_FROM_LIST(harmonicmean)
822T_FROM_LIST(mean)
823
824
825PyObject *py_median(PyObject *, PyObject *args)
826{ PyTRY
827    vector<double> flist;
828    if (args2flist(args, flist))
829      return PyFloat_FromDouble(median(flist));
830
831    PyErr_Clear();
832
833    vector<PyWrapper> wlist;
834    if (args2wlist(args, wlist))
835      return median(wlist);
836
837    PyErr_Clear();
838
839    PyObject *pylist, *pycomp=NULL;
840    if (   PyArg_ParseTuple(args, "O|O", &pylist, &pycomp)
841        || !PyList_Check(pylist))
842      PYERROR(PyExc_AttributeError, "list expected", PYNULL)
843    if (!PyList2wlist(pylist, wlist))
844      return PYNULL;
845
846    return median(wlist, LessThanCallback(pycomp));
847
848  PyCATCH
849}
850
851
852PyObject *py_mode(PyObject *, PyObject *args)
853{ PyTRY
854    vector<double> flist;
855    if (args2flist(args, flist)) {
856      vector<double> modes;
857      int res=mode(flist, modes);
858      return Py_BuildValue("iN", res, flist2PyList(modes));
859    }
860
861    PyErr_Clear();
862
863    PyObject *pylist, *pycomp=NULL;
864    vector<PyWrapper> wlist, modes;
865    if (   !PyArg_ParseTuple(args, "O|O", &pylist, &pycomp)
866        || !PyList_Check(pylist))
867      PYERROR(PyExc_AttributeError, "mode: list and optional compare function expected", PYNULL)
868    if (!PyList2wlist(pylist, wlist))
869      return PYNULL;
870
871    int res= pycomp ? mode(wlist, modes, LessThanCallback(pycomp))
872                    : mode(wlist, modes);
873    PYERROR(PyExc_SystemError, "mode: failed", PYNULL);
874    return Py_BuildValue("iN", res, wlist2PyList(modes));
875 
876  PyCATCH
877}
878
879
880
881/* *********** MOMENTS ************/
882
883T_FROM_LIST_INT(moment)
884T_FROM_LIST(variation)
885T_FROM_LIST(skewness)
886T_FROM_LIST(kurtosis)
887
888
889/* *********** FREQUENCY STATS************/
890
891
892PyObject *py_scoreatpercentile(PyObject *, PyObject *args)
893{ PyTRY
894    PyObject *pylist;
895    double perc;
896    vector<double> flist;
897    if (   PyArg_ParseTuple(args, "Od", &pylist, &perc)
898        && PyList2flist(pylist, flist))
899      return PyFloat_FromDouble(scoreatpercentile(flist, perc));
900
901    PyErr_Clear();
902
903    vector<PyWrapper> wlist;
904    PyObject *pycomp=NULL;
905    if (   PyArg_ParseTuple(args, "Od|O", &pylist, &perc, &pycomp)
906        && PyList2wlist(pylist, wlist))
907      return (PyObject *)(scoreatpercentile(wlist, perc, LessThanCallback(pycomp)));
908
909    PYERROR(PyExc_AttributeError, "scoreatpercentile: list, percentile and optional compare function expected", PYNULL);
910
911  PyCATCH
912}
913
914
915PyObject *py_percentileofscore(PyObject *, PyObject *args)
916{ PyTRY
917    PyObject *pylist;
918    double score;
919    vector<double> flist;
920    if (   PyArg_ParseTuple(args, "Od", &pylist, &score)
921        && PyList2flist(pylist, flist))
922      return PyFloat_FromDouble(percentileofscore(flist, score));
923
924    PyErr_Clear();
925
926    vector<PyWrapper> wlist;
927    PyObject *pyscore, *pycomp=NULL;
928    if (   PyArg_ParseTuple(args, "OO|O", &pylist, &pyscore, &pycomp)
929        && PyList2wlist(pylist, wlist))
930      return PyFloat_FromDouble(percentileofscore(wlist, PyWrapper(pyscore), LessThanCallback(pycomp)));
931
932    PYERROR(PyExc_AttributeError, "percentileofscore: list, score and optional compare function expected", PYNULL);
933
934  PyCATCH
935}
936
937
938#define CALL_HISTOGRAM 0
939#define CALL_CUMFREQ   1
940#define CALL_RELFREQ   2
941
942#define HISTOSWITCH(pars, parsd) \
943  switch (function) { \
944    case CALL_HISTOGRAM: histogram pars; break; \
945    case CALL_CUMFREQ: cumfreq pars; break; \
946    case CALL_RELFREQ: relfreq parsd; break; \
947  }
948
949PyObject *py_histograms(PyObject *args, int function)
950{ PyTRY
951    vector<int> counts;
952    vector<double> dcounts;
953    int extrapoints;
954    PyObject *pylist;
955    int numbins=10;
956   
957    {
958      double min, binsize;
959      const double qNaN=numeric_limits<double>::quiet_NaN();
960      double defaultMin=qNaN, defaultMax=qNaN;
961      vector<double> flist;
962
963      if (   PyArg_ParseTuple(args, "O|idd", &pylist, &numbins, &defaultMin, &defaultMax) 
964          && PyList2flist(pylist, flist)) {
965
966        if ((defaultMin!=qNaN) && (defaultMax!=qNaN))
967          HISTOSWITCH((flist, counts, min, binsize, extrapoints, defaultMin, defaultMax, numbins),
968                      (flist, dcounts, min, binsize, extrapoints, defaultMin, defaultMax, numbins))
969        else
970          HISTOSWITCH((flist, counts, min, binsize, extrapoints, numbins),
971                      (flist, dcounts, min, binsize, extrapoints, numbins))
972
973        return Py_BuildValue("Nddi",
974                             function==CALL_RELFREQ ? flist2PyList(dcounts) : ilist2PyList(counts),
975                             min, binsize, extrapoints);
976      }
977    }
978
979    PyErr_Clear();
980
981    {
982      PyObject *pyMin=NULL, *pyMax=NULL;
983      vector<PyWrapper> wlist;
984      PyWrapper min, binsize;
985
986      if (   PyArg_ParseTuple(args, "O|iOO", &pylist, &numbins, &pyMin, &pyMax)
987          && PyList2wlist(pylist, wlist)) {
988
989        if (pyMin && pyMax)
990          HISTOSWITCH((wlist, counts, min, binsize, extrapoints, PyWrapper(pyMin), PyWrapper(pyMax), numbins),
991                      (wlist, dcounts, min, binsize, extrapoints, PyWrapper(pyMin), PyWrapper(pyMax), numbins))
992        else
993          HISTOSWITCH((wlist, counts, min, binsize, extrapoints, numbins),
994                      (wlist, dcounts, min, binsize, extrapoints, numbins))
995
996        return Py_BuildValue("NNNi", 
997                             function==CALL_RELFREQ ? flist2PyList(dcounts) : ilist2PyList(counts),
998                             (PyObject *)min, (PyObject *)binsize, extrapoints);
999      }
1000    }
1001
1002    PYERROR(PyExc_TypeError, "histogram: invalid arguments", PYNULL);
1003  PyCATCH
1004}
1005
1006
1007PyObject *py_histogram(PyObject *, PyObject *args)
1008{ return py_histograms(args, CALL_HISTOGRAM); }
1009
1010PyObject *py_cumfreq(PyObject *, PyObject *args)
1011{ return py_histograms(args, CALL_CUMFREQ); }
1012
1013PyObject *py_relfreq(PyObject *, PyObject *args)
1014{ return py_histograms(args, CALL_RELFREQ); }
1015
1016
1017
1018/* *********** VARIABILITY ************/
1019
1020T_FROM_LIST(samplevar)
1021T_FROM_LIST(samplestdev)
1022T_FROM_LIST(var)
1023T_FROM_LIST(stdev)
1024T_FROM_LIST(sterr)
1025T_FROM_LIST_T(z)
1026LIST_FROM_LIST(zs)
1027
1028
1029/* *********** TRIMMING FUNCTIONS ************/
1030
1031LIST_FROM_LIST_DOUBLE(trimboth)
1032
1033PyObject *py_trim1(PyObject *, PyObject *args) \
1034{ PyTRY
1035    PyObject *pylist;
1036    double mom;
1037    char *which=NULL;
1038
1039    if (   PyArg_ParseTuple(args, "Od|s", &pylist, &mom, &which)) {
1040
1041      bool right;
1042      if (!which || strcmp(which, "right")==0)
1043        right=true;
1044      else if (strcmp(which, "left")==0)
1045        right=false;
1046      else
1047        PYERROR(PyExc_AttributeError, "trim1: invalid 'tail' argument", PYNULL);
1048
1049      vector<double> flist;
1050      if (PyList2flist(pylist, flist)) {
1051        vector<double> fres;
1052        trim1(flist, mom, fres, right);
1053        return flist2PyList(fres);
1054      }
1055
1056      PyErr_Clear();
1057
1058      vector<PyWrapper> wlist;
1059      if (PyList2wlist(pylist, wlist)) {
1060        vector<PyWrapper> wres;
1061        trim1(wlist, mom, wres, right);
1062        return wlist2PyList(wres);
1063      }
1064    }
1065
1066    PYERROR(PyExc_AttributeError, "trim1: invalid arguments", PYNULL);
1067  PyCATCH
1068}
1069
1070
1071/* *********** CORRELATION FUNCTIONS************/
1072
1073T_T_FROM_LIST_LIST(pearsonr)
1074DOUBLE_DOUBLE_FROM_LIST_LIST(spearmanr)
1075DOUBLE_DOUBLE_FROM_LIST_LIST(pointbiserialr)
1076DOUBLE_DOUBLE_FROM_LIST_LIST(kendalltau)
1077
1078PyObject *py_linregress(PyObject *, PyObject *args)
1079{ PyTRY
1080    #define VARS r, slope, intercepr, probrs, sterrest
1081
1082    vector<double> x, y;
1083    if (args22lists(args, x, y)) {
1084      double VARS;
1085      linregress(x, y, VARS);
1086      return Py_BuildValue("ddddd", VARS);
1087    }
1088   
1089    PyErr_Clear();
1090   
1091    vector<PyWrapper> wx, wy;
1092    if (args22wlists(args, wx, wy)) {
1093      PyWrapper VARS;
1094      linregress(wx, wy, VARS);
1095      return Py_BuildValue("NNNNN", (PyObject *)r, (PyObject *)slope, (PyObject *)intercepr, (PyObject *)probrs, (PyObject *)sterrest);
1096    }
1097
1098    #undef VARS
1099    PYERROR(PyExc_AttributeError, "linregress: two lists expected", PYNULL);
1100  PyCATCH
1101}
1102
1103
1104
1105/* *********** INFERENTIAL STATISTICS ************/
1106
1107T_T_FROM_LIST_T(ttest_1samp)
1108T_T_FROM_LIST_LIST(ttest_rel)
1109
1110PyObject *py_ttest_ind(PyObject *, PyObject *args)
1111{ PyTRY
1112    vector<double> x, y;
1113    if (args22listsne(args, x, y)) {
1114      double res1, res2;
1115      res1=ttest_ind(x, y, res2);
1116      return Py_BuildValue("dd", res1, res2);
1117    }
1118   
1119    PyErr_Clear();
1120   
1121    vector<PyWrapper> wx, wy;
1122    if (args22wlistsne(args, wx, wy)) {
1123      PyWrapper res1, res2;
1124      res1=ttest_ind(wx, wy, res2);
1125      return Py_BuildValue("NN", (PyObject *)res1, (PyObject *)res2);
1126    }
1127   
1128    PYERROR(PyExc_AttributeError, "ttest_ind: two lists of equal size expected", PYNULL);
1129  PyCATCH
1130}
1131
1132PyObject *py_chisquare(PyObject *, PyObject *args)
1133{ PyTRY
1134    PyObject *pylist1, *pylist2=PYNULL;
1135    if (PyArg_ParseTuple(args, "O|O", &pylist1, &pylist2)) {
1136      vector<double> x, y;
1137      if (   PyList2flist(pylist1, x)
1138          && (!pylist2 || PyList2flist(pylist2, y))) {
1139        double res1, res2;
1140        res1=chisquare(x, pylist2 ? &y : NULL, res2);
1141        return Py_BuildValue("dd", res1, res2);
1142      }
1143
1144      PyErr_Clear();
1145
1146      vector<PyWrapper> wx, wy;
1147      if (   PyList2wlist(pylist1, wx)
1148          && (!pylist2 || PyList2wlist(pylist2, wy))) {
1149        PyWrapper res1, res2;
1150        res1=chisquare(wx, pylist2 ? &wy : NULL, res2);
1151        return Py_BuildValue("NN", (PyObject *)res1, (PyObject *)res2);
1152      }
1153
1154    }
1155   
1156    PYERROR(PyExc_AttributeError, "chisquare: one or two lists expected", PYNULL);
1157  PyCATCH
1158}
1159
1160
1161PyObject *py_chisquare2d(PyObject *, PyObject *args)
1162{ PyTRY
1163    #define VARS prob, cramerV, contingency_coeff
1164
1165    vector<vector<double> > x;
1166    if (args2flist2d(args, x)) {
1167      double chi2, VARS;
1168      int df;
1169      chi2=chisquare2d(x, df, VARS);
1170      return Py_BuildValue("diddd", chi2, df, VARS);
1171    }
1172   
1173    PyErr_Clear();
1174   
1175    vector<vector<PyWrapper> > wx;
1176    if (args2wlist2d(args, wx)) {
1177      PyWrapper chi2, VARS;
1178      int df;
1179      chi2=chisquare2d(wx, df, VARS);
1180      return Py_BuildValue("NiNNN", (PyObject *)chi2, df, (PyObject *)prob, (PyObject *)cramerV, (PyObject *)contingency_coeff);
1181    }
1182
1183    #undef VARS
1184    PYERROR(PyExc_AttributeError, "chisquare2d: 2d contingency matrix expected", PYNULL);
1185  PyCATCH
1186}
1187
1188
1189PyObject *py_anova_rel(PyObject *, PyObject *args)
1190{ PyTRY
1191    vector<vector<double> > x;
1192    if (args2flist2d(args, x)) {
1193      double F, prob;
1194      int df_bt, df_err;
1195      F = anova_rel(x, df_bt, df_err, prob);
1196      return Py_BuildValue("diid", F, df_bt, df_err, prob);
1197    }
1198    PYERROR(PyExc_AttributeError, "anova_rel: 2d contingency matrix expected", PYNULL);
1199  PyCATCH
1200}
1201
1202
1203PyObject *py_friedmanf(PyObject *, PyObject *args)
1204{ PyTRY
1205    vector<vector<double> > x;
1206    if (args2flist2d(args, x)) {
1207      double F, prob, chi2;
1208      int dfnum, dfden;
1209      F = friedmanf(x, chi2, dfnum, dfden, prob);
1210      return Py_BuildValue("diidd", F, dfnum, dfden, prob, chi2);
1211    }
1212    PYERROR(PyExc_AttributeError, "friedmanf: 2d contingency matrix expected", PYNULL);
1213  PyCATCH
1214}
1215
1216
1217#define WRAPTEST(name) \
1218PyObject *py_##name(PyObject *, PyObject *args) \
1219{ PyTRY \
1220    double res, prob; \
1221\
1222    vector<double> x, y; \
1223    if (args22listsne(args, x, y)) { \
1224      res=name(x, y, prob); \
1225      return Py_BuildValue("dd", res, prob); \
1226    } \
1227    PyErr_Clear(); \
1228\
1229    vector<PyWrapper> wx, wy; \
1230    if (args22wlistsne(args, wx, wy)) { \
1231      res=name(wx, wy, prob); \
1232      return Py_BuildValue("dd", res, prob); \
1233    } \
1234    PyErr_Clear(); \
1235\
1236    PyObject *pylist, *pygroup=NULL, *pycomp=NULL; \
1237    if (   PyArg_ParseTuple(args, "OOO", &pylist, &pygroup, &pycomp) \
1238        && PyList2wlist(pylist, wx)) { \
1239      res=name(wx, prob, IsTrueCallback(pygroup), LessThanCallback(pycomp)); \
1240      return Py_BuildValue("dd", res, prob);  \
1241    } \
1242\
1243    PYERROR(PyExc_TypeError, #name": two lists or a list with optional group and compare functions expected.", PYNULL); \
1244  PyCATCH \
1245}
1246
1247WRAPTEST(mannwhitneyu)
1248WRAPTEST(ranksums)
1249
1250#undef WRAPTEST
1251
1252DOUBLE_DOUBLE_FROM_LIST_LIST(wilcoxont)
1253
1254
1255/* *********** PROBABILITY CALCULATIONS ************/
1256
1257T_FROM_T(gammln)
1258T_FROM_T_T_T(betai)
1259T_FROM_T_T_T(betacf)
1260T_FROM_T(zprob)
1261T_FROM_T(erf)
1262T_FROM_T(erfc)
1263T_FROM_T(erfcc)
1264T_FROM_T_T(chisqprob)
1265
1266
1267PyObject *py_fprob(PyObject *, PyObject *args)
1268{ 
1269  PyTRY
1270    int dfnum, dfden;
1271    double F;
1272    if (!PyArg_ParseTuple(args, "iid:fprob", &dfnum, &dfden, &F))
1273      return NULL;
1274    return PyFloat_FromDouble(fprob(dfnum, dfden, F));
1275  PyCATCH;
1276}
1277
1278
1279/* *********** RANDOM NUMBERS ***************/
1280
1281T_FROM_T_T(gasdev)
1282
1283/* *********** SUPPORT FUNCTIONS ************/
1284
1285
1286T_FROM_LIST_optT(sum)
1287LIST_FROM_LIST_optT(cumsum)
1288T_FROM_LIST_optT(ss)
1289T_FROM_LIST_LIST_optT(summult)
1290T_FROM_LIST_optT(sumsquared)
1291T_FROM_LIST_LIST_optT(sumdiffsquared)
1292
1293
1294PyObject *py_shellsort(PyObject *, PyObject *args)
1295{ PyTRY
1296    vector<double> flist;
1297    if (args2flist(args, flist)) {
1298      vector<int> indices;
1299      vector<double> items;
1300      if (!shellsort(flist, indices, items))
1301        PYERROR(PyExc_AttributeError, "shellsort failed", NULL);
1302
1303      PyObject *pyind=ilist2PyList(indices), *pyitems=flist2PyList(items);
1304      return Py_BuildValue("NN", pyitems, pyind);
1305    }
1306
1307    PyErr_Clear();
1308
1309    PyObject *pylist, *pycomp=NULL;
1310    if (   !PyArg_ParseTuple(args, "O|O", &pylist, &pycomp)
1311        || !PyList_Check(pylist))
1312      PYERROR(PyExc_AttributeError, "list and optional compare function expected", false)
1313
1314    vector<PyWrapper> wlist;
1315    if (PyList2wlist(pylist, wlist)) {
1316      vector<int> indices;
1317      vector<PyWrapper> items;
1318
1319      if (pycomp ? !shellsort(wlist, indices, items, LessThanCallback(pycomp))
1320                 : !shellsort(wlist, indices, items))
1321          PYERROR(PyExc_AttributeError, "shellsort failed", NULL);
1322
1323      PyObject *pyind=ilist2PyList(indices), *pyitems=wlist2PyList(items);
1324      return Py_BuildValue("NN", pyitems, pyind);
1325    }
1326 
1327    return PYNULL;
1328  PyCATCH
1329}
1330
1331
1332PyObject *py_rankdata(PyObject *, PyObject *args)
1333{ PyTRY
1334    vector<double> flist, ranks;
1335    if (args2flist(args, flist)) {
1336      if (!rankdata(flist, ranks))
1337        PYERROR(PyExc_SystemError, "rankdata: failed", NULL);
1338      return flist2PyList(ranks);
1339    }
1340   
1341    PyErr_Clear();
1342   
1343    vector<PyWrapper> wlist;
1344    PyObject *pylist, *pycomp=NULL;
1345    if (   !PyArg_ParseTuple(args, "O|O", &pylist, &pycomp)
1346        || !PyList_Check(pylist))
1347      PYERROR(PyExc_AttributeError, "rankdata: list and optional compare function expected", PYNULL)
1348
1349    if (pycomp ? !rankdata(wlist, ranks, LessThanCallback(pycomp))
1350               : !rankdata(wlist, ranks))
1351        PYERROR(PyExc_SystemError, "rankdata: failed", NULL);
1352      return flist2PyList(ranks);
1353
1354    return PYNULL;
1355  PyCATCH \
1356}
1357
1358
1359/* *********** LOESS ******************************/
1360
1361
1362
1363int cc_list(PyObject *pylist, void *l)
1364{ 
1365  if (!PyList_Check(pylist))
1366    return 0;
1367
1368  vector<double> *lst = (vector<double> *)l;
1369
1370  int len = PyList_Size(pylist);
1371  *lst = vector<double>();
1372  lst->reserve(len);
1373
1374  for(int i = 0; i<len; i++) {
1375    PyObject *asnum = PyNumber_Float(PyList_GET_ITEM(pylist, i));
1376    if (!asnum)
1377      return 0;
1378    lst->push_back(PyFloat_AsDouble(asnum));
1379    Py_DECREF(asnum);
1380  }
1381
1382  return 1;
1383}
1384
1385
1386PyObject *list2python(const vector<double> &lst)
1387{
1388  PyObject *res = PyList_New(lst.size());
1389  int i = 0;
1390  for(vector<double>::const_iterator li(lst.begin()), le(lst.end()); li!=le; li++, i++)
1391    PyList_SetItem(res, i, PyFloat_FromDouble(*li));
1392  return res;
1393}
1394
1395typedef void TSampFunc(const vector<double> &, int, vector<double> &);
1396TSampFunc *sampFuncs[] = {samplingMinimal, samplingFactor, samplingFixed, samplingUniform};
1397
1398
1399bool getSmootherPars(PyObject *args, vector<pair<double, double> > &points, vector<double> &sampPoints,
1400                  float &smoothPar, const char *method)
1401{
1402  PyObject *pypoints;
1403  int nPoints;
1404  int distMethod;
1405  char buf[20];
1406  vector<double> xpoints;
1407
1408  points.clear();
1409  sampPoints.clear();
1410
1411 
1412  if (PyList_Check(PyTuple_GET_ITEM(args, 1))) {
1413    snprintf(buf, 19, "OO&f:%s", method);
1414    if (!PyArg_ParseTuple(args, buf, &pypoints, cc_list, &sampPoints, &smoothPar))
1415      return false;
1416    distMethod = -1;
1417  }
1418  else {
1419    snprintf(buf, 19, "Oif|i:%s", method);
1420    if (!PyArg_ParseTuple(args, "Oif|i:loess", &pypoints, &nPoints, &smoothPar, &distMethod))
1421      return false;
1422    if ((distMethod < DISTRIBUTE_MINIMAL) || (distMethod > DISTRIBUTE_UNIFORM))
1423      PYERROR(PyExc_TypeError, "invalid point distribution method", false);
1424  }
1425
1426
1427  PyObject *iter = PyObject_GetIter(pypoints);
1428  if (!iter)
1429    PYERROR(PyExc_TypeError, "a list (or a tuple) of points expected", false);
1430
1431  PyObject *item;
1432  for (int i = 0; (item = PyIter_Next(iter)) != NULL; i++) {
1433    PyObject *pyx = NULL, *pyy = NULL;
1434    if (   !PyTuple_Check(item)
1435        || (PyTuple_Size(item)!=2)
1436        || ((pyx = PyNumber_Float(PyTuple_GetItem(item, 0))) == NULL)
1437        || ((pyy = PyNumber_Float(PyTuple_GetItem(item, 1))) == NULL)) {
1438      Py_XDECREF(pyx);
1439      Py_DECREF(item);
1440      Py_DECREF(iter);
1441      PyErr_Format(PyExc_TypeError, "invalid point at index %i", i);
1442      return false;
1443    }
1444
1445    points.push_back(pair<double, double>(PyFloat_AsDouble(pyx), PyFloat_AsDouble(pyy)));
1446    if (distMethod != -1)
1447      xpoints.push_back(PyFloat_AsDouble(pyx));
1448
1449    Py_DECREF(pyy);
1450    Py_DECREF(pyx);
1451    Py_DECREF(item);
1452  }
1453  Py_DECREF(iter);
1454 
1455  if (nUniquePoints(xpoints) < 2)
1456  {
1457      PyErr_Format(PyExc_ValueError, "A list with at least 2 unique points required.");
1458      return false;
1459  }
1460
1461  if (distMethod != -1)
1462    sampFuncs[distMethod](xpoints, nPoints, sampPoints);
1463
1464  return true;
1465}
1466
1467
1468PyObject *curve2PyCurve(const vector<double> xs, const vector<pair<double, double> > yvars)
1469{
1470  PyObject *pypoints = PyList_New(xs.size());
1471  int i = 0;
1472  vector<double>::const_iterator xi(xs.begin());
1473  vector<pair<double, double> >::const_iterator yvi(yvars.begin()), yve(yvars.end());
1474  for (; yvi != yve; yvi++, xi++)
1475    PyList_SetItem(pypoints, i++, Py_BuildValue("fff", *xi, (*yvi).first, (*yvi).second));
1476  return pypoints;
1477}
1478
1479
1480PyObject *py_loess(PyObject *, PyObject *args) 
1481{ PyTRY
1482    float windowProp;
1483    vector<pair<double, double> > points;
1484    vector<double> sampPoints;
1485
1486    if (!getSmootherPars(args, points, sampPoints, windowProp, "loess"))
1487      return PYNULL;
1488
1489    vector<pair<double, double> > loess_curve;
1490    loess(sampPoints, points, windowProp, loess_curve);
1491
1492    return curve2PyCurve(sampPoints, loess_curve);
1493  PyCATCH
1494}
1495
1496
1497PyObject *py_lwr(PyObject *, PyObject *args) 
1498{ PyTRY
1499    float sigmaPercentile;
1500    vector<pair<double, double> > points;
1501    vector<double> sampPoints;
1502
1503    if (!getSmootherPars(args, points, sampPoints, sigmaPercentile, "lwr"))
1504      return PYNULL;
1505
1506    vector<pair<double, double> > lwr_curve;
1507    lwr(sampPoints, points, sigmaPercentile, lwr_curve);
1508
1509    return curve2PyCurve(sampPoints, lwr_curve);
1510  PyCATCH
1511}
1512
1513
1514/* *********** COMBINATORIAL FUNCTIONS ************/
1515
1516
1517#include "lcomb.hpp"
1518
1519#define DOUBLE_FROM_INT(name) \
1520PyObject *py_##name(PyObject *, PyObject *args) \
1521{ PyTRY \
1522    int i; \
1523    if (!PyArg_ParseTuple(args, "i", &i)) \
1524      PYERROR(PyExc_AttributeError, "integer expected", PYNULL) \
1525    double res=name(i); \
1526    return Py_BuildValue("d", res); \
1527  PyCATCH \
1528}
1529
1530#define DOUBLE_FROM_INT_INT(name) \
1531PyObject *py_##name(PyObject *, PyObject *args) \
1532{ PyTRY \
1533    int i1, i2; \
1534    if (!PyArg_ParseTuple(args, "ii", &i1, &i2)) \
1535      PYERROR(PyExc_AttributeError, "integer expected", PYNULL) \
1536    double res=name(i1, i2); \
1537    return Py_BuildValue("d", res); \
1538  PyCATCH \
1539}
1540
1541DOUBLE_FROM_INT(fact)
1542DOUBLE_FROM_INT_INT(comb)
1543DOUBLE_FROM_INT_INT(stirling2)
1544DOUBLE_FROM_INT(bell)
1545
1546DOUBLE_FROM_INT(logfact)
1547DOUBLE_FROM_INT_INT(logcomb)
1548
1549
1550#define PY_SAMPLING(name) \
1551PyObject *py_sampling##name(PyObject *, PyObject *args) \
1552{ \
1553  vector<double> points; \
1554  int nPoints; \
1555  \
1556  if (!PyArg_ParseTuple(args, "O&i:sampling" #name, cc_list, &points, &nPoints)) \
1557    return NULL; \
1558  \
1559  vector<double> lst; \
1560  sampling##name(points, nPoints, lst); \
1561  return list2python(lst); \
1562}
1563
1564PY_SAMPLING(Factor)
1565PY_SAMPLING(Fixed)
1566PY_SAMPLING(Uniform)
1567PY_SAMPLING(Minimal)
1568
1569#undef PY_SAMPLING
1570
1571/* *********** EXPORT DECLARATIONS ************/
1572
1573#define DECLARE(name) \
1574 {#name, (binaryfunc)py_##name, METH_VARARGS},
1575
1576PyMethodDef statc_functions[]={
1577     DECLARE(geometricmean)
1578     DECLARE(harmonicmean)
1579     DECLARE(mean)
1580     DECLARE(median)
1581     {"medianscore", (binaryfunc)py_median, METH_VARARGS},
1582     DECLARE(mode)
1583
1584     DECLARE(moment)
1585     DECLARE(variation)
1586     DECLARE(skewness)
1587     DECLARE(kurtosis)
1588
1589     DECLARE(scoreatpercentile)
1590     DECLARE(percentileofscore)
1591     DECLARE(histogram)
1592     DECLARE(cumfreq)
1593     DECLARE(relfreq)
1594
1595
1596     DECLARE(samplevar)
1597     {"samplestd", (binaryfunc)py_samplestdev, METH_VARARGS},
1598     DECLARE(var)
1599     {"std", (binaryfunc)py_stdev, METH_VARARGS},
1600     DECLARE(z)
1601     DECLARE(zs)
1602     DECLARE(sterr)
1603
1604     DECLARE(trimboth)
1605     DECLARE(trim1)
1606
1607     DECLARE(pearsonr)
1608     DECLARE(spearmanr)
1609     DECLARE(pointbiserialr)
1610     DECLARE(kendalltau)
1611     DECLARE(linregress)
1612
1613     DECLARE(ttest_1samp)
1614     DECLARE(ttest_ind)
1615     DECLARE(ttest_rel)
1616     DECLARE(chisquare)
1617     DECLARE(chisquare2d)
1618     DECLARE(anova_rel)
1619     DECLARE(friedmanf)
1620     DECLARE(mannwhitneyu)
1621     DECLARE(ranksums)
1622     DECLARE(wilcoxont)
1623
1624     DECLARE(chisqprob)
1625     DECLARE(zprob)
1626     DECLARE(fprob)
1627     DECLARE(betacf)
1628     DECLARE(betai)
1629     DECLARE(erf)
1630     DECLARE(erfc)
1631     DECLARE(erfcc)
1632     DECLARE(gammln)
1633
1634
1635     DECLARE(sum)
1636     DECLARE(ss)
1637     DECLARE(sumsquared)
1638     DECLARE(summult)
1639     DECLARE(cumsum)
1640     DECLARE(sumdiffsquared)
1641     DECLARE(shellsort)
1642     DECLARE(rankdata)
1643     DECLARE(spearmanr)
1644
1645     DECLARE(gasdev)
1646
1647     DECLARE(fact)
1648     DECLARE(comb)
1649     DECLARE(stirling2)
1650     DECLARE(bell)
1651
1652     DECLARE(logfact)
1653     DECLARE(logcomb)
1654
1655     {"loess", (binaryfunc)py_loess, METH_VARARGS},
1656     {"lwr", (binaryfunc)py_lwr, METH_VARARGS},
1657     DECLARE(samplingFactor)
1658     DECLARE(samplingFixed)
1659     DECLARE(samplingMinimal)
1660     DECLARE(samplingUniform)
1661
1662     {NULL, NULL}
1663};
1664
1665#undef T_FROM_LIST
1666#undef T_FROM_LIST_optT
1667#undef T_FROM_LIST_LIST
1668#undef T_FROM_LIST_LIST_optT
1669#undef LIST_FROM_LIST
1670#undef LIST_FROM_LIST_optT
1671#undef T_FROM_LIST_T
1672#undef T_FROM_LIST_plus
1673#undef T_FROM_LIST_INT
1674#undef T_FROM_LIST_DOUBLE
1675#undef LIST_FROM_LIST_plus
1676#undef LIST_FROM_LIST_INT
1677#undef LIST_FROM_LIST_DOUBLE
1678#undef DOUBLE_DOUBLE_FROM_LIST_LIST
1679#undef T_T_FROM_LIST_LIST
1680#undef T_T_FROM_LIST_plus
1681#undef T_T_FROM_LIST
1682#undef T_T_FROM_LIST_INT
1683#undef T_T_FROM_LIST_DOUBLE
1684#undef DOUBLE_DOUBLE_FROM_LIST_plus
1685#undef DOUBLE_DOUBLE_FROM_LIST_INT
1686#undef DOUBLE_DOUBLE_FROM_LIST_DOUBLE
1687#undef T_T_FROM_LIST_T
1688#undef T_FROM_T
1689#undef T_FROM_T_T_T
1690#undef CALL_HISTOGRAM
1691#undef CALL_CUMFREQ
1692#undef CALL_RELFREQ
1693#undef HISTOSWITCH
1694#undef WRAPTEST
1695#undef DECLARE
1696
1697#undef PyTRY
1698#undef PyCATCH
1699#undef PYNULL
Note: See TracBrowser for help on using the repository browser.