source: orange/source/orange/lib_components.cpp @ 10478:81f6da13a14b

Revision 10478:81f6da13a14b, 197.8 KB checked in by Janez Demšar <janez.demsar@…>, 2 years ago (diff)

Added patches for 64-bit build by cgohlke (closes #1114)

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 - Orange.classification.CostMatrix, "(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 - Orange.statistics.basic.Variable, "(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 - Orange.statistics.basic.Domain, "(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 - Orange.statistics.contingency.Class, 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 - Orange.statistics.contingency.Table, "(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 - Orange.statistics.contingency.VarClass, "(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 - Orange.statistics.contingency.ClassVar, "(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 - Orange.statistics.contingency.VarVar, "(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 - Orange.statistics.contingency.Domain, "(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 - Orange.distance.DistanceNormalized, ExamplesDistance)
1362C_NAMED(ExamplesDistance_Hamming - Orange.distance.HammingDistance, ExamplesDistance, "()")
1363C_NAMED(ExamplesDistance_Maximal - Orange.distance.MaximalDistance, ExamplesDistance_Normalized, "()")
1364C_NAMED(ExamplesDistance_Manhattan - Orange.distance.ManhattanDistance, ExamplesDistance_Normalized, "()")
1365C_NAMED(ExamplesDistance_Euclidean - Orange.distance.EuclideanDistance, ExamplesDistance_Normalized, "()")
1366C_NAMED(ExamplesDistance_Lp, ExamplesDistance_Normalized, "()")
1367C_NAMED(ExamplesDistance_Relief - Orange.distance.ReliefDistance, ExamplesDistance, "()")
1368C_NAMED(ExamplesDistance_DTW - Orange.distance.DTWDistance, ExamplesDistance_Normalized, "()")
1369
1370C_CALL(ExamplesDistanceConstructor_Hamming - Orange.distance.Hamming, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Hamming")
1371C_CALL(ExamplesDistanceConstructor_Maximal - Orange.distance.Maximal, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Maximal")
1372C_CALL(ExamplesDistanceConstructor_Manhattan - Orange.distance.Manhattan, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Manhattan")
1373C_CALL(ExamplesDistanceConstructor_Euclidean - Orange.distance.Euclidean, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Euclidean")
1374C_CALL(ExamplesDistanceConstructor_Lp, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Lp")
1375C_CALL(ExamplesDistanceConstructor_Relief - Orange.distance.Relief, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_Relief")
1376C_CALL(ExamplesDistanceConstructor_DTW - Orange.distance.DTW, ExamplesDistanceConstructor, "([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance_DTW")
1377
1378
1379PyObject *ExamplesDistanceConstructor_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.distance.DistanceConstructor, "<abstract>")
1380{
1381  if (type == (PyTypeObject *)&PyOrExamplesDistanceConstructor_Type)
1382    return setCallbackFunction(WrapNewOrange(mlnew TExamplesDistanceConstructor_Python(), type), args);
1383  else
1384    return WrapNewOrange(mlnew TExamplesDistanceConstructor_Python(), type);
1385}
1386
1387
1388PyObject *ExamplesDistanceConstructor__reduce__(PyObject *self)
1389{
1390    return callbackReduce(self, PyOrExamplesDistanceConstructor_Type);
1391}
1392
1393
1394PyObject *ExamplesDistance_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.distance.Distance, "<abstract>")
1395{ if (type == (PyTypeObject *)&PyOrExamplesDistance_Type)
1396return setCallbackFunction(WrapNewOrange(mlnew TExamplesDistance_Python(), type), args);
1397else
1398return WrapNewOrange(mlnew TExamplesDistance_Python(), type);
1399}
1400
1401
1402PyObject *ExamplesDistance__reduce__(PyObject *self)
1403{
1404    return callbackReduce(self, PyOrExamplesDistance_Type);
1405}
1406
1407
1408PyObject *ExamplesDistanceConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([examples, weightID][, DomainDistributions][, DomainBasicAttrStat]) -/-> ExamplesDistance")
1409{ PyTRY
1410  if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrExamplesDistanceConstructor_Type) {
1411      PyErr_Format(PyExc_SystemError, "ExamplesDistanceConstructor.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
1412      return PYNULL;
1413  }
1414
1415  NO_KEYWORDS
1416
1417  PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
1418  PExampleGenerator gen;
1419  int weightID = 0;
1420  PDomainDistributions dist;
1421  PDomainBasicAttrStat bstat;
1422  if (!PyArg_UnpackTuple(uargs, "ExamplesDistanceConstructor.call", 0, 4, args+0, args+1, args+2, args+3))
1423  return PYNULL;
1424
1425  PyObject **argp = args, **argc = args;
1426  for (int i=0; i<=3; i++, argp++)
1427  if (*argp)
1428  *argc++ = *argp;
1429
1430  for(argp = args; argp!=argc; argp++) {
1431      if (PyOrDomainDistributions_Check(*argp))
1432          if (dist)
1433              PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments (DomainDistribution given twice)", PYNULL)
1434          else
1435          dist = PyOrange_AsDomainDistributions(*argp);
1436      else if (PyOrDomainBasicAttrStat_Check(*argp))
1437          if (bstat)
1438              PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments (DomainBasicAttrStat given twice)", PYNULL)
1439          else
1440          bstat = PyOrange_AsDomainBasicAttrStat(*argp);
1441      else {
1442          PExampleGenerator gen2 = exampleGenFromParsedArgs(*argp);
1443          if (!gen2)
1444              PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments", PYNULL)
1445          else if (gen)
1446          PYERROR(PyExc_TypeError, "ExamplesDistanceConstructor.__call__: invalid arguments (examples given twice)", PYNULL)
1447          else {
1448              gen = gen2;
1449              if (argp+1 != argc) {
1450                  argp++;
1451                  if (!weightFromArg_byDomain(*argp, gen->domain, weightID))
1452                      return PYNULL;
1453              }
1454          }
1455      }
1456  }
1457
1458  return WrapOrange(SELF_AS(TExamplesDistanceConstructor).call(gen, weightID, dist, bstat));
1459  PyCATCH
1460}
1461
1462
1463PyObject *ExamplesDistance_Normalized_attributeDistances(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(example1, example2) -> [by-attribute distances as floats]")
1464{ PyTRY
1465TExample *ex1, *ex2;
1466if (!PyArg_ParseTuple(args, "O&O&:ExamplesDistance_Normalized.attributeDistances", ptr_Example, &ex1, ptr_Example, &ex2))
1467PYERROR(PyExc_TypeError, "attribute error (two examples expected)", PYNULL);
1468
1469vector<float> difs;
1470SELF_AS(TExamplesDistance_Normalized).getDifs(*ex1, *ex2, difs);
1471
1472PyObject *l = PyList_New(difs.size());
1473for(int i = 0, e = difs.size(); i<e; i++)
1474PyList_SetItem(l, i, PyFloat_FromDouble(difs[i]));
1475
1476return l;
1477PyCATCH
1478}
1479
1480
1481PyObject *ExamplesDistance_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(example1, example2) -> float")
1482{
1483    PyTRY
1484        NO_KEYWORDS
1485
1486        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrExamplesDistance_Type) {
1487            PyErr_Format(PyExc_SystemError, "ExamplesDistance.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
1488            return PYNULL;
1489        }
1490
1491        TExample *ex1, *ex2;
1492        if (!PyArg_ParseTuple(args, "O&O&:ExamplesDistance_Normalized.__call__", ptr_Example, &ex1, ptr_Example, &ex2))
1493            PYERROR(PyExc_TypeError, "attribute error (two examples expected)", PYNULL);
1494
1495        return PyFloat_FromDouble((double)(SELF_AS(TExamplesDistance)(*ex1, *ex2)));
1496        PyCATCH
1497}
1498
1499
1500
1501bool convertFromPython(PyObject *pyobj, TAlignment &align)
1502{
1503    return PyArg_ParseTuple(pyobj, "ii:convertFromPython(Alignment)", &align.i, &align.j) != 0;
1504}
1505
1506
1507PyObject *convertToPython(const TAlignment &align)
1508{
1509    return Py_BuildValue("ii", align.i, align.j);
1510}
1511
1512
1513PyObject *ExamplesDistance_DTW_alignment(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(example1, example2) -> (distance, path)")
1514{
1515    PyTRY
1516        TExample *ex1, *ex2;
1517    if (!PyArg_ParseTuple(args, "O&O&:ExamplesDistance_DTW.attributeDistances", ptr_Example, &ex1, ptr_Example, &ex2))
1518        PYERROR(PyExc_TypeError, "attribute error (two examples expected)", PYNULL);
1519
1520    PWarpPath warpPath;
1521    float distance = SELF_AS(TExamplesDistance_DTW)(*ex1, *ex2, warpPath);
1522    return Py_BuildValue("fO", distance, WrapOrange(warpPath));
1523    PyCATCH
1524}
1525
1526/* ************ FINDNEAREST ************ */
1527
1528#include "nearest.hpp"
1529
1530ABSTRACT(FindNearest, Orange)
1531C_NAMED(FindNearest_BruteForce - Orange.classification.knn.FindNearest, FindNearest, "([distance=, distanceID=, includeSame=])")
1532
1533ABSTRACT(FindNearestConstructor, Orange)
1534C_CALL(FindNearestConstructor_BruteForce - Orange.classification.knn.FindNearestConstructor, FindNearestConstructor, "([examples[, weightID[, distanceID]], distanceConstructor=, includeSame=]) -/-> FindNearest")
1535
1536
1537PyObject *FindNearestConstructor_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(examples[, weightID[, distanceID]]) -> FindNearest")
1538{
1539    PyTRY
1540        NO_KEYWORDS
1541
1542        PExampleGenerator egen;
1543    int weightID = 0;
1544    int distanceID = 0;
1545    PyObject *pydistanceID = PYNULL;
1546
1547    if (   !PyArg_ParseTuple(args, "O&|O&O:FindNearestConstructor.__call__", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weightID, &pydistanceID)
1548        || !weightFromArg_byDomain(pydistanceID, egen->domain, distanceID))
1549        return PYNULL;
1550
1551    return WrapOrange(SELF_AS(TFindNearestConstructor).call(egen, weightID, distanceID));
1552    PyCATCH
1553}
1554
1555
1556
1557PyObject *FindNearest_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(example, k) -> ExampleTable")
1558{
1559    PyTRY
1560        NO_KEYWORDS
1561
1562        float k;
1563    TExample *example;
1564    int needsClass = 0;
1565    // Both forms are allowed for compatibility with older versions
1566    if (!PyArg_ParseTuple(args, "fO&|i", &k, ptr_Example, &example, &needsClass)) {
1567        PyErr_Clear();
1568        if (!PyArg_ParseTuple(args, "O&f|i", ptr_Example, &example, &k, &needsClass))
1569            PYERROR(PyExc_TypeError, "attribute error (number and example, and an optional flag for class expected)", PYNULL);
1570    }
1571
1572    return WrapOrange(SELF_AS(TFindNearest).call(*example, k, needsClass != 0));
1573    PyCATCH
1574}
1575
1576
1577
1578
1579/* ************ FILTERS ************ */
1580
1581#include "filter.hpp"
1582
1583ABSTRACT(ValueFilter, Orange)
1584C_NAMED(ValueFilter_discrete, ValueFilter, "([position=, oper=, values=, acceptSpecial=])")
1585C_NAMED(ValueFilter_continuous, ValueFilter, "([position=, oper=, min=, max=, acceptSpecial=])")
1586C_NAMED(ValueFilter_string, ValueFilter, "([position=, oper=, min=, max=])");
1587C_NAMED(ValueFilter_stringList, ValueFilter, "([position=, oper=, values=])");
1588
1589C_CALL(Filter_random, Filter, "([examples], [negate=..., p=...]) -/-> ExampleTable")
1590C_CALL(Filter_hasSpecial, Filter, "([examples], [negate=..., domain=...]) -/-> ExampleTable")
1591C_CALL(Filter_isDefined, Filter, "([examples], [negate=..., domain=..., check=]) -/-> ExampleTable")
1592C_CALL(Filter_hasMeta, Filter, "([examples], [id=...]) -/-> ExampleTable")
1593C_CALL(Filter_hasClassValue, Filter, "([examples], [negate=..., domain=...]) -/-> ExampleTable")
1594C_CALL(Filter_sameValue, Filter, "([examples], [negate=..., domain=..., position=<int>, value=...]) -/-> ExampleTable")
1595C_CALL(Filter_values, Filter, "([examples], [negate=..., domain=..., values=<see the manual>) -/-> ExampleTable")
1596
1597
1598PValueFilterList PValueFilterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::P_FromArguments(arg); }
1599PyObject *ValueFilterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_FromArguments(type, arg); }
1600PyObject *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); }
1601PyObject *ValueFilterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_getitem(self, index); }
1602int       ValueFilterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_setitem(self, index, item); }
1603PyObject *ValueFilterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_getslice(self, start, stop); }
1604int       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); }
1605Py_ssize_t       ValueFilterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_len(self); }
1606PyObject *ValueFilterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_richcmp(self, object, op); }
1607PyObject *ValueFilterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_concat(self, obj); }
1608PyObject *ValueFilterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_repeat(self, times); }
1609PyObject *ValueFilterList_str(TPyOrange *self) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_str(self); }
1610PyObject *ValueFilterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_str(self); }
1611int       ValueFilterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_contains(self, obj); }
1612PyObject *ValueFilterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ValueFilter) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_append(self, item); }
1613PyObject *ValueFilterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_extend(self, obj); }
1614PyObject *ValueFilterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ValueFilter) -> int") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_count(self, obj); }
1615PyObject *ValueFilterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ValueFilterList") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_filter(self, args); }
1616PyObject *ValueFilterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ValueFilter) -> int") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_index(self, obj); }
1617PyObject *ValueFilterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_insert(self, args); }
1618PyObject *ValueFilterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_native(self); }
1619PyObject *ValueFilterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ValueFilter") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_pop(self, args); }
1620PyObject *ValueFilterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ValueFilter) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_remove(self, obj); }
1621PyObject *ValueFilterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_reverse(self); }
1622PyObject *ValueFilterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_sort(self, args); }
1623PyObject *ValueFilterList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PValueFilterList, TValueFilterList, PValueFilter, &PyOrValueFilter_Type>::_reduce(self); }
1624
1625
1626PyObject *applyFilterP(PFilter filter, PExampleTable gen);
1627
1628PyObject *applyFilter(PFilter filter, PExampleGenerator gen, bool weightGiven, int weightID)
1629{ if (!filter) return PYNULL;
1630
1631TExampleTable *newTable = mlnew TExampleTable(gen->domain);
1632PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
1633filter->reset();
1634PEITERATE(ei, gen)
1635if (filter->operator()(*ei))
1636newTable->addExample(*ei);
1637
1638return weightGiven ? Py_BuildValue("Ni", WrapOrange(newGen), weightID) : WrapOrange(newGen);
1639}
1640
1641
1642PyObject *Filter_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
1643{ if (type == (PyTypeObject *)&PyOrFilter_Type)
1644return setCallbackFunction(WrapNewOrange(mlnew TFilter_Python(), type), args);
1645else
1646return WrapNewOrange(mlnew TFilter_Python(), type);
1647}
1648
1649
1650PyObject *Filter__reduce__(PyObject *self)
1651{
1652    return callbackReduce(self, PyOrFilter_Type);
1653}
1654
1655
1656PyObject *Filter_call(PyObject *self, PyObject *args, PyObject *keywords)
1657{
1658    PyTRY
1659        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrFilter_Type) {
1660            PyErr_Format(PyExc_SystemError, "Filter.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
1661            return PYNULL;
1662        }
1663
1664        CAST_TO(TFilter, filter);
1665
1666        bool savedNegate = filter->negate;
1667        PyObject *res;
1668
1669        try {
1670            if (!((TPyOrange *)self)->call_constructed && keywords) {
1671                const Py_ssize_t sze = PyDict_Size(keywords);
1672                PyObject *neg = sze >= 1 ? PyDict_GetItemString(keywords, "negate") : NULL;
1673                if ((sze > 1) || !neg)
1674                    NO_KEYWORDS;
1675                filter->negate = (PyObject_IsTrue(neg) != 0);
1676            }
1677
1678            if ((PyTuple_Size(args)==1) && PyOrExample_Check(PyTuple_GET_ITEM(args, 0))) {
1679                res = PyInt_FromLong(filter->call(PyExample_AS_ExampleReference(PyTuple_GET_ITEM(args, 0))) ? 1 : 0);
1680            }
1681            else {
1682                PExampleGenerator egen;
1683                int references = 0;
1684                if (!PyArg_ParseTuple(args, "O&|i:Filter.__call__", &pt_ExampleGenerator, &egen, &references)) {
1685                    filter->negate = savedNegate;
1686                    return PYNULL;
1687                }
1688
1689                if (references) {
1690                    if (!egen.is_derived_from(TExampleTable))
1691                        PYERROR(PyExc_TypeError, "cannot return references to examples that are not in example table", PYNULL);
1692                    res = applyFilterP(filter, egen);
1693                }
1694                else
1695                    res = applyFilter(PyOrange_AsFilter(self), egen, false, 0);
1696            }
1697
1698            filter->negate = savedNegate;
1699            return res;
1700        }
1701        catch(...) {
1702            filter->negate = savedNegate;
1703            throw;
1704        }
1705        PyCATCH
1706}
1707
1708PyObject *Filter_deepCopy(PyObject *self) PYARGS(METH_NOARGS, "() -> filter")
1709{
1710    PyTRY
1711        CAST_TO(TFilter, filter);
1712
1713    PFilter res = filter->deepCopy();
1714      return WrapOrange(res);
1715    PyCATCH
1716}
1717
1718PyObject *Filter_count(PyObject *self, PyObject *arg) PYARGS(METH_O, "(examples)")
1719{
1720    PyTRY
1721        PExampleGenerator egen = exampleGenFromParsedArgs(arg);
1722    if (!egen)
1723        PYERROR(PyExc_TypeError, "Filter.count: examples expected", PYNULL);
1724
1725    CAST_TO(TFilter, filter);
1726
1727    filter->reset();
1728    int count = 0;
1729    PEITERATE(ei, egen)
1730        if (filter->operator()(*ei))
1731            count++;
1732
1733    return PyInt_FromLong(count);
1734    PyCATCH
1735}
1736
1737
1738PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen)
1739{
1740    TBoolList *selection = new TBoolList();
1741    PBoolList pselection = selection;
1742    const int nex = egen->numberOfExamples();
1743    if (nex > 0)
1744        selection->reserve(nex);
1745
1746    filter.reset();
1747    PEITERATE(ei, egen)
1748        selection->push_back(filter(*ei));
1749
1750    return WrapOrange(pselection);
1751}
1752
1753
1754PyObject *Filter_selectionVector(PyObject *self, PyObject *arg) PYARGS(METH_O, "(examples)")
1755{
1756    PyTRY
1757        PExampleGenerator egen = exampleGenFromParsedArgs(arg);
1758    if (!egen)
1759        PYERROR(PyExc_TypeError, "Filter.selectionVector: examples expected", PYNULL);
1760
1761    CAST_TO(TFilter, filter);
1762    return filterSelectionVectorLow(SELF_AS(TFilter), egen);
1763    PyCATCH
1764}
1765
1766
1767PYXTRACT_IGNORE PyObject *AttributedBoolList_new(PyTypeObject *type, PyObject *args, PyObject *keywds);
1768
1769int Filter_isDefined_set_check(PyObject *self, PyObject *arg)
1770{
1771    PyTRY
1772        CAST_TO_err(TFilter_isDefined, filter, -1)
1773
1774        if (arg == Py_None) {
1775            filter->check = PAttributedBoolList();
1776            return 0;
1777        }
1778
1779
1780        PyObject *boollist = objectOnTheFly(arg, (PyTypeObject *)&PyOrAttributedBoolList_Type);
1781
1782        //    PyObject *boollist = AttributedBoolList_new((PyTypeObject *)&PyOrAttributedBoolList_Type, arg, PYNULL);
1783        if (!boollist)
1784            return -1;
1785
1786        PAttributedBoolList cli = PyOrange_AsAttributedBoolList(boollist);
1787
1788        if (filter->domain) {
1789            if (cli->attributes) {
1790                TVarList::const_iterator di(filter->domain->variables->begin()), de(filter->domain->variables->end());
1791                TVarList::const_iterator fci(cli->attributes->begin()), fce(cli->attributes->end());
1792                for(; (di!=de) && (fci!=fce); di++, fci++)
1793                    if (*di!=*fci) {
1794                        PyErr_Format(PyExc_AttributeError, "attribute %s in the list does not match the filter's domain", (*fci)->get_name().c_str());
1795                        return -1;
1796                    }
1797                    if (fci!=fce)
1798                        PYERROR(PyExc_AttributeError, "the check list has more attributes than the filter's domain", -1);
1799            }
1800            else {
1801                /* we don't want to modify the list if this is a reference
1802                to a list from somewhere else */
1803                if (!PyOrAttributedBoolList_Check(arg))
1804                    cli->attributes = filter->domain->variables;
1805            }
1806        }
1807
1808        filter->check = cli;
1809        return 0;
1810        PyCATCH_1
1811}
1812
1813#include "valuelisttemplate.hpp"
1814
1815
1816PStringList PStringList_FromArguments(PyObject *arg);
1817
1818int Filter_values_setitem(PyObject *self, PyObject *pyvar, PyObject *args)
1819{
1820    PyTRY
1821        CAST_TO_err(TFilter_values, filter, -1);
1822
1823    if (!filter->domain)
1824        PYERROR(PyExc_IndexError, "Filter_values.__getitem__ cannot work if 'domain' is not set", -1);
1825
1826    PVariable var = varFromArg_byDomain(pyvar, filter->domain);
1827    if (!var)
1828        return -1;
1829
1830
1831    if (!args || (args == Py_None)) {
1832        filter->removeCondition(var);
1833        return 0;
1834    }
1835
1836
1837    if (var->varType == TValue::INTVAR) {
1838        if (PyList_Check(args)) {
1839            PValueList vlist = TValueListMethods::P_FromArguments(args, var);
1840            if (!vlist)
1841                return -1;
1842            filter->addCondition(var, vlist);
1843        }
1844        else if (PyTuple_Check(args)) {
1845            int oper;
1846            PyObject *obj;
1847            if (!PyArg_ParseTuple(args, "iO:Filter_values.__setitem__", &oper, &obj))
1848                return -1;
1849            if ((oper != TValueFilter::Equal) && (oper != TValueFilter::NotEqual))
1850                PYERROR(PyExc_AttributeError, "Filter_values.__setitem__: operations for discrete attributes can be only Equal or NotEqual", -1);
1851            PValueList vlist = TValueListMethods::P_FromArguments(obj, var);
1852            if (!vlist)
1853                return -1;
1854            filter->addCondition(var, vlist, oper == TValueFilter::NotEqual);
1855        }
1856        else {
1857            TValue val;
1858            if (!convertFromPython(args, val, var))
1859                return -1;
1860
1861            filter->addCondition(var, val);
1862        }
1863    }
1864
1865    else if (var->varType == TValue::FLOATVAR) {
1866        if (PyTuple_Check(args)) {
1867            int oper;
1868            float minv, maxv;
1869            if (!PyArg_ParseTuple(args, "if|f:Filter_values.__setitem__", &oper, &minv, &maxv))
1870                return -1;
1871            if ((PyTuple_Size(args) == 3) && (oper != TValueFilter::Between) && (oper != TValueFilter::Outside))
1872                PYERROR(PyExc_TypeError, "Filter_values.__setitem__: only one reference value expected for the given operator", -1);
1873
1874            filter->addCondition(var, oper, minv, maxv);
1875        }
1876        else {
1877            float f;
1878            if (!PyNumber_ToFloat(args, f)) {
1879                PyErr_Format(PyExc_TypeError, "Filter_values.__setitem__: invalid condition for attribute '%s'", var->get_name().c_str());
1880                return -1;
1881            }
1882            filter->addCondition(var, TValueFilter::Equal, f, f);
1883        }
1884    }
1885
1886    else if (var->varType == STRINGVAR) {
1887        if (PyString_Check(args))
1888            filter->addCondition(var, TValueFilter::Equal, PyString_AsString(args), string());
1889
1890        else if (PyList_Check(args)) {
1891            PStringList slist = PStringList_FromArguments(args);
1892            if (!slist)
1893                return -1;
1894            filter->addCondition(var, slist);
1895        }
1896
1897        else if (PyTuple_Check(args) && PyTuple_Size(args)) {
1898            char *mins, *maxs = NULL;
1899            int oper;
1900            if (!PyArg_ParseTuple(args, "is|s:Filter_values.__setitem__", &oper, &mins, &maxs))
1901                return -1;
1902            if ((PyTuple_Size(args) == 3) && (oper != TValueFilter::Between) && (oper != TValueFilter::Outside))
1903                PYERROR(PyExc_TypeError, "Filter_values.__setitem__: only one reference value expected for the given operator", -1);
1904
1905            filter->addCondition(var, oper, mins, maxs ? maxs : string());
1906        }
1907
1908        else {
1909            PyErr_Format(PyExc_TypeError, "Filter_values.__setitem__: invalid condition for attribute '%s'", var->get_name().c_str());
1910            return -1;
1911        }
1912    }
1913
1914    else
1915        PYERROR(PyExc_TypeError, "Filter_values.__setitem__: unsupported attribute type", -1);
1916
1917    return 0;
1918    PyCATCH_1
1919}
1920
1921
1922PyObject *Filter_values_getitem(PyObject *self, PyObject *args)
1923{
1924    PyTRY
1925        CAST_TO(TFilter_values, filter);
1926
1927    PVariable var = varFromArg_byDomain(args, filter->domain);
1928    if (!var)
1929        return PYNULL;
1930
1931    int position;
1932    TValueFilterList::iterator condi = filter->findCondition(var, 0, position);
1933    if (condi == filter->conditions->end()) {
1934        PyErr_Format(PyExc_IndexError, "no condition on '%s'", var->get_name().c_str());
1935        return PYNULL;
1936    }
1937
1938    return WrapOrange(*condi);
1939    PyCATCH
1940}
1941
1942
1943PFilterList PFilterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::P_FromArguments(arg); }
1944PyObject *FilterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_FromArguments(type, arg); }
1945PyObject *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); }
1946PyObject *FilterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_getitem(self, index); }
1947int       FilterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_setitem(self, index, item); }
1948PyObject *FilterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_getslice(self, start, stop); }
1949int       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); }
1950Py_ssize_t       FilterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_len(self); }
1951PyObject *FilterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_richcmp(self, object, op); }
1952PyObject *FilterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_concat(self, obj); }
1953PyObject *FilterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_repeat(self, times); }
1954PyObject *FilterList_str(TPyOrange *self) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_str(self); }
1955PyObject *FilterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_str(self); }
1956int       FilterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_contains(self, obj); }
1957PyObject *FilterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Filter) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_append(self, item); }
1958PyObject *FilterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_extend(self, obj); }
1959PyObject *FilterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Filter) -> int") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_count(self, obj); }
1960PyObject *FilterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> FilterList") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_filter(self, args); }
1961PyObject *FilterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Filter) -> int") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_index(self, obj); }
1962PyObject *FilterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_insert(self, args); }
1963PyObject *FilterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_native(self); }
1964PyObject *FilterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Filter") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_pop(self, args); }
1965PyObject *FilterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Filter) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_remove(self, obj); }
1966PyObject *FilterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_reverse(self); }
1967PyObject *FilterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_sort(self, args); }
1968PyObject *FilterList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PFilterList, TFilterList, PFilter, &PyOrFilter_Type>::_reduce(self); }
1969
1970
1971PyObject *Filter_conjunction_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Filter, "([filter-list])") ALLOWS_EMPTY
1972{
1973    if (!PyTuple_Size(args))
1974        return WrapNewOrange(mlnew TFilter_conjunction(), type);
1975
1976    PFilterList flist = PFilterList_FromArguments(PyTuple_Size(args)>1 ? args : PyTuple_GET_ITEM(args, 0));
1977    if (!flist)
1978        return PYNULL;
1979
1980    return WrapNewOrange(mlnew TFilter_conjunction(flist), type);
1981}
1982
1983
1984PyObject *Filter_disjunction_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Filter, "([filter-list])") ALLOWS_EMPTY
1985{
1986    if (!PyTuple_Size(args))
1987        return WrapNewOrange(mlnew TFilter_disjunction(), type);
1988
1989    PFilterList flist = PFilterList_FromArguments(PyTuple_Size(args)>1 ? args : PyTuple_GET_ITEM(args, 0));
1990    if (!flist)
1991        return PYNULL;
1992
1993    return WrapNewOrange(mlnew TFilter_disjunction(flist), type);
1994}
1995
1996/* ************ IMPUTATION ******************** */
1997
1998#include "imputation.hpp"
1999
2000C_NAMED(TransformValue_IsDefined, TransformValue, "([value=])")
2001
2002ABSTRACT(Imputer - Orange.feature.imputation.Imputer, Orange)
2003C_NAMED(Imputer_asValue - Orange.feature.imputation.AsValue, Imputer, "() -> Imputer_asValue")
2004C_NAMED(Imputer_model - Orange.feature.imputation.Model, Imputer, "() -> Imputer_model")
2005C_NAMED(Imputer_random - Orange.feature.imputation.Random, Imputer, "() -> Imputer_random")
2006
2007PyObject *Imputer_defaults_new(PyTypeObject *tpe, PyObject *args) BASED_ON(Imputer - Orange.feature.imputation.Defaults, "(domain | example) -> Imputer_defaults")
2008{
2009    PyTRY
2010        if (PyTuple_Size(args) == 1) {
2011            PyObject *arg = PyTuple_GET_ITEM(args, 0);
2012            if (PyOrDomain_Check(arg))
2013                return WrapNewOrange(mlnew TImputer_defaults(PyOrange_AsDomain(arg)), tpe);
2014            if (PyOrExample_Check(arg))
2015                return WrapNewOrange(mlnew TImputer_defaults(PyExample_AS_Example(arg)), tpe);
2016        }
2017
2018        PYERROR(PyExc_TypeError, "Imputer_defaults.__init__ expects an example or domain", PYNULL);
2019        PyCATCH
2020}
2021
2022PyObject *Imputer_defaults__reduce__(PyObject *self)
2023{
2024    PyTRY
2025        return Py_BuildValue("O(N)N", self->ob_type,
2026        Example_FromWrappedExample(SELF_AS(TImputer_defaults).defaults),
2027        packOrangeDictionary(self));
2028    PyCATCH
2029}
2030
2031
2032ABSTRACT(ImputerConstructor - Orange.feature.imputation.Constructor, Orange)
2033C_CALL(ImputerConstructor_average - Orange.feature.imputation.AverageConstructor, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2034C_CALL(ImputerConstructor_minimal - Orange.feature.imputation.MinimalConstructor, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2035C_CALL(ImputerConstructor_maximal - Orange.feature.imputation.MaximalConstructor, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2036C_CALL(ImputerConstructor_model - Orange.feature.imputation.ModelConstructor, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2037C_CALL(ImputerConstructor_asValue - Orange.feature.imputation.AsValueConstructor, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2038C_CALL(ImputerConstructor_random - Orange.feature.imputation.RandomConstructor, ImputerConstructor, "(examples[, weightID]) -> Imputer")
2039
2040PyObject *Imputer_call(PyObject *self, PyObject *args, PyObject *keywords)
2041{
2042    PyTRY
2043        NO_KEYWORDS
2044
2045        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrImputer_Type) {
2046            PyErr_Format(PyExc_SystemError, "Imputer.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
2047            return PYNULL;
2048        }
2049
2050        if ((PyTuple_GET_SIZE(args) == 1) && PyOrExample_Check(PyTuple_GET_ITEM(args, 0))) {
2051            TExample example = PyExample_AS_ExampleReference(PyTuple_GET_ITEM(args, 0));
2052            return Example_FromWrappedExample(PExample(PyOrange_AsImputer(self)->call(example)));
2053        }
2054
2055        int weightID = 0;
2056        PExampleGenerator gen = exampleGenFromArgs(args, weightID);
2057        if (gen)
2058            return WrapOrange(SELF_AS(TImputer)(gen, weightID));
2059
2060        PYERROR(PyExc_TypeError, "example or examples expected", PYNULL);
2061        PyCATCH
2062}
2063
2064
2065PyObject *ImputerConstructor_call(PyObject *self, PyObject *args, PyObject *keywords)
2066{
2067    PyTRY
2068        NO_KEYWORDS
2069
2070        int weightID = 0;
2071    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
2072    if (!gen)
2073        return PYNULL;
2074
2075    return WrapOrange(SELF_AS(TImputerConstructor)(gen, weightID));
2076    PyCATCH
2077}
2078
2079
2080/* ************ RANDOM INDICES ******************** */
2081#include "trindex.hpp"
2082
2083ABSTRACT(MakeRandomIndices - Orange.data.sample.SubsetIndices, Orange)
2084C_CALL3(MakeRandomIndices2 - Orange.data.sample.SubsetIndices2, MakeRandomIndices2, MakeRandomIndices, "[n | gen [, p0]], [p0=, stratified=, randseed=] -/-> [int]")
2085C_CALL3(MakeRandomIndicesMultiple - Orange.data.sample.SubsetIndicesMultiple, MakeRandomIndicesMultiple, MakeRandomIndices, "[n | gen [, p]], [p=, stratified=, randseed=] -/-> [int]")
2086C_CALL3(MakeRandomIndicesN - Orange.data.sample.SubsetIndicesN, MakeRandomIndicesN, MakeRandomIndices, "[n | gen [, p]], [p=, stratified=, randseed=] -/-> [int]")
2087C_CALL3(MakeRandomIndicesCV - Orange.data.sample.SubsetIndicesCV, MakeRandomIndicesCV, MakeRandomIndices, "[n | gen [, folds]], [folds=, stratified=, randseed=] -/-> [int]")
2088
2089
2090PyObject *MakeRandomIndices2_call(PyObject *self, PyObject *args, PyObject *keywords)
2091{
2092    PyTRY
2093        CAST_TO(TMakeRandomIndices2, mri2);
2094
2095    float savedP0 = mri2->p0;
2096
2097    try {
2098        if (!((TPyOrange *)self)->call_constructed && keywords) {
2099            const Py_ssize_t sze = PyDict_Size(keywords);
2100            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "p0") : NULL;
2101            if ((sze > 1) || !neg)
2102                NO_KEYWORDS;
2103            if (Orange_setattr1((TPyOrange *)self, "p0", neg) == -1) {
2104                mri2->p0 = savedP0;
2105                return PYNULL;
2106            }
2107        }
2108
2109        int n;
2110        float f;
2111        PExampleGenerator egen;
2112        PRandomIndices res;
2113
2114        if (PyArg_ParseTuple(args, "i", &n)) {
2115            res = (*mri2)(n);
2116            goto out;
2117        }
2118
2119        PyErr_Clear();
2120        if (PyArg_ParseTuple(args, "if", &n, &f)) {
2121            res = (*mri2)(n, f);
2122            goto out;
2123        }
2124
2125        PyErr_Clear();
2126        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2127            res = (*mri2)(egen);
2128            goto out;
2129        }
2130
2131        PyErr_Clear();
2132        if (PyArg_ParseTuple(args, "O&f", pt_ExampleGenerator, &egen, &f)) {
2133            res = (*mri2)(egen, f);
2134            goto out;
2135        }
2136
2137        mri2->p0 = savedP0;
2138        PyErr_Clear();
2139        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2140
2141out:
2142        mri2->p0 = savedP0;
2143        if (!res)
2144            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2145
2146        return WrapOrange(res);
2147    }
2148    catch (...) {
2149        mri2->p0 = savedP0;
2150        throw;
2151    }
2152    PyCATCH
2153}
2154
2155
2156PyObject *MakeRandomIndicesMultiple_call(PyObject *self, PyObject *args, PyObject *keywords)
2157{
2158    PyTRY
2159        CAST_TO(TMakeRandomIndicesMultiple, mrim)
2160
2161        float savedP0 = mrim->p0;
2162
2163    try {
2164        if (!((TPyOrange *)self)->call_constructed && keywords) {
2165            const Py_ssize_t sze = PyDict_Size(keywords);
2166            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "p0") : NULL;
2167            if ((sze > 1) || !neg)
2168                NO_KEYWORDS;
2169            if (Orange_setattr1((TPyOrange *)self, "p0", neg) == -1) {
2170                mrim->p0 = savedP0;
2171                return PYNULL;
2172            }
2173        }
2174
2175        int n;
2176        float f;
2177        PExampleGenerator egen;
2178        PRandomIndices res;
2179
2180        if (PyArg_ParseTuple(args, "i", &n)) {
2181            res = (*mrim)(n);
2182            goto out;
2183        }
2184
2185        PyErr_Clear();
2186        if (PyArg_ParseTuple(args, "if", &n, &f)) {
2187            res = (*mrim)(n, f);
2188            goto out;
2189        }
2190
2191        PyErr_Clear();
2192        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2193            res = (*mrim)(egen);
2194            goto out;
2195        }
2196
2197        PyErr_Clear();
2198        if (PyArg_ParseTuple(args, "O&f", pt_ExampleGenerator, &egen, &f)) {
2199            res = (*mrim)(egen, f);
2200            goto out;
2201        }
2202
2203        mrim->p0 = savedP0;
2204        PyErr_Clear();
2205        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2206
2207out:
2208        mrim->p0 = savedP0;
2209
2210        if (!res)
2211            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2212
2213        return WrapOrange(res);
2214    }
2215
2216    catch(...) {
2217        mrim->p0 = savedP0;
2218        throw;
2219    }
2220    PyCATCH
2221}
2222
2223
2224
2225
2226PyObject *MakeRandomIndicesN_call(PyObject *self, PyObject *args, PyObject *keywords)
2227{
2228    PyTRY
2229        CAST_TO(TMakeRandomIndicesN, mriN)
2230
2231        PFloatList savedP = mriN->p;
2232
2233    try {
2234        if (!((TPyOrange *)self)->call_constructed && keywords) {
2235            const Py_ssize_t sze = PyDict_Size(keywords);
2236            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "p") : NULL;
2237            if ((sze > 1) || !neg)
2238                NO_KEYWORDS;
2239            if (Orange_setattr1((TPyOrange *)self, "p", neg) == -1) {
2240                mriN->p = savedP;
2241                return PYNULL;
2242            }
2243        }
2244
2245        int n;
2246        PFloatList pyvector;
2247        PExampleGenerator egen;
2248        PRandomIndices res;
2249
2250        if (PyArg_ParseTuple(args, "i", &n)) {
2251            res = (*mriN)(n);
2252            goto out;
2253        }
2254
2255        PyErr_Clear();
2256        if (PyArg_ParseTuple(args, "iO&", &n, cc_FloatList, &pyvector)) {
2257            res = (*mriN)(n, pyvector);
2258            goto out;
2259        }
2260
2261        PyErr_Clear();
2262        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2263            res = (*mriN)(egen);
2264            goto out;
2265        }
2266
2267        PyErr_Clear();
2268        if (PyArg_ParseTuple(args, "O&O&", pt_ExampleGenerator, &egen, cc_FloatList, &pyvector)) {
2269            res = (*mriN)(egen, pyvector);
2270            goto out;
2271        }
2272
2273        mriN->p = savedP;
2274        PyErr_Clear();
2275        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2276
2277out:
2278        mriN->p = savedP;
2279
2280        if (!res)
2281            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2282
2283        return WrapOrange(res);
2284    }
2285
2286    catch(...) {
2287        mriN->p = savedP;
2288        throw;
2289    }
2290    PyCATCH
2291}
2292
2293
2294
2295PyObject *MakeRandomIndicesCV_call(PyObject *self, PyObject *args, PyObject *keywords)
2296{
2297    PyTRY
2298        CAST_TO(TMakeRandomIndicesCV, mriCV)
2299
2300        int savedFolds = mriCV->folds;
2301
2302    try {
2303        if (!((TPyOrange *)self)->call_constructed && keywords) {
2304            const Py_ssize_t sze = PyDict_Size(keywords);
2305            PyObject *neg = sze == 1 ? PyDict_GetItemString(keywords, "folds") : NULL;
2306            if ((sze > 1) || !neg)
2307                NO_KEYWORDS;
2308            if (Orange_setattr1((TPyOrange *)self, "folds", neg) == -1) {
2309                mriCV->folds = savedFolds;
2310                return PYNULL;
2311            }
2312        }
2313
2314        int n, f;
2315        PExampleGenerator egen;
2316        PRandomIndices res;
2317
2318        if (PyArg_ParseTuple(args, "i", &n)) {
2319            res = (*mriCV)(n);
2320            goto out;
2321        }
2322
2323        PyErr_Clear();
2324        if (PyArg_ParseTuple(args, "ii", &n, &f)) {
2325            res = (*mriCV)(n, f);
2326            goto out;
2327        }
2328
2329        PyErr_Clear();
2330        if (PyArg_ParseTuple(args, "O&", pt_ExampleGenerator, &egen)) {
2331            res = (*mriCV)(egen);
2332            goto out;
2333        }
2334
2335        PyErr_Clear();
2336        if (PyArg_ParseTuple(args, "O&i", pt_ExampleGenerator, &egen, &f)) {
2337            res = (*mriCV)(egen, f);
2338            goto out;
2339        }
2340
2341        mriCV->folds = savedFolds;
2342        PyErr_Clear();
2343        PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2344
2345out:
2346        mriCV->folds = savedFolds;
2347        if (!res)
2348            PYERROR(PyExc_TypeError, "cannot construct RandomIndices", PYNULL);
2349
2350        return WrapOrange(res);
2351    }
2352    catch(...) {
2353        mriCV->folds = savedFolds;
2354        throw;
2355    }
2356    PyCATCH
2357}
2358
2359
2360/* ************ PROBABILITY ESTIMATION ************ */
2361
2362#include "estimateprob.hpp"
2363
2364ABSTRACT(ProbabilityEstimator, Orange)
2365ABSTRACT(ProbabilityEstimatorConstructor, Orange)
2366C_NAMED(ProbabilityEstimator_FromDistribution, ProbabilityEstimator, "()")
2367C_CALL(ProbabilityEstimatorConstructor_relative, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromDistribution")
2368C_CALL(ProbabilityEstimatorConstructor_Laplace, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromDistribution")
2369C_CALL(ProbabilityEstimatorConstructor_m, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromDistribution")
2370C_CALL(ProbabilityEstimatorConstructor_kernel, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromCurve")
2371C_CALL(ProbabilityEstimatorConstructor_loess, ProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromCurve")
2372
2373ABSTRACT(ConditionalProbabilityEstimator, Orange)
2374ABSTRACT(ConditionalProbabilityEstimatorConstructor, Orange)
2375C_NAMED(ConditionalProbabilityEstimator_FromDistribution, ConditionalProbabilityEstimator, "()")
2376C_NAMED(ConditionalProbabilityEstimator_ByRows, ConditionalProbabilityEstimator, "()")
2377C_CALL(ConditionalProbabilityEstimatorConstructor_ByRows, ConditionalProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ConditionalProbabilityEstimator_[FromDistribution|ByRows]")
2378C_CALL(ConditionalProbabilityEstimatorConstructor_loess, ConditionalProbabilityEstimatorConstructor, "([example generator, weight] | [distribution]) -/-> ProbabilityEstimator_FromCurves")
2379
2380
2381extern PyTypeObject PyOrProbabilityEstimator_Type_inh;
2382
2383PProbabilityEstimatorList PProbabilityEstimatorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::P_FromArguments(arg); }
2384PyObject *ProbabilityEstimatorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_FromArguments(type, arg); }
2385PyObject *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); }
2386PyObject *ProbabilityEstimatorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_getitem(self, index); }
2387int       ProbabilityEstimatorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_setitem(self, index, item); }
2388PyObject *ProbabilityEstimatorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_getslice(self, start, stop); }
2389int       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); }
2390Py_ssize_t       ProbabilityEstimatorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_len(self); }
2391PyObject *ProbabilityEstimatorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_richcmp(self, object, op); }
2392PyObject *ProbabilityEstimatorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_concat(self, obj); }
2393PyObject *ProbabilityEstimatorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_repeat(self, times); }
2394PyObject *ProbabilityEstimatorList_str(TPyOrange *self) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_str(self); }
2395PyObject *ProbabilityEstimatorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_str(self); }
2396int       ProbabilityEstimatorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_contains(self, obj); }
2397PyObject *ProbabilityEstimatorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ProbabilityEstimator) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_append(self, item); }
2398PyObject *ProbabilityEstimatorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_extend(self, obj); }
2399PyObject *ProbabilityEstimatorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ProbabilityEstimator) -> int") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_count(self, obj); }
2400PyObject *ProbabilityEstimatorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ProbabilityEstimatorList") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_filter(self, args); }
2401PyObject *ProbabilityEstimatorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ProbabilityEstimator) -> int") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_index(self, obj); }
2402PyObject *ProbabilityEstimatorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_insert(self, args); }
2403PyObject *ProbabilityEstimatorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_native(self); }
2404PyObject *ProbabilityEstimatorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ProbabilityEstimator") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_pop(self, args); }
2405PyObject *ProbabilityEstimatorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ProbabilityEstimator) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_remove(self, obj); }
2406PyObject *ProbabilityEstimatorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_reverse(self); }
2407PyObject *ProbabilityEstimatorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_sort(self, args); }
2408PyObject *ProbabilityEstimatorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PProbabilityEstimatorList, TProbabilityEstimatorList, PProbabilityEstimator, &PyOrProbabilityEstimator_Type>::_reduce(self); }
2409
2410
2411
2412PConditionalProbabilityEstimatorList PConditionalProbabilityEstimatorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::P_FromArguments(arg); }
2413PyObject *ConditionalProbabilityEstimatorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_FromArguments(type, arg); }
2414PyObject *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); }
2415PyObject *ConditionalProbabilityEstimatorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_getitem(self, index); }
2416int       ConditionalProbabilityEstimatorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_setitem(self, index, item); }
2417PyObject *ConditionalProbabilityEstimatorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_getslice(self, start, stop); }
2418int       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); }
2419Py_ssize_t       ConditionalProbabilityEstimatorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_len(self); }
2420PyObject *ConditionalProbabilityEstimatorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_richcmp(self, object, op); }
2421PyObject *ConditionalProbabilityEstimatorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_concat(self, obj); }
2422PyObject *ConditionalProbabilityEstimatorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_repeat(self, times); }
2423PyObject *ConditionalProbabilityEstimatorList_str(TPyOrange *self) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_str(self); }
2424PyObject *ConditionalProbabilityEstimatorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_str(self); }
2425int       ConditionalProbabilityEstimatorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_contains(self, obj); }
2426PyObject *ConditionalProbabilityEstimatorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_append(self, item); }
2427PyObject *ConditionalProbabilityEstimatorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_extend(self, obj); }
2428PyObject *ConditionalProbabilityEstimatorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> int") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_count(self, obj); }
2429PyObject *ConditionalProbabilityEstimatorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ConditionalProbabilityEstimatorList") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_filter(self, args); }
2430PyObject *ConditionalProbabilityEstimatorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> int") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_index(self, obj); }
2431PyObject *ConditionalProbabilityEstimatorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_insert(self, args); }
2432PyObject *ConditionalProbabilityEstimatorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_native(self); }
2433PyObject *ConditionalProbabilityEstimatorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ConditionalProbabilityEstimator") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_pop(self, args); }
2434PyObject *ConditionalProbabilityEstimatorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ConditionalProbabilityEstimator) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_remove(self, obj); }
2435PyObject *ConditionalProbabilityEstimatorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_reverse(self); }
2436PyObject *ConditionalProbabilityEstimatorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_sort(self, args); }
2437PyObject *ConditionalProbabilityEstimatorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PConditionalProbabilityEstimatorList, TConditionalProbabilityEstimatorList, PConditionalProbabilityEstimator, &PyOrConditionalProbabilityEstimator_Type>::_reduce(self); }
2438
2439
2440PyObject *ProbabilityEstimatorConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([distribution[, apriori]] [example generator[, weight]]) -> ProbabilityEstimator")
2441{
2442    PyTRY
2443        NO_KEYWORDS
2444
2445        CAST_TO(TProbabilityEstimatorConstructor, cest);
2446
2447    PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
2448    PDistribution dist, apriori;
2449    PExampleGenerator gen;
2450    int weightID = 0;
2451    if (!PyArg_UnpackTuple(uargs, "ProbabilityEstimatorConstructor.call", 0, 4, args+0, args+1, args+2, args+3))
2452        return PYNULL;
2453
2454    PyObject **argp = args, **argc = args;
2455    for (int i=0; i<=3; i++, argp++)
2456        if (*argp)
2457            *argc++ = *argp;
2458
2459    argp = args;
2460    if ((argp != argc) && ((*argp==Py_None) || PyOrDistribution_Check(*argp))) {
2461        dist = (*argp==Py_None) ? PDistribution() : PyOrange_AsDistribution(*argp++);
2462        if ((argp != argc) && PyOrDistribution_Check(*argp))
2463            apriori = PyOrange_AsDistribution(*argp++);
2464    }
2465    if (argp != argc) {
2466        gen = exampleGenFromParsedArgs(*argp);
2467        if (gen) {
2468            argp++;
2469            if ((argp != argc) && !weightFromArg_byDomain(*(argp++), gen->domain, weightID))
2470                return PYNULL;
2471        }
2472    }
2473
2474    if (argp != argc)
2475        PYERROR(PyExc_TypeError, "Invalid arguments for 'ProbabilityEstimatorConstructor.call'", PYNULL);
2476
2477    return WrapOrange(cest->call(dist, apriori, gen, weightID));
2478    PyCATCH
2479}
2480
2481
2482PyObject *ProbabilityEstimator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(Value) -> float  |  () -> Distribution")
2483{ PyTRY
2484NO_KEYWORDS
2485
2486CAST_TO(TProbabilityEstimator, cest);
2487
2488PyObject *pyobj = PYNULL;
2489if (!PyArg_ParseTuple(args, "|O:ProbabilityEstimator.call", &pyobj))
2490return PYNULL;
2491
2492if (pyobj) {
2493    TValue val;
2494    if (!convertFromPython(pyobj, val))
2495        PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2496    return PyFloat_FromDouble((double)cest->call(val));
2497}
2498
2499else
2500return WrapOrange(cest->call());
2501PyCATCH
2502}
2503
2504
2505
2506PyObject *ConditionalProbabilityEstimatorConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([contingency[, apriori]] [example generator[, weight]]) -> ProbabilityEstimator")
2507{
2508    PyTRY
2509        NO_KEYWORDS
2510
2511        CAST_TO(TConditionalProbabilityEstimatorConstructor, cest);
2512
2513    PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
2514    PContingency cont, apriori;
2515    PExampleGenerator gen;
2516    int weightID = 0;
2517    if (!PyArg_UnpackTuple(uargs, "ProbabilityEstimatorConstructor.call", 0, 4, args, args+1, args+2, args+3))
2518        return PYNULL;
2519
2520    PyObject **argp = args, **argc = args;
2521    for (int i=0; i<=3; i++, argp++)
2522        if (*argp)
2523            *argc++ = *argp;
2524
2525    argp = args;
2526    if ((argp != argc) && ((*argp==Py_None) || PyOrContingency_Check(*argp))) {
2527        cont = (*argp==Py_None) ? PContingency() : PyOrange_AsContingency(*argp++);
2528        if ((argp != argc) && PyOrDistribution_Check(*argp))
2529            apriori = PyOrange_AsDistribution(*argp++);
2530    }
2531    if (argp != argc) {
2532        gen = exampleGenFromParsedArgs(*argp);
2533        if (gen) {
2534            argp++;
2535            if ((argp != argc) && !weightFromArg_byDomain(*(argp++), gen->domain, weightID))
2536                return PYNULL;
2537        }
2538    }
2539
2540    if (argp != argc)
2541        PYERROR(PyExc_TypeError, "Invalid arguments for 'ProbabilityEstimatorConstructor.call'", PYNULL);
2542
2543    return WrapOrange(cest->call(cont, apriori, gen, weightID));
2544    PyCATCH
2545}
2546
2547
2548PyObject *ConditionalProbabilityEstimator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(Value, Condition) -> float  |  (Condition) -> Distribution | () -> Contingency")
2549{
2550    PyTRY
2551        NO_KEYWORDS
2552
2553        CAST_TO(TConditionalProbabilityEstimator, cest);
2554
2555    PyObject *pyobj1 = PYNULL, *pyobj2 = PYNULL;
2556    if (!PyArg_ParseTuple(args, "|OO:ProbabilityEstimator.call", &pyobj1, &pyobj2))
2557        return PYNULL;
2558
2559    if (pyobj1 && pyobj2) {
2560        TValue val1, val2;
2561        if (!convertFromPython(pyobj1, val1) || !convertFromPython(pyobj2, val2))
2562            PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2563        return PyFloat_FromDouble((double)cest->call(val1, val2));
2564    }
2565
2566    else if (pyobj1) {
2567        TValue val;
2568        if (!convertFromPython(pyobj1, val))
2569            PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2570        return WrapOrange(cest->call(val));
2571    }
2572
2573    else
2574        return WrapOrange(cest->call());
2575    PyCATCH
2576}
2577
2578#include "stat.hpp"
2579
2580/* ************ MEASURES ************ */
2581
2582#include "measures.hpp"
2583#include "relief.hpp"
2584
2585BASED_ON(MeasureAttribute - Orange.feature.scoring.Score, Orange)
2586ABSTRACT(MeasureAttributeFromProbabilities - Orange.feature.scoring.ScoreFromProbabilities, MeasureAttribute)
2587
2588C_CALL(MeasureAttribute_info - Orange.feature.scoring.InfoGain, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2589C_CALL(MeasureAttribute_gini - Orange.feature.scoring.Gini, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2590C_CALL(MeasureAttribute_gainRatio - Orange.feature.scoring.GainRatio, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2591C_CALL(MeasureAttribute_cost - Orange.feature.scoring.Cost, MeasureAttributeFromProbabilities, "(cost=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2592C_CALL(MeasureAttribute_relevance - Orange.feature.scoring.Relevance, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2593
2594C_CALL(MeasureAttribute_gainRatioA, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2595C_CALL(MeasureAttribute_logOddsRatio, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2596C_CALL(MeasureAttribute_chiSquare, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2597
2598C_CALL(MeasureAttribute_MSE - Orange.feature.scoring.MSE, MeasureAttribute, "(estimate=, m=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2599
2600C_CALL(MeasureAttribute_relief - Orange.feature.scoring.Relief, MeasureAttribute, "(estimate=, m=, k=) | (attr, examples[, apriori] [,weightID]) -/-> float")
2601
2602/* obsolete: */
2603PYCONSTANT(MeasureAttribute_splitGain, (PyObject *)&PyOrMeasureAttribute_gainRatio_Type)
2604PYCONSTANT(MeasureAttribute_retis, (PyObject *)&PyOrMeasureAttribute_MSE_Type)
2605
2606
2607PYCLASSCONSTANT_FLOAT(MeasureAttribute, Rejected, ATTRIBUTE_REJECTED)
2608
2609PyObject *MeasureAttribute_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.feature.scoring.Score, "<abstract>")
2610{ if (type == (PyTypeObject *)&PyOrMeasureAttribute_Type)
2611return setCallbackFunction(WrapNewOrange(mlnew TMeasureAttribute_Python(), type), args);
2612else
2613return WrapNewOrange(mlnew TMeasureAttribute_Python(), type);
2614}
2615
2616
2617PyObject *MeasureAttribute__reduce__(PyObject *self)
2618{
2619    return callbackReduce(self, PyOrMeasureAttribute_Type);
2620}
2621
2622
2623PyObject *MeasureAttribute_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(attr, xmpls[, apr, wght]) | (attr, domcont[, apr]) | (cont, clss-dist [,apr]) -> (float, meas-type)")
2624{
2625    PyTRY
2626        NO_KEYWORDS
2627
2628        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrMeasureAttribute_Type) {
2629            PyErr_Format(PyExc_SystemError, "MeasureAttribute.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
2630            return PYNULL;
2631        }
2632
2633        CAST_TO(TMeasureAttribute, meat)
2634
2635            PyObject *arg1;
2636        PDistribution aprClDistr;
2637
2638        // Try (contingency, class distribution, aprior class distribution)
2639
2640        PContingency contingency;
2641        PDistribution clDistr;
2642        if (PyArg_ParseTuple(args, "O&O&|O&", cc_Contingency, &contingency, cc_Distribution, &clDistr, ccn_Distribution, &aprClDistr))
2643            return PyFloat_FromDouble((double)(meat->operator()(contingency, clDistr, aprClDistr)));
2644
2645        PyErr_Clear();
2646
2647
2648        // Try (variable, domaincontingency, aprior class distribution)
2649
2650        PDomainContingency dcont;
2651        if (PyArg_ParseTuple(args, "OO&|O&", &arg1, cc_DomainContingency, &dcont, ccn_Distribution, &aprClDistr)) {
2652
2653            int attrNo;
2654
2655            if (PyInt_Check(arg1)) {
2656                attrNo = int(PyInt_AsLong(arg1));
2657                if ((attrNo<0) || (attrNo>=dcont->size())) {
2658                    PyErr_Format(PyExc_IndexError, "attribute index %i out of range for the given DomainContingency", attrNo);
2659                    return PYNULL;
2660                }
2661            }
2662
2663            else {
2664                TDomainContingency::const_iterator ci(dcont->begin()), ce(dcont->end());
2665                const bool &couter = dcont->classIsOuter;
2666
2667                if (PyOrVariable_Check(arg1)) {
2668                    PVariable var = PyOrange_AsVariable(arg1);
2669                    for(attrNo = 0; (ci!=ce) && (couter ? ((*ci)->innerVariable != var) : ((*ci)->outerVariable != var)); ci++, attrNo++);
2670
2671                    if (ci==ce) {
2672                        PyErr_Format(PyExc_IndexError, "attribute '%s' not in the given DomainContingency", var->get_name().c_str());
2673                        return PYNULL;
2674                    }
2675                }
2676
2677                else if (PyString_Check(arg1)) {
2678                    char *attrName = PyString_AsString(arg1);
2679                    for(attrNo = 0; (ci!=ce) && (couter ? ((*ci)->innerVariable->get_name()!= attrName) : ((*ci)->outerVariable->get_name()!=attrName)); ci++, attrNo++);
2680
2681                    if (ci==ce) {
2682                        PyErr_Format(PyExc_IndexError, "attribute '%s' not in the given DomainContingency", attrName);
2683                        return PYNULL;
2684                    }
2685                }
2686
2687                else {
2688                    PyErr_Format(PyExc_IndexError, "cannot guess the attribute from the object of type '%s'", arg1->ob_type->tp_name);
2689                    return PYNULL;
2690                }
2691            }
2692
2693            return PyFloat_FromDouble((double)(meat->operator()(attrNo, dcont, aprClDistr)));
2694        }
2695
2696
2697        PyErr_Clear();
2698
2699
2700        // Try (variable, examples, aprior class distribution, weight)
2701
2702        PExampleGenerator egen;
2703        if ((PyTuple_Size(args) >= 2) && pt_ExampleGenerator(PyTuple_GET_ITEM(args, 1), &egen)) {
2704
2705            // No need to INCREF (ParseArgs doesn't INCREF either)
2706            PyObject *arg3 = Py_None, *arg4 = Py_None;
2707
2708            arg1 = PyTuple_GET_ITEM(args, 0);
2709
2710            if (PyTuple_Size(args) == 4) {
2711                arg3 = PyTuple_GET_ITEM(args, 2);
2712                arg4 = PyTuple_GET_ITEM(args, 3);
2713            }
2714
2715            else if (PyTuple_Size(args) == 3) {
2716                arg4 = PyTuple_GET_ITEM(args, 2);
2717                // 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
2718                if (PyOrDistribution_Check(arg4)) {
2719                    arg3 = arg4;
2720                    arg4 = Py_None;
2721                }
2722                else
2723                    arg3 = Py_None;
2724            }
2725
2726            int weightID=0;
2727
2728            if (arg3 != Py_None)
2729                if (PyOrDistribution_Check(arg4))
2730                    aprClDistr = PyOrange_AsDistribution(arg3);
2731                else
2732                    PYERROR(PyExc_TypeError, "invalid argument 3 (Distribution or None expected)", PYNULL);
2733
2734            if (arg4 != Py_None)
2735                if (!weightFromArg_byDomain(arg4, egen->domain, weightID))
2736                    PYERROR(PyExc_TypeError, "invalid argument 4 (weightID or None expected)", PYNULL);
2737
2738            if (PyOrVariable_Check(arg1))
2739                return PyFloat_FromDouble((double)(meat->operator()(PyOrange_AsVariable(arg1), egen, aprClDistr, weightID)));
2740
2741            else if (PyInt_Check(arg1)) {
2742                int attrNo = PyInt_AsLong(arg1);
2743                if (attrNo >= (int)egen->domain->attributes->size()) {
2744                    PyErr_Format(PyExc_IndexError, "attribute index %i out of range for the given DomainContingency", attrNo);
2745                    return PYNULL;
2746                }
2747                return PyFloat_FromDouble((double)(meat->operator()(attrNo, egen, aprClDistr, weightID)));
2748            }
2749
2750            else {
2751                int attrNo;
2752                if (!varNumFromVarDom(arg1, egen->domain, attrNo))
2753                    PYERROR(PyExc_TypeError, "invalid argument 1 (attribute index, name or descriptor expected)", PYNULL);
2754
2755                return PyFloat_FromDouble((double)(meat->operator()(attrNo, egen, aprClDistr, weightID)));
2756            }
2757        }
2758
2759        PYERROR(PyExc_TypeError, "invalid set of parameters", PYNULL);
2760        return PYNULL;
2761        PyCATCH;
2762}
2763
2764
2765PyObject *MeasureAttribute_thresholdFunction(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples[, weightID]) | (contingency[, distribution]) -> list")
2766{
2767    PyTRY
2768        TFloatFloatList thresholds;
2769
2770    PyObject *pyvar;
2771    PExampleGenerator gen;
2772    int weightID = 0;
2773    if (PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_thresholdFunction", &pyvar, pt_ExampleGenerator, &gen, &weightID)) {
2774        PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2775        if (!var)
2776            return NULL;
2777
2778        SELF_AS(TMeasureAttribute).thresholdFunction(thresholds, var, gen, PDistribution(), weightID);
2779    }
2780    else {
2781        PyErr_Clear();
2782
2783        PContingency cont;
2784        PDistribution cdist;
2785        if (PyArg_ParseTuple(args, "O&|O&", cc_Contingency, &cont, ccn_Distribution, &cdist)) {
2786            if (!cdist)
2787                cdist = cont->innerDistribution;
2788
2789            SELF_AS(TMeasureAttribute).thresholdFunction(thresholds, cont, cdist);
2790        }
2791        else {
2792            PyErr_Clear();
2793            PYERROR(PyExc_TypeError, "MeasureAttribute.thresholdFunction expects a variable, generator[, weight], or contingency", PYNULL)
2794        }
2795    }
2796
2797    PyObject *res = PyList_New(thresholds.size());
2798    Py_ssize_t li = 0;
2799    for(TFloatFloatList::const_iterator ti(thresholds.begin()), te(thresholds.end()); ti != te; ti++)
2800        PyList_SetItem(res, li++, Py_BuildValue("ff", ti->first, ti->second));
2801    return res;
2802    PyCATCH;
2803}
2804
2805
2806
2807PyObject *MeasureAttribute_relief_pairGains(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> list")
2808{
2809    PyTRY
2810        PyObject *pyvar;
2811    PExampleGenerator gen;
2812    int weightID = 0;
2813    if (!PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_pairGains", &pyvar, pt_ExampleGenerator, &gen, &weightID))
2814        return NULL;
2815
2816    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2817    if (!var)
2818        return NULL;
2819
2820    TPairGainAdder pairGains;
2821    SELF_AS(TMeasureAttribute_relief).pairGains(pairGains, var, gen, weightID);
2822
2823    PyObject *res = PyList_New(pairGains.size());
2824    Py_ssize_t li = 0;
2825    for(TPairGainAdder::const_iterator ti(pairGains.begin()), te(pairGains.end()); ti != te; ti++)
2826        PyList_SetItem(res, li++, Py_BuildValue("(ff)f", ti->e1, ti->e2, ti->gain));
2827    return res;
2828    PyCATCH
2829}
2830
2831
2832PyObject *MeasureAttribute_relief_gainMatrix(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> SymMatrix")
2833{
2834    PyTRY
2835        PyObject *pyvar;
2836    PExampleGenerator gen;
2837    int weightID = 0;
2838    if (!PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_gainMatrix", &pyvar, pt_ExampleGenerator, &gen, &weightID))
2839        return NULL;
2840
2841    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2842    if (!var)
2843        return NULL;
2844
2845    return WrapOrange(SELF_AS(TMeasureAttribute_relief).gainMatrix(var, gen, NULL, weightID, NULL, NULL));
2846    PyCATCH
2847}
2848
2849PyObject *MeasureAttribute_bestThreshold(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> list")
2850{
2851    PyTRY
2852        PyObject *pyvar;
2853    PExampleGenerator gen;
2854    int weightID = 0;
2855    float minSubset = 0.0;
2856    if (!PyArg_ParseTuple(args, "OO&|if:MeasureAttribute_thresholdFunction", &pyvar, pt_ExampleGenerator, &gen, &weightID, &minSubset))
2857        return NULL;
2858
2859    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2860    if (!var)
2861        return NULL;
2862
2863    float threshold, score;
2864    PDistribution distribution;
2865    threshold = SELF_AS(TMeasureAttribute).bestThreshold(distribution, score, var, gen, PDistribution(), weightID);
2866
2867    if (threshold == ILLEGAL_FLOAT)
2868        PYERROR(PyExc_SystemError, "cannot compute the threshold; check the number of instances etc.", PYNULL);
2869
2870    return Py_BuildValue("ffO", threshold, score, WrapOrange(distribution));
2871    PyCATCH
2872}
2873
2874/* ************ EXAMPLE CLUSTERING ************ */
2875
2876#include "exampleclustering.hpp"
2877
2878ABSTRACT(GeneralExampleClustering - Orange.feature.construction.functionDecomposition.GeneralExampleClustering, Orange)
2879C_NAMED(ExampleCluster - Orange.clustering.ExampleCluster, Orange, "([left=, right=, distance=, centroid=])")
2880C_NAMED(ExampleClusters - Orange.feature.construction.functionDecomposition.ExampleClusters, GeneralExampleClustering, "([root=, quality=]")
2881
2882
2883PyObject *GeneralExampleClustering_exampleClusters(PyObject *self) PYARGS(METH_NOARGS, "() -> ExampleClusters")
2884{
2885    PyTRY
2886        return WrapOrange(SELF_AS(TGeneralExampleClustering).exampleClusters());
2887    PyCATCH
2888}
2889
2890
2891PyObject *GeneralExampleClustering_exampleSets(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> ExampleSets")
2892{
2893    PyTRY
2894        float cut = 0.0;
2895    if (!PyArg_ParseTuple(args, "|f", &cut))
2896        return PYNULL;
2897
2898    return WrapOrange(SELF_AS(TGeneralExampleClustering).exampleSets(cut));
2899    PyCATCH
2900}
2901
2902
2903PyObject *GeneralExampleClustering_classifier(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> Classifier")
2904{
2905    PyTRY
2906        float cut = 0.0;
2907    if (!PyArg_ParseTuple(args, "|f", &cut))
2908        return PYNULL;
2909
2910    return WrapOrange(SELF_AS(TGeneralExampleClustering).classifier(cut));
2911    PyCATCH
2912}
2913
2914
2915PyObject *GeneralExampleClustering_feature(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> Variable")
2916{
2917    PyTRY
2918        float cut = 0.0;
2919    if (!PyArg_ParseTuple(args, "|f", &cut))
2920        return PYNULL;
2921
2922    return WrapOrange(SELF_AS(TGeneralExampleClustering).feature(cut));
2923    PyCATCH
2924}
2925
2926
2927#include "calibrate.hpp"
2928
2929C_CALL(ThresholdCA - Orange.wrappers.ThresholdCA, Orange, "([classifier, examples[, weightID, target value]]) -/-> (threshold, optimal CA, list of CAs))")
2930
2931PyObject *ThresholdCA_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(classifier, examples[, weightID, target value]) -> (threshold, optimal CA, list of CAs)")
2932{
2933    PyTRY
2934        NO_KEYWORDS
2935
2936        PClassifier classifier;
2937    PExampleGenerator egen;
2938    int weightID = 0;
2939    PyObject *pyvalue = NULL;
2940    int targetVal = -1;
2941
2942    if (!PyArg_ParseTuple(args, "O&O&|O&O:ThresholdCA.__call__", cc_Classifier, &classifier, pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weightID, &pyvalue))
2943        return PYNULL;
2944    if (pyvalue) {
2945        TValue classVal;
2946        if (!convertFromPython(pyvalue, classVal, classifier->classVar))
2947            return PYNULL;
2948        if (classVal.isSpecial())
2949            PYERROR(PyExc_TypeError, "invalid target value", PYNULL);
2950        targetVal = classVal.intV;
2951    }
2952
2953    TFloatFloatList *ffl = mlnew TFloatFloatList();
2954    PFloatFloatList wfl(ffl);
2955    float optThresh, optCA;
2956    optThresh = SELF_AS(TThresholdCA).call(classifier, egen, weightID, optCA, targetVal, ffl);
2957
2958    PyObject *pyCAs = PyList_New(ffl->size());
2959    Py_ssize_t i = 0;
2960    PITERATE(TFloatFloatList, ffi, ffl)
2961        PyList_SetItem(pyCAs, i++, Py_BuildValue("ff", (*ffi).first, (*ffi).second));
2962
2963    return Py_BuildValue("ffN", optThresh, optCA, pyCAs);
2964    PyCATCH
2965}
2966
2967
2968#include "symmatrix.hpp"
2969
2970PyObject *SymMatrix_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Orange, "(dimension[, initialElement=0] | a list of lists)")
2971{
2972    PyTRY
2973        int dim;
2974    float init = 0;
2975    if (PyArg_ParseTuple(args, "i|f", &dim, &init)) {
2976        if (dim<1)
2977            PYERROR(PyExc_TypeError, "matrix dimension must be positive", PYNULL);
2978
2979        return WrapNewOrange(mlnew TSymMatrix(dim, init), type);
2980    }
2981
2982    PyErr_Clear();
2983
2984    PyObject *arg;
2985    if (PyArg_ParseTuple(args, "O|f", &arg, &init)) {
2986        dim = PySequence_Size(arg);
2987        PyObject *iter = PyObject_GetIter(arg);
2988        if ((dim<0) || !iter)
2989            PYERROR(PyExc_TypeError, "SymMatrix.__init__ expects a list of lists or the dimension, and an optional default element", PYNULL);
2990
2991#define UNKNOWN_F -1e30f
2992
2993        TSymMatrix *symmatrix = mlnew TSymMatrix(dim, UNKNOWN_F);
2994        PyObject *subiter = NULL;
2995
2996#define FREE_ALL  Py_DECREF(iter); delete symmatrix; Py_XDECREF(subiter);
2997
2998        int i, j;
2999
3000        for(i = 0; i<dim; i++) {
3001            PyObject *item = PyIter_Next(iter);
3002            if (!item) {
3003                FREE_ALL
3004                    PYERROR(PyExc_SystemError, "matrix is shorter than promissed ('len' returned more elements than there actuall are)", PYNULL);
3005            }
3006
3007            PyObject *subiter = PyObject_GetIter(item);
3008            Py_DECREF(item);
3009
3010            if (!subiter) {
3011                FREE_ALL
3012                    PyErr_Format(PyExc_TypeError, "row %i is not a sequence", i);
3013                return PYNULL;
3014            }
3015
3016            for(j = 0;; j++) {
3017                PyObject *subitem = PyIter_Next(subiter);
3018                if (!subitem)
3019                    break;
3020
3021                float f;
3022                bool ok = PyNumber_ToFloat(subitem, f);
3023                Py_DECREF(subitem);
3024                if (!ok) {
3025                    FREE_ALL
3026                        PyErr_Format(PyExc_TypeError, "element at (%i, %i) is not a number", i, j);
3027                    return PYNULL;
3028                }
3029
3030
3031                try {
3032                    float &mae = symmatrix->getref(i, j);
3033
3034                    if ((mae != UNKNOWN_F) && (mae!=f)) {
3035                        FREE_ALL
3036                            PyErr_Format(PyExc_TypeError, "the element at (%i, %i) is asymmetric", i, j);
3037                        return PYNULL;
3038                    }
3039
3040                    mae = f;
3041                }
3042                catch (...) {
3043                    FREE_ALL
3044                        throw;
3045                }
3046            }
3047
3048            Py_DECREF(subiter);
3049            subiter = NULL;
3050        }
3051        Py_DECREF(iter);
3052
3053        float *e = symmatrix->elements;
3054        for(i = ((dim+1)*(dim+2)) >> 1; i--; e++)
3055            if (*e == UNKNOWN_F)
3056                *e = init;
3057
3058        return WrapNewOrange(symmatrix, type);
3059
3060#undef UNKNOWN_F
3061#undef FREE_ALL
3062    }
3063
3064    PyErr_Clear();
3065
3066    PYERROR(PyExc_TypeError, "SymMatrix.__init__ expects a list of lists or the dimension and the initial element", PYNULL);
3067
3068    PyCATCH
3069}
3070
3071
3072PyObject *SymMatrix__reduce__(PyObject *self)
3073{
3074    PyTRY
3075        CAST_TO(TSymMatrix, matrix);
3076    const int dim = matrix->dim;
3077    return Py_BuildValue("O(Os#i)N", getExportedFunction("__pickleLoaderSymMatrix"),
3078        self->ob_type,
3079        matrix->elements, sizeof(float) * (((dim+1) * (dim+2)) >> 1),
3080        dim,
3081        packOrangeDictionary(self));
3082    PyCATCH
3083}
3084
3085
3086PyObject *__pickleLoaderSymMatrix(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension)")
3087{
3088    PyTRY
3089        PyTypeObject *type;
3090    char *buf;
3091    int bufSize, dim;
3092    if (!PyArg_ParseTuple(args, "Os#i:__pickleLoaderCostMatrix", &type, &buf, &bufSize, &dim))
3093        return NULL;
3094
3095    TSymMatrix *cm = new TSymMatrix(dim);
3096    memcpy(cm->elements, buf, bufSize);
3097    return WrapNewOrange(cm, type);
3098    PyCATCH
3099}
3100
3101
3102PyObject *SymMatrix_getValues(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "(None -> list of values)")
3103{
3104    PyTRY
3105    CAST_TO(TSymMatrix, matrix)
3106
3107    PyObject* components_list = PyList_New(0);
3108
3109    int i,j;
3110    for (i = 0; i < matrix->dim; i++) {
3111        for (j = i+1; j < matrix->dim; j++) {
3112            double value = 0;
3113            if (matrix->matrixType == 0)
3114                value = matrix->getitem(j,i);
3115            else
3116                value = matrix->getitem(i,j);
3117
3118            PyObject *nel = Py_BuildValue("d", value);
3119            PyList_Append(components_list, nel);
3120            Py_DECREF(nel);
3121        }
3122    }
3123
3124    return components_list;
3125    PyCATCH
3126}
3127
3128PyObject *SymMatrix_getKNN(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "((i, K) -> list of values)")
3129{
3130    PyTRY
3131    CAST_TO(TSymMatrix, matrix)
3132
3133    int kNN;
3134    int i;
3135
3136    if (!PyArg_ParseTuple(args, "ii:SymMatrix.getKNN", &i, &kNN))
3137        return PYNULL;
3138
3139    vector<int> closest;
3140    matrix->getknn(i, kNN, closest);
3141
3142    PyObject* components_list = PyList_New(0);
3143
3144    for (i = 0; i < closest.size(); i++) {
3145        PyObject *nel = Py_BuildValue("i", closest[i]);
3146        PyList_Append(components_list, nel);
3147        Py_DECREF(nel);
3148    }
3149
3150    return components_list;
3151    PyCATCH
3152}
3153
3154PyObject *SymMatrix_avgLinkage(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Clusters -> SymMatrix)")
3155{
3156    PyTRY
3157    CAST_TO(TSymMatrix, matrix);
3158
3159    PyObject *clusters;
3160
3161    if (!PyArg_ParseTuple(args, "O:SymMatrix.avgLinkage", &clusters))
3162        return PYNULL;
3163
3164    int size = PyList_Size(clusters);
3165
3166    TSymMatrix *symmatrix = new TSymMatrix(size);
3167    PSymMatrix wsymmatrix = symmatrix;
3168
3169    symmatrix->matrixType = TSymMatrix::Symmetric;
3170
3171    int i,j,k,l;
3172    for (i = 0; i < size; i++)
3173    {
3174        for (j   = i; j < size; j++)
3175        {
3176            PyObject *cluster_i = PyList_GetItem(clusters, i);
3177            PyObject *cluster_j = PyList_GetItem(clusters, j);
3178            int size_i = PyList_Size(cluster_i);
3179            int size_j = PyList_Size(cluster_j);
3180            float sum = 0;
3181            for (k = 0; k < size_i; k++)
3182            {
3183                for (l = 0; l < size_j; l++)
3184                {
3185                    int item_k = PyInt_AsLong(PyList_GetItem(cluster_i, k));
3186                    int item_l = PyInt_AsLong(PyList_GetItem(cluster_j, l));
3187
3188                    if (item_k >= matrix->dim || item_l >= matrix->dim)
3189                        raiseError("index out of range");
3190
3191                    sum += matrix->getitem(item_k, item_l);
3192                }
3193            }
3194
3195            sum /= (size_i * size_j);
3196            symmatrix->getref(i, j) = sum;
3197        }
3198    }
3199
3200    PyObject *pysymmatrix = WrapOrange(wsymmatrix);
3201    return pysymmatrix;
3202
3203    PyCATCH
3204}
3205
3206PyObject *SymMatrix_invert(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Invert type -> None)")
3207{
3208    /* ******************
3209     * Types:
3210     * 0 - [-X]
3211     * 1 - [1 - X]
3212     * 2 - [max - X]
3213     * 3 - [1 / X]
3214     ********************/
3215    PyTRY
3216    int type;
3217
3218    if (!PyArg_ParseTuple(args, "i:SymMatrix.invert", &type))
3219        return NULL;
3220
3221    if (type < 0 || type > 3)
3222        PYERROR(PyExc_AttributeError, "only types 0 to 3  are supported", PYNULL);
3223
3224    CAST_TO(TSymMatrix, matrix);
3225    int i;
3226    float *e = matrix->elements;
3227    switch(type)
3228    {
3229        case 0:
3230            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3231                *e = 0 - *e;
3232            break;
3233
3234        case 1:
3235            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3236                *e = 1 - *e;
3237            break;
3238
3239        case 2:
3240            float maxval;
3241            maxval = 0;
3242
3243            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3244                if (*e > maxval)
3245                    maxval = *e;
3246
3247            e = matrix->elements;
3248            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3249                *e = maxval - *e;
3250
3251            break;
3252
3253        case 3:
3254            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3255                if (*e == 0)
3256                    raiseError("division by zero");
3257                *e = 1 / *e;
3258            break;
3259    }
3260
3261    RETURN_NONE;
3262    PyCATCH
3263}
3264
3265PyObject *SymMatrix_normalize(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Normalize type -> None)")
3266{
3267    /* ******************
3268     * Types:
3269     * 0 - [0, 1]
3270     * 1 - Sigmoid
3271     ********************/
3272    PyTRY
3273    int type;
3274
3275    if (!PyArg_ParseTuple(args, "i:SymMatrix.normalize", &type))
3276        return NULL;
3277
3278    if (type < 0 || type > 1)
3279        PYERROR(PyExc_AttributeError, "only types 0 and 1 are supported", PYNULL);
3280
3281    CAST_TO(TSymMatrix, matrix);
3282    int i;
3283    float *e = matrix->elements;
3284    float maxval = *e;
3285    float minval = *e;
3286    switch(type)
3287    {
3288        case 0:
3289            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++) {
3290                if (*e > maxval)
3291                    maxval = *e;
3292
3293                if (*e < minval)
3294                    minval = *e;
3295            }
3296            //cout << "minval: " << minval << endl;
3297            //cout << "maxval: " << maxval << endl;
3298
3299            e = matrix->elements;
3300            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3301                *e = (*e - minval) / (maxval - minval);
3302            break;
3303
3304        case 1:
3305            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3306                *e = 1 / (1 + exp(-(*e)));
3307            break;
3308    }
3309
3310    RETURN_NONE;
3311    PyCATCH
3312}
3313
3314PyObject *SymMatrix_get_items(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(List of items -> SymMatrix)")
3315{
3316    PyTRY
3317    CAST_TO(TSymMatrix, matrix);
3318
3319    PyObject *items;
3320
3321    if (!PyArg_ParseTuple(args, "O:SymMatrix.get_items", &items))
3322        return PYNULL;
3323
3324    int size = PyList_Size(items);
3325    PyList_Sort(items);
3326
3327    TSymMatrix *symmatrix = new TSymMatrix(size);
3328    PSymMatrix wsymmatrix = symmatrix;
3329
3330    symmatrix->matrixType = matrix->matrixType;
3331
3332    int i,j;
3333    for (i = 0; i < size; i++)
3334    {
3335        for (j = i; j < size; j++)
3336        {
3337            if (symmatrix->matrixType == TSymMatrix::Lower || symmatrix->matrixType == TSymMatrix::LowerFilled)
3338            {
3339                int item_i = PyInt_AsLong(PyList_GetItem(items, j));
3340                int item_j = PyInt_AsLong(PyList_GetItem(items, i));
3341
3342                float value = matrix->getitem(item_i, item_j);
3343                symmatrix->getref(j, i) = value;
3344            }
3345            else
3346            {
3347                int item_i = PyInt_AsLong(PyList_GetItem(items, i));
3348                int item_j = PyInt_AsLong(PyList_GetItem(items, j));
3349
3350                float value = matrix->getitem(item_i, item_j);
3351                symmatrix->getref(i, j) = value;
3352            }
3353        }
3354    }
3355
3356    PyObject *pysymmatrix = WrapOrange(wsymmatrix);
3357    return pysymmatrix;
3358    PyCATCH
3359}
3360
3361PyObject *SymMatrix_getitem_sq(PyObject *self, Py_ssize_t i)
3362{
3363    PyTRY
3364        CAST_TO(TSymMatrix, matrix)
3365        int dim = matrix->dim;
3366
3367    if (i >= matrix->dim) {
3368        PyErr_Format(PyExc_IndexError, "index %i out of range 0-%i", i, matrix->dim-1);
3369        return PYNULL;
3370    }
3371
3372    Py_ssize_t j;
3373    PyObject *row;
3374    switch (matrix->matrixType) {
3375            case TSymMatrix::Lower:
3376                row = PyTuple_New(i+1);
3377                for(j = 0; j<=i; j++)
3378                    PyTuple_SetItem(row, j, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3379                return row;
3380
3381            case TSymMatrix::Upper:
3382                row = PyTuple_New(matrix->dim - i);
3383                for(j = i; j<dim; j++)
3384                    PyTuple_SetItem(row, j-i, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3385                return row;
3386
3387            default:
3388                row = PyTuple_New(matrix->dim);
3389                for(j = 0; j<dim; j++)
3390                    PyTuple_SetItem(row, j, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3391                return row;
3392    }
3393    PyCATCH
3394}
3395
3396
3397
3398PyObject *SymMatrix_getitem(PyObject *self, PyObject *args)
3399{
3400    PyTRY
3401        CAST_TO(TSymMatrix, matrix)
3402
3403        if ((PyTuple_Check(args) && (PyTuple_Size(args) == 1)) || PyInt_Check(args)) {
3404            if (PyTuple_Check(args)) {
3405                args = PyTuple_GET_ITEM(args, 0);
3406                if (!PyInt_Check(args))
3407                    PYERROR(PyExc_IndexError, "integer index expected", PYNULL);
3408            }
3409
3410            return SymMatrix_getitem_sq(self, (int)PyInt_AsLong(args));
3411        }
3412
3413        else if (PyTuple_Size(args) == 2) {
3414            if (!PyInt_Check(PyTuple_GET_ITEM(args, 0)) || !PyInt_Check(PyTuple_GET_ITEM(args, 1)))
3415                PYERROR(PyExc_IndexError, "integer indices expected", PYNULL);
3416
3417            const int i = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
3418            const int j = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
3419            if ((j>i) && (matrix->matrixType == TSymMatrix::Lower))
3420                PYERROR(PyExc_IndexError, "index out of range for lower triangular matrix", PYNULL);
3421
3422            if ((j<i) && (matrix->matrixType == TSymMatrix::Upper))
3423                PYERROR(PyExc_IndexError, "index out of range for upper triangular matrix", PYNULL);
3424
3425            return PyFloat_FromDouble(matrix->getitem(i, j));
3426        }
3427
3428        PYERROR(PyExc_IndexError, "one or two integer indices expected", PYNULL);
3429        PyCATCH
3430}
3431
3432
3433int SymMatrix_setitem(PyObject *self, PyObject *args, PyObject *obj)
3434{
3435    PyTRY
3436        if (PyTuple_Size(args) == 1)
3437            PYERROR(PyExc_AttributeError, "cannot set entire matrix row", -1);
3438
3439    if (PyTuple_Size(args) != 2)
3440        PYERROR(PyExc_IndexError, "two integer indices expected", -1);
3441
3442    PyObject *pyfl = PyNumber_Float(obj);
3443    if (!pyfl)
3444        PYERROR(PyExc_TypeError, "invalid matrix elements; a number expected", -1);
3445    float f = PyFloat_AsDouble(pyfl);
3446    Py_DECREF(pyfl);
3447
3448    const int i = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
3449    const int j = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
3450
3451    SELF_AS(TSymMatrix).getref(i, j) = f;
3452    return 0;
3453    PyCATCH_1
3454}
3455
3456
3457PyObject *SymMatrix_getslice(PyObject *self, Py_ssize_t start, Py_ssize_t stop)
3458{
3459    PyTRY
3460        CAST_TO(TSymMatrix, matrix)
3461        const int dim = matrix->dim;
3462
3463    if (start>dim)
3464        start = dim;
3465    else if (start<0)
3466        start = 0;
3467
3468    if (stop>dim)
3469        stop=dim;
3470
3471    PyObject *res = PyTuple_New(stop - start);
3472    int i = 0;
3473    while(start<stop)
3474        PyTuple_SetItem(res, i++, SymMatrix_getitem_sq(self, start++));
3475
3476    return res;
3477    PyCATCH
3478}
3479
3480
3481PyObject *SymMatrix_str(PyObject *self)
3482{ PyTRY
3483CAST_TO(TSymMatrix, matrix)
3484const int dim = matrix->dim;
3485const int mattype = matrix->matrixType;
3486
3487float matmax = 0.0;
3488for(float *ei = matrix->elements, *ee = matrix->elements + ((dim*(dim+1))>>1); ei != ee; ei++) {
3489    const float tei = *ei<0 ? fabs(10.0 * *ei) : *ei;
3490    if (tei > matmax)
3491        matmax = tei;
3492}
3493
3494const int plac = 4 + (fabs(matmax) < 1 ? 1 : int(ceil(log10((double)matmax))));
3495const int elements = (matrix->matrixType == TSymMatrix::Lower) ? (dim*(dim+1))>>1 : dim * dim;
3496char *smatr = new char[3 * dim + (plac+2) * elements];
3497char *sptr = smatr;
3498*(sptr++) = '(';
3499*(sptr++) = '(';
3500
3501int i, j;
3502for(i = 0; i<dim; i++) {
3503    switch (mattype) {
3504                case TSymMatrix::Lower:
3505                    for(j = 0; j<i; j++, sptr += (plac+2))
3506                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3507                    break;
3508
3509                case TSymMatrix::Upper:
3510                    for(j = i * (plac+2); j--; *(sptr++) = ' ');
3511                    for(j = i; j < dim-1; j++, sptr += (plac+2))
3512                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3513                    break;
3514
3515                default:
3516                    for(j = 0; j<dim-1; j++, sptr += (plac+2))
3517                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3518    }
3519
3520    sprintf(sptr, "%*.3f)", plac, matrix->getitem(i, j));
3521    sptr += (plac+1);
3522
3523    if (i!=dim-1) {
3524        sprintf(sptr, ",\n (");
3525        sptr += 4;
3526    }
3527}
3528
3529sprintf(sptr, ")");
3530
3531PyObject *res = PyString_FromString(smatr);
3532mldelete smatr;
3533return res;
3534PyCATCH
3535}
3536
3537
3538PyObject *SymMatrix_repr(PyObject *self)
3539{ return SymMatrix_str(self); }
3540
3541
3542#include "hclust.hpp"
3543
3544C_NAMED(HierarchicalCluster - Orange.clustering.hierarchical.HierarchicalCluster, Orange, "()")
3545C_CALL3(HierarchicalClustering - Orange.clustering.hierarchical.HierarchicalClustering, HierarchicalClustering, Orange, "(linkage=)")
3546
3547C_CALL3(HierarchicalClusterOrdering, HierarchicalClusterOrdering, Orange, "(progressCallback=)")
3548
3549PyObject *HierarchicalClustering_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(distance matrix) -> HierarchicalCluster")
3550{
3551    PyTRY
3552        NO_KEYWORDS
3553
3554        PSymMatrix symmatrix;
3555
3556    if (!PyArg_ParseTuple(args, "O&:HierarchicalClustering", cc_SymMatrix, &symmatrix))
3557        return NULL;
3558
3559    PHierarchicalCluster root = SELF_AS(THierarchicalClustering)(symmatrix);
3560
3561    if (symmatrix->myWrapper->orange_dict) {
3562        PyObject *objects = PyDict_GetItemString(symmatrix->myWrapper->orange_dict, "objects");
3563        TPyOrange *pymapping = root->mapping->myWrapper;
3564        if (objects && (objects != Py_None)) {
3565            if (!pymapping->orange_dict)
3566                pymapping->orange_dict = PyOrange_DictProxy_New(pymapping);
3567            PyDict_SetItemString(pymapping->orange_dict, "objects", objects);
3568        }
3569    }
3570    return WrapOrange(root);
3571    PyCATCH
3572}
3573
3574PyObject * HierarchicalClusterOrdering_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(hierarchical cluster, distance_matrix) -> None")
3575{
3576    PyTRY
3577        NO_KEYWORDS
3578        PHierarchicalCluster root;
3579        PSymMatrix matrix;
3580        if (!PyArg_ParseTuple(args, "O&O&:HierarchicalClustering", cc_HierarchicalCluster, &root, cc_SymMatrix, &matrix))
3581            return NULL;
3582        SELF_AS(THierarchicalClusterOrdering).operator ()(root, matrix);
3583        RETURN_NONE
3584    PyCATCH
3585}
3586
3587Py_ssize_t HierarchicalCluster_len_sq(PyObject *self)
3588{
3589    CAST_TO_err(THierarchicalCluster, cluster, -1);
3590    return cluster->last - cluster->first;
3591}
3592
3593
3594PyObject *HierarchicalCluster_getitem_sq(PyObject *self, Py_ssize_t i)
3595{
3596    PyTRY
3597        CAST_TO(THierarchicalCluster, cluster);
3598
3599    if (!cluster->mapping)
3600        PYERROR(PyExc_SystemError, "'HierarchicalCluster' misses 'mapping'", PYNULL);
3601
3602    i += (i>=0) ? cluster->first : cluster->last;
3603    if ((i < cluster->first) || (i >= cluster->last)) {
3604        PyErr_Format(PyExc_IndexError, "index out of range 0-%i", cluster->last - cluster->first - 1);
3605        return PYNULL;
3606    }
3607
3608    if (i >= cluster->mapping->size())
3609        PYERROR(PyExc_SystemError, "internal inconsistency in instance of 'HierarchicalCluster' ('mapping' too short)", PYNULL);
3610
3611    const int elindex = cluster->mapping->at(i);
3612
3613    if (cluster->mapping->myWrapper->orange_dict) {
3614        PyObject *objs = PyDict_GetItemString(cluster->mapping->myWrapper->orange_dict, "objects");
3615        if (objs && (objs != Py_None))
3616            return PySequence_GetItem(objs, elindex);
3617    }
3618
3619    return PyInt_FromLong(elindex);
3620    PyCATCH
3621}
3622
3623
3624PyObject *HierarchicalCluster_get_left(PyObject *self)
3625{
3626    PyTRY
3627        CAST_TO(THierarchicalCluster, cluster);
3628
3629    if (!cluster->branches)
3630        RETURN_NONE
3631
3632        if (cluster->branches->size() > 2)
3633            PYERROR(PyExc_AttributeError, "'left' not defined (cluster has more than two subclusters)", PYNULL);
3634
3635    return WrapOrange(cluster->branches->front());
3636    PyCATCH
3637}
3638
3639
3640PyObject *HierarchicalCluster_get_right(PyObject *self)
3641{
3642    PyTRY
3643        CAST_TO(THierarchicalCluster, cluster);
3644
3645    if (!cluster->branches || (cluster->branches->size() < 2))
3646        RETURN_NONE;
3647
3648    if (cluster->branches->size() > 2)
3649        PYERROR(PyExc_AttributeError, "'right' not defined (cluster has more than two subclusters", PYNULL);
3650
3651    return WrapOrange(cluster->branches->back());
3652    PyCATCH
3653}
3654
3655
3656int HierarchicalClusterLowSet(PyObject *self, PyObject *arg, const int side)
3657{
3658    PyTRY
3659        static const char *sides[2] = {"left", "right"};
3660
3661    if (!PyOrHierarchicalCluster_Check(arg)) {
3662        PyErr_Format(PyExc_TypeError, "'HierarchicalCluster.%s' should be of type 'HierarchicalCluster' (got '%s')", sides[side], arg->ob_type->tp_name);
3663        return -1;
3664    }
3665
3666    CAST_TO_err(THierarchicalCluster, cluster, -1);
3667
3668    if (!cluster->branches)
3669        cluster->branches = mlnew THierarchicalClusterList(2);
3670    else
3671        if (cluster->branches->size() != 2)
3672            PYERROR(PyExc_AttributeError, "'left' not defined (cluster does not have (exactly) two subclusters)", -1);
3673
3674    cluster->branches->at(side) = PyOrange_AsHierarchicalCluster(arg);
3675    return 0;
3676    PyCATCH_1
3677}
3678
3679
3680int HierarchicalCluster_set_left(PyObject *self, PyObject *arg)
3681{
3682    return HierarchicalClusterLowSet(self, arg, 0);
3683}
3684
3685int HierarchicalCluster_set_right(PyObject *self, PyObject *arg)
3686{
3687    return HierarchicalClusterLowSet(self, arg, 1);
3688}
3689
3690
3691PyObject *HierarchicalCluster_swap(PyObject *self, PyObject *arg, PyObject *keyw) PYARGS(METH_NOARGS, "() -> None; swaps the sub clusters")
3692{
3693    PyTRY
3694        SELF_AS(THierarchicalCluster).swap();
3695    RETURN_NONE;
3696    PyCATCH
3697}
3698
3699PyObject *HierarchicalCluster_permute(PyObject *self, PyObject *arg, PyObject *keys) PYARGS(METH_O, "(permutation) -> None")
3700{
3701    PyTRY
3702        PIntList ilist = ListOfUnwrappedMethods<PIntList, TIntList, int>::P_FromArguments(arg);
3703    if (!ilist)
3704        return PYNULL;
3705
3706    SELF_AS(THierarchicalCluster).permute(ilist.getReference());
3707    RETURN_NONE;
3708    PyCATCH
3709}
3710
3711
3712PHierarchicalClusterList PHierarchicalClusterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::P_FromArguments(arg); }
3713PyObject *HierarchicalClusterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_FromArguments(type, arg); }
3714PyObject *HierarchicalClusterList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange - Orange.clustering.hierarchical.HierarchicalClusterList, "(<list of HierarchicalCluster>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_new(type, arg, kwds); }
3715PyObject *HierarchicalClusterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_getitem(self, index); }
3716int       HierarchicalClusterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_setitem(self, index, item); }
3717PyObject *HierarchicalClusterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_getslice(self, start, stop); }
3718int       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); }
3719Py_ssize_t       HierarchicalClusterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_len(self); }
3720PyObject *HierarchicalClusterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_richcmp(self, object, op); }
3721PyObject *HierarchicalClusterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_concat(self, obj); }
3722PyObject *HierarchicalClusterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_repeat(self, times); }
3723PyObject *HierarchicalClusterList_str(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_str(self); }
3724PyObject *HierarchicalClusterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_str(self); }
3725int       HierarchicalClusterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_contains(self, obj); }
3726PyObject *HierarchicalClusterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(HierarchicalCluster) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_append(self, item); }
3727PyObject *HierarchicalClusterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_extend(self, obj); }
3728PyObject *HierarchicalClusterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> int") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_count(self, obj); }
3729PyObject *HierarchicalClusterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> HierarchicalClusterList") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_filter(self, args); }
3730PyObject *HierarchicalClusterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> int") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_index(self, obj); }
3731PyObject *HierarchicalClusterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_insert(self, args); }
3732PyObject *HierarchicalClusterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_native(self); }
3733PyObject *HierarchicalClusterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> HierarchicalCluster") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_pop(self, args); }
3734PyObject *HierarchicalClusterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_remove(self, obj); }
3735PyObject *HierarchicalClusterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_reverse(self); }
3736PyObject *HierarchicalClusterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_sort(self, args); }
3737PyObject *HierarchicalClusterList__reduce__(TPyOrange *self, PyObject *) PYARGS(METH_VARARGS, "()") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_reduce(self); }
3738
3739
3740
3741
3742#include "distancemap.hpp"
3743
3744C_NAMED(DistanceMapConstructor - Orange.distance.DistanceMapConstructor, Orange, "(distanceMatrix=, order=)")
3745
3746
3747
3748PyObject *DistanceMapConstructor_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(squeeze) -> DistanceMap")
3749{
3750    PyTRY
3751        NO_KEYWORDS
3752
3753        float squeeze = 1.0;
3754    if (!PyArg_ParseTuple(args, "|f:DistanceMapConstructor.__call__", &squeeze))
3755        return NULL;
3756
3757    float absLow, absHigh;
3758    PDistanceMap dm = SELF_AS(TDistanceMapConstructor).call(squeeze, absLow, absHigh);
3759    return Py_BuildValue("Nff", WrapOrange(dm), absLow, absHigh);
3760    PyCATCH
3761}
3762
3763
3764PyObject *DistanceMapConstructor_getLegend(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(width, height, gamma) -> bitmap")
3765{
3766    PyTRY
3767        int width, height;
3768    float gamma;
3769    if (!PyArg_ParseTuple(args, "iif:DistanceMapConstructor.getLegend", &width, &height, &gamma))
3770        return NULL;
3771
3772    long size;
3773    unsigned char *bitmap = SELF_AS(TDistanceMapConstructor).getLegend(width, height, gamma, size);
3774    PyObject *res = PyString_FromStringAndSize((const char *)bitmap, (Py_ssize_t)size);
3775    delete bitmap;
3776    return res;
3777    PyCATCH
3778}
3779
3780
3781BASED_ON(DistanceMap - Orange.distance.DistanceMap, Orange)
3782
3783PyObject *DistanceMap__reduce__(PyObject *self)
3784{
3785    PyTRY
3786        CAST_TO(TDistanceMap, matrix);
3787    const int dim = matrix->dim;
3788    return Py_BuildValue("O(Os#iO)N", getExportedFunction("__pickleLoaderDistanceMap"),
3789        self->ob_type,
3790        matrix->cells, dim*dim*sizeof(float),
3791        dim,
3792        WrapOrange(matrix->elementIndices),
3793        packOrangeDictionary(self));
3794    PyCATCH
3795}
3796
3797
3798PyObject *__pickleLoaderDistanceMap(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension, elementIndices)")
3799{
3800    PyTRY
3801        PyTypeObject *type;
3802    char *buf;
3803    int bufSize, dim;
3804    PIntList elementIndices;
3805    if (!PyArg_ParseTuple(args, "Os#iO&:__pickleLoaderDistanceMap", &type, &buf, &bufSize, &dim, ccn_IntList, &elementIndices))
3806        return NULL;
3807
3808    TDistanceMap *cm = new TDistanceMap(dim);
3809    memcpy(cm->cells, buf, bufSize);
3810    cm->elementIndices = elementIndices;
3811    return WrapNewOrange(cm, type);
3812    PyCATCH
3813}
3814
3815
3816PyObject *DistanceMap_getBitmap(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "(cell_width, cell_height, lowerBound, upperBound, gamma) -> bitmap")
3817{
3818    PyTRY
3819        int cellWidth, cellHeight;
3820    float absLow, absHigh, gamma;
3821    int grid = 1;
3822    int matrixType = 2;
3823    if (!PyArg_ParseTuple(args, "iifff|ii:Heatmap.getBitmap", &cellWidth, &cellHeight, &absLow, &absHigh, &gamma, &grid, &matrixType))
3824        return NULL;
3825
3826    CAST_TO(TDistanceMap, dm)
3827
3828        long size;
3829    unsigned char *bitmap = dm->distanceMap2string(cellWidth, cellHeight, absLow, absHigh, gamma, grid!=0, matrixType, size);
3830    PyObject *res = Py_BuildValue("s#ii", (const char *)bitmap, size, cellWidth * dm->dim, cellHeight * dm->dim);
3831    delete bitmap;
3832    return res;
3833    PyCATCH
3834}
3835
3836
3837PyObject *DistanceMap_getCellIntensity(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(row, column) -> float")
3838{
3839    PyTRY
3840        int row, column;
3841    if (!PyArg_ParseTuple(args, "ii:DistanceMap.getCellIntensity", &row, &column))
3842        return NULL;
3843
3844    const float ci = SELF_AS(TDistanceMap).getCellIntensity(row, column);
3845    if (ci == ILLEGAL_FLOAT)
3846        RETURN_NONE;
3847
3848    return PyFloat_FromDouble(ci);
3849    PyCATCH
3850}
3851
3852
3853PyObject *DistanceMap_getPercentileInterval(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(lower_percentile, upper_percentile) -> (min, max)")
3854{
3855    PyTRY
3856        float lowperc, highperc;
3857    if (!PyArg_ParseTuple(args, "ff:DistanceMap_percentileInterval", &lowperc, &highperc))
3858        return PYNULL;
3859
3860    float minv, maxv;
3861    SELF_AS(TDistanceMap).getPercentileInterval(lowperc, highperc, minv, maxv);
3862    return Py_BuildValue("ff", minv, maxv);
3863    PyCATCH
3864}
3865
3866
3867
3868#include "graph.hpp"
3869
3870extern PyTypeObject PyEdge_Type;
3871
3872/* If objectsOnEdges==true, this is a proxy object; double's are actualy PyObject *,
3873but the references are owned by the graph. */
3874class TPyEdge {
3875public:
3876    PyObject_HEAD
3877
3878        PGraph graph;
3879    int v1, v2;
3880    double *weights;
3881    bool objectsOnEdges;
3882    int weightsVersion;
3883
3884    inline double *getWeights()
3885    {
3886        if (weightsVersion != (weights ? graph->lastAddition : graph->lastRemoval)) {
3887            weights = graph->getEdge(v1, v2);
3888            weightsVersion = graph->currentVersion;
3889        }
3890        return weights;
3891    }
3892};
3893
3894
3895#define DOUBLE_AS_PYOBJECT(x) (*(PyObject **)(void *)(&(x)))
3896PyObject *PyEdge_Getitem(TPyEdge *self, Py_ssize_t ind)
3897{
3898    PyTRY
3899        if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3900            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", ind, self->graph->nEdgeTypes);
3901            return PYNULL;
3902        }
3903
3904        if (self->getWeights()) {
3905            const double w = self->weights[ind];
3906
3907            if (!CONNECTED(w))
3908                RETURN_NONE;
3909
3910            if (self->objectsOnEdges) {
3911                Py_INCREF(DOUBLE_AS_PYOBJECT(w));
3912                return DOUBLE_AS_PYOBJECT(w);
3913            }
3914            else
3915                return PyFloat_FromDouble(w);
3916        }
3917
3918        else
3919            RETURN_NONE;
3920        PyCATCH
3921}
3922
3923
3924int PyEdge_Contains(TPyEdge *self, PyObject *pyind)
3925{
3926    PyTRY
3927        if (!PyInt_Check(pyind))
3928            PYERROR(PyExc_IndexError, "edge types must be integers", -1);
3929
3930    int ind = int(PyInt_AsLong(pyind));
3931    if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3932        PyErr_Format(PyExc_IndexError, "edge type %i out of range (0-%i)", ind, self->graph->nEdgeTypes);
3933        return -1;
3934    }
3935
3936    return self->getWeights() && CONNECTED(self->weights[ind]) ? 1 : 0;
3937    PyCATCH_1
3938}
3939
3940
3941int PyEdge_Setitem(TPyEdge *self, Py_ssize_t ind, PyObject *item)
3942{
3943    PyTRY
3944        if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3945            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", ind, self->graph->nEdgeTypes);
3946            return -1;
3947        }
3948
3949        double w;
3950        bool noConnection = !item || (item == Py_None);
3951        if (noConnection)
3952            DISCONNECT(w);
3953        else {
3954            if (!self->objectsOnEdges && !PyNumber_ToDouble(item, w))
3955                PYERROR(PyExc_TypeError, "a number expected for edge weight", -1);
3956        }
3957
3958
3959        if (self->getWeights()) {
3960            if (self->objectsOnEdges) {
3961                // watch the order: first INCREF, then DECREF!
3962                if (!noConnection)
3963                    Py_INCREF(item);
3964                if (CONNECTED(self->weights[ind]))
3965                    Py_DECREF(DOUBLE_AS_PYOBJECT(self->weights[ind]));
3966
3967                DOUBLE_AS_PYOBJECT(self->weights[ind]) = item;
3968            }
3969
3970            else
3971                self->weights[ind] = w;
3972
3973            if (noConnection) {
3974                double *w, *we;
3975                for(w = self->weights, we = self->weights + self->graph->nEdgeTypes; (w != we) && !CONNECTED(*w); w++);
3976                if (w == we) {
3977                    self->graph->removeEdge(self->v1, self->v2);
3978                    self->weights = NULL;
3979                    self->weightsVersion = self->graph->currentVersion;
3980                }
3981            }
3982        }
3983
3984        else {
3985            if (!noConnection) {
3986                double *weights = self->weights = self->graph->getOrCreateEdge(self->v1, self->v2);
3987
3988                if (self->objectsOnEdges) {
3989                    DOUBLE_AS_PYOBJECT(weights[ind]) = item;
3990                    Py_INCREF(item);
3991                }
3992                else
3993                    weights[ind] = w;
3994
3995                self->weightsVersion = self->graph->currentVersion;
3996            }
3997        }
3998
3999        return 0;
4000        PyCATCH_1
4001}
4002
4003
4004/*
4005// I've programmed this by mistake; but it's nice, so let it stay
4006// for the case we need it :)
4007PyObject *PyEdge_Str(TPyEdge *self)
4008{
4009PyTRY
4010int nEdgeTypes = self->graph->nEdgeTypes;
4011
4012if (!self->getWeights()) {
4013if (nEdgeTypes == 1)
4014RETURN_NONE;
4015else {
4016PyObject *res = PyTuple_New(nEdgeTypes);
4017while(nEdgeTypes--) {
4018Py_INCREF(Py_None);
4019PyTuple_SET_ITEM(res, nEdgeTypes, Py_None);
4020}
4021return res;
4022}
4023}
4024
4025if (nEdgeTypes == 1)
4026return PyFloat_FromDouble(*self->weights);
4027else {
4028PyObject *res = PyTuple_New(nEdgeTypes);
4029int i = 0;
4030for(double weights = self->weights; i != nEdgeTypes; weights++, i++)
4031PyTuple_SET_ITEM(res, i, PyFloat_FromDouble(*weights));
4032return res;
4033}
4034PyCATCH
4035}
4036*/
4037
4038PyObject *PyEdge_Str(TPyEdge *self)
4039{
4040    PyTRY
4041        int nEdgeTypes = self->graph->nEdgeTypes;
4042    char *buf;
4043
4044    if (!self->getWeights()) {
4045        if (nEdgeTypes == 1)
4046            return PyString_FromString("None");
4047        else {
4048            buf = new char[nEdgeTypes*6 + 2];
4049            char *b2 = buf;
4050            *b2++ = '(';
4051            while(nEdgeTypes--) {
4052                strcpy(b2, "None, ");
4053                b2 += 6;
4054            }
4055            b2[-1] = 0;
4056            b2[-2] = ')';
4057        }
4058    }
4059
4060    else {
4061        if (self->objectsOnEdges) {
4062            if (nEdgeTypes == 1)
4063                return PyObject_Str(DOUBLE_AS_PYOBJECT(*self->weights));
4064            else {
4065                PyObject *dump = PyString_FromString("(");
4066                PyString_ConcatAndDel(&dump, PyObject_Str(DOUBLE_AS_PYOBJECT(*self->weights)));
4067
4068                for(double *wi = self->weights+1, *we = self->weights + self->graph->nEdgeTypes; wi != we; wi++) {
4069                    PyString_ConcatAndDel(&dump, PyString_FromString(", "));
4070                    PyString_ConcatAndDel(&dump, PyObject_Str(DOUBLE_AS_PYOBJECT(*wi)));
4071                }
4072
4073                PyString_ConcatAndDel(&dump, PyString_FromString(")"));
4074                return dump;
4075            }
4076        }
4077        else {
4078            if (nEdgeTypes == 1) {
4079                buf = new char[20];
4080                char *b2 = buf;
4081                sprintf(b2, "%-10g", *self->weights);
4082                for(; *b2 > 32; b2++);
4083                *b2 = 0;
4084            }
4085            else {
4086                buf = new char[nEdgeTypes*20];
4087                char *b2 = buf;
4088                *b2++ = '(';
4089                for(double *weights = self->weights, *wee = weights + nEdgeTypes; weights != wee; weights++) {
4090                    if (CONNECTED(*weights)) {
4091                        sprintf(b2, "%-10g", *weights);
4092                        for(; *b2 > 32; b2++);
4093                        *b2++ = ',';
4094                        *b2++ = ' ';
4095                    }
4096                    else {
4097                        strcpy(b2, "None, ");
4098                        b2 += 6;
4099                    }
4100                }
4101                b2[-1] = 0;
4102                b2[-2] = ')';
4103            }
4104        }
4105    }
4106
4107    PyObject *res = PyString_FromString(buf);
4108    delete buf;
4109    return res;
4110    PyCATCH
4111}
4112
4113Py_ssize_t PyEdge_Len(TPyEdge *self)
4114{ return self->graph->nEdgeTypes; }
4115
4116
4117int PyEdge_Nonzero(TPyEdge *self)
4118{ return self->getWeights() ? 1 : 0; }
4119
4120
4121int PyEdge_Traverse(TPyEdge *self, visitproc visit, void *arg)
4122{ PVISIT(self->graph)
4123return 0;
4124}
4125
4126
4127int PyEdge_Clear(TPyEdge *self)
4128{ self->graph = POrange();
4129return 0;
4130}
4131
4132
4133void PyEdge_Dealloc(TPyEdge *self)
4134{
4135    self->graph.~PGraph();
4136    self->ob_type->tp_free((PyObject *)self);
4137}
4138
4139
4140PyObject *PyEdge_Richcmp(TPyEdge *self, PyObject *j, int op)
4141{
4142    double ref;
4143    if (self->graph->nEdgeTypes != 1)
4144        PYERROR(PyExc_TypeError, "multiple-type edges cannot be compared", PYNULL);
4145
4146    if (self->graph->nEdgeTypes != 1)
4147        PYERROR(PyExc_TypeError, "multiple-type edges cannot be compared to floats", PYNULL);
4148
4149    if (!self->getWeights() || !CONNECTED(*self->weights))
4150        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4151
4152    if (self->objectsOnEdges)
4153        return PyObject_RichCompare(DOUBLE_AS_PYOBJECT(*self->weights), j, op);
4154
4155    if (!PyNumber_ToDouble(j, ref))
4156        PYERROR(PyExc_TypeError, "edge weights can only be compared to floats", PYNULL);
4157
4158    const double &f = *self->weights;
4159
4160    int cmp;
4161    switch (op) {
4162case Py_LT: cmp = (f<ref); break;
4163case Py_LE: cmp = (f<=ref); break;
4164case Py_EQ: cmp = (f==ref); break;
4165case Py_NE: cmp = (f!=ref); break;
4166case Py_GT: cmp = (f>ref); break;
4167case Py_GE: cmp = (f>=ref); break;
4168default:
4169    Py_INCREF(Py_NotImplemented);
4170    return Py_NotImplemented;
4171    }
4172
4173    PyObject *res;
4174    if (cmp)
4175        res = Py_True;
4176    else
4177        res = Py_False;
4178    Py_INCREF(res);
4179    return res;
4180}
4181
4182
4183PyObject *PyEdge_Float(TPyEdge *self)
4184{
4185    if (self->graph->nEdgeTypes != 1)
4186        PYERROR(PyExc_TypeError, "multiple-type edges cannot be cast to floats", PYNULL);
4187
4188    if (!self->getWeights() || !CONNECTED(*self->weights))
4189        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4190
4191    return self->objectsOnEdges ? PyNumber_Float(DOUBLE_AS_PYOBJECT(*self->weights)) : PyFloat_FromDouble(*self->weights);
4192}
4193
4194PyObject *PyEdge_Int(TPyEdge *self)
4195{
4196    if (self->graph->nEdgeTypes != 1)
4197        PYERROR(PyExc_TypeError, "multiple-type edges cannot be cast to numbers", PYNULL);
4198
4199    if (!self->getWeights() || !CONNECTED(*self->weights))
4200        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4201
4202    return self->objectsOnEdges ? PyNumber_Int(DOUBLE_AS_PYOBJECT(*self->weights)) : PyInt_FromLong(long(*self->weights));
4203}
4204
4205
4206PyNumberMethods PyEdge_as_number = {
4207    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4208    (inquiry)PyEdge_Nonzero,                           /* nb_nonzero */
4209    0, 0, 0, 0, 0, 0, 0,
4210    (unaryfunc)PyEdge_Int,    /* nb_int */
4211    0,
4212    (unaryfunc)PyEdge_Float,  /* nb_float */
4213    0, 0,
4214};
4215
4216static PySequenceMethods PyEdge_as_sequence = {
4217    (lenfunc)PyEdge_Len,                    /* sq_length */
4218    0,                  /* sq_concat */
4219    0,                  /* sq_repeat */
4220    (ssizeargfunc)PyEdge_Getitem,                   /* sq_item */
4221    0,                  /* sq_slice */
4222    (ssizeobjargproc)PyEdge_Setitem,                    /* sq_ass_item */
4223    0,                  /* sq_ass_slice */
4224    (objobjproc)PyEdge_Contains,        /* sq_contains */
4225    0,                  /* sq_inplace_concat */
4226    0,                  /* sq_inplace_repeat */
4227};
4228
4229PyTypeObject PyEdge_Type = {
4230    PyObject_HEAD_INIT(&PyType_Type)
4231    0,                  /* ob_size */
4232    "Graph.Edge",           /* tp_name */
4233    sizeof(TPyEdge),            /* tp_basicsize */
4234    0,                  /* tp_itemsize */
4235    /* methods */
4236    (destructor)PyEdge_Dealloc,         /* tp_dealloc */
4237    0,                  /* tp_print */
4238    0,                  /* tp_getattr */
4239    0,                  /* tp_setattr */
4240    0,                  /* tp_compare */
4241    (reprfunc)PyEdge_Str,                   /* tp_repr */
4242    &PyEdge_as_number,                  /* tp_as_number */
4243    &PyEdge_as_sequence,                    /* tp_as_sequence */
4244    0,                  /* tp_as_mapping */
4245    0,                  /* tp_hash */
4246    0,                  /* tp_call */
4247    (reprfunc)PyEdge_Str,                   /* tp_str */
4248    0,      /* tp_getattro */
4249    0,                  /* tp_setattro */
4250    0,                  /* tp_as_buffer */
4251    Py_TPFLAGS_DEFAULT,         /* tp_flags */
4252    0,                  /* tp_doc */
4253    (traverseproc)PyEdge_Traverse,                  /* tp_traverse */
4254    (inquiry)PyEdge_Clear,                  /* tp_clear */
4255    (richcmpfunc)PyEdge_Richcmp,                    /* tp_richcompare */
4256    0,                  /* tp_weaklistoffset */
4257    0,          /* tp_iter */
4258    0,  /* tp_iternext */
4259    0,                  /* tp_methods */
4260    0,                  /* tp_members */
4261    0,                  /* tp_getset */
4262    0,                  /* tp_base */
4263    0,                  /* tp_dict */
4264    0,                  /* tp_descr_get */
4265    0,                  /* tp_descr_set */
4266    0,                  /* tp_dictoffset */
4267    0,                             /* tp_init */
4268    PyType_GenericAlloc,                               /* tp_alloc */
4269    0,                               /* tp_new */
4270    _PyObject_GC_Del,                                  /* tp_free */
4271};
4272
4273
4274PYXTRACT_IGNORE int Orange_traverse(TPyOrange *self, visitproc visit, void *arg);
4275PYXTRACT_IGNORE int Orange_clear(TPyOrange *self);
4276PYXTRACT_IGNORE void Orange_dealloc(TPyOrange *self);
4277
4278
4279inline bool hasObjectsOnEdges(PyObject *graph)
4280{
4281    PyObject *dict = ((TPyOrange *)graph)->orange_dict;
4282    PyObject *ooe = NULL;
4283    if (dict) {
4284        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4285        if (!ooe) {
4286            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4287        }
4288    }
4289    return ooe && (PyObject_IsTrue(ooe) != 0);
4290}
4291
4292inline bool hasObjectsOnEdges(PGraph graph)
4293{
4294    PyObject *dict = graph->myWrapper->orange_dict;
4295    PyObject *ooe = NULL;
4296    if (dict) {
4297        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4298        if (!ooe) {
4299            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4300        }
4301    }
4302    return ooe && (PyObject_IsTrue(ooe) != 0);
4303}
4304
4305inline bool hasObjectsOnEdges(const TGraph *graph)
4306{
4307    PyObject *dict = graph->myWrapper->orange_dict;
4308    PyObject *ooe = NULL;
4309    if (dict) {
4310        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4311        if (!ooe) {
4312            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4313        }
4314    }
4315    return ooe && (PyObject_IsTrue(ooe) != 0);
4316}
4317
4318void decrefEdge(double *weights, const int &nEdgeTypes)
4319{
4320    if (weights)
4321        for(double *we = weights, *wee = weights + nEdgeTypes; we != wee; we++)
4322            if (CONNECTED(*we))
4323                Py_DECREF(DOUBLE_AS_PYOBJECT(*we));
4324}
4325
4326PyObject *PyEdge_New(PGraph graph, const int &v1, const int &v2, double *weights)
4327{
4328    TPyEdge *self = PyObject_GC_New(TPyEdge, &PyEdge_Type);
4329    if (self == NULL)
4330        return NULL;
4331
4332    // The object constructor has never been called, so we must initialize it
4333    // before assigning to it
4334    self->graph.init();
4335
4336    self->graph = graph;
4337    self->v1 = v1;
4338    self->v2 = v2;
4339    self->weights = weights;
4340    self->objectsOnEdges = hasObjectsOnEdges(graph);
4341
4342    PyObject_GC_Track(self);
4343    return (PyObject *)self;
4344}
4345
4346
4347ABSTRACT(Graph, Orange)
4348RECOGNIZED_ATTRIBUTES(Graph, "objects forceMapping force_mapping returnIndices return_indices objectsOnEdges object_on_edges")
4349
4350int Graph_getindex(TGraph *graph, PyObject *index)
4351{
4352    if (PyInt_Check(index)) {
4353        if (!graph->myWrapper->orange_dict)
4354            return PyInt_AsLong(index);
4355        PyObject *fmap = PyDict_GetItemString(graph->myWrapper->orange_dict, "force_mapping");
4356        if (!fmap) {
4357            fmap = PyDict_GetItemString(graph->myWrapper->orange_dict, "forceMapping");
4358        }
4359        if (!fmap || PyObject_IsTrue(fmap))
4360            return PyInt_AsLong(index);
4361    }
4362
4363    if (graph->myWrapper->orange_dict) {
4364        PyObject *objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "objects");
4365        if (objs && (objs != Py_None)) {
4366
4367            if (PyDict_Check(objs)) {
4368                PyObject *pyidx = PyDict_GetItem(objs, index);
4369                if (!pyidx)
4370                    return -1;
4371                if (!PyInt_Check(pyidx))
4372                    PYERROR(PyExc_IndexError, "vertex index should be an integer", -1);
4373                return PyInt_AsLong(pyidx);
4374            }
4375
4376            PyObject *iter = PyObject_GetIter(objs);
4377            if (!iter)
4378                PYERROR(PyExc_IndexError, "Graph.object should be iterable", -1);
4379            int i = 0;
4380
4381            for(PyObject *item = PyIter_Next(iter); item; item = PyIter_Next(iter), i++) {
4382                int cmp = PyObject_Compare(item, index);
4383                Py_DECREF(item);
4384                if (PyErr_Occurred())
4385                    return -1;
4386                if (!cmp) {
4387                    Py_DECREF(iter);
4388                    return i;
4389                }
4390            }
4391
4392            Py_DECREF(iter);
4393            PYERROR(PyExc_IndexError, "index not found", -1);
4394        }
4395    }
4396
4397    PYERROR(PyExc_IndexError, "invalid index type: should be integer (or 'objects' must be specified)", -1);
4398}
4399
4400
4401PyObject *Graph_nodesToObjects(TGraph *graph, const vector<int> &neighbours)
4402{
4403    if (graph->myWrapper->orange_dict) {
4404        PyObject *objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "returnIndices");
4405        if (!objs || (PyObject_IsTrue(objs) == 0)) {
4406            objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "objects");
4407            if (objs && (objs != Py_None)) {
4408                PyObject *res = PyList_New(neighbours.size());
4409
4410                if (PyDict_Check(objs)) {
4411                    // This is slow, but can't help...
4412                    int el = 0;
4413                    PyObject *key, *value;
4414                    Py_ssize_t pos = 0;
4415
4416                    while (PyDict_Next(objs, &pos, &key, &value))
4417                        if (!PyInt_Check(value)) {
4418                            Py_DECREF(res);
4419                            PYERROR(PyExc_IndexError, "values in Graph.objects dictionary should be integers", PYNULL);
4420                        }
4421
4422                        for(vector<int>::const_iterator ni(neighbours.begin()), ne(neighbours.end()); ni!=ne; ni++, el++) {
4423                            pos = 0;
4424                            bool set = false;
4425                            while (PyDict_Next(objs, &pos, &key, &value) && !set) {
4426                                if (PyInt_AsLong(value) == *ni) {
4427                                    Py_INCREF(key);
4428                                    PyList_SetItem(res, el, key);
4429                                    set = true;
4430                                }
4431                            }
4432
4433                            if (!set) {
4434                                Py_DECREF(res);
4435                                PyErr_Format(PyExc_IndexError, "'objects' miss the key for vertex %i", *ni);
4436                                return PYNULL;
4437                            }
4438                        }
4439                }
4440                else {
4441                    Py_ssize_t el = 0;
4442                    for(vector<int>::const_iterator ni(neighbours.begin()), ne(neighbours.end()); ni!=ne; ni++, el++) {
4443                        PyObject *pyel = PySequence_GetItem(objs, *ni);
4444                        if (!pyel) {
4445                            Py_DECREF(res);
4446                            return PYNULL;
4447                        }
4448                        else
4449                            PyList_SetItem(res, el, pyel);
4450                    }
4451                }
4452                return res;
4453            }
4454        }
4455    }
4456
4457    return convertToPython(neighbours);
4458}
4459
4460
4461PyObject *Graph_getitem(PyObject *self, PyObject *args)
4462{
4463    PyTRY
4464        CAST_TO(TGraph, graph);
4465
4466    PyObject *py1, *py2;
4467    int v1, v2, type = -1;
4468
4469    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4470        || ((v1 = Graph_getindex(graph, py1)) < 0)
4471        || ((v2 = Graph_getindex(graph, py2)) < 0))
4472        return PYNULL;
4473
4474    if (PyTuple_Size(args) == 2) {
4475        PGraph graph = PyOrange_AS_Orange(self);
4476        return PyEdge_New(graph, v1, v2, graph->getEdge(v1, v2));
4477    }
4478
4479    else {
4480        PGraph graph = PyOrange_AS_Orange(self);
4481        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4482            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", type, graph->nEdgeTypes);
4483            return PYNULL;
4484        }
4485        double *weights = graph->getEdge(v1, v2);
4486        if (!weights || !CONNECTED(weights[type]))
4487            RETURN_NONE
4488        else {
4489            if (hasObjectsOnEdges(graph)) {
4490                PyObject *res = DOUBLE_AS_PYOBJECT(weights[type]);
4491                Py_INCREF(res);
4492                return res;
4493            }
4494            else
4495                return PyFloat_FromDouble(weights[type]);
4496        }
4497    }
4498    PyCATCH
4499}
4500
4501
4502PyObject *Graph_edgeExists(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(v1, v2[, type])")
4503{
4504    PyTRY
4505        CAST_TO(TGraph, graph);
4506
4507    PyObject *py1, *py2;
4508    int v1, v2, type = -1;
4509
4510    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4511        || ((v1 = Graph_getindex(graph, py1)) < 0)
4512        || ((v2 = Graph_getindex(graph, py2)) < 0))
4513        return PYNULL;
4514
4515    if (PyTuple_Size(args) == 2)
4516        return PyInt_FromLong(graph->getEdge(v1, v2) ? 1 : 0);
4517
4518    else {
4519        PGraph graph = PyOrange_AS_Orange(self);
4520        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4521            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", type, graph->nEdgeTypes);
4522            return PYNULL;
4523        }
4524        double *weights = graph->getEdge(v1, v2);
4525        return PyInt_FromLong(!weights || !CONNECTED(weights[type]) ? 0 : 1);
4526    }
4527    PyCATCH
4528}
4529
4530int Graph_setitem(PyObject *self, PyObject *args, PyObject *item)
4531{
4532    PyTRY
4533        CAST_TO_err(TGraph, graph, -1);
4534    bool objectsOnEdges = hasObjectsOnEdges(graph);
4535
4536    PyObject *py1, *py2;
4537    int v1, v2, type = -1;
4538
4539    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4540        || ((v1 = Graph_getindex(graph, py1)) < 0)
4541        || ((v2 = Graph_getindex(graph, py2)) < 0))
4542        return -1;
4543
4544    if (PyTuple_Size(args) == 3) {
4545        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4546            PyErr_Format(PyExc_IndexError, "type %i out of range (0-%i)", type, graph->nEdgeTypes);
4547            return -1;
4548        }
4549
4550        double w;
4551
4552        bool noConnection = !item || (item == Py_None);
4553
4554        if (noConnection)
4555            DISCONNECT(w);
4556        else
4557            if (!objectsOnEdges && !PyNumber_ToDouble(item, w))
4558                PYERROR(PyExc_TypeError, "a number expected for edge weight", -1);
4559
4560        // we call getOrCreateEdge only after we check all arguments, so we don't end up
4561        // with a half-created edge
4562        double *weights = graph->getOrCreateEdge(v1, v2);
4563
4564        if (objectsOnEdges) {
4565            if (!noConnection)
4566                Py_INCREF(item);
4567            if (CONNECTED(weights[type]))
4568                Py_DECREF(DOUBLE_AS_PYOBJECT(weights[type]));
4569
4570            DOUBLE_AS_PYOBJECT(weights[type]) = item;
4571        }
4572        else {
4573            weights[type] = w;
4574        }
4575
4576        if (noConnection) {
4577            double *we, *wee;
4578            for(we = weights, wee = weights + graph->nEdgeTypes; (we != wee) && !CONNECTED(*we); we++);
4579            if (we == wee)
4580                graph->removeEdge(v1, v2);
4581        }
4582
4583        return 0;
4584    }
4585
4586    else {
4587        if (!item || (item == Py_None)) {
4588            if (objectsOnEdges)
4589                decrefEdge(graph->getEdge(v1, v2), graph->nEdgeTypes);
4590            graph->removeEdge(v1, v2);
4591            return 0;
4592        }
4593
4594        if (graph->nEdgeTypes == 1) {
4595            double w;
4596            if (objectsOnEdges || PyNumber_ToDouble(item, w)) {
4597                double *weights = graph->getOrCreateEdge(v1, v2);
4598                if (objectsOnEdges) {
4599                    DOUBLE_AS_PYOBJECT(*weights) = item;
4600                    Py_INCREF(item);
4601                }
4602                else
4603                    *weights = w;
4604                return 0;
4605            }
4606        }
4607
4608        if (PySequence_Check(item)) {
4609            if (PySequence_Size(item) != graph->nEdgeTypes)
4610                PYERROR(PyExc_AttributeError, "invalid size of the list of edge weights", -1);
4611
4612            double *ww = new double[graph->nEdgeTypes];
4613            double *wwi = ww;
4614            PyObject *iterator = PyObject_GetIter(item);
4615            if (iterator) {
4616                for(PyObject *item = PyIter_Next(iterator); item; item = PyIter_Next(iterator)) {
4617                    if (item == Py_None)
4618                        DISCONNECT(*(wwi++));
4619                    else
4620                        if (objectsOnEdges) {
4621                            DOUBLE_AS_PYOBJECT(*wwi++) = item;
4622                        }
4623                        else {
4624                            if (!PyNumber_ToDouble(item, *(wwi++))) {
4625                                Py_DECREF(item);
4626                                Py_DECREF(iterator);
4627                                PyErr_Format(PyExc_TypeError, "invalid number for edge type %i", wwi-ww-1);
4628                                delete ww;
4629                                return -1;
4630                            }
4631                            Py_DECREF(item); // no Py_DECREF if objectsOnEdges!
4632                        }
4633                }
4634                Py_DECREF(iterator);
4635            }
4636
4637            double *weights = graph->getOrCreateEdge(v1, v2);
4638            if (objectsOnEdges)
4639                decrefEdge(weights, graph->nEdgeTypes);
4640            memcpy(weights, ww, graph->nEdgeTypes * sizeof(double));
4641            return 0;
4642        }
4643    }
4644
4645    PYERROR(PyExc_AttributeError, "arguments for __setitem__ are [v1, v2, type] = weight|None,  [v1, v2] = list | weight (if nEdgeType=1)", -1);
4646    PyCATCH_1
4647}
4648
4649
4650PyObject *Graph_getNeighbours(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
4651{
4652    PyTRY
4653        CAST_TO(TGraph, graph);
4654
4655    PyObject *pyv;
4656    int vertex, edgeType = -1;
4657    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
4658        || ((vertex = Graph_getindex(graph, pyv)) < 0))
4659        return PYNULL;
4660
4661    vector<int> neighbours;
4662    if (PyTuple_Size(args) == 1)
4663        graph->getNeighbours(vertex, neighbours);
4664    else
4665        graph->getNeighbours(vertex, edgeType, neighbours);
4666
4667    return Graph_nodesToObjects(graph, neighbours);
4668    PyCATCH
4669}
4670
4671
4672PyObject *Graph_getEdgesFrom(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
4673{
4674    PyTRY
4675        CAST_TO(TGraph, graph);
4676
4677    PyObject *pyv;
4678    int vertex, edgeType = -1;
4679    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
4680        || ((vertex = Graph_getindex(graph, pyv)) < 0))
4681        return PYNULL;
4682
4683    vector<int> neighbours;
4684    if (PyTuple_Size(args) == 1)
4685        graph->getNeighboursFrom(vertex, neighbours);
4686    else
4687        graph->getNeighboursFrom(vertex, edgeType, neighbours);
4688
4689    return Graph_nodesToObjects(graph, neighbours);
4690    PyCATCH
4691}
4692
4693PyObject *Graph_addCluster(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> None")
4694{
4695    PyTRY
4696        CAST_TO(TGraph, graph);
4697
4698    PyObject *pyv;
4699
4700    if (!PyArg_ParseTuple(args, "O:Graph.addCluster", &pyv))
4701        return PYNULL;
4702
4703    Py_ssize_t size = PyList_Size(pyv);
4704    int i,j;
4705    for (i = 0; i < size-1; i++)
4706    {
4707        for (j = i+1; j < size; j++)
4708        {
4709            int x = PyInt_AsLong(PyList_GetItem(pyv, i));
4710            int y = PyInt_AsLong(PyList_GetItem(pyv, j));
4711            //cout << x << " " << y;
4712            double* weight = graph->getOrCreateEdge(x, y);
4713            *weight = 1.0;
4714            //cout << "." << endl;
4715        }
4716    }
4717
4718    RETURN_NONE;
4719    PyCATCH
4720}
4721
4722bool lessLength (const set<int>& s1, const set<int>& s2)
4723{
4724    return s1.size() > s2.size();
4725}
4726
4727bool moreLength (const vector<int>& s1, const vector<int>& s2)
4728{
4729    return s1.size() > s2.size();
4730}
4731
4732PyObject *Graph_getConnectedComponents(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_NOARGS, "None -> list of [nodes]")
4733{
4734    PyTRY
4735    CAST_TO(TGraph, graph);
4736    //cout << "Graph_getConnectedComponents" << endl;
4737    int node = 0;
4738    vector<set<int> > components;
4739    set<int> all;
4740
4741    while (node < graph->nVertices)
4742    {
4743        set<int> component = graph->getConnectedComponent(node);
4744        components.push_back(component);
4745        all.insert(component.begin(), component.end());
4746
4747        while(node < graph->nVertices)
4748        {
4749            node++;
4750            if (all.find(node) == all.end())
4751                break;
4752        }
4753    }
4754    sort(components.begin(), components.end(), lessLength);
4755
4756    PyObject* components_list = PyList_New(0);
4757
4758    ITERATE(vector<set<int> >, si, components) {
4759        PyObject* component_list = PyList_New(0);
4760
4761        ITERATE(set<int>, ni, *si) {
4762            PyObject *nel = Py_BuildValue("i", *ni);
4763            PyList_Append(component_list, nel);
4764            Py_DECREF(nel);
4765        }
4766
4767        PyList_Append(components_list, component_list);
4768        Py_DECREF(component_list);
4769    }
4770
4771    return components_list;
4772    PyCATCH
4773}
4774
4775PyObject *Graph_getDegreeDistribution(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(distribution)")
4776{
4777    PyTRY
4778        CAST_TO(TGraph, graph);
4779
4780        PyObject* degrees = PyDict_New();
4781        PyObject *nsize, *pydegree;
4782
4783        int v;
4784        for (v = 0; v < graph->nVertices; v++)
4785        {
4786            vector<int> neighbours;
4787            graph->getNeighbours(v, neighbours);
4788            nsize = PyInt_FromLong(neighbours.size());
4789
4790            pydegree = PyDict_GetItem(degrees, nsize); // returns borrowed reference!
4791            int newdegree = pydegree ? PyInt_AsLong(pydegree) + 1 : 1;
4792
4793            pydegree = PyInt_FromLong(newdegree);
4794      PyDict_SetItem(degrees, nsize, pydegree);
4795      Py_DECREF(pydegree);
4796        }
4797
4798        return degrees;
4799    PyCATCH
4800}
4801
4802PyObject *Graph_getDegrees(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "degrees")
4803{
4804    PyTRY
4805        CAST_TO(TGraph, graph);
4806
4807        PyObject* degrees = PyList_New(graph->nVertices);
4808        for(int v1 = 0; v1 < graph->nVertices; v1++)
4809        {
4810            PyList_SetItem(degrees, v1,  PyInt_FromLong(0));
4811        }
4812
4813        vector<int> neighbours;
4814        for(int v1 = 0; v1 < graph->nVertices; v1++)
4815        {
4816            graph->getNeighboursFrom_Single(v1, neighbours);
4817
4818            ITERATE(vector<int>, ni, neighbours)
4819            {
4820                int v1_degree = PyInt_AsLong(PyList_GetItem(degrees, v1));
4821                int v2_degree = PyInt_AsLong(PyList_GetItem(degrees, *ni));
4822
4823                v2_degree++;
4824                v1_degree++;
4825
4826                PyList_SetItem(degrees, v1,  PyInt_FromLong(v1_degree));
4827                PyList_SetItem(degrees, *ni, PyInt_FromLong(v2_degree));
4828            }
4829        }
4830
4831        if (!graph->directed) {
4832            for(int v1 = 0; v1 < graph->nVertices; v1++) {
4833                int v1_degree = PyInt_AsLong(PyList_GetItem(degrees, v1));
4834                PyList_SetItem(degrees, v1,  PyInt_FromLong(v1_degree / 2));
4835            }
4836        }
4837
4838        return degrees;
4839    PyCATCH
4840}
4841
4842
4843PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference);
4844
4845PyObject *Graph_getSubGraph(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
4846{
4847    PyTRY
4848    CAST_TO(TGraph, graph);
4849    //cout << "Graph_getSubGraph" << endl;
4850    PyObject *vertices;
4851
4852    if (!PyArg_ParseTuple(args, "O:Graph.getSubGraph", &vertices))
4853        return PYNULL;
4854
4855    Py_ssize_t size = PyList_Size(vertices);
4856    PyList_Sort(vertices);
4857
4858    TGraph *subgraph = new TGraphAsList(size, graph->nEdgeTypes, graph->directed);
4859    PGraph wsubgraph = subgraph;
4860
4861    Py_ssize_t i;
4862    vector<int> neighbours;
4863    for (i = 0; i < size; i++) {
4864        int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
4865
4866        graph->getNeighboursFrom_Single(vertex, neighbours);
4867        ITERATE(vector<int>, ni, neighbours) {
4868            if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1) {
4869                int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4870
4871                if (index != -1) {
4872                    double* w = subgraph->getOrCreateEdge(i, index);
4873                    double* oldw = graph->getOrCreateEdge(vertex, *ni);
4874                    int j;
4875                    for (j=0; j < subgraph->nEdgeTypes; j++) {
4876                        w[j] = oldw[j];
4877                    }
4878                }
4879            }
4880        }
4881    }
4882
4883    PyObject *pysubgraph = WrapOrange(wsubgraph); //WrapNewOrange(subgraph, self->ob_type);
4884
4885    // set graphs attribut items of type ExampleTable to subgraph
4886    PyObject *strItems = PyString_FromString("items");
4887    if (PyObject_HasAttr(self, strItems) == 1) {
4888        PyObject* items = PyObject_GetAttr(self, strItems);
4889        /*
4890        cout << PyObject_IsTrue(items) << endl;
4891        cout << PyObject_Size(items) << endl;
4892        cout << graph->nVertices << endl;
4893        */
4894        if (PyObject_IsTrue(items) && PyObject_Size(items) == graph->nVertices) {
4895            PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
4896            Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
4897        }
4898    }
4899    Py_DECREF(strItems);
4900    return pysubgraph;
4901    PyCATCH
4902}
4903
4904
4905PyObject *Graph_getSubGraphMergeCluster(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
4906{
4907    PyTRY
4908        CAST_TO(TGraph, graph);
4909
4910        PyObject *verticesWithout;
4911        PyObject *vertices = PyList_New(0);
4912
4913        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphMergeCluster", &verticesWithout))
4914            return PYNULL;
4915
4916        // create an array of vertices to be in a new graph
4917        int i;
4918        vector<int> neighbours;
4919        for (i = 0; i < graph->nVertices; i++)
4920        {
4921      if (PySequence_Contains(verticesWithout, PyInt_FromLong(i)) == 0)
4922            {
4923        PyObject *nel = Py_BuildValue("i", i);
4924              PyList_Append(vertices, nel);
4925              Py_DECREF(nel);
4926      }
4927    }
4928
4929        // create new graph without cluster
4930        Py_ssize_t size = PyList_Size(vertices);
4931        PyList_Sort(vertices);
4932
4933        TGraph *subgraph = new TGraphAsList(size + 1, graph->nEdgeTypes, graph->directed);
4934        PGraph wsubgraph = subgraph;
4935
4936        for (i = 0; i < size; i++)
4937        {
4938            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
4939
4940            graph->getNeighboursFrom_Single(vertex, neighbours);
4941            ITERATE(vector<int>, ni, neighbours)
4942            {
4943                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
4944                {
4945                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4946
4947                    if (index != -1)
4948                    {
4949                        double* w = subgraph->getOrCreateEdge(i, index);
4950                        *w = 1.0;
4951                    }
4952                }
4953            }
4954        }
4955        // connect new meta-node with all verties
4956        int sizeWithout = PyList_Size(verticesWithout);
4957        for (i = 0; i < sizeWithout; i++)
4958        {
4959            int vertex = PyInt_AsLong(PyList_GetItem(verticesWithout, i));
4960
4961            graph->getNeighbours(vertex, neighbours);
4962            ITERATE(vector<int>, ni, neighbours)
4963            {
4964                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
4965                {
4966                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4967
4968                    if (index != -1)
4969                    {
4970                        double* w = subgraph->getOrCreateEdge(size, index);
4971                        *w = 1.0;
4972                    }
4973                }
4974            }
4975        }
4976
4977        PyObject *pysubgraph = WrapOrange(wsubgraph);
4978
4979        // set graphs attribut items of type ExampleTable to subgraph
4980    PyObject *strItems = PyString_FromString("items");
4981
4982        if (PyObject_HasAttr(self, strItems) == 1)
4983        {
4984            PyObject* items = PyObject_GetAttr(self, strItems);
4985      PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
4986
4987      PExampleTable graph_table = PyOrange_AsExampleTable(selection);
4988      TExample *example = new TExample(graph_table->domain, true);
4989      graph_table->push_back(example);
4990      Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
4991    }
4992
4993      Py_DECREF(strItems);
4994
4995        return pysubgraph;
4996    PyCATCH
4997}
4998
4999
5000PyObject *Graph_getSubGraphMergeClusters(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "List of (vertices) -> list of [v1, v2, ..., vn]")
5001{
5002    PyTRY
5003        CAST_TO(TGraph, graph);
5004
5005        set<int> verticesWithout;
5006        PyObject *fullGraphs;
5007        PyObject *vertices = PyList_New(0);
5008
5009        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphMergeClusters", &fullGraphs))
5010            return PYNULL;
5011
5012        // create an array of vertices to remove from the graph
5013        Py_ssize_t sizeFullGraphs = PyList_Size(fullGraphs);
5014        int i;
5015        for (i = 0; i < sizeFullGraphs; i++)
5016        {
5017            PyObject *fullGraph = PyList_GetItem(fullGraphs, i);
5018            Py_ssize_t sizeFullGraph = PyList_Size(fullGraph);
5019
5020            int j;
5021            for (j = 0; j < sizeFullGraph; j++)
5022            {
5023                int vertex = PyInt_AsLong(PyList_GetItem(fullGraph, j));
5024                verticesWithout.insert(vertex);
5025            }
5026        }
5027
5028        vector<int> neighbours;
5029        // create an array of vertices to be in a new graph
5030        for (i = 0; i < graph->nVertices; i++)
5031        {
5032            set<int>::iterator it = verticesWithout.find(i);
5033            if (it == verticesWithout.end())
5034            {
5035        PyObject *nel = Py_BuildValue("i", i);
5036              PyList_Append(vertices, nel);
5037              Py_DECREF(nel);
5038      }
5039    }
5040
5041        // create new graph without cluster
5042        Py_ssize_t size = PyList_Size(vertices);
5043        PyList_Sort(vertices);
5044
5045        TGraph *subgraph = new TGraphAsList(size + sizeFullGraphs, graph->nEdgeTypes, graph->directed);
5046        PGraph wsubgraph = subgraph;
5047
5048        for (i = 0; i < size; i++)
5049        {
5050            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5051
5052            graph->getNeighboursFrom_Single(vertex, neighbours);
5053            ITERATE(vector<int>, ni, neighbours)
5054            {
5055                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5056                {
5057                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5058
5059                    if (index != -1)
5060                    {
5061                        double* w = subgraph->getOrCreateEdge(i, index);
5062                        *w = 1.0;
5063                    }
5064                }
5065            }
5066        }
5067        // connect new meta-node with all verties
5068        for (i = 0; i < sizeFullGraphs; i++)
5069        {
5070            PyObject *fullGraph = PyList_GetItem(fullGraphs, i);
5071            Py_ssize_t sizeFullGraph = PyList_Size(fullGraph);
5072            int j;
5073            for (j = 0; j < sizeFullGraph; j++)
5074            {
5075                int vertex = PyInt_AsLong(PyList_GetItem(fullGraph, j));
5076                graph->getNeighbours(vertex, neighbours);
5077
5078                // connect with old neighbours
5079                ITERATE(vector<int>, ni, neighbours)
5080                {
5081                    if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5082                    {
5083                        // vertex to connect with is in new graph
5084                        int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5085
5086                        if (index != -1)
5087                        {
5088                            double* w = subgraph->getOrCreateEdge(size + i, index);
5089                            *w = 1.0;
5090                        }
5091                    }
5092                    else
5093                    {
5094                        // vertex to connect with is a new meta node
5095                        int k;
5096                        for (k = 0; k < sizeFullGraphs; k++)
5097                        {
5098                            PyObject *fullGraph = PyList_GetItem(fullGraphs, k);
5099
5100                            if (PySequence_Contains(fullGraph, PyInt_FromLong(*ni)) == 1)
5101                            {
5102                                if (k != i)
5103                                {
5104                                    double* w = subgraph->getOrCreateEdge(size + i, size + k);
5105                                    *w = 1.0;
5106                                }
5107                                break;
5108                            }
5109                        }
5110                    }
5111                }
5112            }
5113        }
5114
5115        PyObject *pysubgraph = WrapOrange(wsubgraph);
5116
5117        // set graphs attribut items of type ExampleTable to subgraph
5118    PyObject *strItems = PyString_FromString("items");
5119
5120        if (PyObject_HasAttr(self, strItems) == 1)
5121        {
5122            PyObject* items = PyObject_GetAttr(self, strItems);
5123      PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
5124
5125      PExampleTable graph_table = PyOrange_AsExampleTable(selection);
5126            for (i = 0; i < sizeFullGraphs; i++)
5127            {
5128                TExample *example = new TExample(graph_table->domain, true);
5129                graph_table->push_back(example);
5130            }
5131      Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
5132    }
5133
5134      Py_DECREF(strItems);
5135
5136        return pysubgraph;
5137    PyCATCH
5138}
5139
5140
5141PyObject *Graph_getSubGraphWithout(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
5142{
5143    PyTRY
5144        CAST_TO(TGraph, graph);
5145
5146        PyObject *verticesWithout;
5147        PyObject *vertices = PyList_New(0);
5148
5149        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphWithout", &verticesWithout))
5150            return PYNULL;
5151
5152    int i;
5153    for (i = 0; i < graph->nVertices; i++)
5154        {
5155      if (PySequence_Contains(verticesWithout, PyInt_FromLong(i)) == 0)
5156            {
5157        PyObject *nel = Py_BuildValue("i", i);
5158              PyList_Append(vertices, nel);
5159              Py_DECREF(nel);
5160      }
5161    }
5162
5163        Py_ssize_t size = PyList_Size(vertices);
5164        PyList_Sort(vertices);
5165
5166        TGraph *subgraph = new TGraphAsList(size, graph->nEdgeTypes, graph->directed);
5167        PGraph wsubgraph = subgraph;
5168
5169        vector<int> neighbours;
5170        for (i = 0; i < size; i++)
5171        {
5172            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5173
5174            graph->getNeighboursFrom_Single(vertex, neighbours);
5175            ITERATE(vector<int>, ni, neighbours)
5176            {
5177                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5178                {
5179                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5180
5181                    if (index != -1)
5182                    {
5183                        double* w = subgraph->getOrCreateEdge(i, index);
5184                        *w = 1.0;
5185                    }
5186                }
5187            }
5188        }
5189
5190        // set graphs attribut items of type ExampleTable to subgraph
5191        /*
5192        TExampleTable *table;
5193        PExampleTable wtable;
5194
5195        if (PyObject_HasAttr(self, PyString_FromString("items")) == 1)
5196        {
5197            PyObject* items = PyObject_GetAttr(self, PyString_FromString("items"));
5198
5199            PExampleTable graph_table;
5200            if (PyArg_ParseTuple(PyTuple_Pack(1,items), "O", &graph_table))
5201            {
5202
5203                table = new TExampleTable(graph_table->domain);
5204                wtable = table;
5205
5206                for (i = 0; i < size; i++)
5207                {
5208                    int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5209
5210                    graph_table.
5211                }
5212
5213                //PyObject_SetAttr((PyObject *)subgraph, PyString_FromString("items"), Py_BuildValue("N", WrapOrange(wtable)));
5214            }
5215        }
5216
5217        return Py_BuildValue("NN", WrapOrange(wsubgraph), WrapOrange(wtable));
5218        /**/
5219        return Py_BuildValue("N", WrapOrange(wsubgraph));
5220    PyCATCH
5221}
5222
5223
5224PyObject *Graph_getHubs(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(n) -> HubList")
5225{
5226  PyTRY
5227        int n;
5228
5229        if (!PyArg_ParseTuple(args, "n:Graph.getHubs", &n))
5230            return NULL;
5231
5232        CAST_TO(TGraph, graph);
5233
5234        int *vertexDegree = new int[graph->nVertices];
5235
5236        int i;
5237        for (i=0; i < graph->nVertices; i++)
5238        {
5239            vertexDegree[i] = 0;
5240        }
5241
5242
5243        vector<int> neighbours;
5244        for(i = 0; i < graph->nVertices; i++)
5245        {
5246            graph->getNeighboursFrom_Single(i, neighbours);
5247
5248            ITERATE(vector<int>, ni, neighbours)
5249            {
5250                vertexDegree[i]++;
5251                vertexDegree[*ni]++;
5252            }
5253        }
5254
5255        PyObject* hubList = PyList_New(n);
5256
5257        for (i=0; i < n; i++)
5258        {
5259            int j;
5260            int ndx_max = -1;
5261            int max = 0;
5262            for (j=0; j < graph->nVertices; j++)
5263            {
5264                if (vertexDegree[j] > max)
5265                {
5266                    ndx_max = j;
5267                    max = vertexDegree[j];
5268                }
5269            }
5270            //cout << "pow: " << vertexPower[ndx_max] << " ndx: " << ndx_max << endl;
5271
5272            vertexDegree[ndx_max] = -2;
5273            PyList_SetItem(hubList, i, PyInt_FromLong(ndx_max));
5274        }
5275
5276        delete [] vertexDegree;
5277        return hubList;
5278  PyCATCH
5279}
5280
5281
5282PyObject *Graph_getEdgesTo(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
5283{
5284    PyTRY
5285        CAST_TO(TGraph, graph);
5286
5287    PyObject *pyv;
5288    int vertex, edgeType = -1;
5289    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
5290        || ((vertex = Graph_getindex(graph, pyv)) < 0))
5291        return PYNULL;
5292
5293    vector<int> neighbours;
5294    if (PyTuple_Size(args) == 1)
5295        graph->getNeighboursTo(vertex, neighbours);
5296    else
5297        graph->getNeighboursTo(vertex, edgeType, neighbours);
5298
5299    return Graph_nodesToObjects(graph, neighbours);
5300    PyCATCH
5301}
5302
5303
5304PyObject *Graph_getEdges(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "([edgetype]) -> list of (v1, v2, weights)")
5305{
5306    PyTRY
5307        CAST_TO(TGraph, graph);
5308
5309    int edgeType = -1;
5310    if (!PyArg_ParseTuple(args, "|i:Graph.getEdges", &edgeType))
5311        return PYNULL;
5312
5313    bool hasType = (PyTuple_Size(args) != 0);
5314    if (hasType && (edgeType<0) || (edgeType >= graph->nEdgeTypes)) {
5315        PyErr_Format(PyExc_IndexError, "edge type out of range 0-%i", graph->nEdgeTypes);
5316        return PYNULL;
5317    }
5318
5319    PyObject *res = PyList_New(0);
5320    vector<int> neighbours;
5321
5322    for(int v1 = 0; v1 < graph->nVertices; v1++) {
5323        neighbours.clear();
5324        if (hasType)
5325            if (graph->directed) {
5326                graph->getNeighboursFrom(v1, edgeType, neighbours);
5327            }
5328            else {
5329                graph->getNeighboursFrom_Single(v1, edgeType, neighbours);
5330            }
5331        else
5332            if (graph->directed) {
5333                graph->getNeighboursFrom(v1, neighbours);
5334            }
5335            else {
5336                graph->getNeighboursFrom_Single(v1, neighbours);
5337            }
5338
5339        ITERATE(vector<int>, ni, neighbours) {
5340            PyObject *nel = Py_BuildValue("ii", v1, *ni);
5341            PyList_Append(res, nel);
5342            Py_DECREF(nel);
5343        }
5344    }
5345
5346    return res;
5347    PyCATCH
5348}
5349
5350PyObject *Graph_getNodes(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "neighbours -> list of (v1, v2, weights)")
5351{
5352    PyTRY
5353        CAST_TO(TGraph, graph);
5354
5355    int noOfNeighbours = -1;
5356    if (!PyArg_ParseTuple(args, "i:Graph.getNodes", &noOfNeighbours))
5357        return PYNULL;
5358
5359    PyObject *res = PyList_New(0);
5360    vector<int> neighbours;
5361
5362    for(int v1 = 0; v1 < graph->nVertices; v1++) {
5363            graph->getNeighbours(v1, neighbours);
5364
5365      if (neighbours.size() == noOfNeighbours)
5366      {
5367              PyObject *nel = Py_BuildValue("i", v1);
5368              PyList_Append(res, nel);
5369              Py_DECREF(nel);
5370          }
5371    }
5372
5373    return res;
5374    PyCATCH
5375}
5376
5377PyObject *Graph_getShortestPaths(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS