source: orange/source/orange/lib_components.cpp @ 11336:da96782f1c2b

Revision 11336:da96782f1c2b, 197.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 14 months ago (diff)

Fixed argument parsing in probability estimator constructors.

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        if (*argp == Py_None){
2462            dist = PDistribution();
2463            argp++;
2464        } else {
2465            dist = PyOrange_AsDistribution(*argp++);
2466        }
2467
2468        if ((argp != argc) && PyOrDistribution_Check(*argp))
2469            apriori = PyOrange_AsDistribution(*argp++);
2470    }
2471    if (argp != argc) {
2472        gen = exampleGenFromParsedArgs(*argp);
2473        if (gen) {
2474            argp++;
2475            if ((argp != argc) && !weightFromArg_byDomain(*(argp++), gen->domain, weightID))
2476                return PYNULL;
2477        }
2478    }
2479
2480    if (argp != argc)
2481        PYERROR(PyExc_TypeError, "Invalid arguments for 'ProbabilityEstimatorConstructor.call'", PYNULL);
2482
2483    return WrapOrange(cest->call(dist, apriori, gen, weightID));
2484    PyCATCH
2485}
2486
2487
2488PyObject *ProbabilityEstimator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(Value) -> float  |  () -> Distribution")
2489{ PyTRY
2490NO_KEYWORDS
2491
2492CAST_TO(TProbabilityEstimator, cest);
2493
2494PyObject *pyobj = PYNULL;
2495if (!PyArg_ParseTuple(args, "|O:ProbabilityEstimator.call", &pyobj))
2496return PYNULL;
2497
2498if (pyobj) {
2499    TValue val;
2500    if (!convertFromPython(pyobj, val))
2501        PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2502    return PyFloat_FromDouble((double)cest->call(val));
2503}
2504
2505else
2506return WrapOrange(cest->call());
2507PyCATCH
2508}
2509
2510
2511
2512PyObject *ConditionalProbabilityEstimatorConstructor_call(PyObject *self, PyObject *uargs, PyObject *keywords) PYDOC("([contingency[, apriori]] [example generator[, weight]]) -> ProbabilityEstimator")
2513{
2514    PyTRY
2515        NO_KEYWORDS
2516
2517        CAST_TO(TConditionalProbabilityEstimatorConstructor, cest);
2518
2519    PyObject *args[4] = {PYNULL, PYNULL, PYNULL, PYNULL};
2520    PContingency cont, apriori;
2521    PExampleGenerator gen;
2522    int weightID = 0;
2523    if (!PyArg_UnpackTuple(uargs, "ConditionalProbabilityEstimatorConstructor.call", 0, 4, args, args+1, args+2, args+3))
2524        return PYNULL;
2525
2526    PyObject **argp = args, **argc = args;
2527    for (int i=0; i<=3; i++, argp++)
2528        if (*argp)
2529            *argc++ = *argp;
2530
2531    argp = args;
2532    if ((argp != argc) && ((*argp==Py_None) || PyOrContingency_Check(*argp))) {
2533        if (*argp==Py_None){
2534            cont = PContingency();
2535            argp++;
2536        } else {
2537            cont = PyOrange_AsContingency(*argp++);
2538        }
2539
2540        if ((argp != argc) && PyOrDistribution_Check(*argp))
2541            apriori = PyOrange_AsDistribution(*argp++);
2542    }
2543    if (argp != argc) {
2544        gen = exampleGenFromParsedArgs(*argp);
2545        if (gen) {
2546            argp++;
2547            if ((argp != argc) && !weightFromArg_byDomain(*(argp++), gen->domain, weightID))
2548                return PYNULL;
2549        }
2550    }
2551
2552    if (argp != argc)
2553        PYERROR(PyExc_TypeError, "Invalid arguments for 'ConditionalProbabilityEstimatorConstructor.call'", PYNULL);
2554
2555    return WrapOrange(cest->call(cont, apriori, gen, weightID));
2556    PyCATCH
2557}
2558
2559
2560PyObject *ConditionalProbabilityEstimator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(Value, Condition) -> float  |  (Condition) -> Distribution | () -> Contingency")
2561{
2562    PyTRY
2563        NO_KEYWORDS
2564
2565        CAST_TO(TConditionalProbabilityEstimator, cest);
2566
2567    PyObject *pyobj1 = PYNULL, *pyobj2 = PYNULL;
2568    if (!PyArg_ParseTuple(args, "|OO:ProbabilityEstimator.call", &pyobj1, &pyobj2))
2569        return PYNULL;
2570
2571    if (pyobj1 && pyobj2) {
2572        TValue val1, val2;
2573        if (!convertFromPython(pyobj1, val1) || !convertFromPython(pyobj2, val2))
2574            PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2575        return PyFloat_FromDouble((double)cest->call(val1, val2));
2576    }
2577
2578    else if (pyobj1) {
2579        TValue val;
2580        if (!convertFromPython(pyobj1, val))
2581            PYERROR(PyExc_TypeError, "ProbabilityEstimator.call: cannot convert the arguments to a Value", PYNULL);
2582        return WrapOrange(cest->call(val));
2583    }
2584
2585    else
2586        return WrapOrange(cest->call());
2587    PyCATCH
2588}
2589
2590#include "stat.hpp"
2591
2592/* ************ MEASURES ************ */
2593
2594#include "measures.hpp"
2595#include "relief.hpp"
2596
2597BASED_ON(MeasureAttribute - Orange.feature.scoring.Score, Orange)
2598ABSTRACT(MeasureAttributeFromProbabilities - Orange.feature.scoring.ScoreFromProbabilities, MeasureAttribute)
2599
2600C_CALL(MeasureAttribute_info - Orange.feature.scoring.InfoGain, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2601C_CALL(MeasureAttribute_gini - Orange.feature.scoring.Gini, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2602C_CALL(MeasureAttribute_gainRatio - Orange.feature.scoring.GainRatio, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2603C_CALL(MeasureAttribute_cost - Orange.feature.scoring.Cost, MeasureAttributeFromProbabilities, "(cost=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2604C_CALL(MeasureAttribute_relevance - Orange.feature.scoring.Relevance, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2605
2606C_CALL(MeasureAttribute_gainRatioA, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori) -/-> float")
2607C_CALL(MeasureAttribute_logOddsRatio, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2608C_CALL(MeasureAttribute_chiSquare, MeasureAttributeFromProbabilities, "(estimate=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2609
2610C_CALL(MeasureAttribute_MSE - Orange.feature.scoring.MSE, MeasureAttribute, "(estimate=, m=) | (attr, examples[, apriori] [,weightID]) | (attrno, domain-cont[, apriori]) | (cont, class dist [,apriori]) -/-> float")
2611
2612C_CALL(MeasureAttribute_relief - Orange.feature.scoring.Relief, MeasureAttribute, "(estimate=, m=, k=) | (attr, examples[, apriori] [,weightID]) -/-> float")
2613
2614/* obsolete: */
2615PYCONSTANT(MeasureAttribute_splitGain, (PyObject *)&PyOrMeasureAttribute_gainRatio_Type)
2616PYCONSTANT(MeasureAttribute_retis, (PyObject *)&PyOrMeasureAttribute_MSE_Type)
2617
2618
2619PYCLASSCONSTANT_FLOAT(MeasureAttribute, Rejected, ATTRIBUTE_REJECTED)
2620
2621PyObject *MeasureAttribute_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.feature.scoring.Score, "<abstract>")
2622{ if (type == (PyTypeObject *)&PyOrMeasureAttribute_Type)
2623return setCallbackFunction(WrapNewOrange(mlnew TMeasureAttribute_Python(), type), args);
2624else
2625return WrapNewOrange(mlnew TMeasureAttribute_Python(), type);
2626}
2627
2628
2629PyObject *MeasureAttribute__reduce__(PyObject *self)
2630{
2631    return callbackReduce(self, PyOrMeasureAttribute_Type);
2632}
2633
2634
2635PyObject *MeasureAttribute_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(attr, xmpls[, apr, wght]) | (attr, domcont[, apr]) | (cont, clss-dist [,apr]) -> (float, meas-type)")
2636{
2637    PyTRY
2638        NO_KEYWORDS
2639
2640        if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrMeasureAttribute_Type) {
2641            PyErr_Format(PyExc_SystemError, "MeasureAttribute.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
2642            return PYNULL;
2643        }
2644
2645        CAST_TO(TMeasureAttribute, meat)
2646
2647            PyObject *arg1;
2648        PDistribution aprClDistr;
2649
2650        // Try (contingency, class distribution, aprior class distribution)
2651
2652        PContingency contingency;
2653        PDistribution clDistr;
2654        if (PyArg_ParseTuple(args, "O&O&|O&", cc_Contingency, &contingency, cc_Distribution, &clDistr, ccn_Distribution, &aprClDistr))
2655            return PyFloat_FromDouble((double)(meat->operator()(contingency, clDistr, aprClDistr)));
2656
2657        PyErr_Clear();
2658
2659
2660        // Try (variable, domaincontingency, aprior class distribution)
2661
2662        PDomainContingency dcont;
2663        if (PyArg_ParseTuple(args, "OO&|O&", &arg1, cc_DomainContingency, &dcont, ccn_Distribution, &aprClDistr)) {
2664
2665            int attrNo;
2666
2667            if (PyInt_Check(arg1)) {
2668                attrNo = int(PyInt_AsLong(arg1));
2669                if ((attrNo<0) || (attrNo>=dcont->size())) {
2670                    PyErr_Format(PyExc_IndexError, "attribute index %i out of range for the given DomainContingency", attrNo);
2671                    return PYNULL;
2672                }
2673            }
2674
2675            else {
2676                TDomainContingency::const_iterator ci(dcont->begin()), ce(dcont->end());
2677                const bool &couter = dcont->classIsOuter;
2678
2679                if (PyOrVariable_Check(arg1)) {
2680                    PVariable var = PyOrange_AsVariable(arg1);
2681                    for(attrNo = 0; (ci!=ce) && (couter ? ((*ci)->innerVariable != var) : ((*ci)->outerVariable != var)); ci++, attrNo++);
2682
2683                    if (ci==ce) {
2684                        PyErr_Format(PyExc_IndexError, "attribute '%s' not in the given DomainContingency", var->get_name().c_str());
2685                        return PYNULL;
2686                    }
2687                }
2688
2689                else if (PyString_Check(arg1)) {
2690                    char *attrName = PyString_AsString(arg1);
2691                    for(attrNo = 0; (ci!=ce) && (couter ? ((*ci)->innerVariable->get_name()!= attrName) : ((*ci)->outerVariable->get_name()!=attrName)); ci++, attrNo++);
2692
2693                    if (ci==ce) {
2694                        PyErr_Format(PyExc_IndexError, "attribute '%s' not in the given DomainContingency", attrName);
2695                        return PYNULL;
2696                    }
2697                }
2698
2699                else {
2700                    PyErr_Format(PyExc_IndexError, "cannot guess the attribute from the object of type '%s'", arg1->ob_type->tp_name);
2701                    return PYNULL;
2702                }
2703            }
2704
2705            return PyFloat_FromDouble((double)(meat->operator()(attrNo, dcont, aprClDistr)));
2706        }
2707
2708
2709        PyErr_Clear();
2710
2711
2712        // Try (variable, examples, aprior class distribution, weight)
2713
2714        PExampleGenerator egen;
2715        if ((PyTuple_Size(args) >= 2) && pt_ExampleGenerator(PyTuple_GET_ITEM(args, 1), &egen)) {
2716
2717            // No need to INCREF (ParseArgs doesn't INCREF either)
2718            PyObject *arg3 = Py_None, *arg4 = Py_None;
2719
2720            arg1 = PyTuple_GET_ITEM(args, 0);
2721
2722            if (PyTuple_Size(args) == 4) {
2723                arg3 = PyTuple_GET_ITEM(args, 2);
2724                arg4 = PyTuple_GET_ITEM(args, 3);
2725            }
2726
2727            else if (PyTuple_Size(args) == 3) {
2728                arg4 = PyTuple_GET_ITEM(args, 2);
2729                // 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
2730                if (PyOrDistribution_Check(arg4)) {
2731                    arg3 = arg4;
2732                    arg4 = Py_None;
2733                }
2734                else
2735                    arg3 = Py_None;
2736            }
2737
2738            int weightID=0;
2739
2740            if (arg3 != Py_None)
2741                if (PyOrDistribution_Check(arg4))
2742                    aprClDistr = PyOrange_AsDistribution(arg3);
2743                else
2744                    PYERROR(PyExc_TypeError, "invalid argument 3 (Distribution or None expected)", PYNULL);
2745
2746            if (arg4 != Py_None)
2747                if (!weightFromArg_byDomain(arg4, egen->domain, weightID))
2748                    PYERROR(PyExc_TypeError, "invalid argument 4 (weightID or None expected)", PYNULL);
2749
2750            if (PyOrVariable_Check(arg1))
2751                return PyFloat_FromDouble((double)(meat->operator()(PyOrange_AsVariable(arg1), egen, aprClDistr, weightID)));
2752
2753            else if (PyInt_Check(arg1)) {
2754                int attrNo = PyInt_AsLong(arg1);
2755                if (attrNo >= (int)egen->domain->attributes->size()) {
2756                    PyErr_Format(PyExc_IndexError, "attribute index %i out of range for the given DomainContingency", attrNo);
2757                    return PYNULL;
2758                }
2759                return PyFloat_FromDouble((double)(meat->operator()(attrNo, egen, aprClDistr, weightID)));
2760            }
2761
2762            else {
2763                int attrNo;
2764                if (!varNumFromVarDom(arg1, egen->domain, attrNo))
2765                    PYERROR(PyExc_TypeError, "invalid argument 1 (attribute index, name or descriptor expected)", PYNULL);
2766
2767                return PyFloat_FromDouble((double)(meat->operator()(attrNo, egen, aprClDistr, weightID)));
2768            }
2769        }
2770
2771        PYERROR(PyExc_TypeError, "invalid set of parameters", PYNULL);
2772        return PYNULL;
2773        PyCATCH;
2774}
2775
2776
2777PyObject *MeasureAttribute_thresholdFunction(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples[, weightID]) | (contingency[, distribution]) -> list")
2778{
2779    PyTRY
2780        TFloatFloatList thresholds;
2781
2782    PyObject *pyvar;
2783    PExampleGenerator gen;
2784    int weightID = 0;
2785    if (PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_thresholdFunction", &pyvar, pt_ExampleGenerator, &gen, &weightID)) {
2786        PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2787        if (!var)
2788            return NULL;
2789
2790        SELF_AS(TMeasureAttribute).thresholdFunction(thresholds, var, gen, PDistribution(), weightID);
2791    }
2792    else {
2793        PyErr_Clear();
2794
2795        PContingency cont;
2796        PDistribution cdist;
2797        if (PyArg_ParseTuple(args, "O&|O&", cc_Contingency, &cont, ccn_Distribution, &cdist)) {
2798            if (!cdist)
2799                cdist = cont->innerDistribution;
2800
2801            SELF_AS(TMeasureAttribute).thresholdFunction(thresholds, cont, cdist);
2802        }
2803        else {
2804            PyErr_Clear();
2805            PYERROR(PyExc_TypeError, "MeasureAttribute.thresholdFunction expects a variable, generator[, weight], or contingency", PYNULL)
2806        }
2807    }
2808
2809    PyObject *res = PyList_New(thresholds.size());
2810    Py_ssize_t li = 0;
2811    for(TFloatFloatList::const_iterator ti(thresholds.begin()), te(thresholds.end()); ti != te; ti++)
2812        PyList_SetItem(res, li++, Py_BuildValue("ff", ti->first, ti->second));
2813    return res;
2814    PyCATCH;
2815}
2816
2817
2818
2819PyObject *MeasureAttribute_relief_pairGains(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> list")
2820{
2821    PyTRY
2822        PyObject *pyvar;
2823    PExampleGenerator gen;
2824    int weightID = 0;
2825    if (!PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_pairGains", &pyvar, pt_ExampleGenerator, &gen, &weightID))
2826        return NULL;
2827
2828    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2829    if (!var)
2830        return NULL;
2831
2832    TPairGainAdder pairGains;
2833    SELF_AS(TMeasureAttribute_relief).pairGains(pairGains, var, gen, weightID);
2834
2835    PyObject *res = PyList_New(pairGains.size());
2836    Py_ssize_t li = 0;
2837    for(TPairGainAdder::const_iterator ti(pairGains.begin()), te(pairGains.end()); ti != te; ti++)
2838        PyList_SetItem(res, li++, Py_BuildValue("(ff)f", ti->e1, ti->e2, ti->gain));
2839    return res;
2840    PyCATCH
2841}
2842
2843
2844PyObject *MeasureAttribute_relief_gainMatrix(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> SymMatrix")
2845{
2846    PyTRY
2847        PyObject *pyvar;
2848    PExampleGenerator gen;
2849    int weightID = 0;
2850    if (!PyArg_ParseTuple(args, "OO&|i:MeasureAttribute_gainMatrix", &pyvar, pt_ExampleGenerator, &gen, &weightID))
2851        return NULL;
2852
2853    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2854    if (!var)
2855        return NULL;
2856
2857    return WrapOrange(SELF_AS(TMeasureAttribute_relief).gainMatrix(var, gen, NULL, weightID, NULL, NULL));
2858    PyCATCH
2859}
2860
2861PyObject *MeasureAttribute_bestThreshold(PyObject *self, PyObject *args, PyObject *kwds) PYARGS(METH_VARARGS, "(attr, examples) -> list")
2862{
2863    PyTRY
2864        PyObject *pyvar;
2865    PExampleGenerator gen;
2866    int weightID = 0;
2867    float minSubset = 0.0;
2868    if (!PyArg_ParseTuple(args, "OO&|if:MeasureAttribute_thresholdFunction", &pyvar, pt_ExampleGenerator, &gen, &weightID, &minSubset))
2869        return NULL;
2870
2871    PVariable var = varFromArg_byDomain(pyvar, gen->domain);
2872    if (!var)
2873        return NULL;
2874
2875    float threshold, score;
2876    PDistribution distribution;
2877    threshold = SELF_AS(TMeasureAttribute).bestThreshold(distribution, score, var, gen, PDistribution(), weightID);
2878
2879    if (threshold == ILLEGAL_FLOAT)
2880        PYERROR(PyExc_SystemError, "cannot compute the threshold; check the number of instances etc.", PYNULL);
2881
2882    return Py_BuildValue("ffO", threshold, score, WrapOrange(distribution));
2883    PyCATCH
2884}
2885
2886/* ************ EXAMPLE CLUSTERING ************ */
2887
2888#include "exampleclustering.hpp"
2889
2890ABSTRACT(GeneralExampleClustering - Orange.feature.construction.functionDecomposition.GeneralExampleClustering, Orange)
2891C_NAMED(ExampleCluster - Orange.clustering.ExampleCluster, Orange, "([left=, right=, distance=, centroid=])")
2892C_NAMED(ExampleClusters - Orange.feature.construction.functionDecomposition.ExampleClusters, GeneralExampleClustering, "([root=, quality=]")
2893
2894
2895PyObject *GeneralExampleClustering_exampleClusters(PyObject *self) PYARGS(METH_NOARGS, "() -> ExampleClusters")
2896{
2897    PyTRY
2898        return WrapOrange(SELF_AS(TGeneralExampleClustering).exampleClusters());
2899    PyCATCH
2900}
2901
2902
2903PyObject *GeneralExampleClustering_exampleSets(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> ExampleSets")
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).exampleSets(cut));
2911    PyCATCH
2912}
2913
2914
2915PyObject *GeneralExampleClustering_classifier(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> Classifier")
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).classifier(cut));
2923    PyCATCH
2924}
2925
2926
2927PyObject *GeneralExampleClustering_feature(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([cut=0.0]) -> Variable")
2928{
2929    PyTRY
2930        float cut = 0.0;
2931    if (!PyArg_ParseTuple(args, "|f", &cut))
2932        return PYNULL;
2933
2934    return WrapOrange(SELF_AS(TGeneralExampleClustering).feature(cut));
2935    PyCATCH
2936}
2937
2938
2939#include "calibrate.hpp"
2940
2941C_CALL(ThresholdCA - Orange.wrappers.ThresholdCA, Orange, "([classifier, examples[, weightID, target value]]) -/-> (threshold, optimal CA, list of CAs))")
2942
2943PyObject *ThresholdCA_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(classifier, examples[, weightID, target value]) -> (threshold, optimal CA, list of CAs)")
2944{
2945    PyTRY
2946        NO_KEYWORDS
2947
2948        PClassifier classifier;
2949    PExampleGenerator egen;
2950    int weightID = 0;
2951    PyObject *pyvalue = NULL;
2952    int targetVal = -1;
2953
2954    if (!PyArg_ParseTuple(args, "O&O&|O&O:ThresholdCA.__call__", cc_Classifier, &classifier, pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weightID, &pyvalue))
2955        return PYNULL;
2956    if (pyvalue) {
2957        TValue classVal;
2958        if (!convertFromPython(pyvalue, classVal, classifier->classVar))
2959            return PYNULL;
2960        if (classVal.isSpecial())
2961            PYERROR(PyExc_TypeError, "invalid target value", PYNULL);
2962        targetVal = classVal.intV;
2963    }
2964
2965    TFloatFloatList *ffl = mlnew TFloatFloatList();
2966    PFloatFloatList wfl(ffl);
2967    float optThresh, optCA;
2968    optThresh = SELF_AS(TThresholdCA).call(classifier, egen, weightID, optCA, targetVal, ffl);
2969
2970    PyObject *pyCAs = PyList_New(ffl->size());
2971    Py_ssize_t i = 0;
2972    PITERATE(TFloatFloatList, ffi, ffl)
2973        PyList_SetItem(pyCAs, i++, Py_BuildValue("ff", (*ffi).first, (*ffi).second));
2974
2975    return Py_BuildValue("ffN", optThresh, optCA, pyCAs);
2976    PyCATCH
2977}
2978
2979
2980#include "symmatrix.hpp"
2981
2982PyObject *SymMatrix_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Orange, "(dimension[, initialElement=0] | a list of lists)")
2983{
2984    PyTRY
2985        int dim;
2986    float init = 0;
2987    if (PyArg_ParseTuple(args, "i|f", &dim, &init)) {
2988        if (dim<1)
2989            PYERROR(PyExc_TypeError, "matrix dimension must be positive", PYNULL);
2990
2991        return WrapNewOrange(mlnew TSymMatrix(dim, init), type);
2992    }
2993
2994    PyErr_Clear();
2995
2996    PyObject *arg;
2997    if (PyArg_ParseTuple(args, "O|f", &arg, &init)) {
2998        dim = PySequence_Size(arg);
2999        PyObject *iter = PyObject_GetIter(arg);
3000        if ((dim<0) || !iter)
3001            PYERROR(PyExc_TypeError, "SymMatrix.__init__ expects a list of lists or the dimension, and an optional default element", PYNULL);
3002
3003#define UNKNOWN_F -1e30f
3004
3005        TSymMatrix *symmatrix = mlnew TSymMatrix(dim, UNKNOWN_F);
3006        PyObject *subiter = NULL;
3007
3008#define FREE_ALL  Py_DECREF(iter); delete symmatrix; Py_XDECREF(subiter);
3009
3010        int i, j;
3011
3012        for(i = 0; i<dim; i++) {
3013            PyObject *item = PyIter_Next(iter);
3014            if (!item) {
3015                FREE_ALL
3016                    PYERROR(PyExc_SystemError, "matrix is shorter than promissed ('len' returned more elements than there actuall are)", PYNULL);
3017            }
3018
3019            PyObject *subiter = PyObject_GetIter(item);
3020            Py_DECREF(item);
3021
3022            if (!subiter) {
3023                FREE_ALL
3024                    PyErr_Format(PyExc_TypeError, "row %i is not a sequence", i);
3025                return PYNULL;
3026            }
3027
3028            for(j = 0;; j++) {
3029                PyObject *subitem = PyIter_Next(subiter);
3030                if (!subitem)
3031                    break;
3032
3033                float f;
3034                bool ok = PyNumber_ToFloat(subitem, f);
3035                Py_DECREF(subitem);
3036                if (!ok) {
3037                    FREE_ALL
3038                        PyErr_Format(PyExc_TypeError, "element at (%i, %i) is not a number", i, j);
3039                    return PYNULL;
3040                }
3041
3042
3043                try {
3044                    float &mae = symmatrix->getref(i, j);
3045
3046                    if ((mae != UNKNOWN_F) && (mae!=f)) {
3047                        FREE_ALL
3048                            PyErr_Format(PyExc_TypeError, "the element at (%i, %i) is asymmetric", i, j);
3049                        return PYNULL;
3050                    }
3051
3052                    mae = f;
3053                }
3054                catch (...) {
3055                    FREE_ALL
3056                        throw;
3057                }
3058            }
3059
3060            Py_DECREF(subiter);
3061            subiter = NULL;
3062        }
3063        Py_DECREF(iter);
3064
3065        float *e = symmatrix->elements;
3066        for(i = ((dim+1)*(dim+2)) >> 1; i--; e++)
3067            if (*e == UNKNOWN_F)
3068                *e = init;
3069
3070        return WrapNewOrange(symmatrix, type);
3071
3072#undef UNKNOWN_F
3073#undef FREE_ALL
3074    }
3075
3076    PyErr_Clear();
3077
3078    PYERROR(PyExc_TypeError, "SymMatrix.__init__ expects a list of lists or the dimension and the initial element", PYNULL);
3079
3080    PyCATCH
3081}
3082
3083
3084PyObject *SymMatrix__reduce__(PyObject *self)
3085{
3086    PyTRY
3087        CAST_TO(TSymMatrix, matrix);
3088    const int dim = matrix->dim;
3089    return Py_BuildValue("O(Os#i)N", getExportedFunction("__pickleLoaderSymMatrix"),
3090        self->ob_type,
3091        matrix->elements, sizeof(float) * (((dim+1) * (dim+2)) >> 1),
3092        dim,
3093        packOrangeDictionary(self));
3094    PyCATCH
3095}
3096
3097
3098PyObject *__pickleLoaderSymMatrix(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension)")
3099{
3100    PyTRY
3101        PyTypeObject *type;
3102    char *buf;
3103    int bufSize, dim;
3104    if (!PyArg_ParseTuple(args, "Os#i:__pickleLoaderCostMatrix", &type, &buf, &bufSize, &dim))
3105        return NULL;
3106
3107    TSymMatrix *cm = new TSymMatrix(dim);
3108    memcpy(cm->elements, buf, bufSize);
3109    return WrapNewOrange(cm, type);
3110    PyCATCH
3111}
3112
3113
3114PyObject *SymMatrix_getValues(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "(None -> list of values)")
3115{
3116    PyTRY
3117    CAST_TO(TSymMatrix, matrix)
3118
3119    PyObject* components_list = PyList_New(0);
3120
3121    int i,j;
3122    for (i = 0; i < matrix->dim; i++) {
3123        for (j = i+1; j < matrix->dim; j++) {
3124            double value = 0;
3125            if (matrix->matrixType == 0)
3126                value = matrix->getitem(j,i);
3127            else
3128                value = matrix->getitem(i,j);
3129
3130            PyObject *nel = Py_BuildValue("d", value);
3131            PyList_Append(components_list, nel);
3132            Py_DECREF(nel);
3133        }
3134    }
3135
3136    return components_list;
3137    PyCATCH
3138}
3139
3140PyObject *SymMatrix_getKNN(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "((i, K) -> list of values)")
3141{
3142    PyTRY
3143    CAST_TO(TSymMatrix, matrix)
3144
3145    int kNN;
3146    int i;
3147
3148    if (!PyArg_ParseTuple(args, "ii:SymMatrix.getKNN", &i, &kNN))
3149        return PYNULL;
3150
3151    vector<int> closest;
3152    matrix->getknn(i, kNN, closest);
3153
3154    PyObject* components_list = PyList_New(0);
3155
3156    for (i = 0; i < closest.size(); i++) {
3157        PyObject *nel = Py_BuildValue("i", closest[i]);
3158        PyList_Append(components_list, nel);
3159        Py_DECREF(nel);
3160    }
3161
3162    return components_list;
3163    PyCATCH
3164}
3165
3166PyObject *SymMatrix_avgLinkage(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Clusters -> SymMatrix)")
3167{
3168    PyTRY
3169    CAST_TO(TSymMatrix, matrix);
3170
3171    PyObject *clusters;
3172
3173    if (!PyArg_ParseTuple(args, "O:SymMatrix.avgLinkage", &clusters))
3174        return PYNULL;
3175
3176    int size = PyList_Size(clusters);
3177
3178    TSymMatrix *symmatrix = new TSymMatrix(size);
3179    PSymMatrix wsymmatrix = symmatrix;
3180
3181    symmatrix->matrixType = TSymMatrix::Symmetric;
3182
3183    int i,j,k,l;
3184    for (i = 0; i < size; i++)
3185    {
3186        for (j   = i; j < size; j++)
3187        {
3188            PyObject *cluster_i = PyList_GetItem(clusters, i);
3189            PyObject *cluster_j = PyList_GetItem(clusters, j);
3190            int size_i = PyList_Size(cluster_i);
3191            int size_j = PyList_Size(cluster_j);
3192            float sum = 0;
3193            for (k = 0; k < size_i; k++)
3194            {
3195                for (l = 0; l < size_j; l++)
3196                {
3197                    int item_k = PyInt_AsLong(PyList_GetItem(cluster_i, k));
3198                    int item_l = PyInt_AsLong(PyList_GetItem(cluster_j, l));
3199
3200                    if (item_k >= matrix->dim || item_l >= matrix->dim)
3201                        raiseError("index out of range");
3202
3203                    sum += matrix->getitem(item_k, item_l);
3204                }
3205            }
3206
3207            sum /= (size_i * size_j);
3208            symmatrix->getref(i, j) = sum;
3209        }
3210    }
3211
3212    PyObject *pysymmatrix = WrapOrange(wsymmatrix);
3213    return pysymmatrix;
3214
3215    PyCATCH
3216}
3217
3218PyObject *SymMatrix_invert(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Invert type -> None)")
3219{
3220    /* ******************
3221     * Types:
3222     * 0 - [-X]
3223     * 1 - [1 - X]
3224     * 2 - [max - X]
3225     * 3 - [1 / X]
3226     ********************/
3227    PyTRY
3228    int type;
3229
3230    if (!PyArg_ParseTuple(args, "i:SymMatrix.invert", &type))
3231        return NULL;
3232
3233    if (type < 0 || type > 3)
3234        PYERROR(PyExc_AttributeError, "only types 0 to 3  are supported", PYNULL);
3235
3236    CAST_TO(TSymMatrix, matrix);
3237    int i;
3238    float *e = matrix->elements;
3239    switch(type)
3240    {
3241        case 0:
3242            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3243                *e = 0 - *e;
3244            break;
3245
3246        case 1:
3247            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3248                *e = 1 - *e;
3249            break;
3250
3251        case 2:
3252            float maxval;
3253            maxval = 0;
3254
3255            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3256                if (*e > maxval)
3257                    maxval = *e;
3258
3259            e = matrix->elements;
3260            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3261                *e = maxval - *e;
3262
3263            break;
3264
3265        case 3:
3266            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3267                if (*e == 0)
3268                    raiseError("division by zero");
3269                *e = 1 / *e;
3270            break;
3271    }
3272
3273    RETURN_NONE;
3274    PyCATCH
3275}
3276
3277PyObject *SymMatrix_normalize(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(Normalize type -> None)")
3278{
3279    /* ******************
3280     * Types:
3281     * 0 - [0, 1]
3282     * 1 - Sigmoid
3283     ********************/
3284    PyTRY
3285    int type;
3286
3287    if (!PyArg_ParseTuple(args, "i:SymMatrix.normalize", &type))
3288        return NULL;
3289
3290    if (type < 0 || type > 1)
3291        PYERROR(PyExc_AttributeError, "only types 0 and 1 are supported", PYNULL);
3292
3293    CAST_TO(TSymMatrix, matrix);
3294    int i;
3295    float *e = matrix->elements;
3296    float maxval = *e;
3297    float minval = *e;
3298    switch(type)
3299    {
3300        case 0:
3301            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++) {
3302                if (*e > maxval)
3303                    maxval = *e;
3304
3305                if (*e < minval)
3306                    minval = *e;
3307            }
3308            //cout << "minval: " << minval << endl;
3309            //cout << "maxval: " << maxval << endl;
3310
3311            e = matrix->elements;
3312            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3313                *e = (*e - minval) / (maxval - minval);
3314            break;
3315
3316        case 1:
3317            for(i = ((matrix->dim+1)*(matrix->dim+2)) >> 1; i--; e++)
3318                *e = 1 / (1 + exp(-(*e)));
3319            break;
3320    }
3321
3322    RETURN_NONE;
3323    PyCATCH
3324}
3325
3326PyObject *SymMatrix_get_items(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(List of items -> SymMatrix)")
3327{
3328    PyTRY
3329    CAST_TO(TSymMatrix, matrix);
3330
3331    PyObject *items;
3332
3333    if (!PyArg_ParseTuple(args, "O:SymMatrix.get_items", &items))
3334        return PYNULL;
3335
3336    int size = PyList_Size(items);
3337    PyList_Sort(items);
3338
3339    TSymMatrix *symmatrix = new TSymMatrix(size);
3340    PSymMatrix wsymmatrix = symmatrix;
3341
3342    symmatrix->matrixType = matrix->matrixType;
3343
3344    int i,j;
3345    for (i = 0; i < size; i++)
3346    {
3347        for (j = i; j < size; j++)
3348        {
3349            if (symmatrix->matrixType == TSymMatrix::Lower || symmatrix->matrixType == TSymMatrix::LowerFilled)
3350            {
3351                int item_i = PyInt_AsLong(PyList_GetItem(items, j));
3352                int item_j = PyInt_AsLong(PyList_GetItem(items, i));
3353
3354                float value = matrix->getitem(item_i, item_j);
3355                symmatrix->getref(j, i) = value;
3356            }
3357            else
3358            {
3359                int item_i = PyInt_AsLong(PyList_GetItem(items, i));
3360                int item_j = PyInt_AsLong(PyList_GetItem(items, j));
3361
3362                float value = matrix->getitem(item_i, item_j);
3363                symmatrix->getref(i, j) = value;
3364            }
3365        }
3366    }
3367
3368    PyObject *pysymmatrix = WrapOrange(wsymmatrix);
3369    return pysymmatrix;
3370    PyCATCH
3371}
3372
3373PyObject *SymMatrix_getitem_sq(PyObject *self, Py_ssize_t i)
3374{
3375    PyTRY
3376        CAST_TO(TSymMatrix, matrix)
3377        int dim = matrix->dim;
3378
3379    if (i >= matrix->dim) {
3380        PyErr_Format(PyExc_IndexError, "index %i out of range 0-%i", i, matrix->dim-1);
3381        return PYNULL;
3382    }
3383
3384    Py_ssize_t j;
3385    PyObject *row;
3386    switch (matrix->matrixType) {
3387            case TSymMatrix::Lower:
3388                row = PyTuple_New(i+1);
3389                for(j = 0; j<=i; j++)
3390                    PyTuple_SetItem(row, j, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3391                return row;
3392
3393            case TSymMatrix::Upper:
3394                row = PyTuple_New(matrix->dim - i);
3395                for(j = i; j<dim; j++)
3396                    PyTuple_SetItem(row, j-i, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3397                return row;
3398
3399            default:
3400                row = PyTuple_New(matrix->dim);
3401                for(j = 0; j<dim; j++)
3402                    PyTuple_SetItem(row, j, PyFloat_FromDouble((double)matrix->getitem(i, j)));
3403                return row;
3404    }
3405    PyCATCH
3406}
3407
3408
3409
3410PyObject *SymMatrix_getitem(PyObject *self, PyObject *args)
3411{
3412    PyTRY
3413        CAST_TO(TSymMatrix, matrix)
3414
3415        if ((PyTuple_Check(args) && (PyTuple_Size(args) == 1)) || PyInt_Check(args)) {
3416            if (PyTuple_Check(args)) {
3417                args = PyTuple_GET_ITEM(args, 0);
3418                if (!PyInt_Check(args))
3419                    PYERROR(PyExc_IndexError, "integer index expected", PYNULL);
3420            }
3421
3422            return SymMatrix_getitem_sq(self, (int)PyInt_AsLong(args));
3423        }
3424
3425        else if (PyTuple_Size(args) == 2) {
3426            if (!PyInt_Check(PyTuple_GET_ITEM(args, 0)) || !PyInt_Check(PyTuple_GET_ITEM(args, 1)))
3427                PYERROR(PyExc_IndexError, "integer indices expected", PYNULL);
3428
3429            const int i = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
3430            const int j = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
3431            if ((j>i) && (matrix->matrixType == TSymMatrix::Lower))
3432                PYERROR(PyExc_IndexError, "index out of range for lower triangular matrix", PYNULL);
3433
3434            if ((j<i) && (matrix->matrixType == TSymMatrix::Upper))
3435                PYERROR(PyExc_IndexError, "index out of range for upper triangular matrix", PYNULL);
3436
3437            return PyFloat_FromDouble(matrix->getitem(i, j));
3438        }
3439
3440        PYERROR(PyExc_IndexError, "one or two integer indices expected", PYNULL);
3441        PyCATCH
3442}
3443
3444
3445int SymMatrix_setitem(PyObject *self, PyObject *args, PyObject *obj)
3446{
3447    PyTRY
3448        if (PyTuple_Size(args) == 1)
3449            PYERROR(PyExc_AttributeError, "cannot set entire matrix row", -1);
3450
3451    if (PyTuple_Size(args) != 2)
3452        PYERROR(PyExc_IndexError, "two integer indices expected", -1);
3453
3454    PyObject *pyfl = PyNumber_Float(obj);
3455    if (!pyfl)
3456        PYERROR(PyExc_TypeError, "invalid matrix elements; a number expected", -1);
3457    float f = PyFloat_AsDouble(pyfl);
3458    Py_DECREF(pyfl);
3459
3460    const int i = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
3461    const int j = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
3462
3463    SELF_AS(TSymMatrix).getref(i, j) = f;
3464    return 0;
3465    PyCATCH_1
3466}
3467
3468
3469PyObject *SymMatrix_getslice(PyObject *self, Py_ssize_t start, Py_ssize_t stop)
3470{
3471    PyTRY
3472        CAST_TO(TSymMatrix, matrix)
3473        const int dim = matrix->dim;
3474
3475    if (start>dim)
3476        start = dim;
3477    else if (start<0)
3478        start = 0;
3479
3480    if (stop>dim)
3481        stop=dim;
3482
3483    PyObject *res = PyTuple_New(stop - start);
3484    int i = 0;
3485    while(start<stop)
3486        PyTuple_SetItem(res, i++, SymMatrix_getitem_sq(self, start++));
3487
3488    return res;
3489    PyCATCH
3490}
3491
3492
3493PyObject *SymMatrix_str(PyObject *self)
3494{ PyTRY
3495CAST_TO(TSymMatrix, matrix)
3496const int dim = matrix->dim;
3497const int mattype = matrix->matrixType;
3498
3499float matmax = 0.0;
3500for(float *ei = matrix->elements, *ee = matrix->elements + ((dim*(dim+1))>>1); ei != ee; ei++) {
3501    const float tei = *ei<0 ? fabs(10.0 * *ei) : *ei;
3502    if (tei > matmax)
3503        matmax = tei;
3504}
3505
3506const int plac = 4 + (fabs(matmax) < 1 ? 1 : int(ceil(log10((double)matmax))));
3507const int elements = (matrix->matrixType == TSymMatrix::Lower) ? (dim*(dim+1))>>1 : dim * dim;
3508char *smatr = new char[3 * dim + (plac+2) * elements];
3509char *sptr = smatr;
3510*(sptr++) = '(';
3511*(sptr++) = '(';
3512
3513int i, j;
3514for(i = 0; i<dim; i++) {
3515    switch (mattype) {
3516                case TSymMatrix::Lower:
3517                    for(j = 0; j<i; j++, sptr += (plac+2))
3518                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3519                    break;
3520
3521                case TSymMatrix::Upper:
3522                    for(j = i * (plac+2); j--; *(sptr++) = ' ');
3523                    for(j = i; j < dim-1; j++, sptr += (plac+2))
3524                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3525                    break;
3526
3527                default:
3528                    for(j = 0; j<dim-1; j++, sptr += (plac+2))
3529                        sprintf(sptr, "%*.3f, ", plac, matrix->getitem(i, j));
3530    }
3531
3532    sprintf(sptr, "%*.3f)", plac, matrix->getitem(i, j));
3533    sptr += (plac+1);
3534
3535    if (i!=dim-1) {
3536        sprintf(sptr, ",\n (");
3537        sptr += 4;
3538    }
3539}
3540
3541sprintf(sptr, ")");
3542
3543PyObject *res = PyString_FromString(smatr);
3544mldelete smatr;
3545return res;
3546PyCATCH
3547}
3548
3549
3550PyObject *SymMatrix_repr(PyObject *self)
3551{ return SymMatrix_str(self); }
3552
3553
3554#include "hclust.hpp"
3555
3556C_NAMED(HierarchicalCluster - Orange.clustering.hierarchical.HierarchicalCluster, Orange, "()")
3557C_CALL3(HierarchicalClustering - Orange.clustering.hierarchical.HierarchicalClustering, HierarchicalClustering, Orange, "(linkage=)")
3558
3559C_CALL3(HierarchicalClusterOrdering, HierarchicalClusterOrdering, Orange, "(progressCallback=)")
3560
3561PyObject *HierarchicalClustering_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(distance matrix) -> HierarchicalCluster")
3562{
3563    PyTRY
3564        NO_KEYWORDS
3565
3566        PSymMatrix symmatrix;
3567
3568    if (!PyArg_ParseTuple(args, "O&:HierarchicalClustering", cc_SymMatrix, &symmatrix))
3569        return NULL;
3570
3571    PHierarchicalCluster root = SELF_AS(THierarchicalClustering)(symmatrix);
3572
3573    if (symmatrix->myWrapper->orange_dict) {
3574        PyObject *objects = PyDict_GetItemString(symmatrix->myWrapper->orange_dict, "objects");
3575        TPyOrange *pymapping = root->mapping->myWrapper;
3576        if (objects && (objects != Py_None)) {
3577            if (!pymapping->orange_dict)
3578                pymapping->orange_dict = PyOrange_DictProxy_New(pymapping);
3579            PyDict_SetItemString(pymapping->orange_dict, "objects", objects);
3580        }
3581    }
3582    return WrapOrange(root);
3583    PyCATCH
3584}
3585
3586PyObject * HierarchicalClusterOrdering_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(hierarchical cluster, distance_matrix) -> None")
3587{
3588    PyTRY
3589        NO_KEYWORDS
3590        PHierarchicalCluster root;
3591        PSymMatrix matrix;
3592        if (!PyArg_ParseTuple(args, "O&O&:HierarchicalClustering", cc_HierarchicalCluster, &root, cc_SymMatrix, &matrix))
3593            return NULL;
3594        SELF_AS(THierarchicalClusterOrdering).operator ()(root, matrix);
3595        RETURN_NONE
3596    PyCATCH
3597}
3598
3599Py_ssize_t HierarchicalCluster_len_sq(PyObject *self)
3600{
3601    CAST_TO_err(THierarchicalCluster, cluster, -1);
3602    return cluster->last - cluster->first;
3603}
3604
3605
3606PyObject *HierarchicalCluster_getitem_sq(PyObject *self, Py_ssize_t i)
3607{
3608    PyTRY
3609        CAST_TO(THierarchicalCluster, cluster);
3610
3611    if (!cluster->mapping)
3612        PYERROR(PyExc_SystemError, "'HierarchicalCluster' misses 'mapping'", PYNULL);
3613
3614    i += (i>=0) ? cluster->first : cluster->last;
3615    if ((i < cluster->first) || (i >= cluster->last)) {
3616        PyErr_Format(PyExc_IndexError, "index out of range 0-%i", cluster->last - cluster->first - 1);
3617        return PYNULL;
3618    }
3619
3620    if (i >= cluster->mapping->size())
3621        PYERROR(PyExc_SystemError, "internal inconsistency in instance of 'HierarchicalCluster' ('mapping' too short)", PYNULL);
3622
3623    const int elindex = cluster->mapping->at(i);
3624
3625    if (cluster->mapping->myWrapper->orange_dict) {
3626        PyObject *objs = PyDict_GetItemString(cluster->mapping->myWrapper->orange_dict, "objects");
3627        if (objs && (objs != Py_None))
3628            return PySequence_GetItem(objs, elindex);
3629    }
3630
3631    return PyInt_FromLong(elindex);
3632    PyCATCH
3633}
3634
3635
3636PyObject *HierarchicalCluster_get_left(PyObject *self)
3637{
3638    PyTRY
3639        CAST_TO(THierarchicalCluster, cluster);
3640
3641    if (!cluster->branches)
3642        RETURN_NONE
3643
3644        if (cluster->branches->size() > 2)
3645            PYERROR(PyExc_AttributeError, "'left' not defined (cluster has more than two subclusters)", PYNULL);
3646
3647    return WrapOrange(cluster->branches->front());
3648    PyCATCH
3649}
3650
3651
3652PyObject *HierarchicalCluster_get_right(PyObject *self)
3653{
3654    PyTRY
3655        CAST_TO(THierarchicalCluster, cluster);
3656
3657    if (!cluster->branches || (cluster->branches->size() < 2))
3658        RETURN_NONE;
3659
3660    if (cluster->branches->size() > 2)
3661        PYERROR(PyExc_AttributeError, "'right' not defined (cluster has more than two subclusters", PYNULL);
3662
3663    return WrapOrange(cluster->branches->back());
3664    PyCATCH
3665}
3666
3667
3668int HierarchicalClusterLowSet(PyObject *self, PyObject *arg, const int side)
3669{
3670    PyTRY
3671        static const char *sides[2] = {"left", "right"};
3672
3673    if (!PyOrHierarchicalCluster_Check(arg)) {
3674        PyErr_Format(PyExc_TypeError, "'HierarchicalCluster.%s' should be of type 'HierarchicalCluster' (got '%s')", sides[side], arg->ob_type->tp_name);
3675        return -1;
3676    }
3677
3678    CAST_TO_err(THierarchicalCluster, cluster, -1);
3679
3680    if (!cluster->branches)
3681        cluster->branches = mlnew THierarchicalClusterList(2);
3682    else
3683        if (cluster->branches->size() != 2)
3684            PYERROR(PyExc_AttributeError, "'left' not defined (cluster does not have (exactly) two subclusters)", -1);
3685
3686    cluster->branches->at(side) = PyOrange_AsHierarchicalCluster(arg);
3687    return 0;
3688    PyCATCH_1
3689}
3690
3691
3692int HierarchicalCluster_set_left(PyObject *self, PyObject *arg)
3693{
3694    return HierarchicalClusterLowSet(self, arg, 0);
3695}
3696
3697int HierarchicalCluster_set_right(PyObject *self, PyObject *arg)
3698{
3699    return HierarchicalClusterLowSet(self, arg, 1);
3700}
3701
3702
3703PyObject *HierarchicalCluster_swap(PyObject *self, PyObject *arg, PyObject *keyw) PYARGS(METH_NOARGS, "() -> None; swaps the sub clusters")
3704{
3705    PyTRY
3706        SELF_AS(THierarchicalCluster).swap();
3707    RETURN_NONE;
3708    PyCATCH
3709}
3710
3711PyObject *HierarchicalCluster_permute(PyObject *self, PyObject *arg, PyObject *keys) PYARGS(METH_O, "(permutation) -> None")
3712{
3713    PyTRY
3714        PIntList ilist = ListOfUnwrappedMethods<PIntList, TIntList, int>::P_FromArguments(arg);
3715    if (!ilist)
3716        return PYNULL;
3717
3718    SELF_AS(THierarchicalCluster).permute(ilist.getReference());
3719    RETURN_NONE;
3720    PyCATCH
3721}
3722
3723
3724PHierarchicalClusterList PHierarchicalClusterList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::P_FromArguments(arg); }
3725PyObject *HierarchicalClusterList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_FromArguments(type, arg); }
3726PyObject *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); }
3727PyObject *HierarchicalClusterList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_getitem(self, index); }
3728int       HierarchicalClusterList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_setitem(self, index, item); }
3729PyObject *HierarchicalClusterList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_getslice(self, start, stop); }
3730int       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); }
3731Py_ssize_t       HierarchicalClusterList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_len(self); }
3732PyObject *HierarchicalClusterList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_richcmp(self, object, op); }
3733PyObject *HierarchicalClusterList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_concat(self, obj); }
3734PyObject *HierarchicalClusterList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_repeat(self, times); }
3735PyObject *HierarchicalClusterList_str(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_str(self); }
3736PyObject *HierarchicalClusterList_repr(TPyOrange *self) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_str(self); }
3737int       HierarchicalClusterList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_contains(self, obj); }
3738PyObject *HierarchicalClusterList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(HierarchicalCluster) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_append(self, item); }
3739PyObject *HierarchicalClusterList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_extend(self, obj); }
3740PyObject *HierarchicalClusterList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> int") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_count(self, obj); }
3741PyObject *HierarchicalClusterList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> HierarchicalClusterList") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_filter(self, args); }
3742PyObject *HierarchicalClusterList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> int") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_index(self, obj); }
3743PyObject *HierarchicalClusterList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_insert(self, args); }
3744PyObject *HierarchicalClusterList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_native(self); }
3745PyObject *HierarchicalClusterList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> HierarchicalCluster") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_pop(self, args); }
3746PyObject *HierarchicalClusterList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(HierarchicalCluster) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_remove(self, obj); }
3747PyObject *HierarchicalClusterList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_reverse(self); }
3748PyObject *HierarchicalClusterList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_sort(self, args); }
3749PyObject *HierarchicalClusterList__reduce__(TPyOrange *self, PyObject *) PYARGS(METH_VARARGS, "()") { return ListOfWrappedMethods<PHierarchicalClusterList, THierarchicalClusterList, PHierarchicalCluster, &PyOrHierarchicalCluster_Type>::_reduce(self); }
3750
3751
3752
3753
3754#include "distancemap.hpp"
3755
3756C_NAMED(DistanceMapConstructor - Orange.distance.DistanceMapConstructor, Orange, "(distanceMatrix=, order=)")
3757
3758
3759
3760PyObject *DistanceMapConstructor_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(squeeze) -> DistanceMap")
3761{
3762    PyTRY
3763        NO_KEYWORDS
3764
3765        float squeeze = 1.0;
3766    if (!PyArg_ParseTuple(args, "|f:DistanceMapConstructor.__call__", &squeeze))
3767        return NULL;
3768
3769    float absLow, absHigh;
3770    PDistanceMap dm = SELF_AS(TDistanceMapConstructor).call(squeeze, absLow, absHigh);
3771    return Py_BuildValue("Nff", WrapOrange(dm), absLow, absHigh);
3772    PyCATCH
3773}
3774
3775
3776PyObject *DistanceMapConstructor_getLegend(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(width, height, gamma) -> bitmap")
3777{
3778    PyTRY
3779        int width, height;
3780    float gamma;
3781    if (!PyArg_ParseTuple(args, "iif:DistanceMapConstructor.getLegend", &width, &height, &gamma))
3782        return NULL;
3783
3784    long size;
3785    unsigned char *bitmap = SELF_AS(TDistanceMapConstructor).getLegend(width, height, gamma, size);
3786    PyObject *res = PyString_FromStringAndSize((const char *)bitmap, (Py_ssize_t)size);
3787    delete bitmap;
3788    return res;
3789    PyCATCH
3790}
3791
3792
3793BASED_ON(DistanceMap - Orange.distance.DistanceMap, Orange)
3794
3795PyObject *DistanceMap__reduce__(PyObject *self)
3796{
3797    PyTRY
3798        CAST_TO(TDistanceMap, matrix);
3799    const int dim = matrix->dim;
3800    return Py_BuildValue("O(Os#iO)N", getExportedFunction("__pickleLoaderDistanceMap"),
3801        self->ob_type,
3802        matrix->cells, dim*dim*sizeof(float),
3803        dim,
3804        WrapOrange(matrix->elementIndices),
3805        packOrangeDictionary(self));
3806    PyCATCH
3807}
3808
3809
3810PyObject *__pickleLoaderDistanceMap(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_matrix, dimension, elementIndices)")
3811{
3812    PyTRY
3813        PyTypeObject *type;
3814    char *buf;
3815    int bufSize, dim;
3816    PIntList elementIndices;
3817    if (!PyArg_ParseTuple(args, "Os#iO&:__pickleLoaderDistanceMap", &type, &buf, &bufSize, &dim, ccn_IntList, &elementIndices))
3818        return NULL;
3819
3820    TDistanceMap *cm = new TDistanceMap(dim);
3821    memcpy(cm->cells, buf, bufSize);
3822    cm->elementIndices = elementIndices;
3823    return WrapNewOrange(cm, type);
3824    PyCATCH
3825}
3826
3827
3828PyObject *DistanceMap_getBitmap(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "(cell_width, cell_height, lowerBound, upperBound, gamma) -> bitmap")
3829{
3830    PyTRY
3831        int cellWidth, cellHeight;
3832    float absLow, absHigh, gamma;
3833    int grid = 1;
3834    int matrixType = 2;
3835    if (!PyArg_ParseTuple(args, "iifff|ii:Heatmap.getBitmap", &cellWidth, &cellHeight, &absLow, &absHigh, &gamma, &grid, &matrixType))
3836        return NULL;
3837
3838    CAST_TO(TDistanceMap, dm)
3839
3840        long size;
3841    unsigned char *bitmap = dm->distanceMap2string(cellWidth, cellHeight, absLow, absHigh, gamma, grid!=0, matrixType, size);
3842    PyObject *res = Py_BuildValue("s#ii", (const char *)bitmap, size, cellWidth * dm->dim, cellHeight * dm->dim);
3843    delete bitmap;
3844    return res;
3845    PyCATCH
3846}
3847
3848
3849PyObject *DistanceMap_getCellIntensity(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(row, column) -> float")
3850{
3851    PyTRY
3852        int row, column;
3853    if (!PyArg_ParseTuple(args, "ii:DistanceMap.getCellIntensity", &row, &column))
3854        return NULL;
3855
3856    const float ci = SELF_AS(TDistanceMap).getCellIntensity(row, column);
3857    if (ci == ILLEGAL_FLOAT)
3858        RETURN_NONE;
3859
3860    return PyFloat_FromDouble(ci);
3861    PyCATCH
3862}
3863
3864
3865PyObject *DistanceMap_getPercentileInterval(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(lower_percentile, upper_percentile) -> (min, max)")
3866{
3867    PyTRY
3868        float lowperc, highperc;
3869    if (!PyArg_ParseTuple(args, "ff:DistanceMap_percentileInterval", &lowperc, &highperc))
3870        return PYNULL;
3871
3872    float minv, maxv;
3873    SELF_AS(TDistanceMap).getPercentileInterval(lowperc, highperc, minv, maxv);
3874    return Py_BuildValue("ff", minv, maxv);
3875    PyCATCH
3876}
3877
3878
3879
3880#include "graph.hpp"
3881
3882extern PyTypeObject PyEdge_Type;
3883
3884/* If objectsOnEdges==true, this is a proxy object; double's are actualy PyObject *,
3885but the references are owned by the graph. */
3886class TPyEdge {
3887public:
3888    PyObject_HEAD
3889
3890        PGraph graph;
3891    int v1, v2;
3892    double *weights;
3893    bool objectsOnEdges;
3894    int weightsVersion;
3895
3896    inline double *getWeights()
3897    {
3898        if (weightsVersion != (weights ? graph->lastAddition : graph->lastRemoval)) {
3899            weights = graph->getEdge(v1, v2);
3900            weightsVersion = graph->currentVersion;
3901        }
3902        return weights;
3903    }
3904};
3905
3906
3907#define DOUBLE_AS_PYOBJECT(x) (*(PyObject **)(void *)(&(x)))
3908PyObject *PyEdge_Getitem(TPyEdge *self, Py_ssize_t ind)
3909{
3910    PyTRY
3911        if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3912            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", ind, self->graph->nEdgeTypes);
3913            return PYNULL;
3914        }
3915
3916        if (self->getWeights()) {
3917            const double w = self->weights[ind];
3918
3919            if (!CONNECTED(w))
3920                RETURN_NONE;
3921
3922            if (self->objectsOnEdges) {
3923                Py_INCREF(DOUBLE_AS_PYOBJECT(w));
3924                return DOUBLE_AS_PYOBJECT(w);
3925            }
3926            else
3927                return PyFloat_FromDouble(w);
3928        }
3929
3930        else
3931            RETURN_NONE;
3932        PyCATCH
3933}
3934
3935
3936int PyEdge_Contains(TPyEdge *self, PyObject *pyind)
3937{
3938    PyTRY
3939        if (!PyInt_Check(pyind))
3940            PYERROR(PyExc_IndexError, "edge types must be integers", -1);
3941
3942    int ind = int(PyInt_AsLong(pyind));
3943    if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3944        PyErr_Format(PyExc_IndexError, "edge type %i out of range (0-%i)", ind, self->graph->nEdgeTypes);
3945        return -1;
3946    }
3947
3948    return self->getWeights() && CONNECTED(self->weights[ind]) ? 1 : 0;
3949    PyCATCH_1
3950}
3951
3952
3953int PyEdge_Setitem(TPyEdge *self, Py_ssize_t ind, PyObject *item)
3954{
3955    PyTRY
3956        if ((ind >= self->graph->nEdgeTypes) || (ind < 0)) {
3957            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", ind, self->graph->nEdgeTypes);
3958            return -1;
3959        }
3960
3961        double w;
3962        bool noConnection = !item || (item == Py_None);
3963        if (noConnection)
3964            DISCONNECT(w);
3965        else {
3966            if (!self->objectsOnEdges && !PyNumber_ToDouble(item, w))
3967                PYERROR(PyExc_TypeError, "a number expected for edge weight", -1);
3968        }
3969
3970
3971        if (self->getWeights()) {
3972            if (self->objectsOnEdges) {
3973                // watch the order: first INCREF, then DECREF!
3974                if (!noConnection)
3975                    Py_INCREF(item);
3976                if (CONNECTED(self->weights[ind]))
3977                    Py_DECREF(DOUBLE_AS_PYOBJECT(self->weights[ind]));
3978
3979                DOUBLE_AS_PYOBJECT(self->weights[ind]) = item;
3980            }
3981
3982            else
3983                self->weights[ind] = w;
3984
3985            if (noConnection) {
3986                double *w, *we;
3987                for(w = self->weights, we = self->weights + self->graph->nEdgeTypes; (w != we) && !CONNECTED(*w); w++);
3988                if (w == we) {
3989                    self->graph->removeEdge(self->v1, self->v2);
3990                    self->weights = NULL;
3991                    self->weightsVersion = self->graph->currentVersion;
3992                }
3993            }
3994        }
3995
3996        else {
3997            if (!noConnection) {
3998                double *weights = self->weights = self->graph->getOrCreateEdge(self->v1, self->v2);
3999
4000                if (self->objectsOnEdges) {
4001                    DOUBLE_AS_PYOBJECT(weights[ind]) = item;
4002                    Py_INCREF(item);
4003                }
4004                else
4005                    weights[ind] = w;
4006
4007                self->weightsVersion = self->graph->currentVersion;
4008            }
4009        }
4010
4011        return 0;
4012        PyCATCH_1
4013}
4014
4015
4016/*
4017// I've programmed this by mistake; but it's nice, so let it stay
4018// for the case we need it :)
4019PyObject *PyEdge_Str(TPyEdge *self)
4020{
4021PyTRY
4022int nEdgeTypes = self->graph->nEdgeTypes;
4023
4024if (!self->getWeights()) {
4025if (nEdgeTypes == 1)
4026RETURN_NONE;
4027else {
4028PyObject *res = PyTuple_New(nEdgeTypes);
4029while(nEdgeTypes--) {
4030Py_INCREF(Py_None);
4031PyTuple_SET_ITEM(res, nEdgeTypes, Py_None);
4032}
4033return res;
4034}
4035}
4036
4037if (nEdgeTypes == 1)
4038return PyFloat_FromDouble(*self->weights);
4039else {
4040PyObject *res = PyTuple_New(nEdgeTypes);
4041int i = 0;
4042for(double weights = self->weights; i != nEdgeTypes; weights++, i++)
4043PyTuple_SET_ITEM(res, i, PyFloat_FromDouble(*weights));
4044return res;
4045}
4046PyCATCH
4047}
4048*/
4049
4050PyObject *PyEdge_Str(TPyEdge *self)
4051{
4052    PyTRY
4053        int nEdgeTypes = self->graph->nEdgeTypes;
4054    char *buf;
4055
4056    if (!self->getWeights()) {
4057        if (nEdgeTypes == 1)
4058            return PyString_FromString("None");
4059        else {
4060            buf = new char[nEdgeTypes*6 + 2];
4061            char *b2 = buf;
4062            *b2++ = '(';
4063            while(nEdgeTypes--) {
4064                strcpy(b2, "None, ");
4065                b2 += 6;
4066            }
4067            b2[-1] = 0;
4068            b2[-2] = ')';
4069        }
4070    }
4071
4072    else {
4073        if (self->objectsOnEdges) {
4074            if (nEdgeTypes == 1)
4075                return PyObject_Str(DOUBLE_AS_PYOBJECT(*self->weights));
4076            else {
4077                PyObject *dump = PyString_FromString("(");
4078                PyString_ConcatAndDel(&dump, PyObject_Str(DOUBLE_AS_PYOBJECT(*self->weights)));
4079
4080                for(double *wi = self->weights+1, *we = self->weights + self->graph->nEdgeTypes; wi != we; wi++) {
4081                    PyString_ConcatAndDel(&dump, PyString_FromString(", "));
4082                    PyString_ConcatAndDel(&dump, PyObject_Str(DOUBLE_AS_PYOBJECT(*wi)));
4083                }
4084
4085                PyString_ConcatAndDel(&dump, PyString_FromString(")"));
4086                return dump;
4087            }
4088        }
4089        else {
4090            if (nEdgeTypes == 1) {
4091                buf = new char[20];
4092                char *b2 = buf;
4093                sprintf(b2, "%-10g", *self->weights);
4094                for(; *b2 > 32; b2++);
4095                *b2 = 0;
4096            }
4097            else {
4098                buf = new char[nEdgeTypes*20];
4099                char *b2 = buf;
4100                *b2++ = '(';
4101                for(double *weights = self->weights, *wee = weights + nEdgeTypes; weights != wee; weights++) {
4102                    if (CONNECTED(*weights)) {
4103                        sprintf(b2, "%-10g", *weights);
4104                        for(; *b2 > 32; b2++);
4105                        *b2++ = ',';
4106                        *b2++ = ' ';
4107                    }
4108                    else {
4109                        strcpy(b2, "None, ");
4110                        b2 += 6;
4111                    }
4112                }
4113                b2[-1] = 0;
4114                b2[-2] = ')';
4115            }
4116        }
4117    }
4118
4119    PyObject *res = PyString_FromString(buf);
4120    delete buf;
4121    return res;
4122    PyCATCH
4123}
4124
4125Py_ssize_t PyEdge_Len(TPyEdge *self)
4126{ return self->graph->nEdgeTypes; }
4127
4128
4129int PyEdge_Nonzero(TPyEdge *self)
4130{ return self->getWeights() ? 1 : 0; }
4131
4132
4133int PyEdge_Traverse(TPyEdge *self, visitproc visit, void *arg)
4134{ PVISIT(self->graph)
4135return 0;
4136}
4137
4138
4139int PyEdge_Clear(TPyEdge *self)
4140{ self->graph = POrange();
4141return 0;
4142}
4143
4144
4145void PyEdge_Dealloc(TPyEdge *self)
4146{
4147    self->graph.~PGraph();
4148    self->ob_type->tp_free((PyObject *)self);
4149}
4150
4151
4152PyObject *PyEdge_Richcmp(TPyEdge *self, PyObject *j, int op)
4153{
4154    double ref;
4155    if (self->graph->nEdgeTypes != 1)
4156        PYERROR(PyExc_TypeError, "multiple-type edges cannot be compared", PYNULL);
4157
4158    if (self->graph->nEdgeTypes != 1)
4159        PYERROR(PyExc_TypeError, "multiple-type edges cannot be compared to floats", PYNULL);
4160
4161    if (!self->getWeights() || !CONNECTED(*self->weights))
4162        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4163
4164    if (self->objectsOnEdges)
4165        return PyObject_RichCompare(DOUBLE_AS_PYOBJECT(*self->weights), j, op);
4166
4167    if (!PyNumber_ToDouble(j, ref))
4168        PYERROR(PyExc_TypeError, "edge weights can only be compared to floats", PYNULL);
4169
4170    const double &f = *self->weights;
4171
4172    int cmp;
4173    switch (op) {
4174case Py_LT: cmp = (f<ref); break;
4175case Py_LE: cmp = (f<=ref); break;
4176case Py_EQ: cmp = (f==ref); break;
4177case Py_NE: cmp = (f!=ref); break;
4178case Py_GT: cmp = (f>ref); break;
4179case Py_GE: cmp = (f>=ref); break;
4180default:
4181    Py_INCREF(Py_NotImplemented);
4182    return Py_NotImplemented;
4183    }
4184
4185    PyObject *res;
4186    if (cmp)
4187        res = Py_True;
4188    else
4189        res = Py_False;
4190    Py_INCREF(res);
4191    return res;
4192}
4193
4194
4195PyObject *PyEdge_Float(TPyEdge *self)
4196{
4197    if (self->graph->nEdgeTypes != 1)
4198        PYERROR(PyExc_TypeError, "multiple-type edges cannot be cast to floats", PYNULL);
4199
4200    if (!self->getWeights() || !CONNECTED(*self->weights))
4201        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4202
4203    return self->objectsOnEdges ? PyNumber_Float(DOUBLE_AS_PYOBJECT(*self->weights)) : PyFloat_FromDouble(*self->weights);
4204}
4205
4206PyObject *PyEdge_Int(TPyEdge *self)
4207{
4208    if (self->graph->nEdgeTypes != 1)
4209        PYERROR(PyExc_TypeError, "multiple-type edges cannot be cast to numbers", PYNULL);
4210
4211    if (!self->getWeights() || !CONNECTED(*self->weights))
4212        PYERROR(PyExc_TypeError, "edge does not exist", PYNULL);
4213
4214    return self->objectsOnEdges ? PyNumber_Int(DOUBLE_AS_PYOBJECT(*self->weights)) : PyInt_FromLong(long(*self->weights));
4215}
4216
4217
4218PyNumberMethods PyEdge_as_number = {
4219    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4220    (inquiry)PyEdge_Nonzero,                           /* nb_nonzero */
4221    0, 0, 0, 0, 0, 0, 0,
4222    (unaryfunc)PyEdge_Int,    /* nb_int */
4223    0,
4224    (unaryfunc)PyEdge_Float,  /* nb_float */
4225    0, 0,
4226};
4227
4228static PySequenceMethods PyEdge_as_sequence = {
4229    (lenfunc)PyEdge_Len,                    /* sq_length */
4230    0,                  /* sq_concat */
4231    0,                  /* sq_repeat */
4232    (ssizeargfunc)PyEdge_Getitem,                   /* sq_item */
4233    0,                  /* sq_slice */
4234    (ssizeobjargproc)PyEdge_Setitem,                    /* sq_ass_item */
4235    0,                  /* sq_ass_slice */
4236    (objobjproc)PyEdge_Contains,        /* sq_contains */
4237    0,                  /* sq_inplace_concat */
4238    0,                  /* sq_inplace_repeat */
4239};
4240
4241PyTypeObject PyEdge_Type = {
4242    PyObject_HEAD_INIT(&PyType_Type)
4243    0,                  /* ob_size */
4244    "Graph.Edge",           /* tp_name */
4245    sizeof(TPyEdge),            /* tp_basicsize */
4246    0,                  /* tp_itemsize */
4247    /* methods */
4248    (destructor)PyEdge_Dealloc,         /* tp_dealloc */
4249    0,                  /* tp_print */
4250    0,                  /* tp_getattr */
4251    0,                  /* tp_setattr */
4252    0,                  /* tp_compare */
4253    (reprfunc)PyEdge_Str,                   /* tp_repr */
4254    &PyEdge_as_number,                  /* tp_as_number */
4255    &PyEdge_as_sequence,                    /* tp_as_sequence */
4256    0,                  /* tp_as_mapping */
4257    0,                  /* tp_hash */
4258    0,                  /* tp_call */
4259    (reprfunc)PyEdge_Str,                   /* tp_str */
4260    0,      /* tp_getattro */
4261    0,                  /* tp_setattro */
4262    0,                  /* tp_as_buffer */
4263    Py_TPFLAGS_DEFAULT,         /* tp_flags */
4264    0,                  /* tp_doc */
4265    (traverseproc)PyEdge_Traverse,                  /* tp_traverse */
4266    (inquiry)PyEdge_Clear,                  /* tp_clear */
4267    (richcmpfunc)PyEdge_Richcmp,                    /* tp_richcompare */
4268    0,                  /* tp_weaklistoffset */
4269    0,          /* tp_iter */
4270    0,  /* tp_iternext */
4271    0,                  /* tp_methods */
4272    0,                  /* tp_members */
4273    0,                  /* tp_getset */
4274    0,                  /* tp_base */
4275    0,                  /* tp_dict */
4276    0,                  /* tp_descr_get */
4277    0,                  /* tp_descr_set */
4278    0,                  /* tp_dictoffset */
4279    0,                             /* tp_init */
4280    PyType_GenericAlloc,                               /* tp_alloc */
4281    0,                               /* tp_new */
4282    _PyObject_GC_Del,                                  /* tp_free */
4283};
4284
4285
4286PYXTRACT_IGNORE int Orange_traverse(TPyOrange *self, visitproc visit, void *arg);
4287PYXTRACT_IGNORE int Orange_clear(TPyOrange *self);
4288PYXTRACT_IGNORE void Orange_dealloc(TPyOrange *self);
4289
4290
4291inline bool hasObjectsOnEdges(PyObject *graph)
4292{
4293    PyObject *dict = ((TPyOrange *)graph)->orange_dict;
4294    PyObject *ooe = NULL;
4295    if (dict) {
4296        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4297        if (!ooe) {
4298            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4299        }
4300    }
4301    return ooe && (PyObject_IsTrue(ooe) != 0);
4302}
4303
4304inline bool hasObjectsOnEdges(PGraph graph)
4305{
4306    PyObject *dict = graph->myWrapper->orange_dict;
4307    PyObject *ooe = NULL;
4308    if (dict) {
4309        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4310        if (!ooe) {
4311            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4312        }
4313    }
4314    return ooe && (PyObject_IsTrue(ooe) != 0);
4315}
4316
4317inline bool hasObjectsOnEdges(const TGraph *graph)
4318{
4319    PyObject *dict = graph->myWrapper->orange_dict;
4320    PyObject *ooe = NULL;
4321    if (dict) {
4322        ooe = PyDict_GetItemString(dict, "objects_on_edges");
4323        if (!ooe) {
4324            ooe = PyDict_GetItemString(dict, "objectsOnEdges");
4325        }
4326    }
4327    return ooe && (PyObject_IsTrue(ooe) != 0);
4328}
4329
4330void decrefEdge(double *weights, const int &nEdgeTypes)
4331{
4332    if (weights)
4333        for(double *we = weights, *wee = weights + nEdgeTypes; we != wee; we++)
4334            if (CONNECTED(*we))
4335                Py_DECREF(DOUBLE_AS_PYOBJECT(*we));
4336}
4337
4338PyObject *PyEdge_New(PGraph graph, const int &v1, const int &v2, double *weights)
4339{
4340    TPyEdge *self = PyObject_GC_New(TPyEdge, &PyEdge_Type);
4341    if (self == NULL)
4342        return NULL;
4343
4344    // The object constructor has never been called, so we must initialize it
4345    // before assigning to it
4346    self->graph.init();
4347
4348    self->graph = graph;
4349    self->v1 = v1;
4350    self->v2 = v2;
4351    self->weights = weights;
4352    self->objectsOnEdges = hasObjectsOnEdges(graph);
4353
4354    PyObject_GC_Track(self);
4355    return (PyObject *)self;
4356}
4357
4358
4359ABSTRACT(Graph, Orange)
4360RECOGNIZED_ATTRIBUTES(Graph, "objects forceMapping force_mapping returnIndices return_indices objectsOnEdges object_on_edges")
4361
4362int Graph_getindex(TGraph *graph, PyObject *index)
4363{
4364    if (PyInt_Check(index)) {
4365        if (!graph->myWrapper->orange_dict)
4366            return PyInt_AsLong(index);
4367        PyObject *fmap = PyDict_GetItemString(graph->myWrapper->orange_dict, "force_mapping");
4368        if (!fmap) {
4369            fmap = PyDict_GetItemString(graph->myWrapper->orange_dict, "forceMapping");
4370        }
4371        if (!fmap || PyObject_IsTrue(fmap))
4372            return PyInt_AsLong(index);
4373    }
4374
4375    if (graph->myWrapper->orange_dict) {
4376        PyObject *objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "objects");
4377        if (objs && (objs != Py_None)) {
4378
4379            if (PyDict_Check(objs)) {
4380                PyObject *pyidx = PyDict_GetItem(objs, index);
4381                if (!pyidx)
4382                    return -1;
4383                if (!PyInt_Check(pyidx))
4384                    PYERROR(PyExc_IndexError, "vertex index should be an integer", -1);
4385                return PyInt_AsLong(pyidx);
4386            }
4387
4388            PyObject *iter = PyObject_GetIter(objs);
4389            if (!iter)
4390                PYERROR(PyExc_IndexError, "Graph.object should be iterable", -1);
4391            int i = 0;
4392
4393            for(PyObject *item = PyIter_Next(iter); item; item = PyIter_Next(iter), i++) {
4394                int cmp = PyObject_Compare(item, index);
4395                Py_DECREF(item);
4396                if (PyErr_Occurred())
4397                    return -1;
4398                if (!cmp) {
4399                    Py_DECREF(iter);
4400                    return i;
4401                }
4402            }
4403
4404            Py_DECREF(iter);
4405            PYERROR(PyExc_IndexError, "index not found", -1);
4406        }
4407    }
4408
4409    PYERROR(PyExc_IndexError, "invalid index type: should be integer (or 'objects' must be specified)", -1);
4410}
4411
4412
4413PyObject *Graph_nodesToObjects(TGraph *graph, const vector<int> &neighbours)
4414{
4415    if (graph->myWrapper->orange_dict) {
4416        PyObject *objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "returnIndices");
4417        if (!objs || (PyObject_IsTrue(objs) == 0)) {
4418            objs = PyDict_GetItemString(graph->myWrapper->orange_dict, "objects");
4419            if (objs && (objs != Py_None)) {
4420                PyObject *res = PyList_New(neighbours.size());
4421
4422                if (PyDict_Check(objs)) {
4423                    // This is slow, but can't help...
4424                    int el = 0;
4425                    PyObject *key, *value;
4426                    Py_ssize_t pos = 0;
4427
4428                    while (PyDict_Next(objs, &pos, &key, &value))
4429                        if (!PyInt_Check(value)) {
4430                            Py_DECREF(res);
4431                            PYERROR(PyExc_IndexError, "values in Graph.objects dictionary should be integers", PYNULL);
4432                        }
4433
4434                        for(vector<int>::const_iterator ni(neighbours.begin()), ne(neighbours.end()); ni!=ne; ni++, el++) {
4435                            pos = 0;
4436                            bool set = false;
4437                            while (PyDict_Next(objs, &pos, &key, &value) && !set) {
4438                                if (PyInt_AsLong(value) == *ni) {
4439                                    Py_INCREF(key);
4440                                    PyList_SetItem(res, el, key);
4441                                    set = true;
4442                                }
4443                            }
4444
4445                            if (!set) {
4446                                Py_DECREF(res);
4447                                PyErr_Format(PyExc_IndexError, "'objects' miss the key for vertex %i", *ni);
4448                                return PYNULL;
4449                            }
4450                        }
4451                }
4452                else {
4453                    Py_ssize_t el = 0;
4454                    for(vector<int>::const_iterator ni(neighbours.begin()), ne(neighbours.end()); ni!=ne; ni++, el++) {
4455                        PyObject *pyel = PySequence_GetItem(objs, *ni);
4456                        if (!pyel) {
4457                            Py_DECREF(res);
4458                            return PYNULL;
4459                        }
4460                        else
4461                            PyList_SetItem(res, el, pyel);
4462                    }
4463                }
4464                return res;
4465            }
4466        }
4467    }
4468
4469    return convertToPython(neighbours);
4470}
4471
4472
4473PyObject *Graph_getitem(PyObject *self, PyObject *args)
4474{
4475    PyTRY
4476        CAST_TO(TGraph, graph);
4477
4478    PyObject *py1, *py2;
4479    int v1, v2, type = -1;
4480
4481    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4482        || ((v1 = Graph_getindex(graph, py1)) < 0)
4483        || ((v2 = Graph_getindex(graph, py2)) < 0))
4484        return PYNULL;
4485
4486    if (PyTuple_Size(args) == 2) {
4487        PGraph graph = PyOrange_AS_Orange(self);
4488        return PyEdge_New(graph, v1, v2, graph->getEdge(v1, v2));
4489    }
4490
4491    else {
4492        PGraph graph = PyOrange_AS_Orange(self);
4493        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4494            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", type, graph->nEdgeTypes);
4495            return PYNULL;
4496        }
4497        double *weights = graph->getEdge(v1, v2);
4498        if (!weights || !CONNECTED(weights[type]))
4499            RETURN_NONE
4500        else {
4501            if (hasObjectsOnEdges(graph)) {
4502                PyObject *res = DOUBLE_AS_PYOBJECT(weights[type]);
4503                Py_INCREF(res);
4504                return res;
4505            }
4506            else
4507                return PyFloat_FromDouble(weights[type]);
4508        }
4509    }
4510    PyCATCH
4511}
4512
4513
4514PyObject *Graph_edgeExists(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(v1, v2[, type])")
4515{
4516    PyTRY
4517        CAST_TO(TGraph, graph);
4518
4519    PyObject *py1, *py2;
4520    int v1, v2, type = -1;
4521
4522    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4523        || ((v1 = Graph_getindex(graph, py1)) < 0)
4524        || ((v2 = Graph_getindex(graph, py2)) < 0))
4525        return PYNULL;
4526
4527    if (PyTuple_Size(args) == 2)
4528        return PyInt_FromLong(graph->getEdge(v1, v2) ? 1 : 0);
4529
4530    else {
4531        PGraph graph = PyOrange_AS_Orange(self);
4532        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4533            PyErr_Format(PyExc_IndexError, "type %s out of range (0-%i)", type, graph->nEdgeTypes);
4534            return PYNULL;
4535        }
4536        double *weights = graph->getEdge(v1, v2);
4537        return PyInt_FromLong(!weights || !CONNECTED(weights[type]) ? 0 : 1);
4538    }
4539    PyCATCH
4540}
4541
4542int Graph_setitem(PyObject *self, PyObject *args, PyObject *item)
4543{
4544    PyTRY
4545        CAST_TO_err(TGraph, graph, -1);
4546    bool objectsOnEdges = hasObjectsOnEdges(graph);
4547
4548    PyObject *py1, *py2;
4549    int v1, v2, type = -1;
4550
4551    if (   !PyArg_ParseTuple(args, "OO|i", &py1, &py2, &type)
4552        || ((v1 = Graph_getindex(graph, py1)) < 0)
4553        || ((v2 = Graph_getindex(graph, py2)) < 0))
4554        return -1;
4555
4556    if (PyTuple_Size(args) == 3) {
4557        if ((type >= graph->nEdgeTypes) || (type < 0)) {
4558            PyErr_Format(PyExc_IndexError, "type %i out of range (0-%i)", type, graph->nEdgeTypes);
4559            return -1;
4560        }
4561
4562        double w;
4563
4564        bool noConnection = !item || (item == Py_None);
4565
4566        if (noConnection)
4567            DISCONNECT(w);
4568        else
4569            if (!objectsOnEdges && !PyNumber_ToDouble(item, w))
4570                PYERROR(PyExc_TypeError, "a number expected for edge weight", -1);
4571
4572        // we call getOrCreateEdge only after we check all arguments, so we don't end up
4573        // with a half-created edge
4574        double *weights = graph->getOrCreateEdge(v1, v2);
4575
4576        if (objectsOnEdges) {
4577            if (!noConnection)
4578                Py_INCREF(item);
4579            if (CONNECTED(weights[type]))
4580                Py_DECREF(DOUBLE_AS_PYOBJECT(weights[type]));
4581
4582            DOUBLE_AS_PYOBJECT(weights[type]) = item;
4583        }
4584        else {
4585            weights[type] = w;
4586        }
4587
4588        if (noConnection) {
4589            double *we, *wee;
4590            for(we = weights, wee = weights + graph->nEdgeTypes; (we != wee) && !CONNECTED(*we); we++);
4591            if (we == wee)
4592                graph->removeEdge(v1, v2);
4593        }
4594
4595        return 0;
4596    }
4597
4598    else {
4599        if (!item || (item == Py_None)) {
4600            if (objectsOnEdges)
4601                decrefEdge(graph->getEdge(v1, v2), graph->nEdgeTypes);
4602            graph->removeEdge(v1, v2);
4603            return 0;
4604        }
4605
4606        if (graph->nEdgeTypes == 1) {
4607            double w;
4608            if (objectsOnEdges || PyNumber_ToDouble(item, w)) {
4609                double *weights = graph->getOrCreateEdge(v1, v2);
4610                if (objectsOnEdges) {
4611                    DOUBLE_AS_PYOBJECT(*weights) = item;
4612                    Py_INCREF(item);
4613                }
4614                else
4615                    *weights = w;
4616                return 0;
4617            }
4618        }
4619
4620        if (PySequence_Check(item)) {
4621            if (PySequence_Size(item) != graph->nEdgeTypes)
4622                PYERROR(PyExc_AttributeError, "invalid size of the list of edge weights", -1);
4623
4624            double *ww = new double[graph->nEdgeTypes];
4625            double *wwi = ww;
4626            PyObject *iterator = PyObject_GetIter(item);
4627            if (iterator) {
4628                for(PyObject *item = PyIter_Next(iterator); item; item = PyIter_Next(iterator)) {
4629                    if (item == Py_None)
4630                        DISCONNECT(*(wwi++));
4631                    else
4632                        if (objectsOnEdges) {
4633                            DOUBLE_AS_PYOBJECT(*wwi++) = item;
4634                        }
4635                        else {
4636                            if (!PyNumber_ToDouble(item, *(wwi++))) {
4637                                Py_DECREF(item);
4638                                Py_DECREF(iterator);
4639                                PyErr_Format(PyExc_TypeError, "invalid number for edge type %i", wwi-ww-1);
4640                                delete ww;
4641                                return -1;
4642                            }
4643                            Py_DECREF(item); // no Py_DECREF if objectsOnEdges!
4644                        }
4645                }
4646                Py_DECREF(iterator);
4647            }
4648
4649            double *weights = graph->getOrCreateEdge(v1, v2);
4650            if (objectsOnEdges)
4651                decrefEdge(weights, graph->nEdgeTypes);
4652            memcpy(weights, ww, graph->nEdgeTypes * sizeof(double));
4653            return 0;
4654        }
4655    }
4656
4657    PYERROR(PyExc_AttributeError, "arguments for __setitem__ are [v1, v2, type] = weight|None,  [v1, v2] = list | weight (if nEdgeType=1)", -1);
4658    PyCATCH_1
4659}
4660
4661
4662PyObject *Graph_getNeighbours(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
4663{
4664    PyTRY
4665        CAST_TO(TGraph, graph);
4666
4667    PyObject *pyv;
4668    int vertex, edgeType = -1;
4669    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
4670        || ((vertex = Graph_getindex(graph, pyv)) < 0))
4671        return PYNULL;
4672
4673    vector<int> neighbours;
4674    if (PyTuple_Size(args) == 1)
4675        graph->getNeighbours(vertex, neighbours);
4676    else
4677        graph->getNeighbours(vertex, edgeType, neighbours);
4678
4679    return Graph_nodesToObjects(graph, neighbours);
4680    PyCATCH
4681}
4682
4683
4684PyObject *Graph_getEdgesFrom(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
4685{
4686    PyTRY
4687        CAST_TO(TGraph, graph);
4688
4689    PyObject *pyv;
4690    int vertex, edgeType = -1;
4691    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
4692        || ((vertex = Graph_getindex(graph, pyv)) < 0))
4693        return PYNULL;
4694
4695    vector<int> neighbours;
4696    if (PyTuple_Size(args) == 1)
4697        graph->getNeighboursFrom(vertex, neighbours);
4698    else
4699        graph->getNeighboursFrom(vertex, edgeType, neighbours);
4700
4701    return Graph_nodesToObjects(graph, neighbours);
4702    PyCATCH
4703}
4704
4705PyObject *Graph_addCluster(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> None")
4706{
4707    PyTRY
4708        CAST_TO(TGraph, graph);
4709
4710    PyObject *pyv;
4711
4712    if (!PyArg_ParseTuple(args, "O:Graph.addCluster", &pyv))
4713        return PYNULL;
4714
4715    Py_ssize_t size = PyList_Size(pyv);
4716    int i,j;
4717    for (i = 0; i < size-1; i++)
4718    {
4719        for (j = i+1; j < size; j++)
4720        {
4721            int x = PyInt_AsLong(PyList_GetItem(pyv, i));
4722            int y = PyInt_AsLong(PyList_GetItem(pyv, j));
4723            //cout << x << " " << y;
4724            double* weight = graph->getOrCreateEdge(x, y);
4725            *weight = 1.0;
4726            //cout << "." << endl;
4727        }
4728    }
4729
4730    RETURN_NONE;
4731    PyCATCH
4732}
4733
4734bool lessLength (const set<int>& s1, const set<int>& s2)
4735{
4736    return s1.size() > s2.size();
4737}
4738
4739bool moreLength (const vector<int>& s1, const vector<int>& s2)
4740{
4741    return s1.size() > s2.size();
4742}
4743
4744PyObject *Graph_getConnectedComponents(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_NOARGS, "None -> list of [nodes]")
4745{
4746    PyTRY
4747    CAST_TO(TGraph, graph);
4748    //cout << "Graph_getConnectedComponents" << endl;
4749    int node = 0;
4750    vector<set<int> > components;
4751    set<int> all;
4752
4753    while (node < graph->nVertices)
4754    {
4755        set<int> component = graph->getConnectedComponent(node);
4756        components.push_back(component);
4757        all.insert(component.begin(), component.end());
4758
4759        while(node < graph->nVertices)
4760        {
4761            node++;
4762            if (all.find(node) == all.end())
4763                break;
4764        }
4765    }
4766    sort(components.begin(), components.end(), lessLength);
4767
4768    PyObject* components_list = PyList_New(0);
4769
4770    ITERATE(vector<set<int> >, si, components) {
4771        PyObject* component_list = PyList_New(0);
4772
4773        ITERATE(set<int>, ni, *si) {
4774            PyObject *nel = Py_BuildValue("i", *ni);
4775            PyList_Append(component_list, nel);
4776            Py_DECREF(nel);
4777        }
4778
4779        PyList_Append(components_list, component_list);
4780        Py_DECREF(component_list);
4781    }
4782
4783    return components_list;
4784    PyCATCH
4785}
4786
4787PyObject *Graph_getDegreeDistribution(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(distribution)")
4788{
4789    PyTRY
4790        CAST_TO(TGraph, graph);
4791
4792        PyObject* degrees = PyDict_New();
4793        PyObject *nsize, *pydegree;
4794
4795        int v;
4796        for (v = 0; v < graph->nVertices; v++)
4797        {
4798            vector<int> neighbours;
4799            graph->getNeighbours(v, neighbours);
4800            nsize = PyInt_FromLong(neighbours.size());
4801
4802            pydegree = PyDict_GetItem(degrees, nsize); // returns borrowed reference!
4803            int newdegree = pydegree ? PyInt_AsLong(pydegree) + 1 : 1;
4804
4805            pydegree = PyInt_FromLong(newdegree);
4806      PyDict_SetItem(degrees, nsize, pydegree);
4807      Py_DECREF(pydegree);
4808        }
4809
4810        return degrees;
4811    PyCATCH
4812}
4813
4814PyObject *Graph_getDegrees(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "degrees")
4815{
4816    PyTRY
4817        CAST_TO(TGraph, graph);
4818
4819        PyObject* degrees = PyList_New(graph->nVertices);
4820        for(int v1 = 0; v1 < graph->nVertices; v1++)
4821        {
4822            PyList_SetItem(degrees, v1,  PyInt_FromLong(0));
4823        }
4824
4825        vector<int> neighbours;
4826        for(int v1 = 0; v1 < graph->nVertices; v1++)
4827        {
4828            graph->getNeighboursFrom_Single(v1, neighbours);
4829
4830            ITERATE(vector<int>, ni, neighbours)
4831            {
4832                int v1_degree = PyInt_AsLong(PyList_GetItem(degrees, v1));
4833                int v2_degree = PyInt_AsLong(PyList_GetItem(degrees, *ni));
4834
4835                v2_degree++;
4836                v1_degree++;
4837
4838                PyList_SetItem(degrees, v1,  PyInt_FromLong(v1_degree));
4839                PyList_SetItem(degrees, *ni, PyInt_FromLong(v2_degree));
4840            }
4841        }
4842
4843        if (!graph->directed) {
4844            for(int v1 = 0; v1 < graph->nVertices; v1++) {
4845                int v1_degree = PyInt_AsLong(PyList_GetItem(degrees, v1));
4846                PyList_SetItem(degrees, v1,  PyInt_FromLong(v1_degree / 2));
4847            }
4848        }
4849
4850        return degrees;
4851    PyCATCH
4852}
4853
4854
4855PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference);
4856
4857PyObject *Graph_getSubGraph(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
4858{
4859    PyTRY
4860    CAST_TO(TGraph, graph);
4861    //cout << "Graph_getSubGraph" << endl;
4862    PyObject *vertices;
4863
4864    if (!PyArg_ParseTuple(args, "O:Graph.getSubGraph", &vertices))
4865        return PYNULL;
4866
4867    Py_ssize_t size = PyList_Size(vertices);
4868    PyList_Sort(vertices);
4869
4870    TGraph *subgraph = new TGraphAsList(size, graph->nEdgeTypes, graph->directed);
4871    PGraph wsubgraph = subgraph;
4872
4873    Py_ssize_t i;
4874    vector<int> neighbours;
4875    for (i = 0; i < size; i++) {
4876        int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
4877
4878        graph->getNeighboursFrom_Single(vertex, neighbours);
4879        ITERATE(vector<int>, ni, neighbours) {
4880            if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1) {
4881                int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4882
4883                if (index != -1) {
4884                    double* w = subgraph->getOrCreateEdge(i, index);
4885                    double* oldw = graph->getOrCreateEdge(vertex, *ni);
4886                    int j;
4887                    for (j=0; j < subgraph->nEdgeTypes; j++) {
4888                        w[j] = oldw[j];
4889                    }
4890                }
4891            }
4892        }
4893    }
4894
4895    PyObject *pysubgraph = WrapOrange(wsubgraph); //WrapNewOrange(subgraph, self->ob_type);
4896
4897    // set graphs attribut items of type ExampleTable to subgraph
4898    PyObject *strItems = PyString_FromString("items");
4899    if (PyObject_HasAttr(self, strItems) == 1) {
4900        PyObject* items = PyObject_GetAttr(self, strItems);
4901        /*
4902        cout << PyObject_IsTrue(items) << endl;
4903        cout << PyObject_Size(items) << endl;
4904        cout << graph->nVertices << endl;
4905        */
4906        if (PyObject_IsTrue(items) && PyObject_Size(items) == graph->nVertices) {
4907            PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
4908            Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
4909        }
4910    }
4911    Py_DECREF(strItems);
4912    return pysubgraph;
4913    PyCATCH
4914}
4915
4916
4917PyObject *Graph_getSubGraphMergeCluster(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
4918{
4919    PyTRY
4920        CAST_TO(TGraph, graph);
4921
4922        PyObject *verticesWithout;
4923        PyObject *vertices = PyList_New(0);
4924
4925        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphMergeCluster", &verticesWithout))
4926            return PYNULL;
4927
4928        // create an array of vertices to be in a new graph
4929        int i;
4930        vector<int> neighbours;
4931        for (i = 0; i < graph->nVertices; i++)
4932        {
4933      if (PySequence_Contains(verticesWithout, PyInt_FromLong(i)) == 0)
4934            {
4935        PyObject *nel = Py_BuildValue("i", i);
4936              PyList_Append(vertices, nel);
4937              Py_DECREF(nel);
4938      }
4939    }
4940
4941        // create new graph without cluster
4942        Py_ssize_t size = PyList_Size(vertices);
4943        PyList_Sort(vertices);
4944
4945        TGraph *subgraph = new TGraphAsList(size + 1, graph->nEdgeTypes, graph->directed);
4946        PGraph wsubgraph = subgraph;
4947
4948        for (i = 0; i < size; i++)
4949        {
4950            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
4951
4952            graph->getNeighboursFrom_Single(vertex, neighbours);
4953            ITERATE(vector<int>, ni, neighbours)
4954            {
4955                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
4956                {
4957                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4958
4959                    if (index != -1)
4960                    {
4961                        double* w = subgraph->getOrCreateEdge(i, index);
4962                        *w = 1.0;
4963                    }
4964                }
4965            }
4966        }
4967        // connect new meta-node with all verties
4968        int sizeWithout = PyList_Size(verticesWithout);
4969        for (i = 0; i < sizeWithout; i++)
4970        {
4971            int vertex = PyInt_AsLong(PyList_GetItem(verticesWithout, i));
4972
4973            graph->getNeighbours(vertex, neighbours);
4974            ITERATE(vector<int>, ni, neighbours)
4975            {
4976                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
4977                {
4978                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
4979
4980                    if (index != -1)
4981                    {
4982                        double* w = subgraph->getOrCreateEdge(size, index);
4983                        *w = 1.0;
4984                    }
4985                }
4986            }
4987        }
4988
4989        PyObject *pysubgraph = WrapOrange(wsubgraph);
4990
4991        // set graphs attribut items of type ExampleTable to subgraph
4992    PyObject *strItems = PyString_FromString("items");
4993
4994        if (PyObject_HasAttr(self, strItems) == 1)
4995        {
4996            PyObject* items = PyObject_GetAttr(self, strItems);
4997      PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
4998
4999      PExampleTable graph_table = PyOrange_AsExampleTable(selection);
5000      TExample *example = new TExample(graph_table->domain, true);
5001      graph_table->push_back(example);
5002      Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
5003    }
5004
5005      Py_DECREF(strItems);
5006
5007        return pysubgraph;
5008    PyCATCH
5009}
5010
5011
5012PyObject *Graph_getSubGraphMergeClusters(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "List of (vertices) -> list of [v1, v2, ..., vn]")
5013{
5014    PyTRY
5015        CAST_TO(TGraph, graph);
5016
5017        set<int> verticesWithout;
5018        PyObject *fullGraphs;
5019        PyObject *vertices = PyList_New(0);
5020
5021        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphMergeClusters", &fullGraphs))
5022            return PYNULL;
5023
5024        // create an array of vertices to remove from the graph
5025        Py_ssize_t sizeFullGraphs = PyList_Size(fullGraphs);
5026        int i;
5027        for (i = 0; i < sizeFullGraphs; i++)
5028        {
5029            PyObject *fullGraph = PyList_GetItem(fullGraphs, i);
5030            Py_ssize_t sizeFullGraph = PyList_Size(fullGraph);
5031
5032            int j;
5033            for (j = 0; j < sizeFullGraph; j++)
5034            {
5035                int vertex = PyInt_AsLong(PyList_GetItem(fullGraph, j));
5036                verticesWithout.insert(vertex);
5037            }
5038        }
5039
5040        vector<int> neighbours;
5041        // create an array of vertices to be in a new graph
5042        for (i = 0; i < graph->nVertices; i++)
5043        {
5044            set<int>::iterator it = verticesWithout.find(i);
5045            if (it == verticesWithout.end())
5046            {
5047        PyObject *nel = Py_BuildValue("i", i);
5048              PyList_Append(vertices, nel);
5049              Py_DECREF(nel);
5050      }
5051    }
5052
5053        // create new graph without cluster
5054        Py_ssize_t size = PyList_Size(vertices);
5055        PyList_Sort(vertices);
5056
5057        TGraph *subgraph = new TGraphAsList(size + sizeFullGraphs, graph->nEdgeTypes, graph->directed);
5058        PGraph wsubgraph = subgraph;
5059
5060        for (i = 0; i < size; i++)
5061        {
5062            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5063
5064            graph->getNeighboursFrom_Single(vertex, neighbours);
5065            ITERATE(vector<int>, ni, neighbours)
5066            {
5067                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5068                {
5069                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5070
5071                    if (index != -1)
5072                    {
5073                        double* w = subgraph->getOrCreateEdge(i, index);
5074                        *w = 1.0;
5075                    }
5076                }
5077            }
5078        }
5079        // connect new meta-node with all verties
5080        for (i = 0; i < sizeFullGraphs; i++)
5081        {
5082            PyObject *fullGraph = PyList_GetItem(fullGraphs, i);
5083            Py_ssize_t sizeFullGraph = PyList_Size(fullGraph);
5084            int j;
5085            for (j = 0; j < sizeFullGraph; j++)
5086            {
5087                int vertex = PyInt_AsLong(PyList_GetItem(fullGraph, j));
5088                graph->getNeighbours(vertex, neighbours);
5089
5090                // connect with old neighbours
5091                ITERATE(vector<int>, ni, neighbours)
5092                {
5093                    if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5094                    {
5095                        // vertex to connect with is in new graph
5096                        int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5097
5098                        if (index != -1)
5099                        {
5100                            double* w = subgraph->getOrCreateEdge(size + i, index);
5101                            *w = 1.0;
5102                        }
5103                    }
5104                    else
5105                    {
5106                        // vertex to connect with is a new meta node
5107                        int k;
5108                        for (k = 0; k < sizeFullGraphs; k++)
5109                        {
5110                            PyObject *fullGraph = PyList_GetItem(fullGraphs, k);
5111
5112                            if (PySequence_Contains(fullGraph, PyInt_FromLong(*ni)) == 1)
5113                            {
5114                                if (k != i)
5115                                {
5116                                    double* w = subgraph->getOrCreateEdge(size + i, size + k);
5117                                    *w = 1.0;
5118                                }
5119                                break;
5120                            }
5121                        }
5122                    }
5123                }
5124            }
5125        }
5126
5127        PyObject *pysubgraph = WrapOrange(wsubgraph);
5128
5129        // set graphs attribut items of type ExampleTable to subgraph
5130    PyObject *strItems = PyString_FromString("items");
5131
5132        if (PyObject_HasAttr(self, strItems) == 1)
5133        {
5134            PyObject* items = PyObject_GetAttr(self, strItems);
5135      PyObject* selection = multipleSelectLow((TPyOrange *)items, vertices, false);
5136
5137      PExampleTable graph_table = PyOrange_AsExampleTable(selection);
5138            for (i = 0; i < sizeFullGraphs; i++)
5139            {
5140                TExample *example = new TExample(graph_table->domain, true);
5141                graph_table->push_back(example);
5142            }
5143      Orange_setattrDictionary((TPyOrange *)pysubgraph, strItems, selection, false);
5144    }
5145
5146      Py_DECREF(strItems);
5147
5148        return pysubgraph;
5149    PyCATCH
5150}
5151
5152
5153PyObject *Graph_getSubGraphWithout(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertices) -> list of [v1, v2, ..., vn]")
5154{
5155    PyTRY
5156        CAST_TO(TGraph, graph);
5157
5158        PyObject *verticesWithout;
5159        PyObject *vertices = PyList_New(0);
5160
5161        if (!PyArg_ParseTuple(args, "O:Graph.getSubGraphWithout", &verticesWithout))
5162            return PYNULL;
5163
5164    int i;
5165    for (i = 0; i < graph->nVertices; i++)
5166        {
5167      if (PySequence_Contains(verticesWithout, PyInt_FromLong(i)) == 0)
5168            {
5169        PyObject *nel = Py_BuildValue("i", i);
5170              PyList_Append(vertices, nel);
5171              Py_DECREF(nel);
5172      }
5173    }
5174
5175        Py_ssize_t size = PyList_Size(vertices);
5176        PyList_Sort(vertices);
5177
5178        TGraph *subgraph = new TGraphAsList(size, graph->nEdgeTypes, graph->directed);
5179        PGraph wsubgraph = subgraph;
5180
5181        vector<int> neighbours;
5182        for (i = 0; i < size; i++)
5183        {
5184            int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5185
5186            graph->getNeighboursFrom_Single(vertex, neighbours);
5187            ITERATE(vector<int>, ni, neighbours)
5188            {
5189                if (PySequence_Contains(vertices, PyInt_FromLong(*ni)) == 1)
5190                {
5191                    int index = PySequence_Index(vertices, PyInt_FromLong(*ni));
5192
5193                    if (index != -1)
5194                    {
5195                        double* w = subgraph->getOrCreateEdge(i, index);
5196                        *w = 1.0;
5197                    }
5198                }
5199            }
5200        }
5201
5202        // set graphs attribut items of type ExampleTable to subgraph
5203        /*
5204        TExampleTable *table;
5205        PExampleTable wtable;
5206
5207        if (PyObject_HasAttr(self, PyString_FromString("items")) == 1)
5208        {
5209            PyObject* items = PyObject_GetAttr(self, PyString_FromString("items"));
5210
5211            PExampleTable graph_table;
5212            if (PyArg_ParseTuple(PyTuple_Pack(1,items), "O", &graph_table))
5213            {
5214
5215                table = new TExampleTable(graph_table->domain);
5216                wtable = table;
5217
5218                for (i = 0; i < size; i++)
5219                {
5220                    int vertex = PyInt_AsLong(PyList_GetItem(vertices, i));
5221
5222                    graph_table.
5223                }
5224
5225                //PyObject_SetAttr((PyObject *)subgraph, PyString_FromString("items"), Py_BuildValue("N", WrapOrange(wtable)));
5226            }
5227        }
5228
5229        return Py_BuildValue("NN", WrapOrange(wsubgraph), WrapOrange(wtable));
5230        /**/
5231        return Py_BuildValue("N", WrapOrange(wsubgraph));
5232    PyCATCH
5233}
5234
5235
5236PyObject *Graph_getHubs(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(n) -> HubList")
5237{
5238  PyTRY
5239        int n;
5240
5241        if (!PyArg_ParseTuple(args, "n:Graph.getHubs", &n))
5242            return NULL;
5243
5244        CAST_TO(TGraph, graph);
5245
5246        int *vertexDegree = new int[graph->nVertices];
5247
5248        int i;
5249        for (i=0; i < graph->nVertices; i++)
5250        {
5251            vertexDegree[i] = 0;
5252        }
5253
5254
5255        vector<int> neighbours;
5256        for(i = 0; i < graph->nVertices; i++)
5257        {
5258            graph->getNeighboursFrom_Single(i, neighbours);
5259
5260            ITERATE(vector<int>, ni, neighbours)
5261            {
5262                vertexDegree[i]++;
5263                vertexDegree[*ni]++;
5264            }
5265        }
5266
5267        PyObject* hubList = PyList_New(n);
5268
5269        for (i=0; i < n; i++)
5270        {
5271            int j;
5272            int ndx_max = -1;
5273            int max = 0;
5274            for (j=0; j < graph->nVertices; j++)
5275            {
5276                if (vertexDegree[j] > max)
5277                {
5278                    ndx_max = j;
5279                    max = vertexDegree[j];
5280                }
5281            }
5282            //cout << "pow: " << vertexPower[ndx_max] << " ndx: " << ndx_max << endl;
5283
5284            vertexDegree[ndx_max] = -2;
5285            PyList_SetItem(hubList, i, PyInt_FromLong(ndx_max));
5286        }
5287
5288        delete [] vertexDegree;
5289        return hubList;
5290  PyCATCH
5291}
5292
5293
5294PyObject *Graph_getEdgesTo(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(vertex[, edgeType])")
5295{
5296    PyTRY
5297        CAST_TO(TGraph, graph);
5298
5299    PyObject *pyv;
5300    int vertex, edgeType = -1;
5301    if (   !PyArg_ParseTuple(args, "O|i:Graph.getNeighbours", &pyv, &edgeType)
5302        || ((vertex = Graph_getindex(graph, pyv)) < 0))
5303        return PYNULL;
5304
5305    vector<int> neighbours;
5306    if (PyTuple_Size(args) == 1)
5307        graph->getNeighboursTo(vertex, neighbours);
5308    else
5309        graph->getNeighboursTo(vertex, edgeType, neighbours);
5310
5311    return Graph_nodesToObjects(graph, neighbours);
5312    PyCATCH
5313}
5314
5315
5316PyObject *Graph_getEdges(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "([edgetype]) -> list of (v1, v2, weights)")
5317{
5318    PyTRY
5319        CAST_TO(TGraph, graph);
5320
5321    int edgeType = -1;
5322    if (!PyArg_ParseTuple(args, "|i:Graph.getEdges", &edgeType))
5323        return PYNULL;
5324
5325    bool hasType = (PyTuple_Size(args) != 0);
5326    if (hasType && (edgeType<0) || (edgeType >= graph->nEdgeTypes)) {
5327        PyErr_Format(PyExc_IndexError, "edge type out of range 0-%i", graph->nEdgeTypes);
5328        return PYNULL;
5329    }
5330
5331    PyObject *res = PyList_New(0);
5332    vector<int> neighbours;
5333
5334    for(int v1 = 0; v1 < graph->nVertices; v1++) {
5335        neighbours.clear();
5336        if (hasType)
5337            if (graph->directed) {
5338                graph->getNeighboursFrom(v1, edgeType, neighbours);
5339            }
5340            else {
5341                graph->getNeighboursFrom_Single(v1, edgeType, neighbours);
5342            }
5343        else
5344            if (graph->directed) {
5345                graph->getNeighboursFrom(v1, neighbours);
5346            }
5347            else {
5348                graph->getNeighboursFrom_Single(v1, neighbours);
5349            }
5350
5351        ITERATE(vector<int>, ni, neighbours) {
5352            PyObject *nel = Py_BuildValue("ii", v1, *ni);
5353            PyList_Append(res, nel);
5354            Py_DECREF(nel);
5355        }
5356    }
5357
5358    return res;
5359    PyCATCH
5360}
5361
5362PyObject *Graph_getNodes(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "neighbours -> list of (v1, v2, weights)")
5363{
5364    PyTRY
5365        CAST_TO(TGraph, graph);
5366
5367    int noOfNeighbours = -1;
5368    if (!PyArg_ParseTuple(args, "i:Graph.getNodes", &noOfNeighbours))
5369        return PYNULL;
5370
5371    PyObject *res = PyList_New(0);
5372    vector<int> neighbours;
5373
5374    for(int v1 = 0; v1 < graph->nVertices; v1++) {
5375            graph->getNeighbours(v1, neighbours);
5376
5377      if (neighbours.size() == noOfNeighbours)
5378      {
5379              PyObject *nel = Py_BuildValue("i", v1);
5380              PyList_Append(res, nel