source: orange/source/orange/lib_components.cpp @ 7665:3aede63f569f

Revision 7665:3aede63f569f, 194.7 KB checked in by markotoplak, 3 years ago (diff)

Replaced Variable->name with setter and getter. Interface to Python remained the same.

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#pragma warning (disable : 4786 4114 4018 4267 4244)
24#endif
25
26#include "vars.hpp"
27#include "stringvars.hpp"
28#include "distvars.hpp"
29#include "domain.hpp"
30#include "examples.hpp"
31#include "examplegen.hpp"
32#include "table.hpp"
33
34#include "cls_value.hpp"
35#include "cls_example.hpp"
36#include "cls_orange.hpp"
37#include "lib_kernel.hpp"
38#include "callback.hpp"
39
40#include "vectortemplates.hpp"
41
42
43#include "converts.hpp"
44#include "slist.hpp"
45
46#include "externs.px"
47
48
49bool convertFromPython(PyObject *, PContingency &, bool allowNull=false, PyTypeObject *type=NULL);
50
51/* ************ COST ************ */
52
53#include "cost.hpp"
54
55
56
57PyObject *convertToPython(const PCostMatrix &matrix)
58{
59    int dim = matrix->dimension;
60    PyObject *pycost = PyList_New(dim);
61    float *ci = matrix->costs;
62    for(int i = 0; i < dim; i++) {
63        PyObject *row = PyList_New(dim);
64        for(int j = 0; j < dim; j++)
65            PyList_SetItem(row, j, PyFloat_FromDouble(*ci++));
66        PyList_SetItem(pycost, i, row);
67    }
68    return pycost;
69}
70
71
72bool readCostMatrix(PyObject *arg, TCostMatrix *&matrix)
73{
74    int dim;
75    const int arglength = PyObject_Length(arg);
76    if (matrix) {
77        dim = matrix->dimension;
78        if (dim != arglength) {
79            PyErr_Format(PyExc_TypeError, "invalid sequence length (expected %i, got %i)", dim, arglength);
80            return false;
81        }
82    }
83    else {
84        dim = arglength;
85        matrix = mlnew TCostMatrix(dim);
86    }
87
88    PyObject *iter = PyObject_GetIter(arg);
89    if (!iter)
90        PYERROR(PyExc_TypeError, "sequence expected", false);
91
92    int i, j;
93
94    for(i = 0; i<dim; i++) {
95        PyObject *item = PyIter_Next(iter);
96        if (!item) {
97            PyErr_Format(PyExc_TypeError, "matrix is too short (%i rows expected)", dim);
98            break;
99        }
100
101        PyObject *subiter = PyObject_GetIter(item);
102        Py_DECREF(item);
103
104        if (!subiter) {
105            PyErr_Format(PyExc_TypeError, "element %i is not a sequence", i);
106            break;
107        }
108
109        for(j = 0; j<dim; j++) {
110            PyObject *subitem = PyIter_Next(subiter);
111            if (!subitem) {
112                PyErr_Format(PyExc_TypeError, "element %i is too short (sequence with %i elements expected)", i, dim);
113                break;
114            }
115
116            float f;
117            bool ok = PyNumber_ToFloat(subitem, f);
118            Py_DECREF(subitem);
119            if (!ok) {
120                PyErr_Format(PyExc_TypeError, "element at (%i, %i) is not a number", i, j);
121                break;
122            }
123
124            // this cannot fail:
125            matrix->cost(i, j) = f;
126        }
127
128        if (j<dim) {
129            Py_DECREF(subiter);
130            break;
131        }
132
133        PyObject *subitem = PyIter_Next(subiter);
134        Py_DECREF(subiter);
135
136        if (subitem) {
137            PyErr_Format(PyExc_TypeError, "element %i is too long (sequence with %i elements expected)", i, dim);
138            Py_DECREF(subitem);
139            break;
140        }
141    }
142
143    Py_DECREF(iter);
144
145    if (i<dim) {
146        mldelete matrix;
147        return false;
148    }
149
150    return true;
151}
152
153
154PyObject *CostMatrix_new(PyTypeObject *type, PyObject *args) BASED_ON(Orange, "(list-of-list-of-prices) -> CostMatrix")
155{
156    PyTRY
157        if (PyTuple_Size(args) == 1) {
158            PyObject *arg = PyTuple_GET_ITEM(args, 0);
159
160            if (PyInt_Check(arg))
161                return WrapNewOrange(mlnew TCostMatrix(PyInt_AsLong(arg)), type);
162
163            if (PyOrVariable_Check(arg))
164                return WrapNewOrange(mlnew TCostMatrix(PyOrange_AsVariable(arg)), type);
165
166            TCostMatrix *nm = NULL;
167            return readCostMatrix(arg, nm) ? WrapNewOrange(nm, type) : PYNULL;
168        }
169
170
171        if (PyTuple_Size(args) == 2) {
172            PyObject *arg1, *arg2;
173            arg1 = PyTuple_GetItem(args, 0);
174            arg2 = PyTuple_GetItem(args, 1);
175
176            float inside;
177            if (PyNumber_ToFloat(arg2, inside)) {
178                if (PyInt_Check(arg1))
179                    return WrapNewOrange(mlnew TCostMatrix(PyInt_AsLong(arg1), inside), type);
180
181                if (PyOrVariable_Check(arg1))
182                    return WrapNewOrange(mlnew TCostMatrix(PyOrange_AsVariable(arg1), inside), type);
183            }
184
185            if (PyOrVariable_Check(arg1)) {
186                TCostMatrix *nm = mlnew TCostMatrix(PyOrange_AsVariable(arg1));
187                return readCostMatrix(arg2, nm) ? WrapNewOrange(nm, type) : PYNULL;
188            }
189        }
190
191        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
192        PyCATCH
193}
194
195
196PyObject *CostMatrix__reduce__(PyObject *self)
197{
198    PyTRY
199        CAST_TO(TCostMatrix, matrix);
200    const int dim = matrix->dimension;
201    return Py_BuildValue("O(Os#i)N", getExportedFunction("__pickleLoaderCostMatrix"),
202        self->ob_type,
203        matrix->costs, dim*dim*sizeof(float),
204        dim,
205        packOrangeDictionary(self));
206    PyCATCH
207}
208
209
210PyObject *__pickleLoaderCostMatrix(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension)")
211{
212    PyTRY
213        PyTypeObject *type;
214    char *buf;
215    int bufSize, dim;
216    if (!PyArg_ParseTuple(args, "Os#i:__pickleLoaderCostMatrix", &type, &buf, &bufSize, &dim))
217        return NULL;
218
219    TCostMatrix *cm = new TCostMatrix(dim);
220    memcpy(cm->costs, buf, bufSize);
221    return WrapNewOrange(cm, type);
222    PyCATCH
223}
224
225
226PyObject *CostMatrix_native(PyObject *self) PYARGS(METH_O, "() -> list of lists of floats")
227{ return convertToPython(PyOrange_AsCostMatrix(self)); }
228
229
230int getCostIndex(PyObject *arg, TCostMatrix *matrix, char *error)
231{
232    if (PyInt_Check(arg)) {
233        int pred = PyInt_AsLong(arg);
234        if ((pred<0) || (pred >= matrix->dimension))
235            PYERROR(PyExc_IndexError, error, -1);
236        return pred;
237    }
238    else {
239        TValue val;
240        return  convertFromPython(arg, val, matrix->classVar) ? int(val) : -1;
241    }
242}
243
244
245
246PyObject *CostMatrix_getcost(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(predicted, correct) -> float")
247{
248    PyTRY
249        CAST_TO(TCostMatrix, matrix);
250
251    if (PyTuple_Size(args) != 2)
252        PYERROR(PyExc_TypeError, "two arguments expected", PYNULL);
253
254    PyObject *arg1 = PyTuple_GET_ITEM(args, 0);
255    PyObject *arg2 = PyTuple_GET_ITEM(args, 1);
256
257    int pred = getCostIndex(arg1, matrix, "predicted value out of range");
258    int corr = getCostIndex(arg2, matrix, "correct value out of range");
259    if ((pred==-1) || (corr==-1))
260        return PYNULL;
261
262    return PyFloat_FromDouble(matrix->cost(pred, corr));
263    PyCATCH
264}
265
266
267PyObject *CostMatrix_setcost(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(predicted, correct, cost) -> float")
268{
269    PyTRY
270        CAST_TO(TCostMatrix, matrix);
271
272    PyObject *arg1, *arg2;
273    float cost;
274
275    if (!PyArg_ParseTuple(args, "OOf:CostMatrix.setcost", &arg1, &arg2, &cost))
276        return PYNULL;
277
278    int pred = getCostIndex(arg1, matrix, "predicted value out of range");
279    int corr = getCostIndex(arg2, matrix, "correct value out of range");
280    if ((pred==-1) || (corr==-1))
281        return PYNULL;
282
283    matrix->cost(pred, corr) = cost;
284    RETURN_NONE;
285    PyCATCH
286}
287
288
289/* ************ BASSTAT ************ */
290
291#include "basstat.hpp"
292
293PyObject *BasicAttrStat_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Orange, "(variable, [examples, weightID, min=, max=, avg=, dev=, n=]) -> BasicAttrStat") ALLOWS_EMPTY
294{
295  PyTRY
296    PyObject *pyvar = NULL;
297    PExampleGenerator egen;
298    int weightID = 0;
299    if (!PyArg_ParseTuple(args, "|OO&i:BasicAttrStat.__new__", &pyvar, pt_ExampleGenerator, &egen, &weightID))
300      return NULL;
301
302    if (!pyvar)
303      return WrapNewOrange(mlnew TBasicAttrStat(PVariable()), type);
304
305    if (!egen) {
306        if (!PyOrVariable_Check(pyvar)) {
307            PyErr_Format(PyExc_TypeError, "BasicAttrStat expects a 'Variable', not a '%s'", pyvar->ob_type->tp_name);
308            return NULL;
309        }
310
311        return WrapNewOrange(mlnew TBasicAttrStat(PyOrange_AsVariable(pyvar)), type);
312    }
313
314    PVariable var = varFromArg_byDomain(pyvar, egen->domain, false);
315    if (!var)
316      return NULL;
317
318    return WrapNewOrange(mlnew TBasicAttrStat(egen, var, weightID), type);
319  PyCATCH
320}
321
322
323PyObject *BasicAttrStat_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value[, weight]) -> None")
324{ PyTRY
325float value, weight=1.0;
326if (!PyArg_ParseTuple(args, "f|f:BasicAttrStat.add", &value, &weight))
327return PYNULL;
328SELF_AS(TBasicAttrStat).add(value, weight);
329RETURN_NONE;
330PyCATCH
331}
332
333
334PyObject *BasicAttrStat_recompute(PyObject *self) PYARGS(METH_NOARGS, "() -> None")
335{ PyTRY
336SELF_AS(TBasicAttrStat).recompute();
337RETURN_NONE;
338PyCATCH
339}
340
341
342PyObject *BasicAttrStat_reset(PyObject *self) PYARGS(METH_NOARGS, "() -> None")
343{ PyTRY
344SELF_AS(TBasicAttrStat).reset();
345RETURN_NONE;
346PyCATCH
347}
348
349
350/* We redefine new (removed from below!) and add mapping methods
351*/
352
353PDomainBasicAttrStat PDomainBasicAttrStat_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::P_FromArguments(arg); }
354PyObject *DomainBasicAttrStat_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_FromArguments(type, arg); }
355PyObject *DomainBasicAttrStat_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_getitem(self, index); }
356int       DomainBasicAttrStat_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_setitem(self, index, item); }
357PyObject *DomainBasicAttrStat_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_getslice(self, start, stop); }
358int       DomainBasicAttrStat_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_setslice(self, start, stop, item); }
359Py_ssize_t       DomainBasicAttrStat_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_len(self); }
360PyObject *DomainBasicAttrStat_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_richcmp(self, object, op); }
361PyObject *DomainBasicAttrStat_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_concat(self, obj); }
362PyObject *DomainBasicAttrStat_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_repeat(self, times); }
363PyObject *DomainBasicAttrStat_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_str(self); }
364PyObject *DomainBasicAttrStat_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_str(self); }
365int       DomainBasicAttrStat_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_contains(self, obj); }
366PyObject *DomainBasicAttrStat_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(BasicAttrStat) -> None") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_append(self, item); }
367PyObject *DomainBasicAttrStat_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_extend(self, obj); }
368PyObject *DomainBasicAttrStat_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(BasicAttrStat) -> int") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_count(self, obj); }
369PyObject *DomainBasicAttrStat_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainBasicAttrStat") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_filter(self, args); }
370PyObject *DomainBasicAttrStat_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(BasicAttrStat) -> int") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_index(self, obj); }
371PyObject *DomainBasicAttrStat_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_insert(self, args); }
372PyObject *DomainBasicAttrStat_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_native(self); }
373PyObject *DomainBasicAttrStat_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> BasicAttrStat") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_pop(self, args); }
374PyObject *DomainBasicAttrStat_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(BasicAttrStat) -> None") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_remove(self, obj); }
375PyObject *DomainBasicAttrStat_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_reverse(self); }
376PyObject *DomainBasicAttrStat_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_sort(self, args); }
377PyObject *DomainBasicAttrStat__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_reduce(self); }
378
379
380/* Note that this is not like callable-constructors. They return different type when given
381parameters, while this one returns the same type, disregarding whether it was given examples or not.
382*/
383PyObject *DomainBasicAttrStat_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange, "(examples | <list of BasicAttrStat>) -> DomainBasicAttrStat") ALLOWS_EMPTY
384{ PyTRY
385if (!args || !PyTuple_Size(args))
386return WrapNewOrange(mlnew TDomainBasicAttrStat(), type);
387
388int weightID;
389PExampleGenerator gen = exampleGenFromArgs(args, weightID);
390if (gen)
391return WrapNewOrange(mlnew TDomainBasicAttrStat(gen, weightID), type);
392
393PyErr_Clear();
394
395PyObject *obj = ListOfWrappedMethods<PDomainBasicAttrStat, TDomainBasicAttrStat, PBasicAttrStat, &PyOrBasicAttrStat_Type>::_new(type, args, keywds);
396if (obj)
397return obj;
398
399PyErr_Clear();
400PYERROR(PyExc_TypeError, "DomainBasicAttrStat.__init__ expects examples or a list of BasicAttrStat", PYNULL);
401PyCATCH
402}
403
404
405PyObject *DomainBasicAttrStat_purge(PyObject *self) PYARGS(METH_NOARGS, "None -> None")
406{ PyTRY
407SELF_AS(TDomainBasicAttrStat).purge();
408RETURN_NONE
409PyCATCH
410}
411
412/* We keep the sequence methods and add mapping interface */
413
414int DomainBasicAttrStat_getItemIndex(PyObject *self, PyObject *args)
415{ CAST_TO_err(TDomainBasicAttrStat, bas, -1);
416
417if (PyInt_Check(args)) {
418    int i=(int)PyInt_AsLong(args);
419    if ((i>=0) && (i<int(bas->size())))
420        return i;
421    else
422        PYERROR(PyExc_IndexError, "index out of range", -1);
423}
424
425if (PyString_Check(args)) {
426    char *s=PyString_AsString(args);
427    PITERATE(TDomainBasicAttrStat, ci, bas)
428        if (*ci && (*ci)->variable && ((*ci)->variable->get_name()==s))
429            return ci - bas->begin();
430
431    PyErr_Format(PyExc_IndexError, "attribute '%s' not found", s);
432    return -1;
433}
434
435if (PyOrVariable_Check(args)) {
436    PVariable var = PyOrange_AsVariable(args);
437    PITERATE(TDomainBasicAttrStat, ci, bas)
438        if (*ci && (*ci)->variable && ((*ci)->variable==var))
439            return ci - bas->begin();
440
441    PyErr_Format(PyExc_IndexError, "attribute '%s' not found", var->get_name().length() ? var->get_name().c_str() : "<no name>");
442    return -1;
443}
444
445PYERROR(PyExc_IndexError, "invalid index type", -1);
446}
447
448
449PyObject *DomainBasicAttrStat_getitem(PyObject *self, PyObject *args)
450{ PyTRY
451int index=DomainBasicAttrStat_getItemIndex(self, args);
452if (index<0)
453return PYNULL;
454return WrapOrange(POrange(SELF_AS(TDomainBasicAttrStat).at(index)));
455PyCATCH
456}
457
458
459int DomainBasicAttrStat_setitem(PyObject *self, PyObject *args, PyObject *obj)
460{ PyTRY
461PBasicAttrStat bas;
462
463if (!PyOrBasicAttrStat_Check(obj))
464PYERROR(PyExc_TypeError, "invalid BasicAttrStat object", -1);
465
466int index=DomainBasicAttrStat_getItemIndex(self, args);
467if (index==-1)
468return -1;
469
470SELF_AS(TDomainBasicAttrStat)[index] = PyOrange_AsBasicAttrStat(obj);
471return 0;
472PyCATCH_1
473}
474
475
476
477PyObject *PearsonCorrelation_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Orange, "(var1, var2, examples[, weightID]) -> PearsonCorrelation")
478{
479  PyTRY
480    PyObject *pyvar1, *pyvar2;
481    PExampleGenerator egen;
482    int weightID = 0;
483    if (!PyArg_ParseTuple(args, "OOO&|i:BasicAttrStat.__new__", &pyvar1, &pyvar2, pt_ExampleGenerator, &egen, &weightID))
484      return NULL;
485
486    PVariable var1 = varFromArg_byDomain(pyvar1, egen->domain, false);
487    if (!var1)
488      return NULL;
489
490    PVariable var2 = varFromArg_byDomain(pyvar2, egen->domain, false);
491    if (!var2)
492      return NULL;
493
494    return WrapNewOrange(mlnew TPearsonCorrelation(egen, var1, var2, weightID), type);
495  PyCATCH
496}
497
498
499
500/* ************ CONTINGENCY ************ */
501
502#include "contingency.hpp"
503#include "estimateprob.hpp"
504
505ABSTRACT(ContingencyClass, Contingency)
506
507PDistribution *Contingency_getItemRef(PyObject *self, PyObject *index)
508{ CAST_TO_err(TContingency, cont, (PDistribution *)NULL);
509if (!cont->outerVariable)
510PYERROR(PyExc_SystemError, "invalid contingency (no variable)", (PDistribution *)NULL);
511
512if (cont->outerVariable->varType==TValue::INTVAR) {
513    int ind=-1;
514    if (PyInt_Check(index))
515        ind=(int)PyInt_AsLong(index);
516    else {
517        TValue val;
518        if (convertFromPython(index, val, cont->outerVariable) && !val.isSpecial())
519            ind=int(val);
520    }
521
522    if ((ind>=0) && (ind<int(cont->discrete->size())))
523        return &cont->discrete->at(ind);
524}
525else if (cont->outerVariable->varType==TValue::FLOATVAR) {
526    float ind;
527    if (!PyNumber_ToFloat(index, ind)) {
528        TValue val;
529        if (convertFromPython(index, val, cont->outerVariable) && !val.isSpecial())
530            ind = float(val);
531        else
532            PYERROR(PyExc_IndexError, "invalid index type (float expected)", NULL);
533    }
534
535    TDistributionMap::iterator mi=cont->continuous->find(ind);
536    if (mi!=cont->continuous->end())
537        return &(*mi).second;
538
539    PyErr_Format(PyExc_IndexError, "invalid index (%5.3f)", ind);
540    return NULL;
541}
542
543PYERROR(PyExc_IndexError, "invalid index", (PDistribution *)NULL);
544}
545
546
547PyObject *Contingency_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Orange, "(outer_desc, inner_desc)")
548{ PyTRY
549PVariable var1, var2;
550if (!PyArg_ParseTuple(args, "O&O&:Contingency.__new__", cc_Variable, &var1, cc_Variable, &var2))
551return PYNULL;
552
553return WrapNewOrange(mlnew TContingency(var1, var2), type);
554PyCATCH
555}
556
557
558PyObject *ContingencyReduceCommon(PyObject *self, const char *loaderFunc)
559{
560    PyTRY
561        CAST_TO(TContingency, cont);
562
563    if (cont->varType == TValue::INTVAR) {
564        PyObject *dvect = PyList_New(cont->discrete->size());
565        int i = 0;
566        PITERATE(TDistributionVector, di, cont->discrete)
567            PyList_SetItem(dvect, i++, WrapOrange(*di));
568
569        return Py_BuildValue("O(ON)N", getExportedFunction(loaderFunc),
570            (PyObject *)(self->ob_type),
571            dvect,
572            packOrangeDictionary(self));
573    }
574
575    else if (cont->varType == TValue::FLOATVAR) {
576        PyObject *dvect = PyList_New(cont->continuous->size());
577        TCharBuffer buf(1024);
578        int i = 0;
579        PITERATE(TDistributionMap, di, cont->continuous) {
580            buf.writeFloat((*di).first);
581            PyList_SetItem(dvect, i++, WrapOrange((*di).second));
582        }
583
584        return Py_BuildValue("O(ONs#)N", getExportedFunction(loaderFunc),
585            (PyObject *)(self->ob_type),
586            dvect,
587            buf.buf, buf.length(),
588            packOrangeDictionary(self));
589    }
590
591    else
592        PYERROR(PyExc_SystemError, "an instance of Contingency for this attribute type cannot be pickled", NULL);
593
594    PyCATCH
595}
596
597
598PyObject *__pickleLoaderContingencyCommon(TContingency *cont, PyObject *args)
599{
600    PyTRY
601        PyTypeObject *type;
602    PyObject *dvect, *packedF = NULL;
603    if (!PyArg_UnpackTuple(args, "__pickleLoaderContingency", 2, 3, &type, &dvect, &packedF)) {
604        delete cont;
605        return NULL;
606    }
607
608    if (packedF) {
609        char *pbuf;
610        Py_ssize_t bufSize;
611        if (PyString_AsStringAndSize(packedF, &pbuf, &bufSize) == -1) {
612            delete cont;
613            return NULL;
614        }
615        TCharBuffer buf(pbuf);
616
617        cont->continuous = new TDistributionMap();
618        TDistributionMap &dmap = *cont->continuous;
619
620        for(Py_ssize_t i = 0, e = PyList_Size(dvect); i < e; i++) {
621            PyObject *dist = PyList_GetItem(dvect, i);
622            if (!PyOrDistribution_Check(dist)) {
623                delete cont;
624                PYERROR(PyExc_TypeError, "a list of distributions expected", NULL);
625            }
626
627            dmap.insert(dmap.end(), pair<float, PDistribution>(buf.readFloat(), PyOrange_AsDistribution(dist)));
628        }
629
630        return WrapNewOrange(cont, type);
631    }
632
633    else {
634        cont->discrete = new TDistributionVector();
635        TDistributionVector &dvec = *cont->discrete;
636
637        for(Py_ssize_t i = 0, e = PyList_Size(dvect); i < e; i++) {
638            PyObject *dist = PyList_GetItem(dvect, i);
639            if (!PyOrDistribution_Check(dist)) {
640                delete cont;
641                PYERROR(PyExc_TypeError, "a list of distributions expected", NULL);
642            }
643
644            dvec.push_back(PyOrange_AsDistribution(dist));
645        }
646
647        return WrapNewOrange(cont, type);
648    }
649
650    PyCATCH
651}
652
653
654PyObject *Contingency__reduce__(PyObject *self, const char *loaderFunc)
655{
656    return ContingencyReduceCommon(self, "__pickleLoaderContingency");
657}
658
659PyObject *__pickleLoaderContingency(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(list of PDistribution, [packed_floats])")
660{
661    return __pickleLoaderContingencyCommon(new TContingency(), args);
662}
663
664
665PyObject *ContingencyAttrClass__reduce__(PyObject *self, const char *loaderFunc)
666{
667    return ContingencyReduceCommon(self, "__pickleLoaderContingencyAttrClass");
668}
669
670PyObject *__pickleLoaderContingencyAttrClass(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(list of PDistribution, [packed_floats])")
671{
672    return __pickleLoaderContingencyCommon(new TContingencyAttrClass(), args);
673}
674
675
676PyObject *ContingencyClassAttr__reduce__(PyObject *self, const char *loaderFunc)
677{
678    return ContingencyReduceCommon(self, "__pickleLoaderContingencyClassAttr");
679}
680
681PyObject *__pickleLoaderContingencyClassAttr(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(list of PDistribution, [packed_floats])")
682{
683    return __pickleLoaderContingencyCommon(new TContingencyClassAttr(), args);
684}
685
686
687PyObject *ContingencyAttrAttr__reduce__(PyObject *self, const char *loaderFunc)
688{
689    return ContingencyReduceCommon(self, "__pickleLoaderContingencyAttrAttr");
690}
691
692PyObject *__pickleLoaderContingencyAttrAttr(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(list of PDistribution, [packed_floats])")
693{
694    return __pickleLoaderContingencyCommon(new TContingencyAttrAttr(), args);
695}
696
697
698
699PyObject *Contingency_add(PyObject *self, PyObject *args)  PYARGS(METH_VARARGS, "(outer_value, inner_value[, w=1]) -> None")
700{
701    PyTRY
702        PyObject *pyouter, *pyinner;
703    float w = 1.0;
704    if (!PyArg_ParseTuple(args, "OO|f:Contingency.add", &pyouter, &pyinner, &w))
705        return PYNULL;
706
707    CAST_TO(TContingency, cont)
708
709        TValue inval, outval;
710    if (   !convertFromPython(pyinner, inval, cont->innerVariable)
711        || !convertFromPython(pyouter, outval, cont->outerVariable))
712        return PYNULL;
713
714    cont->add(outval, inval, w);
715    RETURN_NONE;
716    PyCATCH
717}
718
719
720bool ContingencyClass_getValuePair(TContingencyClass *cont, PyObject *pyattr, PyObject *pyclass, TValue &attrval, TValue &classval)
721{
722    return    convertFromPython(pyattr, attrval, cont->getAttribute())
723        && convertFromPython(pyclass, classval, cont->getClassVar());
724}
725
726
727bool ContingencyClass_getValuePair(TContingencyClass *cont, PyObject *args, char *s, TValue &attrval, TValue &classval)
728{
729    PyObject *pyattr, *pyclass;
730    return    PyArg_ParseTuple(args, s, &pyattr, &pyclass)
731        && ContingencyClass_getValuePair(cont, pyattr, pyclass, attrval, classval);
732}
733
734
735PyObject *ContingencyClass_add_var_class(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(attribute_value, class_value[, w=1]) -> None")
736{
737    PyTRY
738        CAST_TO(TContingencyClass, cont)
739
740        PyObject *pyattr, *pyclass;
741    TValue attrval, classval;
742    float w = 1.0;
743    if (   !PyArg_ParseTuple(args, "OO|f:ContingencyClass.add_attrclass", &pyattr, &pyclass, &w)
744        || !ContingencyClass_getValuePair(cont, pyattr, pyclass, attrval, classval))
745        return PYNULL;
746
747    cont->add_attrclass(attrval, classval, w);
748    RETURN_NONE;
749    PyCATCH
750}
751
752
753PyObject *ContingencyClass_get_classVar(PyObject *self)
754{
755    return WrapOrange(SELF_AS(TContingencyClass).getClassVar());
756}
757
758
759PyObject *ContingencyClass_get_variable(PyObject *self)
760{
761    return WrapOrange(SELF_AS(TContingencyClass).getAttribute());
762}
763
764
765PyObject *ContingencyAttrClass_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(ContingencyClass, "(attribute, class attribute) | (attribute, examples[, weightID])")
766{ PyTRY
767PVariable var1, var2;
768if (PyArg_ParseTuple(args, "O&O&:Contingency.__new__", cc_Variable, &var1, cc_Variable, &var2))
769return WrapNewOrange(mlnew TContingencyAttrClass(var1, var2), type);
770
771PyErr_Clear();
772
773PyObject *object1;
774PExampleGenerator gen;
775int weightID=0;
776if (PyArg_ParseTuple(args, "OO&|O&", &object1, pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID)) {
777    if (PyOrVariable_Check(object1))
778        return WrapNewOrange(mlnew TContingencyAttrClass(gen, PyOrange_AsVariable(object1), weightID), type);
779
780    int attrNo;
781    if (varNumFromVarDom(object1, gen->domain, attrNo))
782        return WrapNewOrange(mlnew TContingencyAttrClass(gen, attrNo, weightID), type);
783}
784
785PYERROR(PyExc_TypeError, "invalid type for ContingencyAttrClass constructor", PYNULL);
786
787PyCATCH
788}
789
790
791PyObject *ContingencyAttrClass_p_class(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(attr_value[, class_value]) -> p | distribution of classes")
792{
793    PyTRY
794        CAST_TO(TContingencyClass, cont);
795
796    if (PyTuple_Size(args) == 1) {
797        TValue attrval;
798        if (!convertFromPython(PyTuple_GET_ITEM(args, 0), attrval, cont->outerVariable))
799            return PYNULL;
800
801        PDistribution dist = CLONE(TDistribution, cont->p_classes(attrval));
802        if (!dist)
803            PYERROR(PyExc_AttributeError, "no distribution", PYNULL);
804
805        dist->normalize();
806        return WrapOrange(dist);
807    }
808
809    else {
810        TValue attrval, classval;
811        if (!ContingencyClass_getValuePair(cont, args, "OO:ContingencyAttrClass.p_class", attrval, classval))
812            return PYNULL;
813
814        return PyFloat_FromDouble(cont->p_class(attrval, classval));
815    }
816    PyCATCH
817}
818
819
820PyObject *ContingencyClassAttr_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(ContingencyClass, "(attribute, class attribute) | (attribute, examples[, weightID])")
821{ PyTRY
822PVariable var1, var2;
823if (PyArg_ParseTuple(args, "O&O&:Contingency.__new__", cc_Variable, &var1, cc_Variable, &var2))
824return WrapNewOrange(mlnew TContingencyClassAttr(var1, var2), type);
825
826PyErr_Clear();
827
828PyObject *object1;
829int weightID=0;
830PExampleGenerator gen;
831if (   PyArg_ParseTuple(args, "OO&|O&", &object1, pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID)) {
832    if (PyOrVariable_Check(object1))
833        return WrapNewOrange(mlnew TContingencyClassAttr(gen, PyOrange_AsVariable(object1), weightID), type);
834    else {
835        int attrNo;
836        if (varNumFromVarDom(object1, gen->domain, attrNo))
837            return WrapNewOrange(mlnew TContingencyClassAttr(gen, attrNo, weightID), type);
838    }
839}
840
841PyCATCH
842
843PYERROR(PyExc_TypeError, "invalid type for ContingencyClassAttr constructor", PYNULL);
844}
845
846
847PyObject *ContingencyClassAttr_p_attr(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([attr_value, ]class_value) -> p | distribution of values")
848{
849    PyTRY
850        CAST_TO(TContingencyClass, cont);
851
852    if (PyTuple_Size(args) == 1) {
853        TValue classval;
854        if (!convertFromPython(PyTuple_GET_ITEM(args, 0), classval, cont->outerVariable))
855            return PYNULL;
856
857        PDistribution dist = CLONE(TDistribution, cont->p_attrs(classval));
858        if (!dist)
859            PYERROR(PyExc_AttributeError, "no distribution", PYNULL);
860
861        dist->normalize();
862        return WrapOrange(dist);
863    }
864
865    else {
866        TValue attrval, classval;
867        if (!ContingencyClass_getValuePair(cont, args, "OO:ContingencyClassAttr.p_attr", attrval, classval))
868            return PYNULL;
869
870        return PyFloat_FromDouble(cont->p_attr(attrval, classval));
871    }
872    PyCATCH
873}
874
875
876PyObject *ContingencyAttrAttr_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Contingency, "(outer_attr, inner_attr[, examples [, weight-id]])")
877{ PyTRY
878PyObject *pyvar, *pyinvar;
879PExampleGenerator gen;
880int weightID=0;
881if (PyArg_ParseTuple(args, "OO|O&O&", &pyvar, &pyinvar, &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID))
882if (gen)
883return WrapNewOrange(mlnew TContingencyAttrAttr(
884                                         varFromArg_byDomain(pyvar, gen->domain),
885                                         varFromArg_byDomain(pyinvar, gen->domain),
886                                         gen, weightID), type);
887
888else
889if (PyOrVariable_Check(pyvar) && PyOrVariable_Check(pyinvar))
890return WrapNewOrange(mlnew TContingencyAttrAttr(
891                                         PyOrange_AsVariable(pyvar),
892                                         PyOrange_AsVariable(pyinvar)),
893                                         type);
894PyCATCH
895
896PYERROR(PyExc_TypeError, "ContingencyAttrAttr: two variables and (opt) examples and (opt) weight expected", PYNULL);
897}
898
899
900
901PyObject *ContingencyAttrAttr_p_attr(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(outer_value[, inner_value]) -> p | distribution of values")
902{
903    PyTRY
904        CAST_TO(TContingencyAttrAttr, cont);
905
906    PyObject *pyouter, *pyinner = PYNULL;
907    TValue outerval, innerval;
908    if (   !PyArg_ParseTuple(args, "O|O:ContingencyAttrAttr.p_attr", &pyouter, &pyinner)
909        || !convertFromPython(pyouter, outerval, cont->outerVariable))
910        return PYNULL;
911
912    if (!pyinner) {
913        PDistribution dist = CLONE(TDistribution, cont->p_attrs(outerval));
914        if (!dist)
915            PYERROR(PyExc_AttributeError, "no distribution", PYNULL);
916
917        dist->normalize();
918        return WrapOrange(dist);
919    }
920
921    else {
922        if (!convertFromPython(pyinner, innerval, cont->innerVariable))
923            return PYNULL;
924
925        return PyFloat_FromDouble(cont->p_attr(outerval, innerval));
926    }
927    PyCATCH
928}
929
930
931PyObject *Contingency_normalize(PyObject *self, PyObject *) PYARGS(0,"() -> None")
932{ PyTRY
933SELF_AS(TContingency).normalize();
934RETURN_NONE
935PyCATCH
936}
937
938
939PyObject *Contingency_getitem(PyObject *self, PyObject *index)
940{ PyTRY
941PDistribution *dist=Contingency_getItemRef(self, index);
942if (!dist)
943return PYNULL;
944
945return WrapOrange(POrange(*dist));
946PyCATCH
947}
948
949
950PyObject *Contingency_getitem_sq(PyObject *self, Py_ssize_t ind)
951{ PyTRY
952CAST_TO(TContingency, cont)
953
954if (cont->outerVariable->varType!=TValue::INTVAR)
955PYERROR(PyExc_TypeError, "cannot iterate through contingency of continuous attribute", PYNULL);
956
957if ((ind<0) || (ind>=Py_ssize_t(cont->discrete->size())))
958PYERROR(PyExc_IndexError, "index out of range", PYNULL);
959
960return WrapOrange(POrange(cont->discrete->at(ind)));
961PyCATCH
962}
963
964
965int Contingency_setitem(PyObject *self, PyObject *index, PyObject *item)
966{ PyTRY
967if (!PyOrDistribution_Check(item))
968PYERROR(PyExc_TypeError, "Distribution expected", -1);
969
970PDistribution *dist=Contingency_getItemRef(self, index);
971if (!dist)
972return -1;
973
974*dist = CLONE(TDistribution, PyOrange_AsDistribution(item));
975return 0;
976PyCATCH_1
977}
978
979Py_ssize_t Contingency_len(PyObject *self)
980{ PyTRY
981CAST_TO_err(TContingency, cont, -1);
982if (cont->outerVariable)
983if (cont->outerVariable->varType==TValue::INTVAR)
984return cont->discrete->size();
985else if (cont->outerVariable->varType==TValue::FLOATVAR)
986return cont->continuous->size();
987
988return 0;
989PyCATCH_1
990}
991
992
993bool convertFromPython(PyObject *obj, PContingency &var, bool allowNull, PyTypeObject *type)
994{ if (!type)
995type = (PyTypeObject *)&PyOrContingency_Type;
996
997if (allowNull && (!obj || (obj==Py_None))) {
998    var=GCPtr<TContingency>();
999    return true;
1000}
1001if (!type)
1002type = (PyTypeObject *)FindOrangeType(typeid(TContingency));
1003
1004if (!obj || !PyObject_TypeCheck(obj, type)) {
1005    PyErr_Format(PyExc_TypeError, "expected '%s', got '%s'", type->tp_name, obj ? obj->ob_type->tp_name : "None");
1006    return false;
1007}
1008
1009var=GCPtr<TContingency>(PyOrange_AS_Orange(obj));
1010return true;
1011}
1012
1013
1014string convertToString(const PDistribution &);
1015
1016string convertToString(const PContingency &cont)
1017{ if (!cont->outerVariable)
1018raiseError("invalid contingency ('outerVariable' not set)");
1019
1020if (cont->outerVariable->varType==TValue::INTVAR) {
1021    TValue val;
1022    cont->outerVariable->firstValue(val);
1023
1024    string res="<";
1025    PITERATE(TDistributionVector, di, cont->discrete) {
1026        if (di!=cont->discrete->begin()) res+=", ";
1027        string vals;
1028        cont->outerVariable->val2str(val,vals);
1029        res+="'"+vals+"': "+convertToString(*di);
1030        cont->outerVariable->nextValue(val);
1031    }
1032    return res+">";
1033}
1034else if (cont->outerVariable->varType==TValue::FLOATVAR) {
1035    string res="<";
1036    char buf[128];
1037
1038    PITERATE(TDistributionMap, di, cont->continuous) {
1039        if (di!=cont->continuous->begin()) res+=", ";
1040        sprintf(buf, "%.3f: ", (*di).first);
1041        res+=buf+convertToString((*di).second);
1042    }
1043    return res+">";
1044}
1045
1046raiseError("invalid contingency");
1047return string();
1048}
1049
1050string convertToString(const PContingencyClass &cc)
1051{ return convertToString((const PContingency &)cc); }
1052
1053PyObject *Contingency_str(PyObject *self)
1054{ PyTRY
1055PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
1056if (result)
1057return result;
1058
1059return PyString_FromString(convertToString(PyOrange_AsContingency(self)).c_str());
1060PyCATCH
1061}
1062
1063
1064PyObject *Contingency_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
1065{ PyTRY
1066CAST_TO(TContingency, cont);
1067if (cont->outerVariable)
1068if (cont->outerVariable->varType==TValue::FLOATVAR) {
1069    PyObject *nl=PyList_New(cont->continuous->size());
1070    Py_ssize_t i=0;
1071    PITERATE(TDistributionMap, ci, cont->continuous)
1072        PyList_SetItem(nl, i++, PyFloat_FromDouble((double)(*ci).first));
1073    return nl;
1074}
1075else if (cont->outerVariable->varType==TValue::INTVAR) {
1076    PyObject *nl=PyList_New(cont->outerVariable->noOfValues());
1077    Py_ssize_t i=0;
1078    PStringList vals=cont->outerVariable.AS(TEnumVariable)->values;
1079    PITERATE(TStringList, ii, vals)
1080        PyList_SetItem(nl, i++, PyString_FromString((*ii).c_str()));
1081    return nl;
1082}
1083
1084raiseError("Invalid contingency ('outerVariable' not set)");
1085return PYNULL;
1086PyCATCH
1087}
1088
1089PyObject *Contingency_values(PyObject *self) PYARGS(0, "() -> [Distribution]")
1090{ PyTRY
1091CAST_TO(TContingency, cont);
1092if (cont->outerVariable)
1093if (cont->outerVariable->varType==TValue::FLOATVAR) {
1094    PyObject *nl=PyList_New(cont->continuous->size());
1095    Py_ssize_t i=0;
1096    PITERATE(TDistributionMap, ci, cont->continuous)
1097        PyList_SetItem(nl, i++, WrapOrange((*ci).second));
1098    return nl;
1099}
1100else if (cont->outerVariable->varType==TValue::INTVAR) {
1101    PyObject *nl=PyList_New(cont->discrete->size());
1102    Py_ssize_t i=0;
1103    PITERATE(TDistributionVector, ci, cont->discrete)
1104        PyList_SetItem(nl, i++, WrapOrange(*ci));
1105    return nl;
1106}
1107
1108PYERROR(PyExc_AttributeError, "Invalid contingency (no variable)", PYNULL);
1109PyCATCH
1110}
1111
1112PyObject *Contingency_items(PyObject *self) PYARGS(0, "() -> [(string, Distribution)] | [(float: Distribution)]")
1113{ PyTRY
1114CAST_TO(TContingency, cont);
1115if (cont->outerVariable)
1116if (cont->outerVariable->varType==TValue::FLOATVAR) {
1117    PyObject *nl=PyList_New(cont->continuous->size());
1118    Py_ssize_t i=0;
1119    PITERATE(TDistributionMap, ci, cont->continuous)
1120        PyList_SetItem(nl, i++,
1121        Py_BuildValue("fN", (double)(*ci).first, WrapOrange((*ci).second)));
1122    return nl;
1123}
1124else if (cont->outerVariable->varType==TValue::INTVAR) {
1125    PyObject *nl=PyList_New(cont->outerVariable->noOfValues());
1126    Py_ssize_t i=0;
1127    TStringList::const_iterator ii(cont->outerVariable.AS(TEnumVariable)->values->begin());
1128    PITERATE(TDistributionVector, ci, cont->discrete)
1129        PyList_SetItem(nl, i++,
1130        Py_BuildValue("sN", (*(ii++)).c_str(), WrapOrange(*ci)));
1131    return nl;
1132}
1133
1134PYERROR(PyExc_AttributeError, "Invalid contingency (no variable)", PYNULL);
1135PyCATCH
1136}
1137
1138
1139
1140/* We redefine new (removed from below!) and add mapping methods
1141*/
1142
1143PDomainContingency PDomainContingency_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::P_FromArguments(arg); }
1144PyObject *DomainContingency_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_FromArguments(type, arg); }
1145PyObject *DomainContingency_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_getitem(self, index); }
1146int       DomainContingency_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_setitem(self, index, item); }
1147PyObject *DomainContingency_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_getslice(self, start, stop); }
1148int       DomainContingency_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_setslice(self, start, stop, item); }
1149Py_ssize_t       DomainContingency_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_len(self); }
1150PyObject *DomainContingency_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_richcmp(self, object, op); }
1151PyObject *DomainContingency_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_concat(self, obj); }
1152PyObject *DomainContingency_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_repeat(self, times); }
1153PyObject *DomainContingency_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_str(self); }
1154PyObject *DomainContingency_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_str(self); }
1155int       DomainContingency_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_contains(self, obj); }
1156PyObject *DomainContingency_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Contingency) -> None") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_append(self, item); }
1157PyObject *DomainContingency_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_extend(self, obj); }
1158PyObject *DomainContingency_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Contingency) -> int") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_count(self, obj); }
1159PyObject *DomainContingency_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainContingency") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_filter(self, args); }
1160PyObject *DomainContingency_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Contingency) -> int") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_index(self, obj); }
1161PyObject *DomainContingency_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_insert(self, args); }
1162PyObject *DomainContingency_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_native(self); }
1163PyObject *DomainContingency_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Contingency") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_pop(self, args); }
1164PyObject *DomainContingency_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Contingency) -> None") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_remove(self, obj); }
1165PyObject *DomainContingency_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_reverse(self); }
1166PyObject *DomainContingency_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_sort(self, args); }
1167PyObject *DomainContingency__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainContingency, TDomainContingency, PContingencyClass, &PyOrContingency_Type>::_reduce(self); }
1168
1169
1170CONSTRUCTOR_KEYWORDS(DomainContingency, "classIsOuter class_is_outer")
1171
1172PyObject *DomainContingency_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange, "(examples [, weightID] | <list of Contingency>) -> DomainContingency") ALLOWS_EMPTY
1173{ PyTRY
1174if (!args || !PyTuple_Size(args))
1175return WrapNewOrange(mlnew TDomainContingency(), type);
1176
1177int weightID;
1178PExampleGenerator gen = exampleGenFromArgs(args, weightID);
1179if (gen) {
1180    bool classOuter = false;
1181    if (keywds) {
1182        PyObject *couter = PyDict_GetItemString(keywds, "class_is_outer");
1183        if (!couter) {
1184            couter = PyDict_GetItemString(keywds, "classIsOuter");
1185        }
1186        if (couter) {
1187            classOuter = (PyObject_IsTrue(couter) != 0);
1188            Py_DECREF(couter);
1189        }
1190    }
1191
1192    return WrapNewOrange(mlnew TDomainContingency(gen, weightID, classOuter), type);
1193}
1194
1195PyObject *obj = ListOfWrappedMethods<PDomainContingency, TDomainContingency, PDomainContingency, &PyOrContingency_Type>::_new(type, args, keywds);
1196if (obj)
1197return obj;
1198
1199PyErr_Clear();
1200PYERROR(PyExc_TypeError, "DomainContingency.__init__ expects examples or a list of Contingencies", PYNULL);
1201PyCATCH
1202}
1203
1204
1205int pt_DomainContingency(PyObject *args, void *egen)
1206{ if (PyOrDomainContingency_Check(args)) {
1207    *(PDomainContingency *)(egen) = PyOrange_AsDomainContingency(args);
1208    return 1;
1209}
1210else {
1211    egen = NULL;
1212    PYERROR(PyExc_TypeError, "invalid domain contingency", 0);
1213}
1214}
1215
1216
1217int ptn_DomainContingency(PyObject *args, void *egen)
1218{
1219    if (args == Py_None) {
1220        *(PDomainContingency *)(egen) = PDomainContingency();
1221        return 1;
1222    }
1223    else if (PyOrDomainContingency_Check(args)) {
1224        *(PDomainContingency *)(egen) = PyOrange_AsDomainContingency(args);
1225        return 1;
1226    }
1227    else {
1228        egen = NULL;
1229        PYERROR(PyExc_TypeError, "invalid domain contingency", 0);
1230    }
1231}
1232
1233
1234
1235int DomainContingency_getItemIndex(PyObject *self, PyObject *args)
1236{ PyTRY
1237CAST_TO_err(TDomainContingency, cont, -1);
1238
1239const bool &couter = cont->classIsOuter;
1240
1241if (PyInt_Check(args)) {
1242    int i=(int)PyInt_AsLong(args);
1243    if ((i>=0) && (i<int(cont->size())))
1244        return i;
1245    else
1246        PYERROR(PyExc_IndexError, "index out of range", -1);
1247}
1248
1249if (PyString_Check(args)) {
1250    char *s=PyString_AsString(args);
1251    PITERATE(TDomainContingency, ci, cont)
1252        if (couter ? (*ci)->innerVariable && ((*ci)->innerVariable->get_name()==s)
1253            : (*ci)->outerVariable && ((*ci)->outerVariable->get_name()==s))
1254            return ci - cont->begin();
1255  PyErr_Format(PyExc_IndexError, "Domain contingency has no variable '%s'", s);
1256  return -1;
1257}
1258
1259if (PyOrVariable_Check(args)) {
1260    PVariable var = PyOrange_AsVariable(args);
1261    PITERATE(TDomainContingency, ci, cont)
1262        if (couter ? (*ci)->innerVariable && ((*ci)->innerVariable==var)
1263            : (*ci)->outerVariable && ((*ci)->outerVariable==var))
1264            return ci - cont->begin();
1265  PyErr_Format(PyExc_IndexError, "Domain contingency has no variable '%s'", var->get_name().c_str());
1266  return -1;
1267}
1268
1269PYERROR(PyExc_TypeError, "invalid index type", -1);
1270PyCATCH_1
1271}
1272
1273
1274
1275
1276PyObject *DomainContingency_getitem(PyObject *self, PyObject *args)
1277{ PyTRY
1278int index=DomainContingency_getItemIndex(self, args);
1279if (index<0)
1280return PYNULL;
1281
1282return WrapOrange(POrange(SELF_AS(TDomainContingency)[index]));
1283PyCATCH
1284}
1285
1286
1287int DomainContingency_setitem(PyObject *self, PyObject *args, PyObject *obj)
1288{ PyTRY
1289PContingency cont;
1290if (!convertFromPython(obj, cont))
1291PYERROR(PyExc_TypeError, "invalid Contingency object", -1);
1292
1293int index = DomainContingency_getItemIndex(self, args);
1294if (index==-1)
1295return -1;
1296
1297SELF_AS(TDomainContingency)[index] = cont;
1298return 0;
1299PyCATCH_1
1300}
1301
1302
1303string convertToString(const PDomainContingency &cont)
1304{
1305    string res=string("{");
1306    const_PITERATE(TDomainContingency, di, cont) {
1307        if (di!=cont->begin()) res+=", ";
1308        res += (*di)->outerVariable->get_name()+": "+convertToString(*di);
1309    }
1310    return res+"}";
1311}
1312
1313
1314PyObject *DomainContingency_normalize(PyObject *self, PyObject *) PYARGS(0, "() -> None")
1315{ PyTRY
1316if (!PyOrange_AS_Orange(self))
1317PYERROR(PyExc_SystemError, "NULL contingency matrix", PYNULL);
1318
1319SELF_AS(TDomainContingency).normalize();
1320RETURN_NONE
1321PyCATCH
1322}
1323
1324
1325C_CALL3(ComputeDomainContingency, ComputeDomainContingency, Orange, "([examples, weightID]) -/-> DomainContingency")
1326
1327PyObject *ComputeDomainContingency_call(PyObject *self, PyObject *args)
1328{
1329  int weightID;
1330  PExampleGenerator gen = exampleGenFromArgs(args, weightID);
1331  if (!gen)
1332    PYERROR(PyExc_AttributeError, "examples and, optionally, weight ID expected", PYNULL);
1333
1334  return WrapOrange(SELF_AS(TComputeDomainContingency).call(gen, weightID));
1335}
1336
1337
1338/* ************ DOMAIN TRANSFORMER ************ */
1339
1340#include "transdomain.hpp"
1341
1342ABSTRACT(DomainTransformerConstructor, Orange)
1343
1344PyObject *DomainTransformerConstructor_call(PyObject *self, PyObject *args)
1345{
1346  int weightID;
1347  PExampleGenerator gen = exampleGenFromArgs(args, weightID);
1348  if (!gen)
1349    PYERROR(PyExc_AttributeError, "examples and, optionally, weight ID expected", PYNULL);
1350
1351  return WrapOrange(SELF_AS(TDomainTransformerConstructor).call(gen, weightID));
1352}
1353
1354
1355
1356/* ************ DISTANCE ************ */
1357
1358#include "distance.hpp"
1359#include "distance_dtw.hpp"
1360
1361ABSTRACT(ExamplesDistance_Normalized, ExamplesDistance)
1362C_NAMED(ExamplesDistance_Hamming, ExamplesDistance, "()")
1363C_NAMED(ExamplesDistance_Maximal, ExamplesDistance_Normalized, "()")
1364C_NAMED(ExamplesDistance_Manhattan, ExamplesDistance_Normalized, "()")
1365C_NAMED(ExamplesDistance_Euclidean, ExamplesDistance_Normalized, "()")
1366C_NAMED(ExamplesDistance_Relief, ExamplesDistance, "()")
1367C_NAMED(ExamplesDistance_DTW, ExamplesDistance_Normalized, "()")
1368
1369C_CALL(ExamplesDistanceConstructor_Hamming, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Hamming")
1370C_CALL(ExamplesDistanceConstructor_Maximal, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Maximal")
1371C_CALL(ExamplesDistanceConstructor_Manhattan, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Manhattan")
1372C_CALL(ExamplesDistanceConstructor_Euclidean, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Euclidean")
1373C_CALL(ExamplesDistanceConstructor_Relief, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Relief")
1374C_CALL(ExamplesDistanceConstructor_DTW, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_DTW")
1375
1376
1377PyObject *ExamplesDistanceConstructor_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
1378{
1379  if (type == (PyTypeObject *)&PyOrExamplesDistanceConstructor_Type)
1380    return setCallbackFunction(WrapNewOrange(mlnew TExamplesDistanceConstructor_Python(), type), args);
1381  else
1382    return WrapNewOrange(mlnew TExamplesDistanceConstructor_Python(), type);
1383}
1384
1385
1386PyObject *ExamplesDistanceConstructor__reduce__(PyObject *self)
1387{
1388    return callbackReduce(self, PyOrExamplesDistanceConstructor_Type);
1389}
1390
1391
1392PyObject *ExamplesDistance_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
1393{ if (type == (PyTypeObject *)&PyOrExamplesDistance_Type)
1394return setCallbackFunction(WrapNewOrange(mlnew TExamplesDistance_Python(), type), args);
1395else
1396return WrapNewOrange(mlnew TExamplesDistance_Python(), type);
1397}
1398
1399
1400PyObject *ExamplesDistance__reduce__(PyObject *self)
1401{
1402    return callbackReduce(self, PyOrExamplesDistance_Type);
1403}
1404
1405
1406PyObject *ExamplesDistanceConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance")
1407{ PyTRY
1408  if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrExamplesDistanceConstructor_Type) {
1409      PyErr_Format(PyExc_SystemError, "ExamplesDistanceConstructor.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
1410      return PYNULL;
1411  }
1412
1413  NO_KEYWORDS
1414
1415  PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
1416  PExampleGenerator gen;
1417  int weightID = 0;
1418  PDomainDistributions dist;
1419  PDomainBasicAttrStat bstat;
1420  if (!PyArg_UnpackTuple(uargs, "ExamplesDistanceConstructor.call", 0, 4, args+0, args+1, args+2, args+3))
1421  return PYNULL;
1422
1423  PyObject **argp = args, **argc = args;
1424  for (int i=0; i<=3; i++, argp++)
1425  if (*argp)
1426  *argc++ = *argp;
1427
1428  for(argp = args; argp!=argc; argp++) {
1429      if (PyOrDomainDistributions_Check(*argp))
1430          if (dist)
1431              PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments (DomainDistribution given twice)", PYNULL)
1432          else
1433          dist = PyOrange_AsDomainDistributions(*argp);
1434      else if (PyOrDomainBasicAttrStat_Check(*argp))
1435          if (bstat)
1436              PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments (DomainBasicAttrStat given twice)", PYNULL)
1437          else
1438          bstat = PyOrange_AsDomainBasicAttrStat(*argp);
1439      else {
1440          PExampleGenerator gen2 = exampleGenFromParsedArgs(*argp);
1441          if (!gen2)
1442              PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments", PYNULL)
1443          else if (gen)
1444          PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments (examples given twice)", PYNULL)
1445          else {
1446              gen = gen2;
1447              if (argp+1 != argc) {
1448                  argp++;
1449                  if (!weightFromArg_byDomain(*argp, gen->domain, weightID))
1450                      return PYNULL;
1451              }
1452          }
1453      }
1454  }
1455
1456  return WrapOrange(SELF_AS(TExamplesDistanceConstructor).call(gen, weightID, dist, bstat));
1457  PyCATCH
1458}
1459
1460
1461PyObject *ExamplesDistance_Normalized_attributeDistances(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(example1, example2) -> [by-attribute distances as floats]")
1462{ PyTRY
1463TExample *ex1, *ex2;
1464if (!PyArg_ParseTuple(args, "O&O&:ExamplesDistance_Normalized.attributeDistances", ptr_Example, &ex1, ptr_Example, &ex2))
1465PYERROR(PyExc_TypeError, "attribute error (two examples expected)", PYNULL);
1466
1467vector<float> difs;
1468SELF_AS(TExamplesDistance_Normalized).getDifs(*ex1, *ex2, difs);
1469
1470PyObject *l = PyList_New(difs.size());
1471for(int i = 0, e = difs.size(); i<e; i++)
1472PyList_SetItem(l, i, PyFloat_FromDouble(difs[i]));
1473
1474return l;
1475PyCATCH
1476}
1477
1478
1479PyObject *ExamplesDistance_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(example1, example2) -> float")
1480{
1481    PyTRY
1482        NO_KEYWORDS
1483
1484        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrExamplesDistance_Type) {
1485            PyErr_Format(PyExc_SystemError, "ExamplesDistance.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
1486            return PYNULL;
1487        }
1488
1489        TExample *ex1, *ex2;
1490        if (!PyArg_ParseTuple(args, "O&O&:ExamplesDistance_Normalized.__call__", ptr_Example, &ex1, ptr_Example, &ex2))
1491            PYERROR(PyExc_TypeError, "attribute error (two examples expected)", PYNULL);
1492
1493        return PyFloat_FromDouble((double)(SELF_AS(TExamplesDistance)(*ex1, *ex2)));
1494        PyCATCH
1495}
1496
1497
1498
1499bool convertFromPython(PyObject *pyobj, TAlignment &align)
1500{
1501    return PyArg_ParseTuple(pyobj, "ii:convertFromPython(Alignment)", &align.i, &align.j) != 0;
1502}
1503
1504
1505PyObject *convertToPython(const TAlignment &align)
1506{
1507    return Py_BuildValue("ii", align.i, align.j);
1508}
1509
1510
1511PyObject *ExamplesDistance_DTW_alignment(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(example1, example2) -> (distance, path)")
1512{
1513    PyTRY
1514        TExample *ex1, *ex2;
1515    if (!PyArg_ParseTuple(args, "O&O&:ExamplesDistance_DTW.attributeDistances", ptr_Example, &ex1, ptr_Example, &ex2))
1516        PYERROR(PyExc_TypeError, "attribute error (two examples expected)", PYNULL);
1517
1518    PWarpPath warpPath;
1519    float distance = SELF_AS(TExamplesDistance_DTW)(*ex1, *ex2, warpPath);
1520    return Py_BuildValue("fO", distance, WrapOrange(warpPath));
1521    PyCATCH
1522}
1523
1524/* ************ FINDNEAREST ************ */
1525
1526#include "nearest.hpp"
1527
1528ABSTRACT(FindNearest, Orange)
1529C_NAMED(FindNearest_BruteForce, FindNearest, "([distance=, distanceID=, includeSame=])")
1530
1531ABSTRACT(FindNearestConstructor, Orange)
1532C_CALL(FindNearestConstructor_BruteForce, FindNearestConstructor, "([examples[, weightID[, distanceID]], distanceConstructor=, includeSame=]) -/-> FindNearest")
1533
1534
1535PyObject *FindNearestConstructor_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(examples[, weightID[, distanceID]]) -> FindNearest")
1536{
1537    PyTRY
1538        NO_KEYWORDS
1539
1540        PExampleGenerator egen;
1541    int weightID = 0;
1542    int distanceID = 0;
1543    PyObject *pydistanceID = PYNULL;
1544
1545    if (   !PyArg_ParseTuple(args, "O&|O&O:FindNearestConstructor.__call__", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weightID, &pydistanceID)
1546        || !weightFromArg_byDomain(pydistanceID, egen->domain, distanceID))
1547        return PYNULL;
1548
1549    return WrapOrange(SELF_AS(TFindNearestConstructor).call(egen, weightID, distanceID));
1550    PyCATCH
1551}
1552
1553
1554
1555PyObject *FindNearest_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(example, k) -> ExampleTable")
1556{
1557    PyTRY
1558        NO_KEYWORDS
1559
1560        float k;
1561    TExample *example;
1562    int needsClass = 0;
1563    // Both forms are allowed for compatibility with older versions
1564    if (!PyArg_ParseTuple(args, "fO&|i", &k, ptr_Example, &example, &needsClass)) {
1565        PyErr_Clear();
1566        if (!PyArg_ParseTuple(args, "O&f|i", ptr_Example, &example, &k, &needsClass))
1567            PYERROR(PyExc_TypeError, "attribute error (number and example, and an optional flag for class expected)", PYNULL);
1568    }
1569
1570    return WrapOrange(SELF_AS(TFindNearest).call(*example, k, needsClass != 0));
1571    PyCATCH
1572}
1573
1574
1575
1576
1577/* ************ FILTERS ************ */
1578
1579#include "filter.hpp"
1580
1581ABSTRACT(ValueFilter, Orange)
1582C_NAMED(ValueFilter_discrete, ValueFilter, "([position=, oper=, values=, acceptSpecial=])")
1583C_NAMED(ValueFilter_continuous, ValueFilter, "([position=, oper=, min=, max=, acceptSpecial=])")
1584C_NAMED(ValueFilter_string, ValueFilter, "([position=, oper=, min=, max=])");
1585C_NAMED(ValueFilter_stringList, ValueFilter, "([position=, oper=, values=])");
1586
1587C_CALL(Filter_random, Filter, "([examples], [negate=..., p=...]) -/-> ExampleTable")
1588C_CALL(Filter_hasSpecial, Filter, "([examples], [negate=..., domain=...]) -/-> ExampleTable")
1589C_CALL(Filter_isDefined, Filter, "([examples], [negate=..., domain=..., check=]) -/-> ExampleTable")
1590C_CALL(Filter_hasMeta, Filter, "([examples], [id=...]) -/-> ExampleTable")
1591C_CALL(Filter_hasClassValue, Filter, "([examples], [negate=..., domain=...]) -/-> ExampleTable")
1592C_CALL(Filter_sameValue, Filter, "([examples], [negate=..., domain=..., position=<int>, value=...]) -/-> ExampleTable")
1593C_CALL(Filter_values, Filter, "([examples], [negate=..., domain=..., values=<see the manual>) -/-> ExampleTable")
1594
1595
1596PValueFilterList PValueFilterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::P_FromArguments(arg); }
1597PyObject *ValueFilterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_FromArguments(type, arg); }
1598PyObject *ValueFilterList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of ValueFilter>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_new(type, arg, kwds); }
1599PyObject *ValueFilterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_getitem(self, index); }
1600int       ValueFilterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_setitem(self, index, item); }
1601PyObject *ValueFilterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_getslice(self, start, stop); }
1602int       ValueFilterList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_setslice(self, start, stop, item); }
1603Py_ssize_t       ValueFilterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_len(self); }
1604PyObject *ValueFilterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_richcmp(self, object, op); }
1605PyObject *ValueFilterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_concat(self, obj); }
1606PyObject *ValueFilterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_repeat(self, times); }
1607PyObject *ValueFilterList_str(TPyOrange *self) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_str(self); }
1608PyObject *ValueFilterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_str(self); }
1609int       ValueFilterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_contains(self, obj); }
1610PyObject *ValueFilterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ValueFilter) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_append(self, item); }
1611PyObject *ValueFilterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_extend(self, obj); }
1612PyObject *ValueFilterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ValueFilter) -> int") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_count(self, obj); }
1613PyObject *ValueFilterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ValueFilterList") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_filter(self, args); }
1614PyObject *ValueFilterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ValueFilter) -> int") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_index(self, obj); }
1615PyObject *ValueFilterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_insert(self, args); }
1616PyObject *ValueFilterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_native(self); }
1617PyObject *ValueFilterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ValueFilter") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_pop(self, args); }
1618PyObject *ValueFilterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ValueFilter) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_remove(self, obj); }
1619PyObject *ValueFilterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_reverse(self); }
1620PyObject *ValueFilterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_sort(self, args); }
1621PyObject *ValueFilterList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_reduce(self); }
1622
1623
1624PyObject *applyFilterP(PFilter filter, PExampleTable gen);
1625
1626PyObject *applyFilter(PFilter filter, PExampleGenerator gen, bool weightGiven, int weightID)
1627{ if (!filter) return PYNULL;
1628
1629TExampleTable *newTable = mlnew TExampleTable(gen->domain);
1630PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
1631filter->reset();
1632PEITERATE(ei, gen)
1633if (filter->operator()(*ei))
1634newTable->addExample(*ei);
1635
1636return weightGiven ? Py_BuildValue("Ni", WrapOrange(newGen), weightID) : WrapOrange(newGen);
1637}
1638
1639
1640PyObject *Filter_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
1641{ if (type == (PyTypeObject *)&PyOrFilter_Type)
1642return setCallbackFunction(WrapNewOrange(mlnew TFilter_Python(), type), args);
1643else
1644return WrapNewOrange(mlnew TFilter_Python(), type);
1645}
1646
1647
1648PyObject *Filter__reduce__(PyObject *self)
1649{
1650    return callbackReduce(self, PyOrFilter_Type);
1651}
1652
1653
1654PyObject *Filter_call(PyObject *self, PyObject *args, PyObject *keywords)
1655{
1656    PyTRY
1657        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrFilter_Type) {
1658            PyErr_Format(PyExc_SystemError, "Filter.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
1659            return PYNULL;
1660        }
1661
1662        CAST_TO(TFilter, filter);
1663
1664        bool savedNegate = filter->negate;
1665        PyObject *res;
1666
1667        try {
1668            if (!((TPyOrange *)self)->call_constructed && keywords) {
1669                const Py_ssize_t sze = PyDict_Size(keywords);
1670                PyObject *neg = sze >= 1 ? PyDict_GetItemString(keywords, "negate") : NULL;
1671                if ((sze > 1) || !neg)
1672                    NO_KEYWORDS;
1673                filter->negate = (PyObject_IsTrue(neg) != 0);
1674            }
1675
1676            if ((PyTuple_Size(args)==1) && PyOrExample_Check(PyTuple_GET_ITEM(args, 0))) {
1677                res = PyInt_FromLong(filter->call(PyExample_AS_ExampleReference(PyTuple_GET_ITEM(args, 0))) ? 1 : 0);
1678            }
1679            else {
1680                PExampleGenerator egen;
1681                int references = 0;
1682                if (!PyArg_ParseTuple(args, "O&|i:Filter.__call__", &pt_ExampleGenerator, &egen, &references)) {
1683                    filter->negate = savedNegate;
1684                    return PYNULL;
1685                }
1686
1687                if (references) {
1688                    if (!egen.is_derived_from(TExampleTable))
1689                        PYERROR(PyExc_TypeError, "cannot return references to examples that are not in example table", PYNULL);
1690                    res = applyFilterP(filter, egen);
1691                }
1692                else
1693                    res = applyFilter(PyOrange_AsFilter(self), egen, false, 0);
1694            }
1695
1696            filter->negate = savedNegate;
1697            return res;
1698        }
1699        catch(...) {
1700            filter->negate = savedNegate;
1701            throw;
1702        }
1703        PyCATCH
1704}
1705
1706PyObject *Filter_deepCopy(PyObject *self) PYARGS(METH_NOARGS, "() -> filter")
1707{
1708    PyTRY
1709        CAST_TO(TFilter, filter);
1710
1711    PFilter res = filter->deepCopy();
1712      return WrapOrange(res);
1713    PyCATCH
1714}
1715
1716PyObject *Filter_count(PyObject *self, PyObject *arg) PYARGS(METH_O, "(examples)")
1717{
1718    PyTRY
1719        PExampleGenerator egen = exampleGenFromParsedArgs(arg);
1720    if (!egen)
1721        PYERROR(PyExc_TypeError, "Filter.count: examples expected", PYNULL);
1722
1723    CAST_TO(TFilter, filter);
1724
1725    filter->reset();
1726    int count = 0;
1727    PEITERATE(ei, egen)
1728        if (filter->operator()(*ei))
1729            count++;
1730
1731    return PyInt_FromLong(count);
1732    PyCATCH
1733}
1734
1735
1736PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen)
1737{
1738    TBoolList *selection = new TBoolList();
1739    PBoolList pselection = selection;
1740    const int nex = egen->numberOfExamples();
1741    if (nex > 0)
1742        selection->reserve(nex);
1743
1744    filter.reset();
1745    PEITERATE(ei, egen)
1746        selection->push_back(filter(*ei));
1747
1748    return WrapOrange(pselection);
1749}
1750
1751
1752PyObject *Filter_selectionVector(PyObject *self, PyObject *arg) PYARGS(METH_O, "(examples)")
1753{
1754    PyTRY
1755        PExampleGenerator egen = exampleGenFromParsedArgs(arg);
1756    if (!egen)
1757        PYERROR(PyExc_TypeError, "Filter.selectionVector: examples expected", PYNULL);
1758
1759    CAST_TO(TFilter, filter);
1760    return filterSelectionVectorLow(SELF_AS(TFilter), egen);
1761    PyCATCH
1762}
1763
1764
1765PYXTRACT_IGNORE PyObject *AttributedBoolList_new(PyTypeObject *type, PyObject *args, PyObject *keywds);
1766
1767int Filter_isDefined_set_check(PyObject *self, PyObject *arg)
1768{
1769    PyTRY
1770        CAST_TO_err(TFilter_isDefined, filter, -1)
1771
1772        if (arg == Py_None) {
1773            filter->check = PAttributedBoolList();
1774            return 0;
1775        }
1776
1777
1778        PyObject *boollist = objectOnTheFly(arg, (PyTypeObject *)&PyOrAttributedBoolList_Type);
1779
1780        //    PyObject *boollist = AttributedBoolList_new((PyTypeObject *)&PyOrAttributedBoolList_Type, arg, PYNULL);
1781        if (!boollist)
1782            return -1;
1783
1784        PAttributedBoolList cli = PyOrange_AsAttributedBoolList(boollist);
1785
1786        if (filter->domain) {
1787            if (cli->attributes) {
1788                TVarList::const_iterator di(filter->domain->variables->begin()), de(filter->domain->variables->end());
1789                TVarList::const_iterator fci(cli->attributes->begin()), fce(cli->attributes->end());
1790                for(; (di!=de) && (fci!=fce); di++, fci++)
1791                    if (*di!=*fci) {
1792                        PyErr_Format(PyExc_AttributeError, "attribute %s in the list does not match the filter's domain", (*fci)->get_name().c_str());
1793                        return -1;
1794                    }
1795                    if (fci!=fce)
1796                        PYERROR(PyExc_AttributeError, "the check list has more attributes than the filter's domain", -1);
1797            }
1798            else {
1799                /* we don't want to modify the list if this is a reference
1800                to a list from somewhere else */
1801                if (!PyOrAttributedBoolList_Check(arg))
1802                    cli->attributes = filter->domain->variables;
1803            }
1804        }
1805
1806        filter->check = cli;
1807        return 0;
1808        PyCATCH_1
1809}
1810
1811#include "valuelisttemplate.hpp"
1812
1813
1814PStringList PStringList_FromArguments(PyObject *arg);
1815
1816int Filter_values_setitem(PyObject *self, PyObject *pyvar, PyObject *args)
1817{
1818    PyTRY
1819        CAST_TO_err(TFilter_values, filter, -1);
1820
1821    if (!filter->domain)
1822        PYERROR(PyExc_IndexError, "Filter_values.__getitem__ cannot work if 'domain' is not set", -1);
1823
1824    PVariable var = varFromArg_byDomain(pyvar, filter->domain);
1825    if (!var)
1826        return -1;
1827
1828
1829    if (!args || (args == Py_None)) {
1830        filter->removeCondition(var);
1831        return 0;
1832    }
1833
1834
1835    if (var->varType == TValue::INTVAR) {
1836        if (PyList_Check(args)) {
1837            PValueList vlist = TValueListMethods::P_FromArguments(args, var);
1838            if (!vlist)
1839                return -1;
1840            filter->addCondition(var, vlist);
1841        }
1842        else if (PyTuple_Check(args)) {
1843            int oper;
1844            PyObject *obj;
1845            if (!PyArg_ParseTuple(args, "iO:Filter_values.__setitem__", &oper, &obj))
1846                return -1;
1847            if ((oper != TValueFilter::Equal) && (oper != TValueFilter::NotEqual))
1848                PYERROR(PyExc_AttributeError, "Filter_values.__setitem__: operations for discrete attributes can be only Equal or NotEqual", -1);
1849            PValueList vlist = TValueListMethods::P_FromArguments(obj, var);
1850            if (!vlist)
1851                return -1;
1852            filter->addCondition(var, vlist, oper == TValueFilter::NotEqual);
1853        }
1854        else {
1855            TValue val;
1856            if (!convertFromPython(args, val, var))
1857                return -1;
1858
1859            filter->addCondition(var, val);
1860        }
1861    }
1862
1863    else if (var->varType == TValue::FLOATVAR) {
1864        if (PyTuple_Check(args)) {
1865            int oper;
1866            float minv, maxv;
1867            if (!PyArg_ParseTuple(args, "if|f:Filter_values.__setitem__", &oper, &minv, &maxv))
1868                return -1;
1869            if ((PyTuple_Size(args) == 3) && (oper != TValueFilter::Between) && (oper != TValueFilter::Outside))
1870                PYERROR(PyExc_TypeError, "Filter_values.__setitem__: only one reference value expected for the given operator", -1);
1871
1872            filter->addCondition(var, oper, minv, maxv);
1873        }
1874        else {
1875            float f;
1876            if (!PyNumber_ToFloat(args, f)) {
1877                PyErr_Format(PyExc_TypeError, "Filter_values.__setitem__: invalid condition for attribute '%s'", var->get_name().c_str());
1878                return -1;
1879            }
1880            filter->addCondition(var, TValueFilter::Equal, f, f);
1881        }
1882    }
1883
1884    else if (var->varType == STRINGVAR) {
1885        if (PyString_Check(args))
1886            filter->addCondition(var, TValueFilter::Equal, PyString_AsString(args), string());
1887
1888        else if (PyList_Check(args)) {
1889            PStringList slist = PStringList_FromArguments(args);
1890            if (!slist)
1891                return -1;
1892            filter->addCondition(var, slist);
1893        }
1894
1895        else if (PyTuple_Check(args) && PyTuple_Size(args)) {
1896            char *mins, *maxs = NULL;
1897            int oper;
1898            if (!PyArg_ParseTuple(args, "is|s:Filter_values.__setitem__", &oper, &mins, &maxs))
1899                return -1;
1900            if ((PyTuple_Size(args) == 3) && (oper != TValueFilter::Between) && (oper != TValueFilter::Outside))
1901                PYERROR(PyExc_TypeError, "Filter_values.__setitem__: only one reference value expected for the given operator", -1);
1902
1903            filter->addCondition(var, oper, mins, maxs ? maxs : string());
1904        }
1905
1906        else {
1907            PyErr_Format(PyExc_TypeError, "Filter_values.__setitem__: invalid condition for attribute '%s'", var->get_name().c_str());
1908            return -1;
1909        }
1910    }
1911
1912    else
1913        PYERROR(PyExc_TypeError, "Filter_values.__setitem__: unsupported attribute type", -1);
1914
1915    return 0;
1916    PyCATCH_1
1917}
1918
1919
1920PyObject *Filter_values_getitem(PyObject *self, PyObject *args)
1921{
1922    PyTRY
1923        CAST_TO(TFilter_values, filter);
1924
1925    PVariable var = varFromArg_byDomain(args, filter->domain);
1926    if (!var)
1927        return PYNULL;
1928
1929    int position;
1930    TValueFilterList::iterator condi = filter->findCondition(var, 0, position);
1931    if (condi == filter->conditions->end()) {
1932        PyErr_Format(PyExc_IndexError, "no condition on '%s'", var->get_name().c_str());
1933        return PYNULL;
1934    }
1935
1936    return WrapOrange(*condi);
1937    PyCATCH
1938}
1939
1940
1941PFilterList PFilterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::P_FromArguments(arg); }
1942PyObject *FilterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_FromArguments(type, arg); }
1943PyObject *FilterList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of Filter>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_new(type, arg, kwds); }
1944PyObject *FilterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_getitem(self, index); }
1945int       FilterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_setitem(self, index, item); }
1946PyObject *FilterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_getslice(self, start, stop); }
1947int       FilterList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_setslice(self, start, stop, item); }
1948Py_ssize_t       FilterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_len(self); }
1949PyObject *FilterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_richcmp(self, object, op); }
1950PyObject *FilterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_concat(self, obj); }
1951PyObject *FilterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_repeat(self, times); }
1952PyObject *FilterList_str(TPyOrange *self) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_str(self); }
1953PyObject *FilterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_str(self); }
1954int       FilterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_contains(self, obj); }
1955PyObject *FilterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Filter) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_append(self, item); }
1956PyObject *FilterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_extend(self, obj); }
1957PyObject *FilterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Filter) -> int") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_count(self, obj); }
1958PyObject *FilterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> FilterList") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_filter(self, args); }
1959PyObject *FilterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Filter) -> int") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_index(self, obj); }
1960PyObject *FilterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_insert(self, args); }
1961PyObject *FilterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_native(self); }
1962PyObject *FilterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Filter") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_pop(self, args); }
1963PyObject *FilterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Filter) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_remove(self, obj); }
1964PyObject *FilterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_reverse(self); }
1965PyObject *FilterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_sort(self, args); }
1966PyObject *FilterList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_reduce(self); }
1967
1968
1969PyObject *Filter_conjunction_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Filter, "([filter-list])") ALLOWS_EMPTY
1970{
1971    if (!PyTuple_Size(args))
1972        return WrapNewOrange(mlnew TFilter_conjunction(), type);
1973
1974    PFilterList flist = PFilterList_FromArguments(PyTuple_Size(args)>1 ? args : PyTuple_GET_ITEM(args, 0));
1975    if (!flist)
1976        return PYNULL;
1977
1978    return WrapNewOrange(mlnew TFilter_conjunction(flist), type);
1979}
1980
1981
1982PyObject *Filter_disjunction_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Filter, "([filter-list])") ALLOWS_EMPTY
1983{
1984    if (!PyTuple_Size(args))
1985        return WrapNewOrange(mlnew TFilter_disjunction(), type);
1986
1987    PFilterList flist = PFilterList_FromArguments(PyTuple_Size(args)>1 ? args : PyTuple_GET_ITEM(args, 0));
1988    if (!flist)
1989        return PYNULL;
1990
1991    return WrapNewOrange(mlnew TFilter_disjunction(flist), type);
1992}
1993
1994/* ************ IMPUTATION ******************** */
1995
1996#include "imputation.hpp"
1997
1998C_NAMED(TransformValue_IsDefined, TransformValue, "([value=])")
1999
2000ABSTRACT(Imputer, Orange)
2001C_NAMED(Imputer_asValue, Imputer, "() -> Imputer_asValue")
2002C_NAMED(Imputer_model, Imputer, "() -> Imputer_model")
2003C_NAMED(Imputer_random, Imputer, "() -> Imputer_random")
2004
2005PyObject *Imputer_defaults_new(PyTypeObject *tpe, PyObject *args) BASED_ON(Imputer, "(domain | example) -> Imputer_defaults")
2006{
2007    PyTRY
2008        if (PyTuple_Size(args) == 1) {
2009            PyObject *arg = PyTuple_GET_ITEM(args, 0);
2010            if (PyOrDomain_Check(arg))
2011                return WrapNewOrange(mlnew TImputer_defaults(PyOrange_AsDomain(arg)), tpe);
2012            if (PyOrExample_Check(arg))
2013                return WrapNewOrange(mlnew TImputer_defaults(PyExample_AS_Example(arg)), tpe);
2014        }
2015
2016        PYERROR(PyExc_TypeError, "Imputer_defaults.__init__ expects an example or domain", PYNULL);
2017        PyCATCH
2018}
2019
2020PyObject *Imputer_defaults__reduce__(PyObject *self)
2021{
2022    PyTRY
2023        return Py_BuildValue("O(N)N", self->ob_type,
2024        Example_FromWrappedExample(SELF_AS(TImputer_defaults).defaults),
2025        packOrangeDictionary(self));
2026    PyCATCH
2027}
2028
2029
2030ABSTRACT(ImputerConstructor, Orange)
2031C_CALL(ImputerConstructor_average, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2032C_CALL(ImputerConstructor_minimal, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2033C_CALL(ImputerConstructor_maximal, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2034C_CALL(ImputerConstructor_model, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2035C_CALL(ImputerConstructor_asValue, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2036C_CALL(ImputerConstructor_random, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2037
2038PyObject *Imputer_call(PyObject *self, PyObject *args, PyObject *keywords)
2039{
2040    PyTRY
2041        NO_KEYWORDS
2042
2043        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrImputer_Type) {
2044            PyErr_Format(PyExc_SystemError, "Imputer.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
2045            return PYNULL;
2046        }
2047
2048        if ((PyTuple_GET_SIZE(args) == 1) && PyOrExample_Check(PyTuple_GET_ITEM(args, 0))) {
2049            TExample example = PyExample_AS_ExampleReference(PyTuple_GET_ITEM(args, 0));
2050            return Example_FromWrappedExample(PExample(PyOrange_AsImputer(self)->call(example)));
2051        }
2052
2053        int weightID = 0;
2054        PExampleGenerator gen = exampleGenFromArgs(args, weightID);
2055        if (gen)
2056            return WrapOrange(SELF_AS(TImputer)(gen, weightID));
2057
2058        PYERROR(PyExc_TypeError, "example or examples expected", PYNULL);
2059        PyCATCH
2060}
2061
2062
2063PyObject *ImputerConstructor_call(PyObject *self, PyObject *args, PyObject *keywords)
2064{
2065    PyTRY
2066        NO_KEYWORDS
2067
2068        int weightID = 0;
2069    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
2070    if (!gen)
2071        return PYNULL;
2072
2073    return WrapOrange(SELF_AS(TImputerConstructor)(gen, weightID));
2074    PyCATCH
2075}
2076
2077
2078/* ************ RANDOM INDICES ******************** */
2079#include "trindex.hpp"
2080
2081ABSTRACT(MakeRandomIndices, Orange)
2082C_CALL3(MakeRandomIndices2, MakeRandomIndices2, MakeRandomIndices, "[n | gen [, p0]], [p0=, stratified=, randseed=] -/-> [int]")
2083C_CALL3(MakeRandomIndicesMultiple, MakeRandomIndicesMultiple, MakeRandomIndices, "[n | gen [, p]], [p=, stratified=, randseed=] -/-> [int]")
2084C_CALL3(MakeRandomIndicesN, MakeRandomIndicesN, MakeRandomIndices, "[n | gen [, p]], [p=, stratified=, randseed=] -/-> [int]")
2085C_CALL3(MakeRandomIndicesCV, MakeRandomIndicesCV, MakeRandomIndices, "[n | gen [, folds]], [folds=, stratified=, randseed=] -/-> [int]")
2086
2087
2088PyObject *MakeRandomIndices2_call(PyObject *self, PyObject *args, PyObject *keywords)
2089{
2090    PyTRY
2091        CAST_TO(TMakeRandomIndices2, mri2);
2092
2093    float savedP0 = mri2->p0;
2094
2095    try {
2096        if (!((TPyOrange *)self)->call_constructed && keywords) {
2097            const Py_ssize_t sze = PyDict_Size(keywords);
2098            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "p0") : NULL;
2099            if ((sze > 1) || !neg)
2100                NO_KEYWORDS;
2101            if (Orange_setattr1((TPyOrange *)self, "p0", neg) == -1) {
2102                mri2->p0 = savedP0;
2103                return PYNULL;
2104            }
2105        }
2106
2107        int n;
2108        float f;
2109        PExampleGenerator egen;
2110        PRandomIndices res;
2111
2112        if (PyArg_ParseTuple(args, "i", &n)) {
2113            res = (*mri2)(n);
2114            goto out;
2115        }
2116
2117        PyErr_Clear();
2118        if (PyArg_ParseTuple(args, "if", &n, &f)) {
2119            res = (*mri2)(n, f);
2120            goto out;
2121        }
2122
2123        PyErr_Clear();
2124        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2125            res = (*mri2)(egen);
2126            goto out;
2127        }
2128
2129        PyErr_Clear();
2130        if (PyArg_ParseTuple(args, "O&f", pt_ExampleGenerator, &egen, &f)) {
2131            res = (*mri2)(egen, f);
2132            goto out;
2133        }
2134
2135        mri2->p0 = savedP0;
2136        PyErr_Clear();
2137        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2138
2139out:
2140        mri2->p0 = savedP0;
2141        if (!res)
2142            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2143
2144        return WrapOrange(res);
2145    }
2146    catch (...) {
2147        mri2->p0 = savedP0;
2148        throw;
2149    }
2150    PyCATCH
2151}
2152
2153
2154PyObject *MakeRandomIndicesMultiple_call(PyObject *self, PyObject *args, PyObject *keywords)
2155{
2156    PyTRY
2157        CAST_TO(TMakeRandomIndicesMultiple, mrim)
2158
2159        float savedP0 = mrim->p0;
2160
2161    try {
2162        if (!((TPyOrange *)self)->call_constructed && keywords) {
2163            const Py_ssize_t sze = PyDict_Size(keywords);
2164            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "p0") : NULL;
2165            if ((sze > 1) || !neg)
2166                NO_KEYWORDS;
2167            if (Orange_setattr1((TPyOrange *)self, "p0", neg) == -1) {
2168                mrim->p0 = savedP0;
2169                return PYNULL;
2170            }
2171        }
2172
2173        int n;
2174        float f;
2175        PExampleGenerator egen;
2176        PRandomIndices res;
2177
2178        if (PyArg_ParseTuple(args, "i", &n)) {
2179            res = (*mrim)(n);
2180            goto out;
2181        }
2182
2183        PyErr_Clear();
2184        if (PyArg_ParseTuple(args, "if", &n, &f)) {
2185            res = (*mrim)(n, f);
2186            goto out;
2187        }
2188
2189        PyErr_Clear();
2190        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2191            res = (*mrim)(egen);
2192            goto out;
2193        }
2194
2195        PyErr_Clear();
2196        if (PyArg_ParseTuple(args, "O&f", pt_ExampleGenerator, &egen, &f)) {
2197            res = (*mrim)(egen, f);
2198            goto out;
2199        }
2200
2201        mrim->p0 = savedP0;
2202        PyErr_Clear();
2203        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2204
2205out:
2206        mrim->p0 = savedP0;
2207
2208        if (!res)
2209            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2210
2211        return WrapOrange(res);
2212    }
2213
2214    catch(...) {
2215        mrim->p0 = savedP0;
2216        throw;
2217    }
2218    PyCATCH
2219}
2220
2221
2222
2223
2224PyObject *MakeRandomIndicesN_call(PyObject *self, PyObject *args, PyObject *keywords)
2225{
2226    PyTRY
2227        CAST_TO(TMakeRandomIndicesN, mriN)
2228
2229        PFloatList savedP = mriN->p;
2230
2231    try {
2232        if (!((TPyOrange *)self)->call_constructed && keywords) {
2233            const Py_ssize_t sze = PyDict_Size(keywords);
2234            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "p") : NULL;
2235            if ((sze > 1) || !neg)
2236                NO_KEYWORDS;
2237            if (Orange_setattr1((TPyOrange *)self, "p", neg) == -1) {
2238                mriN->p = savedP;
2239                return PYNULL;
2240            }
2241        }
2242
2243        int n;
2244        PFloatList pyvector;
2245        PExampleGenerator egen;
2246        PRandomIndices res;
2247
2248        if (PyArg_ParseTuple(args, "i", &n)) {
2249            res = (*mriN)(n);
2250            goto out;
2251        }
2252
2253        PyErr_Clear();
2254        if (PyArg_ParseTuple(args, "iO&", &n, cc_FloatList, &pyvector)) {
2255            res = (*mriN)(n, pyvector);
2256            goto out;
2257        }
2258
2259        PyErr_Clear();
2260        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2261            res = (*mriN)(egen);
2262            goto out;
2263        }
2264
2265        PyErr_Clear();
2266        if (PyArg_ParseTuple(args, "O&O&", pt_ExampleGenerator, &egen, cc_FloatList, &pyvector)) {
2267            res = (*mriN)(egen, pyvector);
2268            goto out;
2269        }
2270
2271        mriN->p = savedP;
2272        PyErr_Clear();
2273        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2274
2275out:
2276        mriN->p = savedP;
2277
2278        if (!res)
2279            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2280
2281        return WrapOrange(res);
2282    }
2283
2284    catch(...) {
2285        mriN->p = savedP;
2286        throw;
2287    }
2288    PyCATCH
2289}
2290
2291
2292
2293PyObject *MakeRandomIndicesCV_call(PyObject *self, PyObject *args, PyObject *keywords)
2294{
2295    PyTRY
2296        CAST_TO(TMakeRandomIndicesCV, mriCV)
2297
2298        int savedFolds = mriCV->folds;
2299
2300    try {
2301        if (!((TPyOrange *)self)->call_constructed && keywords) {
2302            const Py_ssize_t sze = PyDict_Size(keywords);
2303            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "folds") : NULL;
2304            if ((sze > 1) || !neg)
2305                NO_KEYWORDS;
2306            if (Orange_setattr1((TPyOrange *)self, "folds", neg) == -1) {
2307                mriCV->folds = savedFolds;
2308                return PYNULL;
2309            }
2310        }
2311
2312        int n, f;
2313        PExampleGenerator egen;
2314        PRandomIndices res;
2315
2316        if (PyArg_ParseTuple(args, "i", &n)) {
2317            res = (*mriCV)(n);
2318            goto out;
2319        }
2320
2321        PyErr_Clear();
2322        if (PyArg_ParseTuple(args, "ii", &n, &f)) {
2323            res = (*mriCV)(n, f);
2324            goto out;
2325        }
2326
2327        PyErr_Clear();
2328        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2329            res = (*mriCV)(egen);
2330            goto out;
2331        }
2332
2333        PyErr_Clear();
2334        if (PyArg_ParseTuple(args, "O&i", pt_ExampleGenerator, &egen, &f)) {
2335            res = (*mriCV)(egen, f);
2336            goto out;
2337        }
2338
2339        mriCV->folds = savedFolds;
2340        PyErr_Clear();
2341        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2342
2343out:
2344        mriCV->folds = savedFolds;
2345        if (!res)
2346            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2347
2348        return WrapOrange(res);
2349    }
2350    catch(...) {
2351        mriCV->folds = savedFolds;
2352        throw;
2353    }
2354    PyCATCH
2355}
2356
2357
2358/* ************ PROBABILITY ESTIMATION ************ */
2359
2360#include "estimateprob.hpp"
2361
2362ABSTRACT(ProbabilityEstimator, Orange)
2363ABSTRACT(ProbabilityEstimatorConstructor, Orange)
2364C_NAMED(ProbabilityEstimator_FromDistribution, ProbabilityEstimator, "()")
2365C_CALL(ProbabilityEstimatorConstructor_relative, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromDistribution")
2366C_CALL(ProbabilityEstimatorConstructor_Laplace, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromDistribution")
2367C_CALL(ProbabilityEstimatorConstructor_m, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromDistribution")
2368C_CALL(ProbabilityEstimatorConstructor_kernel, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromCurve")
2369C_CALL(ProbabilityEstimatorConstructor_loess, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromCurve")
2370
2371ABSTRACT(ConditionalProbabilityEstimator, Orange)
2372ABSTRACT(ConditionalProbabilityEstimatorConstructor, Orange)
2373C_NAMED(ConditionalProbabilityEstimator_FromDistribution, ConditionalProbabilityEstimator, "()")
2374C_NAMED(ConditionalProbabilityEstimator_ByRows, ConditionalProbabilityEstimator, "()")
2375C_CALL(ConditionalProbabilityEstimatorConstructor_ByRows, ConditionalProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ConditionalProbabilityEstimator_[FromDistribution|ByRows]")
2376C_CALL(ConditionalProbabilityEstimatorConstructor_loess, ConditionalProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromCurves")
2377
2378
2379extern PyTypeObject PyOrProbabilityEstimator_Type_inh;
2380
2381PProbabilityEstimatorList PProbabilityEstimatorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::P_FromArguments(arg); }
2382PyObject *ProbabilityEstimatorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_FromArguments(type, arg); }
2383PyObject *ProbabilityEstimatorList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of ProbabilityEstimator>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_new(type, arg, kwds); }
2384PyObject *ProbabilityEstimatorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_getitem(self, index); }
2385int       ProbabilityEstimatorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_setitem(self, index, item); }
2386PyObject *ProbabilityEstimatorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_getslice(self, start, stop); }
2387int       ProbabilityEstimatorList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_setslice(self, start, stop, item); }
2388Py_ssize_t       ProbabilityEstimatorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_len(self); }
2389PyObject *ProbabilityEstimatorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_richcmp(self, object, op); }
2390PyObject *ProbabilityEstimatorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_concat(self, obj); }
2391PyObject *ProbabilityEstimatorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_repeat(self, times); }
2392PyObject *ProbabilityEstimatorList_str(TPyOrange *self) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_str(self); }
2393PyObject *ProbabilityEstimatorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_str(self); }
2394int       ProbabilityEstimatorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_contains(self, obj); }
2395PyObject *ProbabilityEstimatorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ProbabilityEstimator) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_append(self, item); }
2396PyObject *ProbabilityEstimatorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_extend(self, obj); }
2397PyObject *ProbabilityEstimatorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ProbabilityEstimator) -> int") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_count(self, obj); }
2398PyObject *ProbabilityEstimatorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ProbabilityEstimatorList") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_filter(self, args); }
2399PyObject *ProbabilityEstimatorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ProbabilityEstimator) -> int") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_index(self, obj); }
2400PyObject *ProbabilityEstimatorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_insert(self, args); }
2401PyObject *ProbabilityEstimatorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_native(self); }
2402PyObject *ProbabilityEstimatorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ProbabilityEstimator") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_pop(self, args); }
2403PyObject *ProbabilityEstimatorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ProbabilityEstimator) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_remove(self, obj); }
2404PyObject *ProbabilityEstimatorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_reverse(self); }
2405PyObject *ProbabilityEstimatorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_sort(self, args); }
2406PyObject *ProbabilityEstimatorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_reduce(self); }
2407
2408
2409
2410PConditionalProbabilityEstimatorList PConditionalProbabilityEstimatorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::P_FromArguments(arg); }
2411PyObject *ConditionalProbabilityEstimatorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_FromArguments(type, arg); }
2412PyObject *ConditionalProbabilityEstimatorList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of ConditionalProbabilityEstimator>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_new(type, arg, kwds); }
2413PyObject *ConditionalProbabilityEstimatorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_getitem(self, index); }
2414int       ConditionalProbabilityEstimatorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_setitem(self, index, item); }
2415PyObject *ConditionalProbabilityEstimatorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_getslice(self, start, stop); }
2416int       ConditionalProbabilityEstimatorList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_setslice(self, start, stop, item); }
2417Py_ssize_t       ConditionalProbabilityEstimatorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_len(self); }
2418PyObject *ConditionalProbabilityEstimatorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_richcmp(self, object, op); }
2419PyObject *ConditionalProbabilityEstimatorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_concat(self, obj); }
2420PyObject *ConditionalProbabilityEstimatorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_repeat(self, times); }
2421PyObject *ConditionalProbabilityEstimatorList_str(TPyOrange *self) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_str(self); }
2422PyObject *ConditionalProbabilityEstimatorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_str(self); }
2423int       ConditionalProbabilityEstimatorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_contains(self, obj); }
2424PyObject *ConditionalProbabilityEstimatorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_append(self, item); }
2425PyObject *ConditionalProbabilityEstimatorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_extend(self, obj); }
2426PyObject *ConditionalProbabilityEstimatorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> int") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_count(self, obj); }
2427PyObject *ConditionalProbabilityEstimatorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ConditionalProbabilityEstimatorList") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_filter(self, args); }
2428PyObject *ConditionalProbabilityEstimatorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> int") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_index(self, obj); }
2429PyObject *ConditionalProbabilityEstimatorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_insert(self, args); }
2430PyObject *ConditionalProbabilityEstimatorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_native(self); }
2431PyObject *ConditionalProbabilityEstimatorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ConditionalProbabilityEstimator") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_pop(self, args); }
2432PyObject *ConditionalProbabilityEstimatorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_remove(self, obj); }
2433PyObject *ConditionalProbabilityEstimatorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_reverse(self); }
2434PyObject *ConditionalProbabilityEstimatorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_sort(self, args); }
2435PyObject *ConditionalProbabilityEstimatorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_reduce(self); }
2436
2437
2438PyObject *ProbabilityEstimatorConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([distribution[, apriori]] [example generator[, weight]]) -> ProbabilityEstimator")
2439{
2440    PyTRY
2441        NO_KEYWORDS
2442
2443        CAST_TO(TProbabilityEstimatorConstructor, cest);
2444
2445    PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
2446    PDistribution dist, apriori;
2447    PExampleGenerator gen;
2448    int weightID = 0;
2449    if (!PyArg_UnpackTuple(uargs, "ProbabilityEstimatorConstructor.call", 0, 4, args+0, args+1, args+2, args+3))
2450        return PYNULL;
2451
2452    PyObject **argp = args, **argc = args;
2453    for (int i=0; i<=3; i++, argp++)
2454        if (*argp)
2455            *argc++ = *argp;
2456
2457    argp = args;
2458    if ((argp != argc) && ((*argp==Py_None) || PyOrDistribution_Check(*argp))) {
2459        dist = (*argp==Py_None) ? PDistribution() : PyOrange_AsDistribution(*argp++);
2460        if ((argp != argc) && PyOrDistribution_Check(*argp))
2461            apriori = PyOrange_AsDistribution(*argp++);
2462    }
2463    if (argp != argc) {
2464        gen = exampleGenFromParsedArgs(*argp);
2465        if (gen) {
2466            argp++;
2467            if ((argp != argc) && !weightFromArg_byDomain(*(argp++), gen->domain, weightID))
2468                return PYNULL;
2469        }
2470    }
2471
2472    if (argp != argc)
2473        PYERROR(PyExc_TypeError, "Invalid arguments for 'ProbabilityEstimatorConstructor.call'", PYNULL);
2474
2475    return WrapOrange(cest->call(dist, apriori, gen, weightID));
2476    PyCATCH
2477}
2478
2479
2480PyObject *ProbabilityEstimator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(Value) -> float  |  () -> Distribution")
2481{ PyTRY
2482NO_KEYWORDS
2483
2484CAST_TO(TProbabilityEstimator, cest);
2485
2486PyObject *pyobj = PYNULL;
2487if (!PyArg_ParseTuple(args, "|O:ProbabilityEstimator.call", &pyobj))
2488return PYNULL;
2489
2490if (pyobj) {
2491    TValue val;
2492    if (!convertFromPython(pyobj, val))
2493        PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2494    return PyFloat_FromDouble((double)cest->call(val));
2495}
2496
2497else
2498return WrapOrange(cest->call());
2499PyCATCH
2500}
2501
2502
2503
2504PyObject *ConditionalProbabilityEstimatorConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([contingency[, apriori]] [example generator[, weight]]) -> ProbabilityEstimator")
2505{
2506    PyTRY
2507        NO_KEYWORDS
2508
2509        CAST_TO(TConditionalProbabilityEstimatorConstructor, cest);
2510
2511    PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
2512    PContingency cont, apriori;
2513    PExampleGenerator gen;
2514    int weightID = 0;
2515    if (!PyArg_UnpackTuple(uargs, "ProbabilityEstimatorConstructor.call", 0, 4, args, args+1, args+2, args+3))
2516        return PYNULL;
2517
2518    PyObject **argp = args, **argc = args;
2519    for (int i=0; i<=3; i++, argp++)
2520        if (*argp)
2521            *argc++ = *argp;
2522
2523    argp = args;
2524    if ((argp != argc) && ((*argp==Py_None) || PyOrContingency_Check(*argp))) {
2525        cont = (*argp==Py_None) ? PContingency() : PyOrange_AsContingency(*argp++);
2526        if ((argp != argc) && PyOrDistribution_Check(*argp))
2527            apriori = PyOrange_AsDistribution(*argp++);
2528    }
2529    if (argp != argc) {
2530        gen = exampleGenFromParsedArgs(*argp);
2531        if (gen) {
2532            argp++;
2533            if ((argp != argc) && !weightFromArg_byDomain(*(argp++), gen->domain, weightID))
2534                return PYNULL;
2535        }
2536    }
2537
2538    if (argp != argc)
2539        PYERROR(PyExc_TypeError, "Invalid arguments for 'ProbabilityEstimatorConstructor.call'", PYNULL);
2540
2541    return WrapOrange(cest->call(cont, apriori, gen, weightID));
2542    PyCATCH
2543}
2544
2545
2546PyObject *ConditionalProbabilityEstimator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(Value, Condition) -> float  |  (Condition) -> Distribution | () -> Contingency")
2547{
2548    PyTRY
2549        NO_KEYWORDS
2550
2551        CAST_TO(TConditionalProbabilityEstimator, cest);
2552
2553    PyObject *pyobj1 = PYNULL, *pyobj2 = PYNULL;
2554    if (!PyArg_ParseTuple(args, "|OO:ProbabilityEstimator.call", &pyobj1, &pyobj2))
2555        return PYNULL;
2556
2557    if (pyobj1 && pyobj2) {
2558        TValue val1, val2;
2559        if (!convertFromPython(pyobj1, val1) || !convertFromPython(pyobj2, val2))
2560            PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2561        return PyFloat_FromDouble((double)cest->call(val1, val2));
2562    }
2563
2564    else if (pyobj1) {
2565        TValue val;
2566        if (!convertFromPython(pyobj1, val))
2567            PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2568        return WrapOrange(cest->call(val));
2569    }
2570
2571    else
2572        return WrapOrange(cest->call());
2573    PyCATCH
2574}
2575
2576#include "stat.hpp"
2577
2578/* ************ MEASURES ************ */
2579
2580#include "measures.hpp"
2581#include "relief.hpp"
2582
2583BASED_ON(MeasureAttribute, Orange)
2584ABSTRACT(MeasureAttributeFromProbabilities, MeasureAttribute)
2585
2586C_CALL(MeasureAttribute_info, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2587C_CALL(MeasureAttribute_gini, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2588C_CALL(MeasureAttribute_gainRatio, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2589C_CALL(MeasureAttribute_gainRatioA, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2590C_CALL(MeasureAttribute_cost, MeasureAttributeFromProbabilities, "(cost=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2591C_CALL(MeasureAttribute_relevance, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2592C_CALL(MeasureAttribute_logOddsRatio, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2593C_CALL(MeasureAttribute_chiSquare, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2594
2595C_CALL(MeasureAttribute_MSE, MeasureAttribute, "(estimate=, m=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2596
2597C_CALL(MeasureAttribute_relief, MeasureAttribute, "(estimate=, m=, k=) | (attr, examples[, apriori] [,weightID]) -/-> float")
2598
2599/* obsolete: */
2600PYCONSTANT(MeasureAttribute_splitGain, (PyObject *)&PyOrMeasureAttribute_gainRatio_Type)
2601PYCONSTANT(MeasureAttribute_retis, (PyObject *)&PyOrMeasureAttribute_MSE_Type)
2602
2603
2604PYCLASSCONSTANT_FLOAT(MeasureAttribute, Rejected, ATTRIBUTE_REJECTED)
2605
2606PyObject *MeasureAttribute_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
2607{ if (type == (PyTypeObject *)&PyOrMeasureAttribute_Type)
2608return setCallbackFunction(WrapNewOrange(mlnew TMeasureAttribute_Python(), type), args);
2609else
2610return WrapNewOrange(mlnew TMeasureAttribute_Python(), type);
2611}
2612
2613
2614PyObject *MeasureAttribute__reduce__(PyObject *self)
2615{
2616    return callbackReduce(self, PyOrMeasureAttribute_Type);
2617}
2618
2619
2620PyObject *MeasureAttribute_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(attr, xmpls[, apr, wght]) | (attr, domcont[, apr]) | (cont, clss-dist [,apr]) -> (float, meas-type)")
2621{
2622    PyTRY
2623        NO_KEYWORDS
2624
2625        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrMeasureAttribute_Type) {
2626            PyErr_Format(PyExc_SystemError, "MeasureAttribute.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
2627            return PYNULL;
2628        }
2629
2630        CAST_TO(TMeasureAttribute, meat)
2631
2632            PyObject *arg1;
2633        PDistribution aprClDistr;
2634
2635        // Try (contingency, class distribution, aprior class distribution)
2636
2637        PContingency contingency;
2638        PDistribution clDistr;
2639        if (PyArg_ParseTuple(args, "O&O&|O&", cc_Contingency, &contingency, cc_Distribution, &clDistr, ccn_Distribution, &aprClDistr))
2640            return PyFloat_FromDouble((double)(meat->operator()(contingency, clDistr, aprClDistr)));
2641
2642        PyErr_Clear();
2643
2644
2645        // Try (variable, domaincontingency, aprior class distribution)
2646
2647        PDomainContingency dcont;
2648        if (PyArg_ParseTuple(args, "OO&|O&", &arg1, cc_DomainContingency, &dcont, ccn_Distribution, &aprClDistr)) {
2649
2650            int attrNo;
2651
2652            if (PyInt_Check(arg1)) {
2653                attrNo = int(PyInt_AsLong(arg1));
2654                if ((attrNo<0) || (attrNo>=dcont->size())) {
2655                    PyErr_Format(PyExc_IndexError, "attribute index %i out of range for the given DomainContingency", attrNo);
2656                    return PYNULL;
2657                }
2658            }
2659
2660            else {
2661                TDomainContingency::const_iterator ci(dcont->begin()), ce(dcont->end());
2662                const bool &couter = dcont->classIsOuter;
2663
2664                if (PyOrVariable_Check(arg1)) {
2665                    PVariable var = PyOrange_AsVariable(arg1);
2666                    for(attrNo = 0; (ci!=ce) && (couter ? ((*ci)->innerVariable != var) : ((*ci)->outerVariable != var)); ci++, attrNo++);
2667
2668                    if (ci==ce) {
2669                        PyErr_Format(PyExc_IndexError, "attribute '%s' not in the given DomainContingency", var->get_name().c_str());
2670                        return PYNULL;
2671                    }
2672                }
2673
2674                else if (PyString_Check(arg1)) {
2675                    char *attrName = PyString_AsString(arg1);
2676                    for(attrNo = 0; (ci!=ce) && (couter ? ((*ci)->innerVariable->get_name()!= attrName) : ((*ci)->outerVariable->get_name()!=attrName)); ci++, attrNo++);
2677
2678                    if (ci==ce) {
2679                        PyErr_Format(PyExc_IndexError, "attribute '%s' not in the given DomainContingency", attrName);
2680                        return PYNULL;
2681                    }
2682                }
2683
2684                else {
2685                    PyErr_Format(PyExc_IndexError, "cannot guess the attribute from the object of type '%s'", arg1->ob_type->tp_name);
2686                    return PYNULL;
2687                }
2688            }
2689
2690            return PyFloat_FromDouble((double)(meat->operator()(attrNo, dcont, aprClDistr)));
2691        }
2692
2693
2694        PyErr_Clear();
2695
2696
2697        // Try (variable, examples, aprior class distribution, weight)
2698
2699        PExampleGenerator egen;
2700        if ((PyTuple_Size(args) >= 2) && pt_ExampleGenerator(PyTuple_GET_ITEM(args, 1), &egen)) {
2701
2702            // No need to INCREF (ParseArgs doesn't INCREF either)
2703            PyObject *arg3 = Py_None, *arg4 = Py_None;
2704
2705            arg1 = PyTuple_GET_ITEM(args, 0);
2706
2707            if (PyTuple_Size(args) == 4) {
2708                arg3 = PyTuple_GET_ITEM(args, 2);
2709                arg4 = PyTuple_GET_ITEM(args, 3);
2710            }
2711
2712            else if (PyTuple_Size(args) == 3) {
2713                arg4 = PyTuple_GET_ITEM(args, 2);
2714                // This mess is for compatibility; previously, weightID could only be the 4th argument; 3rd had to be either Distribution or None if 4th was to be given
2715                if (PyOrDistribution_Check(arg4)) {
2716                    arg3 = arg4;
2717                    arg4 = Py_None;
2718                }
2719                else
2720                    arg3 = Py_None;
2721            }
2722
2723            int weightID=0;
2724
2725            if (arg3 != Py_None)
2726                if (PyOrDistribution_Check(arg4))
2727                    aprClDistr = PyOrange_AsDistribution(arg3);
2728                else
2729                    PYERROR(PyExc_TypeError, "invalid argument 3 (Distribution or None expected)", PYNULL);
2730
2731            if (arg4 != Py_None)
2732                if (!weightFromArg_byDomain(arg4, egen->domain, weightID))
2733                    PYERROR(PyExc_TypeError, "invalid argument 4 (weightID or None expected)", PYNULL);
2734
2735            if (PyOrVariable_Check(arg1))
2736                return PyFloat_FromDouble((double)(meat->operator()(PyOrange_AsVariable(arg1), egen, aprClDistr, weightID)));
2737
2738            else if (PyInt_Check(arg1)) {
2739                int attrNo = PyInt_AsLong(arg1);
2740                if (attrNo >= (int)egen->domain->attributes->size()) {
2741                    PyErr_Format(PyExc_IndexError, "attribute index %i out of range for the given DomainContingency", attrNo);
2742                    return PYNULL;
2743                }
2744                return PyFloat_FromDouble((double)(meat->operator()(attrNo, egen, aprClDistr, weightID)));
2745            }
2746
2747            else {
2748                int attrNo;
2749                if (!varNumFromVarDom(arg1, egen->domain, attrNo))
2750                    PYERROR(PyExc_TypeError, "invalid argument 1 (attribute index, name or descriptor expected)", PYNULL);
2751
2752                return PyFloat_FromDouble((double)(meat->operator()(attrNo, egen, aprClDistr, weightID)));
2753            }
2754        }
2755
2756        PYERROR(PyExc_TypeError, "invalid set of parameters", PYNULL);
2757        return PYNULL;
2758        PyCATCH;
2759}
2760
2761
2762PyObject *MeasureAttribute_thresholdFunction(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples[, weightID]) | (contingency[, distribution]) -> list")
2763{
2764    PyTRY
2765        TFloatFloatList thresholds;
2766
2767    PyObject *pyvar;
2768    PExampleGenerator gen;
2769    int weightID = 0;
2770    if (PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_thresholdFunction", &pyvar, pt_ExampleGenerator, &gen, &weightID)) {
2771        PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2772        if (!var)
2773            return NULL;
2774
2775        SELF_AS(TMeasureAttribute).thresholdFunction(thresholds, var, gen, PDistribution(), weightID);
2776    }
2777    else {
2778        PyErr_Clear();
2779
2780        PContingency cont;
2781        PDistribution cdist;
2782        if (PyArg_ParseTuple(args, "O&|O&", cc_Contingency, &cont, ccn_Distribution, &cdist)) {
2783            if (!cdist)
2784                cdist = cont->innerDistribution;
2785
2786            SELF_AS(TMeasureAttribute).thresholdFunction(thresholds, cont, cdist);
2787        }
2788        else {
2789            PyErr_Clear();
2790            PYERROR(PyExc_TypeError, "MeasureAttribute.thresholdFunction expects a variable, generator[, weight], or contingency", PYNULL)
2791        }
2792    }
2793
2794    PyObject *res = PyList_New(thresholds.size());
2795    Py_ssize_t li = 0;
2796    for(TFloatFloatList::const_iterator ti(thresholds.begin()), te(thresholds.end()); ti != te; ti++)
2797        PyList_SetItem(res, li++, Py_BuildValue("ff", ti->first, ti->second));
2798    return res;
2799    PyCATCH;
2800}
2801
2802
2803
2804PyObject *MeasureAttribute_relief_pairGains(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> list")
2805{
2806    PyTRY
2807        PyObject *pyvar;
2808    PExampleGenerator gen;
2809    int weightID = 0;
2810    if (!PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_pairGains", &pyvar, pt_ExampleGenerator, &gen, &weightID))
2811        return NULL;
2812
2813    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2814    if (!var)
2815        return NULL;
2816
2817    TPairGainAdder pairGains;
2818    SELF_AS(TMeasureAttribute_relief).pairGains(pairGains, var, gen, weightID);
2819
2820    PyObject *res = PyList_New(pairGains.size());
2821    Py_ssize_t li = 0;
2822    for(TPairGainAdder::const_iterator ti(pairGains.begin()), te(pairGains.end()); ti != te; ti++)
2823        PyList_SetItem(res, li++, Py_BuildValue("(ff)f", ti->e1, ti->e2, ti->gain));
2824    return res;
2825    PyCATCH
2826}
2827
2828
2829PyObject *MeasureAttribute_relief_gainMatrix(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> SymMatrix")
2830{
2831    PyTRY
2832        PyObject *pyvar;
2833    PExampleGenerator gen;
2834    int weightID = 0;
2835    if (!PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_gainMatrix", &pyvar, pt_ExampleGenerator, &gen, &weightID))
2836        return NULL;
2837
2838    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2839    if (!var)
2840        return NULL;
2841
2842    return WrapOrange(SELF_AS(TMeasureAttribute_relief).gainMatrix(var, gen, NULL, weightID, NULL, NULL));
2843    PyCATCH
2844}
2845
2846PyObject *MeasureAttribute_bestThreshold(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> list")
2847{
2848    PyTRY
2849        PyObject *pyvar;
2850    PExampleGenerator gen;
2851    int weightID = 0;
2852    float minSubset = 0.0;
2853    if (!PyArg_ParseTuple(args, "OO&|if:MeasureAttribute_thresholdFunction", &pyvar, pt_ExampleGenerator, &gen, &weightID, &minSubset))
2854        return NULL;
2855
2856    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2857    if (!var)
2858        return NULL;
2859
2860    float threshold, score;
2861    PDistribution distribution;
2862    threshold = SELF_AS(TMeasureAttribute).bestThreshold(distribution, score, var, gen, PDistribution(), weightID);
2863
2864    if (threshold == ILLEGAL_FLOAT)
2865        PYERROR(PyExc_SystemError, "cannot compute the threshold; check the number of instances etc.", PYNULL);
2866
2867    return Py_BuildValue("ffO", threshold, score, WrapOrange(distribution));
2868    PyCATCH
2869}
2870
2871/* ************ EXAMPLE CLUSTERING ************ */
2872
2873#include "exampleclustering.hpp"
2874
2875ABSTRACT(GeneralExampleClustering, Orange)
2876C_NAMED(ExampleCluster, Orange, "([left=, right=, distance=, centroid=])")
2877C_NAMED(ExampleClusters, GeneralExampleClustering, "([root=, quality=]")
2878
2879
2880PyObject *GeneralExampleClustering_exampleClusters(PyObject *self) PYARGS(METH_NOARGS, "() -> ExampleClusters")
2881{
2882    PyTRY
2883        return WrapOrange(SELF_AS(TGeneralExampleClustering).exampleClusters());
2884    PyCATCH
2885}
2886
2887
2888PyObject *GeneralExampleClustering_exampleSets(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> ExampleSets")
2889{
2890    PyTRY
2891        float cut = 0.0;
2892    if (!PyArg_ParseTuple(args, "|f", &cut))
2893        return PYNULL;
2894
2895    return WrapOrange(SELF_AS(TGeneralExampleClustering).exampleSets(cut));
2896    PyCATCH
2897}
2898
2899
2900PyObject *GeneralExampleClustering_classifier(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> Classifier")
2901{
2902    PyTRY
2903        float cut = 0.0;
2904    if (!PyArg_ParseTuple(args, "|f", &cut))
2905        return PYNULL;
2906
2907    return WrapOrange(SELF_AS(TGeneralExampleClustering).classifier(cut));
2908    PyCATCH
2909}
2910
2911
2912PyObject *GeneralExampleClustering_feature(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> Variable")
2913{
2914    PyTRY
2915        float cut = 0.0;
2916    if (!PyArg_ParseTuple(args, "|f", &cut))
2917        return PYNULL;
2918
2919    return WrapOrange(SELF_AS(TGeneralExampleClustering).feature(cut));
2920    PyCATCH
2921}
2922
2923
2924#include "calibrate.hpp"
2925
2926C_CALL(ThresholdCA, Orange, "([classifier, examples[, weightID, target value]]) -/-> (threshold, optimal CA, list of CAs))")
2927
2928PyObject *ThresholdCA_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(classifier, examples[, weightID, target value]) -> (threshold, optimal CA, list of CAs)")
2929{
2930    PyTRY
2931        NO_KEYWORDS
2932
2933        PClassifier classifier;
2934    PExampleGenerator egen;
2935    int weightID = 0;
2936    PyObject *pyvalue = NULL;
2937    int targetVal = -1;
2938
2939    if (!PyArg_ParseTuple(args, "O&O&|O&O:ThresholdCA.__call__", cc_Classifier, &classifier, pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weightID, &pyvalue))
2940        return PYNULL;
2941    if (pyvalue) {
2942        TValue classVal;
2943        if (!convertFromPython(pyvalue, classVal, classifier->classVar))
2944            return PYNULL;
2945        if (classVal.isSpecial())
2946            PYERROR(PyExc_TypeError, "invalid target value", PYNULL);
2947        targetVal = classVal.intV;
2948    }
2949
2950    TFloatFloatList *ffl = mlnew TFloatFloatList();
2951    PFloatFloatList wfl(ffl);
2952    float optThresh, optCA;
2953    optThresh = SELF_AS(TThresholdCA).call(classifier, egen, weightID, optCA, targetVal, ffl);
2954
2955    PyObject *pyCAs = PyList_New(ffl->size());
2956    Py_ssize_t i = 0;
2957    PITERATE(TFloatFloatList, ffi, ffl)
2958        PyList_SetItem(pyCAs, i++, Py_BuildValue("ff", (*ffi).first, (*ffi).second));
2959
2960    return Py_BuildValue("ffN", optThresh, optCA, pyCAs);
2961    PyCATCH
2962}
2963
2964
2965#include "symmatrix.hpp"
2966
2967PyObject *SymMatrix_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Orange, "(dimension[, initialElement=0] | a list of lists)")
2968{
2969    PyTRY
2970        int dim;
2971    float init = 0;
2972    if (PyArg_ParseTuple(args, "i|f", &dim, &init)) {
2973        if (dim<1)
2974            PYERROR(PyExc_TypeError, "matrix dimension must be positive", PYNULL);
2975
2976        return WrapNewOrange(mlnew TSymMatrix(dim, init), type);
2977    }
2978
2979    PyErr_Clear();
2980
2981    PyObject *arg;
2982    if (PyArg_ParseTuple(args, "O|f", &arg, &init)) {
2983        dim = PySequence_Size(arg);
2984        PyObject *iter = PyObject_GetIter(arg);
2985        if ((dim<0) || !iter)
2986            PYERROR(PyExc_TypeError, "SymMatrix.__init__ expects a list of lists or the dimension, and an optional default element", PYNULL);
2987
2988#define UNKNOWN_F -1e30f
2989
2990        TSymMatrix *symmatrix = mlnew TSymMatrix(dim, UNKNOWN_F);
2991        PyObject *subiter = NULL;
2992
2993#define FREE_ALL  Py_DECREF(iter); delete symmatrix; Py_XDECREF(subiter);
2994
2995        int i, j;
2996
2997        for(i = 0; i<dim; i++) {
2998            PyObject *item = PyIter_Next(iter);
2999            if (!item) {
3000                FREE_ALL
3001                    PYERROR(PyExc_SystemError, "matrix is shorter than promissed ('len' returned more elements than there actuall are)", PYNULL);
3002            }
3003
3004            PyObject *subiter = PyObject_GetIter(item);
3005            Py_DECREF(item);
3006
3007            if (!subiter) {
3008                FREE_ALL
3009                    PyErr_Format(PyExc_TypeError, "row %i is not a sequence", i);
3010                return PYNULL;
3011            }
3012
3013            for(j = 0;; j++) {
3014                PyObject *subitem = PyIter_Next(subiter);
3015                if (!subitem)
3016                    break;
3017
3018                float f;
3019                bool ok = PyNumber_ToFloat(subitem, f);
3020                Py_DECREF(subitem);
3021                if (!ok) {
3022                    FREE_ALL
3023                        PyErr_Format(PyExc_TypeError, "element at (%i, %i) is not a number", i, j);
3024                    return PYNULL;
3025                }
3026
3027
3028                try {
3029                    float &mae = symmatrix->getref(i, j);
3030
3031                    if ((mae != UNKNOWN_F) && (mae!=f)) {
3032                        FREE_ALL
3033                            PyErr_Format(PyExc_TypeError, "the element at (%i, %i) is asymmetric", i, j);
3034                        return PYNULL;
3035                    }
3036
3037                    mae = f;
3038                }
3039                catch (...) {
3040                    FREE_ALL
3041                        throw;
3042                }
3043            }
3044
3045            Py_DECREF(subiter);
3046            subiter = NULL;
3047        }
3048        Py_DECREF(iter);
3049
3050        float *e = symmatrix->elements;
3051        for(i = ((dim+1)*(dim+2)) >> 1; i--; e++)
3052            if (*e == UNKNOWN_F)
3053                *e = init;
3054
3055        return WrapNewOrange(symmatrix, type);
3056
3057#undef UNKNOWN_F
3058#undef FREE_ALL
3059    }
3060
3061    PyErr_Clear();
3062
3063    PYERROR(PyExc_TypeError, "SymMatrix.__init__ expects a list of lists or the dimension and the initial element", PYNULL);
3064
3065    PyCATCH
3066}
3067
3068
3069PyObject *SymMatrix__reduce__(PyObject *self)
3070{
3071    PyTRY
3072        CAST_TO(TSymMatrix, matrix);
3073    const int dim = matrix->dim;
3074    return Py_BuildValue("O(Os#i)N", getExportedFunction("__pickleLoaderSymMatrix"),
3075        self->ob_type,
3076        matrix->elements, sizeof(float) * (((dim+1) * (dim+2)) >> 1),
3077        dim,
3078        packOrangeDictionary(self));
3079    PyCATCH
3080}
3081
3082
3083PyObject *__pickleLoaderSymMatrix(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension)")
3084{
3085    PyTRY
3086        PyTypeObject *type;
3087    char *buf;
3088    int bufSize, dim;
3089    if (!PyArg_ParseTuple(args, "Os#i:__pickleLoaderCostMatrix", &type, &buf, &bufSize, &dim))
3090        return NULL;
3091
3092    TSymMatrix *cm = new TSymMatrix(dim);
3093    memcpy(cm->elements, buf, bufSize);
3094    return WrapNewOrange(cm, type);
3095    PyCATCH
3096}
3097
3098
3099PyObject *SymMatrix_getValues(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "(None -> list of values)")
3100{
3101    PyTRY
3102    CAST_TO(TSymMatrix, matrix)
3103
3104    PyObject* components_list = PyList_New(0);
3105
3106    int i,j;
3107    for (i = 0; i < matrix->dim; i++) {
3108        for (j = i+1; j < matrix->dim; j++) {
3109            double value = 0;
3110            if (matrix->matrixType == 0)
3111                value = matrix->getitem(j,i);
3112            else
3113                value = matrix->getitem(i,j);
3114
3115            PyObject *nel = Py_BuildValue("d", value);
3116            PyList_Append(components_list, nel);
3117            Py_DECREF(nel);
3118        }
3119    }
3120
3121    return components_list;
3122    PyCATCH
3123}
3124
3125PyObject *SymMatrix_getKNN(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "((i, K) -> list of values)")
3126{
3127    PyTRY
3128    CAST_TO(TSymMatrix, matrix)
3129
3130    int kNN;
3131    int i;
3132
3133    if (!PyArg_ParseTuple(args, "ii:SymMatrix.getKNN", &i, &kNN))
3134        return PYNULL;
3135
3136    vector<int> closest;
3137    matrix->getknn(i, kNN, closest);
3138
3139    PyObject* components_list = PyList_New(0);
3140
3141    for (i = 0; i < closest.size(); i++) {
3142        PyObject *nel = Py_BuildValue("i", closest[i]);
3143        PyList_Append(components_list, nel);
3144        Py_DECREF(nel);
3145    }
3146
3147    return components_list;
3148    PyCATCH
3149}
3150
3151PyObject *SymMatrix_avgLinkage(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Clusters -> SymMatrix)")
3152{
3153    PyTRY
3154    CAST_TO(TSymMatrix, matrix);
3155
3156    PyObject *clusters;
3157
3158    if (!PyArg_ParseTuple(args, "O:SymMatrix.avgLinkage", &clusters))
3159        return PYNULL;
3160
3161    int size = PyList_Size(clusters);
3162
3163    TSymMatrix *symmatrix = new TSymMatrix(size);
3164    PSymMatrix wsymmatrix = symmatrix;
3165
3166    symmatrix->matrixType = TSymMatrix::Symmetric;
3167
3168    int i,j,k,l;
3169    for (i = 0; i < size; i++)
3170    {
3171        for (j   = i; j < size; j++)
3172        {
3173            PyObject *cluster_i = PyList_GetItem(clusters, i);
3174            PyObject *cluster_j = PyList_GetItem(clusters, j);
3175            int size_i = PyList_Size(cluster_i);
3176            int size_j = PyList_Size(cluster_j);
3177            float sum = 0;
3178            for (k = 0; k < size_i; k++)
3179            {
3180                for (l = 0; l < size_j; l++)
3181                {
3182                    int item_k = PyInt_AsLong(PyList_GetItem(cluster_i, k));
3183                    int item_l = PyInt_AsLong(PyList_GetItem(cluster_j, l));
3184
3185                    if (item_k >= matrix->dim || item_l >= matrix->dim)
3186                        raiseError("index out of range");
3187
3188                    sum += matrix->getitem(item_k, item_l);
3189                }
3190            }
3191
3192            sum /= (size_i * size_j);
3193            symmatrix->getref(i, j) = sum;
3194        }
3195    }
3196
3197    PyObject *pysymmatrix = WrapOrange(wsymmatrix);
3198    return pysymmatrix;
3199
3200    PyCATCH
3201}
3202
3203PyObject *SymMatrix_invert(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Invert type -> None)")
3204{
3205    /* ******************
3206     * Types:
3207     * 0 - [-X]
3208     * 1 - [1 - X]
3209     * 2 - [max - X]
3210     * 3 - [1 / X]
3211     ********************/
3212    PyTRY
3213    int type;
3214
3215    if (!PyArg_ParseTuple(args, "i:SymMatrix.invert", &type))
3216        return NULL;
3217
3218    if (type < 0 || type > 3)
3219        PYERROR(PyExc_AttributeError, "only types 0 to 3  are supported", PYNULL);
3220
3221    CAST_TO(TSymMatrix, matrix);
3222    int i;
3223    float *e = matrix->elements;
3224    switch(type)
3225    {
3226        case 0:
3227            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3228                *e = 0 - *e;
3229            break;
3230
3231        case 1:
3232            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3233                *e = 1 - *e;
3234            break;
3235
3236        case 2:
3237            float maxval;
3238            maxval = 0;
3239
3240            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3241                if (*e > maxval)
3242                    maxval = *e;
3243
3244            e = matrix->elements;
3245            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3246                *e = maxval - *e;
3247
3248            break;
3249
3250        case 3:
3251            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3252                if (*e == 0)
3253                    raiseError("division by zero");
3254                *e = 1 / *e;
3255            break;
3256    }
3257
3258    RETURN_NONE;
3259    PyCATCH
3260}
3261
3262PyObject *SymMatrix_normalize(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Normalize type -> None)")
3263{
3264    /* ******************
3265     * Types:
3266     * 0 - [0, 1]
3267     * 1 - Sigmoid
3268     ********************/
3269    PyTRY
3270    int type;
3271
3272    if (!PyArg_ParseTuple(args, "i:SymMatrix.normalize", &type))
3273        return NULL;
3274
3275    if (type < 0 || type > 1)
3276        PYERROR(PyExc_AttributeError, "only types 0 and 1 are supported", PYNULL);
3277
3278    CAST_TO(TSymMatrix, matrix);
3279    int i;
3280    float *e = matrix->elements;
3281    float maxval = *e;
3282    float minval = *e;
3283    switch(type)
3284    {
3285        case 0:
3286            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++) {
3287                if (*e > maxval)
3288                    maxval = *e;
3289
3290                if (*e < minval)
3291                    minval = *e;
3292            }
3293            //cout << "minval: " << minval << endl;
3294            //cout << "maxval: " << maxval << endl;
3295
3296            e = matrix->elements;
3297            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3298                *e = (*e - minval) / (maxval - minval);
3299            break;
3300
3301        case 1:
3302            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3303                *e = 1 / (1 + exp(-(*e)));
3304            break;
3305    }
3306
3307    RETURN_NONE;
3308    PyCATCH
3309}
3310
3311PyObject *SymMatrix_get_items(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(List of items -> SymMatrix)")
3312{
3313    PyTRY
3314    CAST_TO(TSymMatrix, matrix);
3315
3316    PyObject *items;
3317
3318    if (!PyArg_ParseTuple(args, "O:SymMatrix.get_items", &items))
3319        return PYNULL;
3320
3321    int size = PyList_Size(items);
3322    PyList_Sort(items);
3323
3324    TSymMatrix *symmatrix = new TSymMatrix(size);
3325    PSymMatrix wsymmatrix = symmatrix;
3326
3327    symmatrix->matrixType = matrix->matrixType;
3328
3329    int i,j;
3330    for (i = 0; i < size; i++)
3331    {
3332        for (j = i; j < size; j++)
3333        {
3334            if (symmatrix->matrixType == TSymMatrix::Lower || symmatrix->matrixType == TSymMatrix::LowerFilled)
3335            {
3336                int item_i = PyInt_AsLong(PyList_GetItem(items, j));
3337                int item_j = PyInt_AsLong(PyList_GetItem(items, i));
3338
3339                float value = matrix->getitem(item_i, item_j);
3340                symmatrix->getref(j, i) = value;
3341            }
3342            else
3343            {
3344                int item_i = PyInt_AsLong(PyList_GetItem(items, i));
3345                int item_j = PyInt_AsLong(PyList_GetItem(items, j));
3346
3347                float value = matrix->getitem(item_i, item_j);
3348                symmatrix->getref(i, j) = value;
3349            }
3350        }
3351    }
3352
3353    PyObject *pysymmatrix = WrapOrange(wsymmatrix);
3354    return pysymmatrix;
3355    PyCATCH
3356}
3357
3358PyObject *SymMatrix_getitem_sq(PyObject *self, Py_ssize_t i)
3359{
3360    PyTRY
3361        CAST_TO(TSymMatrix, matrix)
3362        int dim = matrix->dim;
3363
3364    if (i >= matrix->dim) {
3365        PyErr_Format(PyExc_IndexError, "index %i out of range 0-%i", i, matrix->dim-1);
3366        return PYNULL;
3367    }
3368
3369    Py_ssize_t j;
3370    PyObject *row;
3371    switch (matrix->matrixType) {
3372            case TSymMatrix::Lower:
3373                row = PyTuple_New(i+1);
3374                for(j = 0; j<=i; j++)
3375                    PyTuple_SetItem(row, j, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3376                return row;
3377
3378            case TSymMatrix::Upper:
3379                row = PyTuple_New(matrix->dim - i);
3380                for(j = i; j<dim; j++)
3381                    PyTuple_SetItem(row, j-i, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3382                return row;
3383
3384            default:
3385                row = PyTuple_New(matrix->dim);
3386                for(j = 0; j<dim; j++)
3387                    PyTuple_SetItem(row, j, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3388                return row;
3389    }
3390    PyCATCH
3391}
3392
3393
3394
3395PyObject *SymMatrix_getitem(PyObject *self, PyObject *args)
3396{
3397    PyTRY
3398        CAST_TO(TSymMatrix, matrix)
3399
3400        if ((PyTuple_Check(args) && (PyTuple_Size(args) == 1)) || PyInt_Check(args)) {
3401            if (PyTuple_Check(args)) {
3402                args = PyTuple_GET_ITEM(args, 0);
3403                if (!PyInt_Check(args))
3404                    PYERROR(PyExc_IndexError, "integer index expected", PYNULL);
3405            }
3406
3407            return SymMatrix_getitem_sq(self, (int)PyInt_AsLong(args));
3408        }
3409
3410        else if (PyTuple_Size(args) == 2) {
3411            if (!PyInt_Check(PyTuple_GET_ITEM(args, 0)) || !PyInt_Check(PyTuple_GET_ITEM(args, 1)))
3412                PYERROR(PyExc_IndexError, "integer indices expected", PYNULL);
3413
3414            const int i = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
3415            const int j = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
3416            if ((j>i) && (matrix->matrixType == TSymMatrix::Lower))
3417                PYERROR(PyExc_IndexError, "index out of range for lower triangular matrix", PYNULL);
3418
3419            if ((j<i) && (matrix->matrixType == TSymMatrix::Upper))
3420                PYERROR(PyExc_IndexError, "index out of range for upper triangular matrix", PYNULL);
3421
3422            return PyFloat_FromDouble(matrix->getitem(i, j));
3423        }
3424
3425        PYERROR(PyExc_IndexError, "one or two integer indices expected", PYNULL);
3426        PyCATCH
3427}
3428
3429
3430int SymMatrix_setitem(PyObject *self, PyObject *args, PyObject *obj)
3431{
3432    PyTRY
3433        if (PyTuple_Size(args) == 1)
3434            PYERROR(PyExc_AttributeError, "cannot set entire matrix row", -1);
3435
3436    if (PyTuple_Size(args) != 2)
3437        PYERROR(PyExc_IndexError, "two integer indices expected", -1);
3438
3439    PyObject *pyfl = PyNumber_Float(obj);
3440    if (!pyfl)
3441        PYERROR(PyExc_TypeError, "invalid matrix elements; a number expected", -1);
3442    float f = PyFloat_AsDouble(pyfl);
3443    Py_DECREF(pyfl);
3444
3445    const int i = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
3446    const int j = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
3447
3448    SELF_AS(TSymMatrix).getref(i, j) = f;
3449    return 0;
3450    PyCATCH_1
3451}
3452
3453
3454PyObject *SymMatrix_getslice(PyObject *self, Py_ssize_t start, Py_ssize_t stop)
3455{
3456    PyTRY
3457        CAST_TO(TSymMatrix, matrix)
3458        const int dim = matrix->dim;
3459
3460    if (start>dim)
3461        start = dim;
3462    else if (start<0)
3463        start = 0;
3464
3465    if (stop>dim)
3466        stop=dim;
3467
3468    PyObject *res = PyTuple_New(stop - start);
3469    int i = 0;
3470    while(start<stop)
3471        PyTuple_SetItem(res, i++, SymMatrix_getitem_sq(self, start++));
3472
3473    return res;
3474    PyCATCH
3475}
3476
3477
3478PyObject *SymMatrix_str(PyObject *self)
3479{ PyTRY
3480CAST_TO(TSymMatrix, matrix)
3481const int dim = matrix->dim;
3482const int mattype = matrix->matrixType;
3483
3484float matmax = 0.0;
3485for(float *ei = matrix->elements, *ee = matrix->elements + ((dim*(dim+1))>>1); ei != ee; ei++) {
3486    const float tei = *ei<0 ? fabs(10.0 * *ei) : *ei;
3487    if (tei > matmax)
3488        matmax = tei;
3489}
3490
3491const int plac = 4 + (fabs(matmax) < 1 ? 1 : int(ceil(log10((double)matmax))));
3492const int elements = (matrix->matrixType == TSymMatrix::Lower) ? (dim*(dim+1))>>1 : dim * dim;
3493char *smatr = new char[3 * dim + (plac+2) * elements];
3494char *sptr = smatr;
3495*(sptr++) = '(';
3496*(sptr++) = '(';
3497
3498int i, j;
3499for(i = 0; i<dim; i++) {
3500    switch (mattype) {
3501                case TSymMatrix::Lower:
3502                    for(j = 0; j<i; j++, sptr += (plac+2))
3503                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3504                    break;
3505
3506                case TSymMatrix::Upper:
3507                    for(j = i * (plac+2); j--; *(sptr++) = ' ');
3508                    for(j = i; j < dim-1; j++, sptr += (plac+2))
3509                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3510                    break;
3511
3512                default:
3513                    for(j = 0; j<dim-1; j++, sptr += (plac+2))
3514                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3515    }
3516
3517    sprintf(sptr, "%*.3f)", plac, matrix->getitem(i, j));
3518    sptr += (plac+1);
3519
3520    if (i!=dim-1) {
3521        sprintf(sptr, ",\n (");
3522        sptr += 4;
3523    }
3524}
3525
3526sprintf(sptr, ")");
3527
3528PyObject *res = PyString_FromString(smatr);
3529mldelete smatr;
3530return res;
3531PyCATCH
3532}
3533
3534
3535PyObject *SymMatrix_repr(PyObject *self)
3536{ return SymMatrix_str(self); }
3537
3538
3539#include "hclust.hpp"
3540
3541C_NAMED(HierarchicalCluster, Orange, "()")
3542C_CALL3(HierarchicalClustering, HierarchicalClustering, Orange, "(linkage=)")
3543
3544PyObject *HierarchicalClustering_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(distance matrix) -> HierarchicalCluster")
3545{
3546    PyTRY
3547        NO_KEYWORDS
3548
3549        PSymMatrix symmatrix;
3550
3551    if (!PyArg_ParseTuple(args, "O&:HierarchicalClustering", cc_SymMatrix, &symmatrix))
3552        return NULL;
3553
3554    PHierarchicalCluster root = SELF_AS(THierarchicalClustering)(symmatrix);
3555
3556    if (symmatrix->myWrapper->orange_dict) {
3557        PyObject *objects = PyDict_GetItemString(symmatrix->myWrapper->orange_dict, "objects");
3558        TPyOrange *pymapping = root->mapping->myWrapper;
3559        if (objects && (objects != Py_None)) {
3560            if (!pymapping->orange_dict)
3561                pymapping->orange_dict = PyOrange_DictProxy_New(pymapping);
3562            PyDict_SetItemString(pymapping->orange_dict, "objects", objects);
3563        }
3564    }
3565    return WrapOrange(root);
3566    PyCATCH
3567}
3568
3569
3570Py_ssize_t HierarchicalCluster_len_sq(PyObject *self)
3571{
3572    CAST_TO_err(THierarchicalCluster, cluster, -1);
3573    return cluster->last - cluster->first;
3574}
3575
3576
3577PyObject *HierarchicalCluster_getitem_sq(PyObject *self, Py_ssize_t i)
3578{
3579    PyTRY
3580        CAST_TO(THierarchicalCluster, cluster);
3581
3582    if (!cluster->mapping)
3583        PYERROR(PyExc_SystemError, "'HierarchicalCluster' misses 'mapping'", PYNULL);
3584
3585    i += (i>=0) ? cluster->first : cluster->last;
3586    if ((i < cluster->first) || (i >= cluster->last)) {
3587        PyErr_Format(PyExc_IndexError, "index out of range 0-%i", cluster->last - cluster->first - 1);
3588        return PYNULL;
3589    }
3590
3591    if (i >= cluster->mapping->size())
3592        PYERROR(PyExc_SystemError, "internal inconsistency in instance of 'HierarchicalCluster' ('mapping' too short)", PYNULL);
3593
3594    const int elindex = cluster->mapping->at(i);
3595
3596    if (cluster->mapping->myWrapper->orange_dict) {
3597        PyObject *objs = PyDict_GetItemString(cluster->mapping->myWrapper->orange_dict, "objects");
3598        if (objs && (objs != Py_None))
3599            return PySequence_GetItem(objs, elindex);
3600    }
3601
3602    return PyInt_FromLong(elindex);
3603    PyCATCH
3604}
3605
3606
3607PyObject *HierarchicalCluster_get_left(PyObject *self)
3608{
3609    PyTRY
3610        CAST_TO(THierarchicalCluster, cluster);
3611
3612    if (!cluster->branches)
3613        RETURN_NONE
3614
3615        if (cluster->branches->size() > 2)
3616            PYERROR(PyExc_AttributeError, "'left' not defined (cluster has more than two subclusters)", PYNULL);
3617
3618    return WrapOrange(cluster->branches->front());
3619    PyCATCH
3620}
3621
3622
3623PyObject *HierarchicalCluster_get_right(PyObject *self)
3624{
3625    PyTRY
3626        CAST_TO(THierarchicalCluster, cluster);
3627
3628    if (!cluster->branches || (cluster->branches->size() < 2))
3629        RETURN_NONE;
3630
3631    if (cluster->branches->size() > 2)
3632        PYERROR(PyExc_AttributeError, "'right' not defined (cluster has more than two subclusters", PYNULL);
3633
3634    return WrapOrange(cluster->branches->back());
3635    PyCATCH
3636}
3637
3638
3639int HierarchicalClusterLowSet(PyObject *self, PyObject *arg, const int side)
3640{
3641    PyTRY
3642        static const char *sides[2] = {"left", "right"};
3643
3644    if (!PyOrHierarchicalCluster_Check(arg)) {
3645        PyErr_Format(PyExc_TypeError, "'HierarchicalCluster.%s' should be of type 'HierarchicalCluster' (got '%s')", sides[side], arg->ob_type->tp_name);
3646        return -1;
3647    }
3648
3649    CAST_TO_err(THierarchicalCluster, cluster, -1);
3650
3651    if (!cluster->branches)
3652        cluster->branches = mlnew THierarchicalClusterList(2);
3653    else
3654        if (cluster->branches->size() != 2)
3655            PYERROR(PyExc_AttributeError, "'left' not defined (cluster does not have (exactly) two subclusters)", -1);
3656
3657    cluster->branches->at(side) = PyOrange_AsHierarchicalCluster(arg);
3658    return 0;
3659    PyCATCH_1
3660}
3661
3662
3663int HierarchicalCluster_set_left(PyObject *self, PyObject *arg)
3664{
3665    return HierarchicalClusterLowSet(self, arg, 0);
3666}
3667
3668int HierarchicalCluster_set_right(PyObject *self, PyObject *arg)
3669{
3670    return HierarchicalClusterLowSet(self, arg, 1);
3671}
3672
3673
3674PyObject *HierarchicalCluster_swap(PyObject *self, PyObject *arg, PyObject *keyw) PYARGS(METH_NOARGS, "() -> None; swaps the sub clusters")
3675{
3676    PyTRY
3677        SELF_AS(THierarchicalCluster).swap();
3678    RETURN_NONE;
3679    PyCATCH
3680}
3681
3682PyObject *HierarchicalCluster_permute(PyObject *self, PyObject *arg, PyObject *keys) PYARGS(METH_O, "(permutation) -> None")
3683{
3684    PyTRY
3685        PIntList ilist = ListOfUnwrappedMethods<PIntList, TIntList, int>::P_FromArguments(arg);
3686    if (!ilist)
3687        return PYNULL;
3688
3689    SELF_AS(THierarchicalCluster).permute(ilist.getReference());
3690    RETURN_NONE;
3691    PyCATCH
3692}
3693
3694
3695PHierarchicalClusterList PHierarchicalClusterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::P_FromArguments(arg); }
3696PyObject *HierarchicalClusterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_FromArguments(type, arg); }
3697PyObject *HierarchicalClusterList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of HierarchicalCluster>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_new(type, arg, kwds); }
3698PyObject *HierarchicalClusterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_getitem(self, index); }
3699int       HierarchicalClusterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_setitem(self, index, item); }
3700PyObject *HierarchicalClusterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_getslice(self, start, stop); }
3701int       HierarchicalClusterList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_setslice(self, start, stop, item); }
3702Py_ssize_t       HierarchicalClusterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_len(self); }
3703PyObject *HierarchicalClusterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_richcmp(self, object, op); }
3704PyObject *HierarchicalClusterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_concat(self, obj); }
3705PyObject *HierarchicalClusterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_repeat(self, times); }
3706PyObject *HierarchicalClusterList_str(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_str(self); }
3707PyObject *HierarchicalClusterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_str(self); }
3708int       HierarchicalClusterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_contains(self, obj); }
3709PyObject *HierarchicalClusterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(HierarchicalCluster) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_append(self, item); }
3710PyObject *HierarchicalClusterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_extend(self, obj); }
3711PyObject *HierarchicalClusterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> int") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_count(self, obj); }
3712PyObject *HierarchicalClusterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> HierarchicalClusterList") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_filter(self, args); }
3713PyObject *HierarchicalClusterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> int") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_index(self, obj); }
3714PyObject *HierarchicalClusterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_insert(self, args); }
3715PyObject *HierarchicalClusterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_native(self); }
3716PyObject *HierarchicalClusterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> HierarchicalCluster") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_pop(self, args); }
3717PyObject *HierarchicalClusterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_remove(self, obj); }
3718PyObject *HierarchicalClusterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_reverse(self); }
3719PyObject *HierarchicalClusterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_sort(self, args); }
3720PyObject *HierarchicalClusterList__reduce__(TPyOrange *self, PyObject *) PYARGS(METH_VARARGS, "()") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_reduce(self); }
3721
3722
3723
3724
3725#include "distancemap.hpp"
3726
3727C_NAMED(DistanceMapConstructor, Orange, "(distanceMatrix=, order=)")
3728
3729
3730
3731PyObject *DistanceMapConstructor_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(squeeze) -> DistanceMap")
3732{
3733    PyTRY
3734        NO_KEYWORDS
3735
3736        float squeeze = 1.0;
3737    if (!PyArg_ParseTuple(args, "|f:DistanceMapConstructor.__call__", &squeeze))
3738        return NULL;
3739
3740    float absLow, absHigh;
3741    PDistanceMap dm = SELF_AS(TDistanceMapConstructor).call(squeeze, absLow, absHigh);
3742    return Py_BuildValue("Nff", WrapOrange(dm), absLow, absHigh);
3743    PyCATCH
3744}
3745
3746
3747PyObject *DistanceMapConstructor_getLegend(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(width, height, gamma) -> bitmap")
3748{
3749    PyTRY
3750        int width, height;
3751    float gamma;
3752    if (!PyArg_ParseTuple(args, "iif:DistanceMapConstructor.getLegend", &width, &height, &gamma))
3753        return NULL;
3754
3755    long size;
3756    unsigned char *bitmap = SELF_AS(TDistanceMapConstructor).getLegend(width, height, gamma, size);
3757    PyObject *res = PyString_FromStringAndSize((const char *)bitmap, (Py_ssize_t)size);
3758    delete bitmap;
3759    return res;
3760    PyCATCH
3761}
3762
3763
3764BASED_ON(DistanceMap, Orange)
3765
3766PyObject *DistanceMap__reduce__(PyObject *self)
3767{
3768    PyTRY
3769        CAST_TO(TDistanceMap, matrix);
3770    const int dim = matrix->dim;
3771    return Py_BuildValue("O(Os#iO)N", getExportedFunction("__pickleLoaderDistanceMap"),
3772        self->ob_type,
3773        matrix->cells, dim*dim*sizeof(float),
3774        dim,
3775        WrapOrange(matrix->elementIndices),
3776        packOrangeDictionary(self));
3777    PyCATCH
3778}
3779
3780
3781PyObject *__pickleLoaderDistanceMap(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension, elementIndices)")
3782{
3783    PyTRY
3784        PyTypeObject *type;
3785    char *buf;
3786    int bufSize, dim;
3787    PIntList elementIndices;
3788    if (!PyArg_ParseTuple(args, "Os#iO&:__pickleLoaderDistanceMap", &type, &buf, &bufSize, &dim, ccn_IntList, &elementIndices))
3789        return NULL;
3790
3791    TDistanceMap *cm = new TDistanceMap(dim);
3792    memcpy(cm->cells, buf, bufSize);
3793    cm->elementIndices = elementIndices;
3794    return WrapNewOrange(cm, type);
3795    PyCATCH
3796}
3797
3798
3799PyObject *DistanceMap_getBitmap(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "(cell_width, cell_height, lowerBound, upperBound, gamma) -> bitmap")
3800{
3801    PyTRY
3802        int cellWidth, cellHeight;
3803    float absLow, absHigh, gamma;
3804    int grid = 1;
3805    int matrixType = 2;
3806    if (!PyArg_ParseTuple(args, "iifff|ii:Heatmap.getBitmap", &cellWidth, &cellHeight, &absLow, &absHigh, &gamma, &grid, &matrixType))
3807        return NULL;
3808
3809    CAST_TO(TDistanceMap, dm)
3810
3811        long size;
3812    unsigned char *bitmap = dm->distanceMap2string(cellWidth, cellHeight, absLow, absHigh, gamma, grid!=0, matrixType, size);
3813    PyObject *res = Py_BuildValue("s#ii", (const char *)bitmap, size, cellWidth * dm->dim, cellHeight * dm->dim);
3814    delete bitmap;
3815    return res;
3816    PyCATCH
3817}
3818
3819
3820PyObject *DistanceMap_getCellIntensity(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(row, column) -> float")
3821{
3822    PyTRY
3823        int row, column;
3824    if (!PyArg_ParseTuple(args, "ii:DistanceMap.getCellIntensity", &row, &column))
3825        return NULL;
3826
3827    const float ci = SELF_AS(TDistanceMap).getCellIntensity(row, column);
3828    if (ci == ILLEGAL_FLOAT)
3829        RETURN_NONE;
3830
3831    return PyFloat_FromDouble(ci);
3832    PyCATCH
3833}
3834
3835
3836PyObject *DistanceMap_getPercentileInterval(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(lower_percentile, upper_percentile) -> (min, max)")
3837{
3838    PyTRY
3839        float lowperc, highperc;
3840    if (!PyArg_ParseTuple(args, "ff:DistanceMap_percentileInterval", &lowperc, &highperc))
3841        return PYNULL;
3842
3843    float minv, maxv;
3844    SELF_AS(TDistanceMap).getPercentileInterval(lowperc, highperc, minv, maxv);
3845    return Py_BuildValue("ff", minv, maxv);
3846    PyCATCH
3847}
3848
3849
3850
3851#include "graph.hpp"
3852
3853extern PyTypeObject PyEdge_Type;
3854
3855/* If objectsOnEdges==true, this is a proxy object; double's are actualy PyObject *,
3856but the references are owned by the graph. */
3857class TPyEdge {
3858public:
3859    PyObject_HEAD
3860
3861        PGraph graph;
3862    int v1, v2;
3863    double *weights;
3864    bool objectsOnEdges;
3865    int weightsVersion;
3866
3867    inline double *getWeights()
3868    {
3869        if (weightsVersion != (weights ? graph->lastAddition : graph->lastRemoval)) {
3870            weights = graph->getEdge(v1, v2);
3871            weightsVersion = graph->currentVersion;
3872        }
3873        return weights;
3874    }
3875};
3876
3877
3878#define DOUBLE_AS_PYOBJECT(x) (*(PyObject **)(void *)(&(x)))
3879PyObject *PyEdge_Getitem(TPyEdge *self, Py_ssize_t ind)
3880{
3881    PyTRY
3882        if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3883            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", ind, self->graph->nEdgeTypes);
3884            return PYNULL;
3885        }
3886
3887        if (self->getWeights()) {
3888            const double w = self->weights[ind];
3889
3890            if (!CONNECTED(w))
3891                RETURN_NONE;
3892
3893            if (self->objectsOnEdges) {
3894                Py_INCREF(DOUBLE_AS_PYOBJECT(w));
3895                return DOUBLE_AS_PYOBJECT(w);
3896            }
3897            else
3898                return PyFloat_FromDouble(w);
3899        }
3900
3901        else
3902            RETURN_NONE;
3903        PyCATCH
3904}
3905
3906
3907int PyEdge_Contains(TPyEdge *self, PyObject *pyind)
3908{
3909    PyTRY
3910        if (!PyInt_Check(pyind))
3911            PYERROR(PyExc_IndexError, "edge types must be integers", -1);
3912
3913    int ind = int(PyInt_AsLong(pyind));
3914    if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3915        PyErr_Format(PyExc_IndexError, "edge type %i out of range (0-%i)", ind, self->graph->nEdgeTypes);
3916        return -1;
3917    }
3918
3919    return self->getWeights() && CONNECTED(self->weights[ind]) ? 1 : 0;
3920    PyCATCH_1
3921}
3922
3923
3924int PyEdge_Setitem(TPyEdge *self, Py_ssize_t ind, PyObject *item)
3925{
3926    PyTRY
3927        if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3928            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", ind, self->graph->nEdgeTypes);
3929            return -1;
3930        }
3931
3932        double w;
3933        bool noConnection = !item || (item == Py_None);
3934        if (noConnection)
3935            DISCONNECT(w);
3936        else {
3937            if (!self->objectsOnEdges && !PyNumber_ToDouble(item, w))
3938                PYERROR(PyExc_TypeError, "a number expected for edge weight", -1);
3939        }
3940
3941
3942        if (self->getWeights()) {
3943            if (self->objectsOnEdges) {
3944                // watch the order: first INCREF, then DECREF!
3945                if (!noConnection)
3946                    Py_INCREF(item);
3947                if (CONNECTED(self->weights[ind]))
3948                    Py_DECREF(DOUBLE_AS_PYOBJECT(self->weights[ind]));
3949
3950                DOUBLE_AS_PYOBJECT(self->weights[ind]) = item;
3951            }
3952
3953            else
3954                self->weights[ind] = w;
3955
3956            if (noConnection) {
3957                double *w, *we;
3958                for(w = self->weights, we = self->weights + self->graph->nEdgeTypes; (w != we) && !CONNECTED(*w); w++);
3959                if (w == we) {
3960                    self->graph->removeEdge(self->v1, self->v2);
3961                    self->weights = NULL;
3962                    self->weightsVersion = self->graph->currentVersion;
3963                }
3964            }
3965        }
3966
3967        else {
3968            if (!noConnection) {
3969                double *weights = self->weights = self->graph->getOrCreateEdge(self->v1, self->v2);
3970
3971                if (self->objectsOnEdges) {
3972                    DOUBLE_AS_PYOBJECT(weights[ind]) = item;
3973                    Py_INCREF(item);
3974                }
3975                else
3976                    weights[ind] = w;
3977
3978                self->weightsVersion = self->graph->currentVersion;
3979            }
3980        }
3981
3982        return 0;
3983        PyCATCH_1
3984}
3985
3986
3987/*
3988// I've programmed this by mistake; but it's nice, so let it stay
3989// for the case we need it :)
3990PyObject *PyEdge_Str(TPyEdge *self)
3991{
3992PyTRY
3993int nEdgeTypes = self->graph->nEdgeTypes;
3994
3995if (!self->getWeights()) {
3996if (nEdgeTypes == 1)
3997RETURN_NONE;
3998else {
3999PyObject *res = PyTuple_New(nEdgeTypes);
4000while(nEdgeTypes--) {
4001Py_INCREF(Py_None);
4002PyTuple_SET_ITEM(res, nEdgeTypes, Py_None);
4003}
4004return res;
4005}
4006}
4007
4008if (nEdgeTypes == 1)
4009return PyFloat_FromDouble(*self->weights);
4010else {
4011PyObject *res = PyTuple_New(nEdgeTypes);
4012int i = 0;
4013for(double weights = self->weights; i != nEdgeTypes; weights++, i++)
4014PyTuple_SET_ITEM(res, i, PyFloat_FromDouble(*weights));
4015return res;
4016}
4017PyCATCH
4018}
4019*/
4020
4021PyObject *PyEdge_Str(TPyEdge *self)
4022{
4023    PyTRY
4024        int nEdgeTypes = self->graph->nEdgeTypes;
4025    char *buf;
4026
4027    if (!self->getWeights()) {
4028        if (nEdgeTypes == 1)
4029            return PyString_FromString("None");
4030        else {
4031            buf = new char[nEdgeTypes*6 + 2];
4032            char *b2 = buf;
4033            *b2++ = '(';
4034            while(nEdgeTypes--) {
4035                strcpy(b2, "None, ");
4036                b2 += 6;
4037            }
4038            b2[-1] = 0;
4039            b2[-2] = ')';
4040        }
4041    }
4042
4043    else {
4044        if (self->objectsOnEdges) {
4045            if (nEdgeTypes == 1)
4046                return PyObject_Str(DOUBLE_AS_PYOBJECT(*self->weights));
4047            else {
4048                PyObject *dump = PyString_FromString("(");
4049                PyString_ConcatAndDel(&dump, PyObject_Str(DOUBLE_AS_PYOBJECT(*self->weights)));
4050
4051                for(double *wi = self->weights+1, *we = self->weights + self->graph->nEdgeTypes; wi != we; wi++) {
4052                    PyString_ConcatAndDel(&dump, PyString_FromString(", "));
4053                    PyString_ConcatAndDel(&dump, PyObject_Str(DOUBLE_AS_PYOBJECT(*wi)));
4054                }
4055
4056                PyString_ConcatAndDel(&dump, PyString_FromString(")"));
4057                return dump;
4058            }
4059        }
4060        else {
4061            if (nEdgeTypes == 1) {
4062                buf = new char[20];
4063                char *b2 = buf;
4064                sprintf(b2, "%-10g", *self->weights);
4065                for(; *b2 > 32; b2++);
4066                *b2 = 0;
4067            }
4068            else {
4069                buf = new char[nEdgeTypes*20];
4070                char *b2 = buf;
4071                *b2++ = '(';
4072                for(double *weights = self->weights, *wee = weights + nEdgeTypes; weights != wee; weights++) {
4073                    if (CONNECTED(*weights)) {
4074                        sprintf(b2, "%-10g", *weights);
4075                        for(; *b2 > 32; b2++);
4076                        *b2++ = ',';
4077                        *b2++ = ' ';
4078                    }
4079                    else {
4080                        strcpy(b2, "None, ");
4081                        b2 += 6;
4082                    }
4083                }
4084                b2[-1] = 0;
4085                b2[-2] = ')';
4086            }
4087        }
4088    }
4089
4090    PyObject *res = PyString_FromString(buf);
4091    delete buf;
4092    return res;
4093    PyCATCH
4094}
4095
4096Py_ssize_t PyEdge_Len(TPyEdge *self)
4097{ return self->graph->nEdgeTypes; }
4098
4099
4100int PyEdge_Nonzero(TPyEdge *self)
4101{ return self->getWeights() ? 1 : 0; }
4102
4103
4104int PyEdge_Traverse(TPyEdge *self, visitproc visit, void *arg)
4105{ PVISIT(self->graph)
4106return 0;
4107}
4108
4109
4110int PyEdge_Clear(TPyEdge *self)
4111{ self->graph = POrange();
4112return 0;
4113}
4114
4115
4116void PyEdge_Dealloc(TPyEdge *self)
4117{
4118    self->graph.~PGraph();
4119    self->ob_type->tp_free((PyObject *)self);
4120}
4121
4122
4123PyObject *PyEdge_Richcmp(TPyEdge *self, PyObject *j, int op)
4124{
4125    double ref;
4126    if (self->graph->nEdgeTypes != 1)
4127        PYERROR(PyExc_TypeError, "multiple-type edges cannot be compared", PYNULL);
4128
4129    if (self->graph->nEdgeTypes != 1)
4130        PYERROR(PyExc_TypeError, "multiple-type edges cannot be compared to floats", PYNULL);
4131
4132    if (!self->getWeights() || !CONNECTED(*self->weights))
4133        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4134
4135    if (self->objectsOnEdges)
4136        return PyObject_RichCompare(DOUBLE_AS_PYOBJECT(*self->weights), j, op);
4137
4138    if (!PyNumber_ToDouble(j, ref))
4139        PYERROR(PyExc_TypeError, "edge weights can only be compared to floats", PYNULL);
4140
4141    const double &f = *self->weights;
4142
4143    int cmp;
4144    switch (op) {
4145case Py_LT: cmp = (f<ref); break;
4146case Py_LE: cmp = (f<=ref); break;
4147case Py_EQ: cmp = (f==ref); break;
4148case Py_NE: cmp = (f!=ref); break;
4149case Py_GT: cmp = (f>ref); break;
4150case Py_GE: cmp = (f>=ref); break;
4151default:
4152    Py_INCREF(Py_NotImplemented);
4153    return Py_NotImplemented;
4154    }
4155
4156    PyObject *res;
4157    if (cmp)
4158        res = Py_True;
4159    else
4160        res = Py_False;
4161    Py_INCREF(res);
4162    return res;
4163}
4164
4165
4166PyObject *PyEdge_Float(TPyEdge *self)
4167{
4168    if (self->graph->nEdgeTypes != 1)
4169        PYERROR(PyExc_TypeError, "multiple-type edges cannot be cast to floats", PYNULL);
4170
4171    if (!self->getWeights() || !CONNECTED(*self->weights))
4172        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4173
4174    return self->objectsOnEdges ? PyNumber_Float(DOUBLE_AS_PYOBJECT(*self->weights)) : PyFloat_FromDouble(*self->weights);
4175}
4176
4177PyObject *PyEdge_Int(TPyEdge *self)
4178{
4179    if (self->graph->nEdgeTypes != 1)
4180        PYERROR(PyExc_TypeError, "multiple-type edges cannot be cast to numbers", PYNULL);
4181
4182    if (!self->getWeights() || !CONNECTED(*self->weights))
4183        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4184
4185    return self->objectsOnEdges ? PyNumber_Int(DOUBLE_AS_PYOBJECT(*self->weights)) : PyInt_FromLong(long(*self->weights));
4186}
4187
4188
4189PyNumberMethods PyEdge_as_number = {
4190    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4191    (inquiry)PyEdge_Nonzero,                           /* nb_nonzero */
4192    0, 0, 0, 0, 0, 0, 0,
4193    (unaryfunc)PyEdge_Int,    /* nb_int */
4194    0,
4195    (unaryfunc)PyEdge_Float,  /* nb_float */
4196    0, 0,
4197};
4198
4199static PySequenceMethods PyEdge_as_sequence = {
4200    (inquiry)PyEdge_Len,                    /* sq_length */
4201    0,                  /* sq_concat */
4202    0,                  /* sq_repeat */
4203    (intargfunc)PyEdge_Getitem,                 /* sq_item */
4204    0,                  /* sq_slice */
4205    (intobjargproc)PyEdge_Setitem,                  /* sq_ass_item */
4206    0,                  /* sq_ass_slice */
4207    (objobjproc)PyEdge_Contains,        /* sq_contains */
4208    0,                  /* sq_inplace_concat */
4209    0,                  /* sq_inplace_repeat */
4210};
4211
4212PyTypeObject PyEdge_Type = {
4213    PyObject_HEAD_INIT(&PyType_Type)
4214    0,                  /* ob_size */
4215    "Graph.Edge",           /* tp_name */
4216    sizeof(TPyEdge),            /* tp_basicsize */
4217    0,                  /* tp_itemsize */
4218    /* methods */
4219    (destructor)PyEdge_Dealloc,         /* tp_dealloc */
4220    0,                  /* tp_print */
4221    0,                  /* tp_getattr */
4222    0,                  /* tp_setattr */
4223    0,                  /* tp_compare */
4224    (reprfunc)PyEdge_Str,                   /* tp_repr */
4225    &PyEdge_as_number,                  /* tp_as_number */
4226    &PyEdge_as_sequence,                    /* tp_as_sequence */
4227    0,                  /* tp_as_mapping */
4228    0,                  /* tp_hash */
4229    0,                  /* tp_call */
4230    (reprfunc)PyEdge_Str,                   /* tp_str */
4231    0,      /* tp_getattro */
4232    0,                  /* tp_setattro */
4233    0,                  /* tp_as_buffer */
4234    Py_TPFLAGS_DEFAULT,         /* tp_flags */
4235    0,                  /* tp_doc */
4236    (traverseproc)PyEdge_Traverse,                  /* tp_traverse */
4237    (inquiry)PyEdge_Clear,                  /* tp_clear */
4238    (richcmpfunc)PyEdge_Richcmp,                    /* tp_richcompare */
4239    0,                  /* tp_weaklistoffset */
4240    0,          /* tp_iter */
4241    0,  /* tp_iternext */
4242    0,                  /* tp_methods */
4243    0,                  /* tp_members */
4244    0,                  /* tp_getset */
4245    0,                  /* tp_base */
4246    0,                  /* tp_dict */
4247    0,                  /* tp_descr_get */
4248    0,                  /* tp_descr_set */
4249    0,                  /* tp_dictoffset */
4250    0,                             /* tp_init */
4251    PyType_GenericAlloc,                               /* tp_alloc */
4252    0,                               /* tp_new */
4253    _PyObject_GC_Del,                                  /* tp_free */
4254};
4255
4256
4257PYXTRACT_IGNORE int Orange_traverse(TPyOrange *self, visitproc visit, void *arg);
4258PYXTRACT_IGNORE int Orange_clear(TPyOrange *self);
4259PYXTRACT_IGNORE void Orange_dealloc(TPyOrange *self);
4260
4261
4262inline bool hasObjectsOnEdges(PyObject *graph)
4263{
4264    PyObject *dict = ((TPyOrange *)graph)->orange_dict;
4265    PyObject *ooe = NULL;
4266    if (dict) {
4267        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4268        if (!ooe) {
4269            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4270        }
4271    }
4272    return ooe && (PyObject_IsTrue(ooe) != 0);
4273}
4274
4275inline bool hasObjectsOnEdges(PGraph graph)
4276{
4277    PyObject *dict = graph->myWrapper->orange_dict;
4278    PyObject *ooe = NULL;
4279    if (dict) {
4280        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4281        if (!ooe) {
4282            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4283        }
4284    }
4285    return ooe && (PyObject_IsTrue(ooe) != 0);
4286}
4287
4288inline bool hasObjectsOnEdges(const TGraph *graph)
4289{
4290    PyObject *dict = graph->myWrapper->orange_dict;
4291    PyObject *ooe = NULL;
4292    if (dict) {
4293        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4294        if (!ooe) {
4295            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4296        }
4297    }
4298    return ooe && (PyObject_IsTrue(ooe) != 0);
4299}
4300
4301void decrefEdge(double *weights, const int &nEdgeTypes)
4302{
4303    if (weights)
4304        for(double *we = weights, *wee = weights + nEdgeTypes; we != wee; we++)
4305            if (CONNECTED(*we))
4306                Py_DECREF(DOUBLE_AS_PYOBJECT(*we));
4307}
4308
4309PyObject *PyEdge_New(PGraph graph, const int &v1, const int &v2, double *weights)
4310{
4311    TPyEdge *self = PyObject_GC_New(TPyEdge, &PyEdge_Type);
4312    if (self == NULL)
4313        return NULL;
4314
4315    // The object constructor has never been called, so we must initialize it
4316    // before assigning to it
4317    self->graph.init();
4318
4319    self->graph = graph;
4320    self->v1 = v1;
4321    self->v2 = v2;
4322    self->weights = weights;
4323    self->objectsOnEdges = hasObjectsOnEdges(graph);
4324
4325    PyObject_GC_Track(self);
4326    return (PyObject *)self;
4327}
4328
4329
4330ABSTRACT(Graph, Orange)
4331RECOGNIZED_ATTRIBUTES(Graph, "objects forceMapping force_mapping returnIndices return_indices objectsOnEdges object_on_edges")
4332
4333int Graph_getindex(TGraph *graph, PyObject *index)
4334{
4335    if (PyInt_Check(index)) {
4336        if (!graph->myWrapper->orange_dict)
4337            return PyInt_AsLong(index);
4338        PyObject *fmap = PyDict_GetItemString(graph->myWrapper->orange_dict, "force_mapping");
4339        if (!fmap) {
4340            fmap = PyDict_GetItemString(graph->myWrapper->orange_dict, "forceMapping");
4341        }
4342        if (!fmap || PyObject_IsTrue(fmap))
4343            return PyInt_AsLong(index);
4344    }
4345
4346    if (graph->myWrapper->orange_dict) {
4347        PyObject *objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "objects");
4348        if (objs && (objs != Py_None)) {
4349
4350            if (PyDict_Check(objs)) {
4351                PyObject *pyidx = PyDict_GetItem(objs, index);
4352                if (!pyidx)
4353                    return -1;
4354                if (!PyInt_Check(pyidx))
4355                    PYERROR(PyExc_IndexError, "vertex index should be an integer", -1);
4356                return PyInt_AsLong(pyidx);
4357            }
4358
4359            PyObject *iter = PyObject_GetIter(objs);
4360            if (!iter)
4361                PYERROR(PyExc_IndexError, "Graph.object should be iterable", -1);
4362            int i = 0;
4363
4364            for(PyObject *item = PyIter_Next(iter); item; item = PyIter_Next(iter), i++) {
4365                int cmp = PyObject_Compare(item, index);
4366                Py_DECREF(item);
4367                if (PyErr_Occurred())
4368                    return -1;
4369                if (!cmp) {
4370                    Py_DECREF(iter);
4371                    return i;
4372                }
4373            }
4374
4375            Py_DECREF(iter);
4376            PYERROR(PyExc_IndexError, "index not found", -1);
4377        }
4378    }
4379
4380    PYERROR(PyExc_IndexError, "invalid index type: should be integer (or 'objects' must be specified)", -1);
4381}
4382
4383
4384PyObject *Graph_nodesToObjects(TGraph *graph, const vector<int> &neighbours)
4385{
4386    if (graph->myWrapper->orange_dict) {
4387        PyObject *objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "returnIndices");
4388        if (!objs || (PyObject_IsTrue(objs) == 0)) {
4389            objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "objects");
4390            if (objs && (objs != Py_None)) {
4391                PyObject *res = PyList_New(neighbours.size());
4392
4393                if (PyDict_Check(objs)) {
4394                    // This is slow, but can't help...
4395                    int el = 0;
4396                    PyObject *key, *value;
4397                    Py_ssize_t pos = 0;
4398
4399                    while (PyDict_Next(objs, &pos, &key, &value))
4400                        if (!PyInt_Check(value)) {
4401                            Py_DECREF(res);
4402                            PYERROR(PyExc_IndexError, "values in Graph.objects dictionary should be integers", PYNULL);
4403                        }
4404
4405                        for(vector<int>::const_iterator ni(neighbours.begin()), ne(neighbours.end()); ni!=ne; ni++, el++) {
4406                            pos = 0;
4407                            bool set = false;
4408                            while (PyDict_Next(objs, &pos, &key, &value) && !set) {
4409                                if (PyInt_AsLong(value) == *ni) {
4410                                    Py_INCREF(key);
4411                                    PyList_SetItem(res, el, key);
4412                                    set = true;
4413                                }
4414                            }
4415
4416                            if (!set) {
4417                                Py_DECREF(res);
4418                                PyErr_Format(PyExc_IndexError, "'objects' miss the key for vertex %i", *ni);
4419                                return PYNULL;
4420                            }
4421                        }
4422                }
4423                else {
4424                    Py_ssize_t el = 0;
4425                    for(vector<int>::const_iterator ni(neighbours.begin()), ne(neighbours.end()); ni!=ne; ni++, el++) {
4426                        PyObject *pyel = PySequence_GetItem(objs, *ni);
4427                        if (!pyel) {
4428                            Py_DECREF(res);
4429                            return PYNULL;
4430                        }
4431                        else
4432                            PyList_SetItem(res, el, pyel);
4433                    }
4434                }
4435                return res;
4436            }
4437        }
4438    }
4439
4440    return convertToPython(neighbours);
4441}
4442
4443
4444PyObject *Graph_getitem(PyObject *self, PyObject *args)
4445{
4446    PyTRY
4447        CAST_TO(TGraph, graph);
4448
4449    PyObject *py1, *py2;
4450    int v1, v2, type = -1;
4451
4452    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4453        || ((v1 = Graph_getindex(graph, py1)) < 0)
4454        || ((v2 = Graph_getindex(graph, py2)) < 0))
4455        return PYNULL;
4456
4457    if (PyTuple_Size(args) == 2) {
4458        PGraph graph = PyOrange_AS_Orange(self);
4459        return PyEdge_New(graph, v1, v2, graph->getEdge(v1, v2));
4460    }
4461
4462    else {
4463        PGraph graph = PyOrange_AS_Orange(self);
4464        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4465            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", type, graph->nEdgeTypes);
4466            return PYNULL;
4467        }
4468        double *weights = graph->getEdge(v1, v2);
4469        if (!weights || !CONNECTED(weights[type]))
4470            RETURN_NONE
4471        else {
4472            if (hasObjectsOnEdges(graph)) {
4473                PyObject *res = DOUBLE_AS_PYOBJECT(weights[type]);
4474                Py_INCREF(res);
4475                return res;
4476            }
4477            else
4478                return PyFloat_FromDouble(weights[type]);
4479        }
4480    }
4481    PyCATCH
4482}
4483
4484
4485PyObject *Graph_edgeExists(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(v1, v2[, type])")
4486{
4487    PyTRY
4488        CAST_TO(TGraph, graph);
4489
4490    PyObject *py1, *py2;
4491    int v1, v2, type = -1;
4492
4493    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4494        || ((v1 = Graph_getindex(graph, py1)) < 0)
4495        || ((v2 = Graph_getindex(graph, py2)) < 0))
4496        return PYNULL;
4497
4498    if (PyTuple_Size(args) == 2)
4499        return PyInt_FromLong(graph->getEdge(v1, v2) ? 1 : 0);
4500
4501    else {
4502        PGraph graph = PyOrange_AS_Orange(self);
4503        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4504            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", type, graph->nEdgeTypes);
4505            return PYNULL;
4506        }
4507        double *weights = graph->getEdge(v1, v2);
4508        return PyInt_FromLong(!weights || !CONNECTED(weights[type]) ? 0 : 1);
4509    }
4510    PyCATCH
4511}
4512
4513int Graph_setitem(PyObject *self, PyObject *args, PyObject *item)
4514{
4515    PyTRY
4516        CAST_TO_err(TGraph, graph, -1);
4517    bool objectsOnEdges = hasObjectsOnEdges(graph);
4518
4519    PyObject *py1, *py2;
4520    int v1, v2, type = -1;
4521
4522    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4523        || ((v1 = Graph_getindex(graph, py1)) < 0)
4524        || ((v2 = Graph_getindex(graph, py2)) < 0))
4525        return -1;
4526
4527    if (PyTuple_Size(args) == 3) {
4528        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4529            PyErr_Format(PyExc_IndexError, "type %i out of range (0-%i)", type, graph->nEdgeTypes);
4530            return -1;
4531        }
4532
4533        double w;
4534
4535        bool noConnection = !item || (item == Py_None);
4536
4537        if (noConnection)
4538            DISCONNECT(w);
4539        else
4540            if (!objectsOnEdges && !PyNumber_ToDouble(item, w))
4541                PYERROR(PyExc_TypeError, "a number expected for edge weight", -1);
4542
4543        // we call getOrCreateEdge only after we check all arguments, so we don't end up
4544        // with a half-created edge
4545        double *weights = graph->getOrCreateEdge(v1, v2);
4546
4547        if (objectsOnEdges) {
4548            if (!noConnection)
4549                Py_INCREF(item);
4550            if (CONNECTED(weights[type]))
4551                Py_DECREF(DOUBLE_AS_PYOBJECT(weights[type]));
4552
4553            DOUBLE_AS_PYOBJECT(weights[type]) = item;
4554        }
4555        else {
4556            weights[type] = w;
4557        }
4558
4559        if (noConnection) {
4560            double *we, *wee;
4561            for(we = weights, wee = weights + graph->nEdgeTypes; (we != wee) && !CONNECTED(*we); we++);
4562            if (we == wee)
4563                graph->removeEdge(v1, v2);
4564        }
4565
4566        return 0;
4567    }
4568
4569    else {
4570        if (!item || (item == Py_None)) {
4571            if (objectsOnEdges)
4572                decrefEdge(graph->getEdge(v1, v2), graph->nEdgeTypes);
4573            graph->removeEdge(v1, v2);
4574            return 0;
4575        }
4576
4577        if (graph->nEdgeTypes == 1) {
4578            double w;
4579            if (objectsOnEdges || PyNumber_ToDouble(item, w)) {
4580                double *weights = graph->getOrCreateEdge(v1, v2);
4581                if (objectsOnEdges) {
4582                    DOUBLE_AS_PYOBJECT(*weights) = item;
4583                    Py_INCREF(item);
4584                }
4585                else
4586                    *weights = w;
4587                return 0;
4588            }
4589        }
4590
4591        if (PySequence_Check(item)) {
4592            if (PySequence_Size(item) != graph->nEdgeTypes)
4593                PYERROR(PyExc_AttributeError, "invalid size of the list of edge weights", -1);
4594
4595            double *ww = new double[graph->nEdgeTypes];
4596            double *wwi = ww;
4597            PyObject *iterator = PyObject_GetIter(item);
4598            if (iterator) {
4599                for(PyObject *item = PyIter_Next(iterator); item; item = PyIter_Next(iterator)) {
4600                    if (item == Py_None)
4601                        DISCONNECT(*(wwi++));
4602                    else
4603                        if (objectsOnEdges) {
4604                            DOUBLE_AS_PYOBJECT(*wwi++) = item;
4605                        }
4606                        else {
4607                            if (!PyNumber_ToDouble(item, *(wwi++))) {
4608                                Py_DECREF(item);
4609                                Py_DECREF(iterator);
4610                                PyErr_Format(PyExc_TypeError, "invalid number for edge type %i", wwi-ww-1);
4611                                delete ww;
4612                                return -1;
4613                            }
4614                            Py_DECREF(item); // no Py_DECREF if objectsOnEdges!
4615                        }
4616                }
4617                Py_DECREF(iterator);
4618            }
4619
4620            double *weights = graph->getOrCreateEdge(v1, v2);
4621            if (objectsOnEdges)
4622                decrefEdge(weights, graph->nEdgeTypes);
4623            memcpy(weights, ww, graph->nEdgeTypes * sizeof(double));
4624            return 0;
4625        }
4626    }
4627
4628    PYERROR(PyExc_AttributeError, "arguments for __setitem__ are [v1, v2, type] = weight|None,  [v1, v2] = list | weight (if nEdgeType=1)", -1);
4629    PyCATCH_1
4630}
4631
4632
4633PyObject *Graph_getNeighbours(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
4634{
4635    PyTRY
4636        CAST_TO(TGraph, graph);
4637
4638    PyObject *pyv;
4639    int vertex, edgeType = -1;
4640    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
4641        || ((vertex = Graph_getindex(graph, pyv)) < 0))
4642        return PYNULL;
4643
4644    vector<int> neighbours;
4645    if (PyTuple_Size(args) == 1)
4646        graph->getNeighbours(vertex, neighbours);
4647    else
4648        graph->getNeighbours(vertex, edgeType, neighbours);
4649
4650    return Graph_nodesToObjects(graph, neighbours);
4651    PyCATCH
4652}
4653
4654
4655PyObject *Graph_getEdgesFrom(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
4656{
4657    PyTRY
4658        CAST_TO(TGraph, graph);
4659
4660    PyObject *pyv;
4661    int vertex, edgeType = -1;
4662    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
4663        || ((vertex = Graph_getindex(graph, pyv)) < 0))
4664        return PYNULL;
4665
4666    vector<int> neighbours;
4667    if (PyTuple_Size(args) == 1)
4668        graph->getNeighboursFrom(vertex, neighbours);
4669    else
4670        graph->getNeighboursFrom(vertex, edgeType, neighbours);
4671
4672    return Graph_nodesToObjects(graph, neighbours);
4673    PyCATCH
4674}
4675
4676PyObject *Graph_addCluster(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> None")
4677{
4678    PyTRY
4679        CAST_TO(TGraph, graph);
4680
4681    PyObject *pyv;
4682
4683    if (!PyArg_ParseTuple(args, "O:Graph.addCluster", &pyv))
4684        return PYNULL;
4685
4686    Py_ssize_t size = PyList_Size(pyv);
4687    int i,j;
4688    for (i = 0; i < size-1; i++)
4689    {
4690        for (j = i+1; j < size; j++)
4691        {
4692            int x = PyInt_AsLong(PyList_GetItem(pyv, i));
4693            int y = PyInt_AsLong(PyList_GetItem(pyv, j));
4694            //cout << x << " " << y;
4695            double* weight = graph->getOrCreateEdge(x, y);
4696            *weight = 1.0;
4697            //cout << "." << endl;
4698        }
4699    }
4700
4701    RETURN_NONE;
4702    PyCATCH
4703}
4704
4705bool lessLength (const set<int>& s1, const set<int>& s2)
4706{
4707    return s1.size() > s2.size();
4708}
4709
4710bool moreLength (const vector<int>& s1, const vector<int>& s2)
4711{
4712    return s1.size() > s2.size();
4713}
4714
4715PyObject *Graph_getConnectedComponents(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_NOARGS, "None -> list of [nodes]")
4716{
4717    PyTRY
4718    CAST_TO(TGraph, graph);
4719    //cout << "Graph_getConnectedComponents" << endl;
4720    int node = 0;
4721    vector<set<int> > components;
4722    set<int> all;
4723
4724    while (node < graph->nVertices)
4725    {
4726        set<int> component = graph->getConnectedComponent(node);
4727        components.push_back(component);
4728        all.insert(component.begin(), component.end());
4729
4730        while(node < graph->nVertices)
4731        {
4732            node++;
4733            if (all.find(node) == all.end())
4734                break;
4735        }
4736    }
4737    sort(components.begin(), components.end(), lessLength);
4738
4739    PyObject* components_list = PyList_New(0);
4740
4741    ITERATE(vector<set<int> >, si, components) {
4742        PyObject* component_list = PyList_New(0);
4743
4744        ITERATE(set<int>, ni, *si) {
4745            PyObject *nel = Py_BuildValue("i", *ni);
4746            PyList_Append(component_list, nel);
4747            Py_DECREF(nel);
4748        }
4749
4750        PyList_Append(components_list, component_list);
4751        Py_DECREF(component_list);
4752    }
4753
4754    return components_list;
4755    PyCATCH
4756}
4757
4758PyObject *Graph_getDegreeDistribution(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(distribution)")
4759{
4760    PyTRY
4761        CAST_TO(TGraph, graph);
4762
4763        PyObject* degrees = PyDict_New();
4764        PyObject *nsize, *pydegree;
4765
4766        int v;
4767        for (v = 0; v < graph->nVertices; v++)
4768        {
4769            vector<int> neighbours;
4770            graph->getNeighbours(v, neighbours);
4771            nsize = PyInt_FromLong(neighbours.size());
4772
4773            pydegree = PyDict_GetItem(degrees, nsize); // returns borrowed reference!
4774            int newdegree = pydegree ? PyInt_AsLong(pydegree) + 1 : 1;
4775
4776            pydegree = PyInt_FromLong(newdegree);
4777      PyDict_SetItem(degrees, nsize, pydegree);
4778      Py_DECREF(pydegree);
4779        }
4780
4781        return degrees;
4782    PyCATCH
4783}
4784
4785PyObject *Graph_getDegrees(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "degrees")
4786{
4787    PyTRY
4788        CAST_TO(TGraph, graph);
4789
4790        PyObject* degrees = PyList_New(graph->nVertices);
4791        for(int v1 = 0; v1 < graph->nVertices; v1++)
4792        {
4793            PyList_SetItem(degrees, v1,  PyInt_FromLong(0));
4794        }
4795
4796        vector<int> neighbours;
4797        for(int v1 = 0; v1 < graph->nVertices; v1++)
4798        {
4799            graph->getNeighboursFrom_Single(v1, neighbours);
4800
4801            ITERATE(vector<int>, ni, neighbours)
4802            {
4803                int v1_degree = PyInt_AsLong(PyList_GetItem(degrees, v1));
4804                int v2_degree = PyInt_AsLong(PyList_GetItem(degrees, *ni));
4805
4806                v2_degree++;
4807                v1_degree++;
4808
4809                PyList_SetItem(degrees, v1,  PyInt_FromLong(v1_degree));
4810                PyList_SetItem(degrees, *ni, PyInt_FromLong(v2_degree));
4811            }
4812        }
4813
4814        if (!graph->directed) {
4815            for(int v1 = 0; v1 < graph->nVertices; v1++) {
4816                int v1_degree = PyInt_AsLong(PyList_GetItem(degrees, v1));
4817                PyList_SetItem(degrees, v1,  PyInt_FromLong(v1_degree / 2));
4818            }
4819        }
4820
4821        return degrees;
4822    PyCATCH
4823}
4824
4825
4826PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference);
4827
4828PyObject *Graph_getSubGraph(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
4829{
4830    PyTRY
4831    CAST_TO(TGraph, graph);
4832    //cout << "Graph_getSubGraph" << endl;
4833    PyObject *vertices;
4834
4835    if (!PyArg_ParseTuple(args, "O:Graph.getSubGraph", &vertices))
4836        return PYNULL;
4837
4838    Py_ssize_t size = PyList_Size(vertices);
4839    PyList_Sort(vertices);
4840
4841    TGraph *subgraph = new TGraphAsList(size, graph->nEdgeTypes, graph->directed);
4842    PGraph wsubgraph = subgraph;
4843
4844    Py_ssize_t i;
4845    vector<int> neighbours;
4846    for (i = 0; i < size; i++) {
4847        int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
4848
4849        graph->getNeighboursFrom_Single(vertex, neighbours);
4850        ITERATE(vector<int>, ni, neighbours) {
4851            if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1) {
4852                int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4853
4854                if (index != -1) {
4855                    double* w = subgraph->getOrCreateEdge(i, index);
4856                    double* oldw = graph->getOrCreateEdge(vertex, *ni);
4857                    int j;
4858                    for (j=0; j < subgraph->nEdgeTypes; j++) {
4859                        w[j] = oldw[j];
4860                    }
4861                }
4862            }
4863        }
4864    }
4865
4866    PyObject *pysubgraph = WrapOrange(wsubgraph); //WrapNewOrange(subgraph, self->ob_type);
4867
4868    // set graphs attribut items of type ExampleTable to subgraph
4869    PyObject *strItems = PyString_FromString("items");
4870    if (PyObject_HasAttr(self, strItems) == 1) {
4871        PyObject* items = PyObject_GetAttr(self, strItems);
4872        /*
4873        cout << PyObject_IsTrue(items) << endl;
4874        cout << PyObject_Size(items) << endl;
4875        cout << graph->nVertices << endl;
4876        */
4877        if (PyObject_IsTrue(items) && PyObject_Size(items) == graph->nVertices) {
4878            PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
4879            Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
4880        }
4881    }
4882    Py_DECREF(strItems);
4883    return pysubgraph;
4884    PyCATCH
4885}
4886
4887
4888PyObject *Graph_getSubGraphMergeCluster(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
4889{
4890    PyTRY
4891        CAST_TO(TGraph, graph);
4892
4893        PyObject *verticesWithout;
4894        PyObject *vertices = PyList_New(0);
4895
4896        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphMergeCluster", &verticesWithout))
4897            return PYNULL;
4898
4899        // create an array of vertices to be in a new graph
4900        int i;
4901        vector<int> neighbours;
4902        for (i = 0; i < graph->nVertices; i++)
4903        {
4904      if (PySequence_Contains(verticesWithout, PyInt_FromLong(i)) == 0)
4905            {
4906        PyObject *nel = Py_BuildValue("i", i);
4907              PyList_Append(vertices, nel);
4908              Py_DECREF(nel);
4909      }
4910    }
4911
4912        // create new graph without cluster
4913        Py_ssize_t size = PyList_Size(vertices);
4914        PyList_Sort(vertices);
4915
4916        TGraph *subgraph = new TGraphAsList(size + 1, graph->nEdgeTypes, graph->directed);
4917        PGraph wsubgraph = subgraph;
4918
4919        for (i = 0; i < size; i++)
4920        {
4921            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
4922
4923            graph->getNeighboursFrom_Single(vertex, neighbours);
4924            ITERATE(vector<int>, ni, neighbours)
4925            {
4926                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
4927                {
4928                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4929
4930                    if (index != -1)
4931                    {
4932                        double* w = subgraph->getOrCreateEdge(i, index);
4933                        *w = 1.0;
4934                    }
4935                }
4936            }
4937        }
4938        // connect new meta-node with all verties
4939        int sizeWithout = PyList_Size(verticesWithout);
4940        for (i = 0; i < sizeWithout; i++)
4941        {
4942            int vertex = PyInt_AsLong(PyList_GetItem(verticesWithout, i));
4943
4944            graph->getNeighbours(vertex, neighbours);
4945            ITERATE(vector<int>, ni, neighbours)
4946            {
4947                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
4948                {
4949                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4950
4951                    if (index != -1)
4952                    {
4953                        double* w = subgraph->getOrCreateEdge(size, index);
4954                        *w = 1.0;
4955                    }
4956                }
4957            }
4958        }
4959
4960        PyObject *pysubgraph = WrapOrange(wsubgraph);
4961
4962        // set graphs attribut items of type ExampleTable to subgraph
4963    PyObject *strItems = PyString_FromString("items");
4964
4965        if (PyObject_HasAttr(self, strItems) == 1)
4966        {
4967            PyObject* items = PyObject_GetAttr(self, strItems);
4968      PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
4969
4970      PExampleTable graph_table = PyOrange_AsExampleTable(selection);
4971      TExample *example = new TExample(graph_table->domain, true);
4972      graph_table->push_back(example);
4973      Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
4974    }
4975
4976      Py_DECREF(strItems);
4977
4978        return pysubgraph;
4979    PyCATCH
4980}
4981
4982
4983PyObject *Graph_getSubGraphMergeClusters(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "List of (vertices) -> list of [v1, v2, ..., vn]")
4984{
4985    PyTRY
4986        CAST_TO(TGraph, graph);
4987
4988        set<int> verticesWithout;
4989        PyObject *fullGraphs;
4990        PyObject *vertices = PyList_New(0);
4991
4992        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphMergeClusters", &fullGraphs))
4993            return PYNULL;
4994
4995        // create an array of vertices to remove from the graph
4996        Py_ssize_t sizeFullGraphs = PyList_Size(fullGraphs);
4997        int i;
4998        for (i = 0; i < sizeFullGraphs; i++)
4999        {
5000            PyObject *fullGraph = PyList_GetItem(fullGraphs, i);
5001            Py_ssize_t sizeFullGraph = PyList_Size(fullGraph);
5002
5003            int j;
5004            for (j = 0; j < sizeFullGraph; j++)
5005            {
5006                int vertex = PyInt_AsLong(PyList_GetItem(fullGraph, j));
5007                verticesWithout.insert(vertex);
5008            }
5009        }
5010
5011        vector<int> neighbours;
5012        // create an array of vertices to be in a new graph
5013        for (i = 0; i < graph->nVertices; i++)
5014        {
5015            set<int>::iterator it = verticesWithout.find(i);
5016            if (it == verticesWithout.end())
5017            {
5018        PyObject *nel = Py_BuildValue("i", i);
5019              PyList_Append(vertices, nel);
5020              Py_DECREF(nel);
5021      }
5022    }
5023
5024        // create new graph without cluster
5025        Py_ssize_t size = PyList_Size(vertices);
5026        PyList_Sort(vertices);
5027
5028        TGraph *subgraph = new TGraphAsList(size + sizeFullGraphs, graph->nEdgeTypes, graph->directed);
5029        PGraph wsubgraph = subgraph;
5030
5031        for (i = 0; i < size; i++)
5032        {
5033            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5034
5035            graph->getNeighboursFrom_Single(vertex, neighbours);
5036            ITERATE(vector<int>, ni, neighbours)
5037            {
5038                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5039                {
5040                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5041
5042                    if (index != -1)
5043                    {
5044                        double* w = subgraph->getOrCreateEdge(i, index);
5045                        *w = 1.0;
5046                    }
5047                }
5048            }
5049        }
5050        // connect new meta-node with all verties
5051        for (i = 0; i < sizeFullGraphs; i++)
5052        {
5053            PyObject *fullGraph = PyList_GetItem(fullGraphs, i);
5054            Py_ssize_t sizeFullGraph = PyList_Size(fullGraph);
5055            int j;
5056            for (j = 0; j < sizeFullGraph; j++)
5057            {
5058                int vertex = PyInt_AsLong(PyList_GetItem(fullGraph, j));
5059                graph->getNeighbours(vertex, neighbours);
5060
5061                // connect with old neighbours
5062                ITERATE(vector<int>, ni, neighbours)
5063                {
5064                    if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5065                    {
5066                        // vertex to connect with is in new graph
5067                        int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5068
5069                        if (index != -1)
5070                        {
5071                            double* w = subgraph->getOrCreateEdge(size + i, index);
5072                            *w = 1.0;
5073                        }
5074                    }
5075                    else
5076                    {
5077                        // vertex to connect with is a new meta node
5078                        int k;
5079                        for (k = 0; k < sizeFullGraphs; k++)
5080                        {
5081                            PyObject *fullGraph = PyList_GetItem(fullGraphs, k);
5082
5083                            if (PySequence_Contains(fullGraph, PyInt_FromLong(*ni)) == 1)
5084                            {
5085                                if (k != i)
5086                                {
5087                                    double* w = subgraph->getOrCreateEdge(size + i, size + k);
5088                                    *w = 1.0;
5089                                }
5090                                break;
5091                            }
5092                        }
5093                    }
5094                }
5095            }
5096        }
5097
5098        PyObject *pysubgraph = WrapOrange(wsubgraph);
5099
5100        // set graphs attribut items of type ExampleTable to subgraph
5101    PyObject *strItems = PyString_FromString("items");
5102
5103        if (PyObject_HasAttr(self, strItems) == 1)
5104        {
5105            PyObject* items = PyObject_GetAttr(self, strItems);
5106      PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
5107
5108      PExampleTable graph_table = PyOrange_AsExampleTable(selection);
5109            for (i = 0; i < sizeFullGraphs; i++)
5110            {
5111                TExample *example = new TExample(graph_table->domain, true);
5112                graph_table->push_back(example);
5113            }
5114      Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
5115    }
5116
5117      Py_DECREF(strItems);
5118
5119        return pysubgraph;
5120    PyCATCH
5121}
5122
5123
5124PyObject *Graph_getSubGraphWithout(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
5125{
5126    PyTRY
5127        CAST_TO(TGraph, graph);
5128
5129        PyObject *verticesWithout;
5130        PyObject *vertices = PyList_New(0);
5131
5132        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphWithout", &verticesWithout))
5133            return PYNULL;
5134
5135    int i;
5136    for (i = 0; i < graph->nVertices; i++)
5137        {
5138      if (PySequence_Contains(verticesWithout, PyInt_FromLong(i)) == 0)
5139            {
5140        PyObject *nel = Py_BuildValue("i", i);
5141              PyList_Append(vertices, nel);
5142              Py_DECREF(nel);
5143      }
5144    }
5145
5146        Py_ssize_t size = PyList_Size(vertices);
5147        PyList_Sort(vertices);
5148
5149        TGraph *subgraph = new TGraphAsList(size, graph->nEdgeTypes, graph->directed);
5150        PGraph wsubgraph = subgraph;
5151
5152        vector<int> neighbours;
5153        for (i = 0; i < size; i++)
5154        {
5155            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5156
5157            graph->getNeighboursFrom_Single(vertex, neighbours);
5158            ITERATE(vector<int>, ni, neighbours)
5159            {
5160                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5161                {
5162                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5163
5164                    if (index != -1)
5165                    {
5166                        double* w = subgraph->getOrCreateEdge(i, index);
5167                        *w = 1.0;
5168                    }
5169                }
5170            }
5171        }
5172
5173        // set graphs attribut items of type ExampleTable to subgraph
5174        /*
5175        TExampleTable *table;
5176        PExampleTable wtable;
5177
5178        if (PyObject_HasAttr(self, PyString_FromString("items")) == 1)
5179        {
5180            PyObject* items = PyObject_GetAttr(self, PyString_FromString("items"));
5181
5182            PExampleTable graph_table;
5183            if (PyArg_ParseTuple(PyTuple_Pack(1,items), "O", &graph_table))
5184            {
5185
5186                table = new TExampleTable(graph_table->domain);
5187                wtable = table;
5188
5189                for (i = 0; i < size; i++)
5190                {
5191                    int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5192
5193                    graph_table.
5194                }
5195
5196                //PyObject_SetAttr((PyObject *)subgraph, PyString_FromString("items"), Py_BuildValue("N", WrapOrange(wtable)));
5197            }
5198        }
5199
5200        return Py_BuildValue("NN", WrapOrange(wsubgraph), WrapOrange(wtable));
5201        /**/
5202        return Py_BuildValue("N", WrapOrange(wsubgraph));
5203    PyCATCH
5204}
5205
5206
5207PyObject *Graph_getHubs(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(n) -> HubList")
5208{
5209  PyTRY
5210        int n;
5211
5212        if (!PyArg_ParseTuple(args, "n:Graph.getHubs", &n))
5213            return NULL;
5214
5215        CAST_TO(TGraph, graph);
5216
5217        int *vertexDegree = new int[graph->nVertices];
5218
5219        int i;
5220        for (i=0; i < graph->nVertices; i++)
5221        {
5222            vertexDegree[i] = 0;
5223        }
5224
5225
5226        vector<int> neighbours;
5227        for(i = 0; i < graph->nVertices; i++)
5228        {
5229            graph->getNeighboursFrom_Single(i, neighbours);
5230
5231            ITERATE(vector<int>, ni, neighbours)
5232            {
5233                vertexDegree[i]++;
5234                vertexDegree[*ni]++;
5235            }
5236        }
5237
5238        PyObject* hubList = PyList_New(n);
5239
5240        for (i=0; i < n; i++)
5241        {
5242            int j;
5243            int ndx_max = -1;
5244            int max = 0;
5245            for (j=0; j < graph->nVertices; j++)
5246            {
5247                if (vertexDegree[j] > max)
5248                {
5249                    ndx_max = j;
5250                    max = vertexDegree[j];
5251                }
5252            }
5253            //cout << "pow: " << vertexPower[ndx_max] << " ndx: " << ndx_max << endl;
5254
5255            vertexDegree[ndx_max] = -2;
5256            PyList_SetItem(hubList, i, PyInt_FromLong(ndx_max));
5257        }
5258
5259        delete [] vertexDegree;
5260        return hubList;
5261  PyCATCH
5262}
5263
5264
5265PyObject *Graph_getEdgesTo(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
5266{
5267    PyTRY
5268        CAST_TO(TGraph, graph);
5269
5270    PyObject *pyv;
5271    int vertex, edgeType = -1;
5272    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
5273        || ((vertex = Graph_getindex(graph, pyv)) < 0))
5274        return PYNULL;
5275
5276    vector<int> neighbours;
5277    if (PyTuple_Size(args) == 1)
5278        graph->getNeighboursTo(vertex, neighbours);
5279    else
5280        graph->getNeighboursTo(vertex, edgeType, neighbours);
5281
5282    return Graph_nodesToObjects(graph, neighbours);
5283    PyCATCH
5284}
5285
5286
5287PyObject *Graph_getEdges(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "([edgetype]) -> list of (v1, v2, weights)")
5288{
5289    PyTRY
5290        CAST_TO(TGraph, graph);
5291
5292    int edgeType = -1;
5293    if (!PyArg_ParseTuple(args, "|i:Graph.getEdges", &edgeType))
5294        return PYNULL;
5295
5296    bool hasType = (PyTuple_Size(args) != 0);
5297    if (hasType && (edgeType<0) || (edgeType >= graph->nEdgeTypes)) {
5298        PyErr_Format(PyExc_IndexError, "edge type out of range 0-%i", graph->nEdgeTypes);
5299        return PYNULL;
5300    }
5301
5302    PyObject *res = PyList_New(0);
5303    vector<int> neighbours;
5304
5305    for(int v1 = 0; v1 < graph->nVertices; v1++) {
5306        neighbours.clear();
5307        if (hasType)
5308            if (graph->directed) {
5309                graph->getNeighboursFrom(v1, edgeType, neighbours);
5310            }
5311            else {
5312                graph->getNeighboursFrom_Single(v1, edgeType, neighbours);
5313            }
5314        else
5315            if (graph->directed) {
5316                graph->getNeighboursFrom(v1, neighbours);
5317            }
5318            else {
5319                graph->getNeighboursFrom_Single(v1, neighbours);
5320            }
5321
5322        ITERATE(vector<int>, ni, neighbours) {
5323            PyObject *nel = Py_BuildValue("ii", v1, *ni);
5324            PyList_Append(res, nel);
5325            Py_DECREF(nel);
5326        }
5327    }
5328
5329    return res;
5330    PyCATCH
5331}
5332
5333PyObject *Graph_getNodes(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "neighbours -> list of (v1, v2, weights)")
5334{
5335    PyTRY
5336        CAST_TO(TGraph, graph);
5337
5338    int noOfNeighbours = -1;
5339    if (!PyArg_ParseTuple(args, "i:Graph.getNodes", &noOfNeighbours))
5340        return PYNULL;
5341
5342    PyObject *res = PyList_New(0);
5343    vector<int> neighbours;
5344
5345    for(int v1 = 0; v1 < graph->nVertices; v1++) {
5346            graph->getNeighbours(v1, neighbours);
5347
5348      if (neighbours.size() == noOfNeighbours)
5349      {
5350              PyObject *nel = Py_BuildValue("i", v1);
5351              PyList_Append(res, nel);
5352              Py_DECREF(nel);
5353          }
5354    }
5355
5356    return res;
5357    PyCATCH
5358}
5359
5360PyObject *Graph_getShortestPaths(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(u, v) -> list of [v1, v2, ..., vn]")
5361{
5362    PyTRY
5363        CAST_TO(TGraph, graph);
5364
5365    int u, v;
5366    u = v = -1;
5367    if (!PyArg_ParseTuple(args, "ii:Graph.getShortestPaths", &u, &v))
5368        return PYNULL;
5369
5370    vector<int> path = graph->getShortestPaths(u, v);
5371
5372    //cout << "vector size: " << neighbours.size() << endl;
5373    PyObject *res = PyList_New(0);
5374
5375    ITERATE(vector<int>, ni, path) {
5376        PyObject *nel = Py_BuildValue("i", *ni);
5377        PyList_Append(res, nel);
5378        Py_DECREF(nel);
5379    }
5380
5381    return res;
5382    PyCATCH
5383}
5384
5385PyObject *Graph_getDistance(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(u, v) -> distance")
5386{
5387    PyTRY
5388        CAST_TO(TGraph, graph);
5389
5390    int u, v;
5391    u = v = -1;
5392    if (!PyArg_ParseTuple(args, "ii:Graph.getDistance", &u, &v))
5393        return PYNULL;
5394
5395    vector<int> path = graph->getShortestPaths(u, v);
5396
5397    return Py_BuildValue("i", path.size() - 1);
5398    PyCATCH
5399}
5400
5401PyObject *Graph_getDiameter(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "None -> diameter")
5402{
5403    PyTRY
5404        CAST_TO(TGraph, graph);
5405
5406      return Py_BuildValue("i", graph->getDiameter());
5407    PyCATCH
5408}
5409
5410PyObject *Graph_getClusters(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "None -> list of clusters")
5411{
5412  PyTRY
5413    //cout << "clustering C++" << endl;
5414      /*
5415      if (!PyArg_ParseTuple(args, ":NetworkOptimization.getClusters", ))
5416          return NULL;
5417      */
5418      CAST_TO(TGraph, graph);
5419
5420      graph->getClusters();
5421      //return Py_BuildValue("id", ndx, sqrt(min));
5422      RETURN_NONE;
5423  PyCATCH
5424}
5425
5426PyObject *Graph_getClusteringCoefficient(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "None -> clustering_coefficient")
5427{
5428  PyTRY
5429  CAST_TO(TGraph, graph);
5430
5431  double coef = graph->getClusteringCoefficient();
5432  return Py_BuildValue("d", coef