source: orange/source/orange/lib_kernel.cpp @ 11703:9b8d8ab7820c

Revision 11703:9b8d8ab7820c, 212.6 KB checked in by janezd <janez.demsar@…>, 7 months ago (diff)

Removed the GPL copyright notice from all files except orangeqt.

Line 
1#ifdef _MSC_VER
2  #pragma warning (disable : 4786 4114 4018 4267 4244)
3#endif
4
5#include "vars.hpp"
6#include "domain.hpp"
7#include "examplegen.hpp"
8#include "table.hpp"
9#include "learn.hpp"
10#include "estimateprob.hpp"
11#include "preprocessors.hpp"
12#include "callback.hpp"
13
14#include "cls_value.hpp"
15#include "cls_example.hpp"
16#include "lib_kernel.hpp"
17#include "vectortemplates.hpp"
18
19
20#include "externs.px"
21
22#include "converts.hpp"
23#include "cls_orange.hpp"
24#include "slist.hpp"
25
26WRAPPER(ExampleTable);
27
28PStringList PStringList_FromArguments(PyObject *arg);
29
30/* This was moved from lib_vectors.cpp:
31    - nobody used it
32    - lib_vectors.cpp is automatically generated and I'd hate to add this as an exception
33
34int pt_FloatList(PyObject *args, void *floatlist)
35{
36  *(PFloatList *)(floatlist) = PFloatList_FromArguments(args);
37  return PyErr_Occurred() ? -1 : 0;
38}
39*/
40
41
42int pt_StringList(PyObject *args, void *stringList)
43{
44  PStringList &rsl = *(PStringList *)stringList;
45
46  if (PyOrStringList_Check(args))
47    rsl = PyOrange_AsStringList(args);
48  else
49    rsl = PStringList_FromArguments(args);
50
51  return rsl ? 1 : 0;
52}
53
54int ptn_StringList(PyObject *args, void *stringList)
55{
56  if (args == Py_None) {
57    *(PStringList *)stringList = PStringList();
58    return 1;
59  }
60
61  return pt_StringList(args, stringList);
62}
63
64
65/* ************ PROGRESS CALLBACK ************ */
66
67#include "progress.hpp"
68
69PyObject *ProgressCallback_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
70{ if (type == (PyTypeObject *)&PyOrProgressCallback_Type)
71    return setCallbackFunction(WrapNewOrange(mlnew TProgressCallback_Python(), type), args);
72  else
73    return WrapNewOrange(mlnew TProgressCallback_Python(), type);
74}
75
76
77PyObject *ProgressCallback__reduce__(PyObject *self)
78{
79  return callbackReduce(self, PyOrProgressCallback_Type);
80}
81
82
83PyObject *ProgressCallback_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(float[, Orange]) -> bool")
84{
85  PyTRY
86    NO_KEYWORDS
87
88    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrProgressCallback_Type) {
89      PyErr_Format(PyExc_SystemError, "ProgressCallback.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
90      return PYNULL;
91    }
92
93    float f;
94    POrange o;
95    if (!PyArg_ParseTuple(targs, "f|O&:ProgressCallback", &f, ccn_Orange, &o))
96      return PYNULL;
97
98    return PyInt_FromLong(SELF_AS(TProgressCallback)(f, o) ? 1 : 0);
99  PyCATCH
100}
101
102/* ************ VARIABLE ************ */
103
104PVarList PVarList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::P_FromArguments(arg); }
105PyObject *VarList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_FromArguments(type, arg); }
106PyObject *VarList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of Variable>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_new(type, arg, kwds); }
107PyObject *VarList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_getitem(self, index); }
108int       VarList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_setitem(self, index, item); }
109PyObject *VarList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_getslice(self, start, stop); }
110int       VarList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_setslice(self, start, stop, item); }
111Py_ssize_t       VarList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_len(self); }
112PyObject *VarList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_richcmp(self, object, op); }
113PyObject *VarList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_concat(self, obj); }
114PyObject *VarList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_repeat(self, times); }
115PyObject *VarList_str(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_str(self); }
116PyObject *VarList_repr(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_str(self); }
117int       VarList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_contains(self, obj); }
118PyObject *VarList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Variable) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_append(self, item); }
119PyObject *VarList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_extend(self, obj); }
120PyObject *VarList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> int") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_count(self, obj); }
121PyObject *VarList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> VarList") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_filter(self, args); }
122PyObject *VarList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> int") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_index(self, obj); }
123PyObject *VarList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_insert(self, args); }
124PyObject *VarList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_native(self); }
125PyObject *VarList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Variable") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_pop(self, args); }
126PyObject *VarList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_remove(self, obj); }
127PyObject *VarList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_reverse(self); }
128PyObject *VarList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_sort(self, args); }
129PyObject *VarList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_reduce(self); }
130
131
132PVarListList PVarListList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::P_FromArguments(arg); }
133PyObject *VarListList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_FromArguments(type, arg); }
134PyObject *VarListList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of VarList>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_new(type, arg, kwds); }
135PyObject *VarListList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_getitem(self, index); }
136int       VarListList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_setitem(self, index, item); }
137PyObject *VarListList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_getslice(self, start, stop); }
138int       VarListList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_setslice(self, start, stop, item); }
139Py_ssize_t       VarListList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_len(self); }
140PyObject *VarListList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_richcmp(self, object, op); }
141PyObject *VarListList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_concat(self, obj); }
142PyObject *VarListList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_repeat(self, times); }
143PyObject *VarListList_str(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_str(self); }
144PyObject *VarListList_repr(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_str(self); }
145int       VarListList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_contains(self, obj); }
146PyObject *VarListList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(VarList) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_append(self, item); }
147PyObject *VarListList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_extend(self, obj); }
148PyObject *VarListList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> int") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_count(self, obj); }
149PyObject *VarListList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> VarListList") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_filter(self, args); }
150PyObject *VarListList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> int") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_index(self, obj); }
151PyObject *VarListList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_insert(self, args); }
152PyObject *VarListList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_native(self); }
153PyObject *VarListList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> VarList") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_pop(self, args); }
154PyObject *VarListList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_remove(self, obj); }
155PyObject *VarListList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_reverse(self); }
156PyObject *VarListList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_sort(self, args); }
157PyObject *VarListList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_reduce(self); }
158
159
160PVarList knownVars(PyObject *keywords)
161{
162  PVarList variables;
163  PyObject *pyknownVars=keywords ? PyDict_GetItemString(keywords, "use") : PYNULL;
164  if (!pyknownVars || (pyknownVars == Py_None))
165    return PVarList();
166
167  if (PyOrVarList_Check(pyknownVars))
168    variables = ((GCPtr<TVarList>)(PyOrange_AS_Orange(pyknownVars)));
169
170  else if (PyOrDomain_Check(pyknownVars)) {
171    PDomain domain = PyOrange_AsDomain(pyknownVars);
172    variables = mlnew TVarList(domain->variables.getReference());
173    ITERATE(TMetaVector, mi, domain->metas)
174      variables->push_back((*mi).variable);
175  }
176
177  else
178    variables= PVarList_FromArguments(pyknownVars);
179
180  if (!variables)
181    raiseError("invalid value for 'use' argument"); // PYERROR won't do - NULL is a valid value to return...
182
183  return variables;
184}
185
186
187PDomain knownDomain(PyObject *keywords)
188{
189  PVarList variables;
190  PyObject *pyknownDomain = keywords ? PyDict_GetItemString(keywords, "domain") : PYNULL;
191  if (!pyknownDomain || (pyknownDomain == Py_None))
192    return PDomain();
193
194  if (!PyOrDomain_Check(pyknownDomain))
195    raiseError("invalid value for 'domain' argument"); // PYERROR won't do - NULL is a valid value to return...
196
197  return PyOrange_AsDomain(pyknownDomain);
198}
199
200
201TMetaVector *knownMetas(PyObject *keywords)
202{
203  if (!keywords)
204    return NULL;
205
206  PyObject *pyknownDomain = PyDict_GetItemString(keywords, "domain");
207  if (pyknownDomain && (pyknownDomain != Py_None)) {
208    if (!PyOrDomain_Check(pyknownDomain))
209      raiseError("invalid value for 'domain' argument"); // PYERROR won't do - NULL is a valid value to return...
210    return &PyOrange_AsDomain(pyknownDomain)->metas;
211  }
212
213  pyknownDomain = PyDict_GetItemString(keywords, "use");
214  if (pyknownDomain && PyOrDomain_Check(pyknownDomain))
215    return &PyOrange_AsDomain(pyknownDomain)->metas;
216
217  return NULL;
218}
219
220ABSTRACT(Variable - Orange.feature.Descriptor, Orange)
221C_NAMED(EnumVariable - Orange.feature.Discrete, Variable, "([name=, values=, autoValues=, distributed=, getValueFrom=])")
222C_NAMED(FloatVariable - Orange.feature.Continuous, Variable, "([name=, startValue=, endValue=, stepValue=, distributed=, getValueFrom=])")
223
224PyObject *PyVariable_MakeStatus_FromLong(long ok);
225
226/* Left for compatibility (also put into the header, as for others */
227PyObject *MakeStatus()
228{ PyObject *mt=PyModule_New("MakeStatus");
229  PyModule_AddObject(mt, "OK", PyVariable_MakeStatus_FromLong((long)TVariable::OK));
230  PyModule_AddObject(mt, "MissingValues", PyVariable_MakeStatus_FromLong((long)TVariable::MissingValues));
231  PyModule_AddObject(mt, "NoRecognizedValues", PyVariable_MakeStatus_FromLong((long)TVariable::NoRecognizedValues));
232  PyModule_AddObject(mt, "Incompatible", PyVariable_MakeStatus_FromLong((long)TVariable::Incompatible));
233  PyModule_AddObject(mt, "NotFound", PyVariable_MakeStatus_FromLong((long)TVariable::NotFound));
234  return mt;
235}
236
237PYCLASSCONSTANT(Variable, MakeStatus, MakeStatus())
238
239
240PyObject *Variable_getExisting(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, failOn]]) -> (Variable|None, status)")
241{
242  PyTRY
243    char *varName;
244    int varType;
245    PStringList values;
246    PStringList unorderedValues_asList;
247    int failOn = TVariable::Incompatible;
248
249    if (!PyArg_ParseTuple(args, "si|O&O&i:Variable.getExisting", &varName, &varType, ptn_StringList, &values, ptn_StringList, &unorderedValues_asList, &failOn))
250      return NULL;
251
252    set<string> unorderedValues;
253    if (unorderedValues_asList)
254      unorderedValues.insert(unorderedValues_asList->begin(), unorderedValues_asList->end());
255
256    int status;
257    PVariable var = TVariable::getExisting(varName, varType, values.getUnwrappedPtr(), &unorderedValues, failOn, &status);
258    return Py_BuildValue("NN", WrapOrange(var), PyVariable_MakeStatus_FromLong(status));
259  PyCATCH
260}
261
262
263PyObject *Variable_retrieve(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, failOn]]) -> (Variable|None, status)")
264{
265    return Variable_getExisting(NULL, args);
266}
267
268
269PyObject *newmetaid(PyObject *, PyObject *args);
270
271PyObject *Variable_new_meta_id(PyObject *, PyObject *args)  PYARGS(METH_VARARGS | METH_STATIC, "([Variable]) -> int")
272{
273    return newmetaid(NULL, args);
274}
275
276PyObject *Variable_make(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, createNewOn]]) -> (Variable|None, status)")
277{
278  PyTRY
279    char *varName;
280    int varType;
281    PStringList values;
282    PStringList unorderedValues_asList;
283    int createNewOn = TVariable::Incompatible;
284
285    if (!PyArg_ParseTuple(args, "si|O&O&i:Variable.make", &varName, &varType, ptn_StringList, &values, ptn_StringList, &unorderedValues_asList, &createNewOn))
286      return NULL;
287
288    set<string> unorderedValues;
289    if (unorderedValues_asList)
290      unorderedValues.insert(unorderedValues_asList->begin(), unorderedValues_asList->end());
291
292    int status;
293    PVariable var = TVariable::make(varName, varType, values.getUnwrappedPtr(), &unorderedValues, createNewOn, &status);
294    return Py_BuildValue("NN", WrapOrange(var), PyVariable_MakeStatus_FromLong(status));
295  PyCATCH
296}
297
298//set and get name
299int Variable_set_name(PyObject *self, PyObject *name)
300{ 
301    char *varName;
302    if (!PyString_Check(name))
303        PYERROR(PyExc_AttributeError, "string expected", 0);
304    varName = PyString_AsString(name);
305    PVariable var = PyOrange_AsVariable(self);
306    var->set_name(string(varName));
307    return 0;
308}
309
310
311PyObject *Variable_get_name(PyObject *self) 
312{
313    PVariable var = PyOrange_AsVariable(self);
314    return Py_BuildValue("s", var->get_name().c_str());
315}
316
317
318#include "stringvars.hpp"
319C_NAMED(StringVariable - Orange.feature.String, Variable, "([name=])")
320
321#include "pythonvars.hpp"
322C_NAMED(PythonVariable - Orange.feature.Python, Variable, "([name=])")
323
324PyObject *PythonValue_new(PyTypeObject *type, PyObject *args, PyObject *kwds) BASED_ON(SomeValue, "([object])")
325{
326  if (!PyTuple_Size(args))
327    return WrapNewOrange(mlnew TPythonValue(), type);
328
329  if (PyTuple_Size(args)==1)
330    return WrapNewOrange(mlnew TPythonValue(PyTuple_GET_ITEM(args, 0)), type);
331
332  else
333    PYERROR(PyExc_TypeError, "PythonValue.__init__ expects up to one Python object", PYNULL);
334}
335
336
337PyObject *PythonValueSpecial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) BASED_ON(Orange, "(int)") ALLOWS_EMPTY
338{
339  int vtype = 1;
340  if (!PyArg_ParseTuple(args, "|i:PythonValueSpecial.__init__", &vtype))
341    return PYNULL;
342
343  return WrapNewOrange(mlnew TPythonValueSpecial(vtype), type);
344}
345
346
347int PythonValue_set_value(PyObject *self, PyObject *value)
348{
349  Py_INCREF(value);
350  SELF_AS(TPythonValue).value = value;
351  return 0;
352}
353
354
355PyObject *PythonValue_get_value(PyObject *self)
356{
357  PyObject *res = SELF_AS(TPythonValue).value;
358  Py_INCREF(res);
359  return res;
360}
361
362
363PyObject *PythonValue__reduce__(PyObject *self)
364{
365  return Py_BuildValue("O(O)", (PyObject *)(self->ob_type), SELF_AS(TPythonValue).value);
366}
367
368
369PyObject *Variable_getattr(TPyOrange *self, PyObject *name)
370{
371  if (PyString_Check(name) && !strcmp(PyString_AsString(name), "attributes")
372      && (!self->orange_dict || !PyDict_Contains(self->orange_dict, name))) {
373    PyObject *dict = PyDict_New();
374    Orange_setattrDictionary(self, name, dict, false);
375    Py_DECREF(dict);
376  }
377
378  return Orange_getattr(self, name);
379}
380
381PyObject *Variable_randomvalue(PyObject *self, PyObject *args) PYARGS(0, "() -> Value")
382{ PyTRY
383    CAST_TO(TVariable, var);
384    if (args && !PyArg_ParseTuple(args, ""))
385      PYERROR(PyExc_TypeError, "no parameters expected", PYNULL);
386
387    return Value_FromVariableValue(PyOrange_AsVariable(self), var->randomValue());
388  PyCATCH
389}
390
391PyObject *Variable_firstvalue(PyObject *self, PyObject *args) PYARGS(0, "() -> Value | None")
392{ PyTRY
393    CAST_TO(TVariable, var);
394    if (args && !PyArg_ParseTuple(args, ""))
395      PYERROR(PyExc_TypeError, "no parameters expected", PYNULL);
396
397    TValue val;
398    if (!var->firstValue(val)) RETURN_NONE;
399
400    return Value_FromVariableValue(PyOrange_AsVariable(self), val);
401  PyCATCH
402}
403
404PyObject *Variable_nextvalue(PyObject *self, PyObject *val) PYARGS(METH_O, "(value)  -> Value | None")
405{ PyTRY
406    CAST_TO(TVariable, var);
407    if (   !PyOrValue_Check(val)
408        || (PyValue_AS_Variable(val) ? (PyValue_AS_Variable(val) != var) : (PyValue_AS_Value(val).varType != var->varType)))
409      PYERROR(PyExc_TypeError, "invalid value parameter", PYNULL);
410
411    TValue sval = PyValue_AS_Value(val);
412
413    if (!var->nextValue(sval))
414      RETURN_NONE;
415
416    return Value_FromVariableValue(PyOrange_AsVariable(self), sval);
417  PyCATCH
418}
419
420
421PyObject *Variable_computeValue(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> Value")
422{ PyTRY
423    CAST_TO(TVariable, var);
424    if (!PyOrExample_Check(args))
425      PYERROR(PyExc_TypeError, "Variable.computeValue: 'Example' expected", PYNULL);
426
427    const TExample &ex = PyExample_AS_ExampleReference(args);
428
429    int idx = ex.domain->getVarNum(var, false);
430    if (idx != ILLEGAL_INT)
431      return Value_FromVariableValue(var, ex[idx]);
432
433    if (!var->getValueFrom)
434      PYERROR(PyExc_SystemError, "Variable.computeValue: 'getValueFrom' not defined", PYNULL);
435
436    return Value_FromVariableValue(var, var->computeValue(PyExample_AS_ExampleReference(args)));
437  PyCATCH
438}
439
440
441PyObject *Variable_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
442{ PyTRY
443    NO_KEYWORDS
444
445    PyObject *object;
446    TValue value;
447
448    if (   !PyArg_ParseTuple(args, "O:Variable.__call__", &object)
449        || !convertFromPython(object, value, PyOrange_AsVariable(self)))
450      return PYNULL;
451
452    return Value_FromVariableValue(PyOrange_AsVariable(self), value);
453  PyCATCH
454}
455
456
457PyObject *Variable_DC(PyObject *self) PYARGS(METH_NOARGS, "() -> DC")
458{
459  PyTRY
460    PVariable var = PyOrange_AsVariable(self);
461    return Value_FromVariableValue(var, var->DC());
462  PyCATCH
463}
464
465
466
467PyObject *Variable_DK(PyObject *self) PYARGS(METH_NOARGS, "() -> DK")
468{
469  PyTRY
470    PVariable var = PyOrange_AsVariable(self);
471    return Value_FromVariableValue(var, var->DK());
472  PyCATCH
473}
474
475
476PyObject *Variable_specialValue(PyObject *self, PyObject *arg) PYARGS(METH_O, "(int) -> special value")
477{
478  PyTRY
479    int valType;
480    if (!convertFromPython(arg, valType))
481      return PYNULL;
482    PVariable var = PyOrange_AsVariable(self);
483    return Value_FromVariableValue(var, var->specialValue(valType));
484  PyCATCH
485}
486
487
488
489PyObject *replaceVarWithEquivalent(PyObject *pyvar)
490{
491  PVariable newVar = PyOrange_AsVariable(pyvar);
492  TEnumVariable *enewVar = newVar.AS(TEnumVariable);
493  TVariable *oldVar = TVariable::getExisting(newVar->get_name(), newVar->varType, enewVar ? enewVar->values.getUnwrappedPtr() : NULL, NULL, TVariable::Incompatible);
494  if (oldVar && oldVar->isEquivalentTo(newVar.getReference())) {
495    if (newVar->sourceVariable)
496      oldVar->sourceVariable = newVar->sourceVariable;
497    if (newVar->getValueFrom)
498      oldVar->getValueFrom = newVar->getValueFrom;
499    Py_DECREF(pyvar);
500    return WrapOrange(PVariable(oldVar));
501  }
502  return pyvar;
503}
504
505
506PyObject *Variable__reduce__(PyObject *self)
507{
508    PyTRY
509        PyObject *name = PyObject_GetAttrString(self, "name");
510        PyObject *dict = packOrangeDictionary(self);
511        PyMapping_SetItemString(dict, "name", name);
512        Py_DECREF(name);
513        PyObject *state = PyDict_New();
514        PyObject *pygetvf = PyDict_GetItemString(dict, "get_value_from");
515        if (pygetvf) {
516            // get_value_from can contain a reference to this variable itself
517            PyDict_SetItemString(state, "get_value_from", pygetvf);
518            PyDict_DelItemString(dict, "get_value_from");
519        }
520        return Py_BuildValue("O(ON)N", getExportedFunction("__pickleLoaderVariable"), self->ob_type, dict, state); //packOrangeDictionary(self));
521    PyCATCH
522}
523
524
525PyObject *__pickleLoaderVariable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, dictionary)")
526{
527  PyTRY
528    PyTypeObject *type;
529    PyObject *dict;
530      if (!PyArg_ParseTuple(args, "OO:__pickleLoaderEnumVariable", &type, &dict))
531          return NULL;
532        PyObject *emptyTuple = PyTuple_New(0);
533        PyObject *pyVar = type->tp_new(type, emptyTuple, NULL);
534        Py_DECREF(emptyTuple);
535        if (unpackOrangeDictionary(pyVar, dict) == -1)
536          PYERROR(PyExc_AttributeError, "cannot construct the variable from the pickle", PYNULL)
537        return replaceVarWithEquivalent(pyVar);
538    PyCATCH
539}
540
541
542PyObject *EnumVariable__reduce__(PyObject *self)
543{
544    PyTRY
545        PyObject *name = PyObject_GetAttrString(self, "name");
546        PyObject *dict = packOrangeDictionary(self);
547        PyMapping_SetItemString(dict, "name", name);
548        Py_DECREF(name);
549        PyObject *state = PyDict_New();
550        PyObject *pygetvf = PyDict_GetItemString(dict, "get_value_from");
551        if (pygetvf) {
552            // get_value_from can contain a reference to this variable itself
553            PyDict_SetItemString(state, "get_value_from", pygetvf);
554            PyDict_DelItemString(dict, "get_value_from");
555        }
556        return Py_BuildValue("O(ON)N", getExportedFunction("__pickleLoaderEnumVariable"), self->ob_type, dict, state); //packOrangeDictionary(self));
557    PyCATCH
558}
559
560
561PyObject *__pickleLoaderEnumVariable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, dictionary)")
562{
563  PyTRY
564    PyTypeObject *type;
565    PyObject *dict;
566      if (!PyArg_ParseTuple(args, "OO:__pickleLoaderEnumVariable", &type, &dict))
567          return NULL;
568
569    char *name = NULL;
570    TStringList *values = NULL;
571
572    PyObject *pyname = PyDict_GetItemString(dict, "name");
573    if (pyname)
574      name = PyString_AsString(pyname);
575
576    PyObject *pyvalues = PyDict_GetItemString(dict, "values");
577    if (pyvalues)
578      values = PyOrange_AsStringList((TPyOrange *)pyvalues).getUnwrappedPtr();
579   
580    if (!(values && name))
581        PYERROR(PyExc_ValueError, "cannot construct the variable from the pickle", PYNULL);
582    TVariable *var = TVariable::getExisting(name, TValue::INTVAR, values, NULL);
583    PVariable pvar = var;
584    if (!var) {
585      TEnumVariable *evar = new TEnumVariable(name ? name : "");
586      pvar = evar;
587      if (values)
588        const_PITERATE(TStringList, vi, values)
589          evar->addValue(*vi);
590    }
591
592    PyObject *pyvar = WrapOrange(pvar);
593
594    PyObject *d_key, *d_value;
595    Py_ssize_t i = 0;
596    while (PyDict_Next(dict, &i, &d_key, &d_value)) {
597      if (   strcmp("values", PyString_AsString(d_key))
598          && Orange_setattrLow((TPyOrange *)pyvar, d_key, d_value, false) < 0
599         ) {
600          Py_DECREF(pyvar);
601          return NULL;
602        }
603    }
604
605    return replaceVarWithEquivalent(pyvar);
606    PyCATCH
607}
608
609PyObject *EnumVariable_getitem_sq(PyObject *self, Py_ssize_t index)
610{ PyTRY
611    CAST_TO(TEnumVariable, var)
612    if (!var->values || (index<0) || (index>=var->values->size()))
613      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
614    return Value_FromVariableValue(PyOrange_AsVariable(self), TValue((int)index));
615  PyCATCH
616}
617
618PyObject *EnumVariable_addValue(PyObject *self, PyObject *arg) PYARGS(METH_O, "(string) -> None")
619{
620  PyTRY
621    if (!PyString_Check(arg))
622      PYERROR(PyExc_TypeError, "string argument expected", PYNULL);
623    PyOrange_AsEnumVariable(self)->addValue(PyString_AsString(arg));
624    RETURN_NONE;
625  PyCATCH
626}
627
628PyObject *FloatVariable_getitem_sq(PyObject *self, Py_ssize_t index)
629{ PyTRY
630    CAST_TO(TFloatVariable, var);
631    if ((var->stepValue<=0) || (var->startValue>var->endValue))
632      PYERROR(PyExc_IndexError, "interval not specified", PYNULL);
633
634    float maxInd = (var->endValue - var->startValue)/var->stepValue;
635
636    if ((index<0) || (index>maxInd))
637      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
638    return Value_FromVariableValue(PyOrange_AsVariable(self), TValue(var->startValue+var->stepValue*index));
639  PyCATCH
640}
641
642
643bool convertFromPythonWithVariable(PyObject *obj, string &str)
644{ return convertFromPythonWithML(obj, str, *FindOrangeType(typeid(TVariable))); }
645
646
647bool varListFromDomain(PyObject *boundList, PDomain domain, TVarList &boundSet, bool allowSingle, bool checkForIncludance)
648{ if (PyOrVarList_Check(boundList)) {
649    PVarList variables = PyOrange_AsVarList(boundList);
650    if (checkForIncludance)
651      const_PITERATE(TVarList, vi, variables)
652        if (!domain || (domain->getVarNum(*vi, false)==ILLEGAL_INT)) {
653          PyErr_Format(PyExc_IndexError, "variable '%s' does not exist in the domain", (*vi)->get_name().c_str());
654          return false;
655        }
656    boundSet=variables.getReference();
657    return true;
658  }
659
660  if (PySequence_Check(boundList)) {
661    PyObject *iterator = PyObject_GetIter(boundList);
662    if (iterator) {
663      for(PyObject *item = PyIter_Next(iterator); item; item = PyIter_Next(iterator)) {
664        PVariable variable=varFromArg_byDomain(item, domain, checkForIncludance);
665        Py_DECREF(item);
666        if (!variable) {
667          Py_DECREF(iterator);
668          return false;
669        }
670        boundSet.push_back(variable);
671      }
672
673      Py_DECREF(iterator);
674      return true;
675    }
676  }
677
678  else if (allowSingle) {
679    PVariable variable=varFromArg_byDomain(boundList, domain, checkForIncludance);
680    if (variable) {
681      boundSet.push_back(variable);
682      return true;
683    }
684  }
685  PYERROR(PyExc_TypeError, "invalid argument (list of variables expected)", false);
686}
687
688
689// Given a parameter from Python and a domain, it returns a variable.
690// Python's parameter can be a string name, an index or Variable
691PVariable varFromArg_byDomain(PyObject *obj, PDomain domain, bool checkForIncludance)
692{ PVariable var;
693  if (domain) {
694    PyTRY
695      if (PyString_Check(obj)) {
696        const char *attr = PyString_AS_STRING(obj);
697        PVariable res = domain->getVar(attr, true, false);
698        if (!res)
699          PyErr_Format(PyExc_IndexError, "attribute '%s' not found", attr);
700        return res;
701      }
702      if (PyInt_Check(obj)) {
703        int idx = PyInt_AsLong(obj);
704
705        if (idx<0) {
706          PVariable res = domain->getMetaVar(idx, false);
707          if (!res)
708            PyErr_Format(PyExc_IndexError, "meta attribute %i not found", idx);
709          return res;
710        }
711
712        if (idx>=domain->variables->size())
713          PYERROR(PyExc_IndexError, "index out of range", PVariable());
714
715        return domain->getVar(idx);
716      }
717    PyCATCH_r(PVariable())
718  }
719
720  if (PyOrVariable_Check(obj)) {
721    PVariable var(PyOrange_AsVariable(obj));
722    if (checkForIncludance)
723      if (!domain || (domain->getVarNum(var, false)==ILLEGAL_INT))
724        PYERROR(PyExc_IndexError, "variable does not exist in the domain", PVariable());
725    return var;
726  }
727
728  PYERROR(PyExc_TypeError, "invalid type for variable", PVariable());
729}
730
731
732bool varListFromVarList(PyObject *boundList, PVarList varlist, TVarList &boundSet, bool allowSingle, bool checkForIncludance)
733{ if (PyOrVarList_Check(boundList)) {
734    PVarList variables = PyOrange_AsVarList(boundList);
735    if (checkForIncludance)
736      const_PITERATE(TVarList, vi, variables) {
737        TVarList::const_iterator fi(varlist->begin()), fe(varlist->end());
738        for(; (fi!=fe) && (*fi != *vi); fi++);
739        if (fi==fe) {
740          PyErr_Format(PyExc_IndexError, "variable '%s' does not exist in the domain", (*vi)->get_name().c_str());
741          return false;
742        }
743      }
744    boundSet = variables.getReference();
745    return true;
746  }
747
748  if (PyList_Check(boundList)) {
749    for(Py_ssize_t pos=0, max=PyList_Size(boundList); pos<max; pos++) {
750      PyObject *li=PyList_GetItem(boundList, pos);
751      if (!li)
752        PYERROR(PyExc_TypeError, "can't read the argument list", false);
753      PVariable variable = varFromArg_byVarList(li, varlist, checkForIncludance);
754      if (!variable)
755        return false;
756      boundSet.push_back(variable);
757    }
758    return true;
759  }
760  else if (allowSingle) {
761    PVariable variable = varFromArg_byVarList(boundList, varlist, checkForIncludance);
762    if (!variable)
763      return false;
764    boundSet.push_back(variable);
765    return true;
766  }
767
768  PYERROR(PyExc_TypeError, "invalid attribute for list of variables", false);
769}
770
771
772// Given a parameter from Python and a list of variables, it returns a variable.
773// Python's parameter can be a string name, an index or Variable
774PVariable varFromArg_byVarList(PyObject *obj, PVarList varlist, bool checkForIncludance)
775{ PVariable var;
776  if (varlist) {
777    PyTRY
778      if (PyString_Check(obj)) {
779        char *s = PyString_AS_STRING(obj);
780        TVarList::const_iterator fi(varlist->begin()), fe(varlist->end());
781        for(; (fi!=fe) && ((*fi)->get_name() != s); fi++);
782        if (fi==fe) {
783          PyErr_Format(PyExc_IndexError, "variable '%s' does not exist in the domain", s);
784          return PVariable();
785        }
786        else
787          return *fi;
788      }
789    PyCATCH_r(PVariable())
790  }
791
792  if (PyOrVariable_Check(obj)) {
793    PVariable var(PyOrange_AsVariable(obj));
794    if (checkForIncludance) {
795      TVarList::const_iterator fi(varlist->begin()), fe(varlist->end());
796      for(; (fi!=fe) && (*fi != var); fi++);
797      if (fi==fe)
798        PYERROR(PyExc_IndexError, "variable does not exist in the domain", PVariable());
799    }
800    return var;
801  }
802
803  PYERROR(PyExc_TypeError, "invalid type for variable", PVariable());
804}
805
806
807bool varNumFromVarDom(PyObject *pyvar, PDomain domain, int &attrNo)
808{
809  PVariable var=varFromArg_byDomain(pyvar, domain);
810  if (!var)
811    return false; // varFromArg_byDomain has already set the error message
812
813  PITERATE(TVarList, vi, domain->attributes)
814    if (*vi==var) {
815      attrNo = vi-domain->attributes->begin();
816      return true;
817    }
818
819  attrNo = domain->getMetaNum(var, false);
820  return attrNo != ILLEGAL_INT;
821}
822
823
824bool weightFromArg_byDomain(PyObject *pyweight, PDomain domain, int &weightID)
825{
826  if (!pyweight || (pyweight == Py_None))
827    weightID = 0;
828
829  else if (PyInt_Check(pyweight))
830    weightID =  PyInt_AsLong(pyweight);
831
832  else {
833    PVariable var = varFromArg_byDomain(pyweight, domain);
834    if (!var)
835      PYERROR(PyExc_TypeError, "invalid or unknown weight attribute", false);
836
837    weightID = domain->getVarNum(var);
838  }
839
840  return true;
841}
842
843
844static PExampleGenerator *ptw_examplegenerator;
845
846int ptw_weightByDomainCB(PyObject *args, void *weight)
847{
848  PDomain dom = ptw_examplegenerator ? (*ptw_examplegenerator)->domain : PDomain();
849  ptw_examplegenerator = NULL;
850  return weightFromArg_byDomain(args, dom, *(int *)weight) ? 1 : 0;
851}
852
853converter pt_weightByGen(PExampleGenerator &peg)
854{
855  ptw_examplegenerator = &peg;
856  return ptw_weightByDomainCB;
857}
858
859
860PyObject *StringValue_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.data.StringValue, "(string)")
861{ char *s;
862  if (!PyArg_ParseTuple(args, "s:StringValue", &s))
863    return PYNULL;
864
865  return WrapNewOrange(mlnew TStringValue(s), type);
866}
867
868
869PyObject *StringValue__reduce__(PyObject *self)
870{
871  return Py_BuildValue("O(s)", (PyObject *)(self->ob_type), SELF_AS(TStringValue).value.c_str());
872}
873
874
875/* ************ ATTRIBUTED FLOAT LIST ************ */
876
877PyObject *AttributedFloatList_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(FloatList, "(attributes, list)") ALLOWS_EMPTY
878{
879  PyObject *ob1 = NULL, *ob2 = NULL;
880  if (!PyArg_UnpackTuple(args, "AttributedFloatList.new", 0, 2, &ob1, &ob2))
881    return PYNULL;
882
883  PyObject *wabl = ListOfUnwrappedMethods<PAttributedFloatList, TAttributedFloatList, float>::_new(type, ob2 ? ob2 : ob1, keywds);
884
885  if (ob2) {
886    PVarList attributes = PVarList_FromArguments(ob1);
887    if (!attributes)
888      return PYNULL;
889
890    PyOrange_AsAttributedFloatList(wabl)->attributes = attributes;
891  }
892
893  return wabl;
894}
895
896
897PyObject * /*no pyxtract!*/ FloatList_getitem_sq(TPyOrange *self, Py_ssize_t index);
898int        /*no pyxtract!*/ FloatList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item);
899
900int AttributedList_getIndex(const int &listsize, PVarList attributes, PyObject *index)
901{
902  int res;
903
904  if (!listsize)
905    PYERROR(PyExc_IndexError, "the list is empty", ILLEGAL_INT);
906
907  if (PyInt_Check(index)) {
908    res = (int)PyInt_AsLong(index);
909    if (res < 0)
910      res += listsize;
911  }
912
913  else {
914    if (!attributes)
915      PYERROR(PyExc_AttributeError, "variable list not defined, need integer indices", ILLEGAL_INT);
916
917    if (PyOrVariable_Check(index)) {
918      PVariable var = PyOrange_AsVariable(index);
919      TVarList::const_iterator vi(attributes->begin()), ve(attributes->end());
920      int ind = 0;
921      for(; vi!=ve; vi++, ind++)
922        if (*vi == var) {
923          res = ind;
924          break;
925        }
926
927      if (vi == ve) {
928        PyErr_Format(PyExc_AttributeError, "attribute '%s' not found in the list", var->get_name().c_str());
929        return ILLEGAL_INT;
930      }
931    }
932
933    else if (PyString_Check(index)) {
934      const char *name = PyString_AsString(index);
935      TVarList::const_iterator vi(attributes->begin()), ve(attributes->end());
936      int ind = 0;
937      for(; vi!=ve; vi++, ind++)
938        if ((*vi)->get_name() == name) {
939          res = ind;
940          break;
941        }
942
943      if (vi == ve) {
944        PyErr_Format(PyExc_AttributeError, "attribute '%s' not found in the list", name);
945        return ILLEGAL_INT;
946      }
947    }
948
949    else {
950      PyErr_Format(PyExc_TypeError, "cannot index the list by '%s'", index->ob_type->tp_name);
951      return ILLEGAL_INT;
952    }
953  }
954
955  if ((res >= listsize) || (res < 0)) {
956    PyErr_Format(PyExc_IndexError, "index %i out of range 0-%i", res, listsize-1);
957    return ILLEGAL_INT;
958  }
959
960  return res;
961}
962
963
964PyObject *AttributedFloatList_getitem(TPyOrange *self, PyObject *index)
965{
966  PyTRY
967    CAST_TO(TAttributedFloatList, aflist)
968
969    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
970    if (ind == ILLEGAL_INT)
971      return PYNULL;
972
973    return FloatList_getitem_sq(self, ind);
974  PyCATCH
975}
976
977
978int AttributedFloatList_setitem(TPyOrange *self, PyObject *index, PyObject *value)
979{
980  PyTRY
981    CAST_TO_err(TAttributedFloatList, aflist, -1)
982
983    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
984    if (ind == ILLEGAL_INT)
985      return -1;
986
987    return FloatList_setitem_sq(self, ind, value);
988  PyCATCH_1
989}
990
991
992
993PyObject *AttributedBoolList_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(BoolList, "(attributes, list)") ALLOWS_EMPTY
994{
995  PyObject *ob1 = NULL, *ob2 = NULL;
996  if (!PyArg_UnpackTuple(args, "AttributedBoolList.new", 0, 2, &ob1, &ob2))
997    return PYNULL;
998
999  PyObject *wabl = ListOfUnwrappedMethods<PAttributedBoolList, TAttributedBoolList, bool>::_new(type, ob2 ? ob2 : ob1, keywds);
1000
1001  if (ob2) {
1002    PVarList attributes = PVarList_FromArguments(ob1);
1003    if (!attributes)
1004      return PYNULL;
1005
1006    PyOrange_AsAttributedBoolList(wabl)->attributes = attributes;
1007  }
1008
1009  return wabl;
1010}
1011
1012
1013PyObject * /*no pyxtract!*/ BoolList_getitem_sq(TPyOrange *self, Py_ssize_t index);
1014int        /*no pyxtract!*/ BoolList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item);
1015
1016
1017PyObject *AttributedBoolList_getitem(TPyOrange *self, PyObject *index)
1018{
1019  PyTRY
1020    CAST_TO(TAttributedBoolList, aflist)
1021
1022    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
1023    if (ind == ILLEGAL_INT)
1024      return PYNULL;
1025
1026    return BoolList_getitem_sq(self, ind);
1027  PyCATCH
1028}
1029
1030
1031int AttributedBoolList_setitem(TPyOrange *self, PyObject *index, PyObject *value)
1032{
1033  PyTRY
1034    CAST_TO_err(TAttributedBoolList, aflist, -1)
1035
1036    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
1037    if (ind == ILLEGAL_INT)
1038      return -1;
1039
1040    return BoolList_setitem_sq(self, ind, value);
1041  PyCATCH_1
1042}
1043
1044
1045/* ************ DOMAIN ************ */
1046
1047#include "domain.hpp"
1048
1049const TMetaDescriptor *metaDescriptorFromArg(TDomain &domain, PyObject *rar)
1050{
1051  TMetaDescriptor *desc = NULL;
1052
1053  if (PyString_Check(rar))
1054    desc = domain.metas[string(PyString_AsString(rar))];
1055
1056  else if (PyOrVariable_Check(rar))
1057    desc = domain.metas[PyOrange_AsVariable(rar)->get_name()];
1058
1059  else if (PyInt_Check(rar))
1060    desc = domain.metas[PyInt_AsLong(rar)];
1061
1062  else
1063    PYERROR(PyExc_TypeError, "invalid meta descriptor", NULL);
1064
1065  if (!desc)
1066    PYERROR(PyExc_AttributeError, "meta attribute does not exist", NULL);
1067
1068  return desc;
1069}
1070
1071
1072PyObject *Domain_isOptionalMeta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | int | descriptor) -> bool")
1073{
1074  PyTRY
1075    const TMetaDescriptor *desc = metaDescriptorFromArg(SELF_AS(TDomain), rar);
1076    return desc ? PyBool_FromLong(desc->optional ? 1 : 0) : NULL;
1077
1078  PyCATCH
1079}
1080
1081
1082PyObject *Domain_meta_id(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | descriptor) -> int")
1083{ PyTRY
1084    const TMetaDescriptor *desc = metaDescriptorFromArg(SELF_AS(TDomain), rar);
1085    return desc ? PyInt_FromLong(desc->id) : NULL;
1086  PyCATCH
1087}
1088
1089
1090PyObject *Domain_has_meta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | int | descriptor) -> bool")
1091{
1092  PyTRY
1093    CAST_TO(TDomain, domain)
1094
1095    TMetaDescriptor *desc = NULL;
1096
1097    if (PyString_Check(rar))
1098      desc = domain->metas[string(PyString_AsString(rar))];
1099
1100    else if (PyOrVariable_Check(rar))
1101      desc = domain->metas[PyOrange_AsVariable(rar)->get_name()];
1102
1103    else if (PyInt_Check(rar))
1104      desc = domain->metas[PyInt_AsLong(rar)];
1105
1106    else
1107      PYERROR(PyExc_TypeError, "invalid meta descriptor", NULL);
1108
1109    return PyBool_FromLong(desc ? 1 : 0);
1110  PyCATCH
1111}
1112
1113
1114PyObject *Domain_get_meta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | int) -> Variable")
1115{ PyTRY
1116    const TMetaDescriptor *desc = metaDescriptorFromArg(SELF_AS(TDomain), rar);
1117    return desc ? WrapOrange(desc->variable) : NULL;
1118  PyCATCH
1119}
1120
1121
1122PyObject *Domain_getmetasLow(const TDomain &domain)
1123{
1124  PyObject *dict = PyDict_New();
1125  const_ITERATE(TMetaVector, mi, domain.metas)
1126    PyDict_SetItem(dict, PyInt_FromLong((*mi).id), WrapOrange((*mi).variable));
1127  return dict;
1128}
1129
1130
1131PyObject *Domain_getmetasLow(const TDomain &domain, const int optional)
1132{
1133  PyObject *dict = PyDict_New();
1134  const_ITERATE(TMetaVector, mi, domain.metas)
1135    if (optional == (*mi).optional)
1136      PyDict_SetItem(dict, PyInt_FromLong((*mi).id), WrapOrange((*mi).variable));
1137  return dict;
1138}
1139
1140
1141PyObject *Domain_get_metas(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([optional]) -> {int: Variable}")
1142{ PyTRY
1143    if (PyTuple_Size(args) && (PyTuple_GET_ITEM(args, 0) != Py_None)) {
1144      int opt;
1145      if (!PyArg_ParseTuple(args, "i:Domain.getmetas", &opt))
1146        return NULL;
1147
1148      return Domain_getmetasLow(SELF_AS(TDomain), opt);
1149    }
1150
1151    return Domain_getmetasLow(SELF_AS(TDomain));
1152  PyCATCH
1153}
1154
1155
1156PyObject *Domain_add_meta(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(id, descriptor[, optional]) -> None")
1157{ PyTRY
1158    CAST_TO(TDomain, domain);
1159
1160    int id;
1161    PVariable var;
1162    int opt = 0;
1163    if (!PyArg_ParseTuple(args, "iO&|i", &id, cc_Variable, &var, &opt))
1164      return PYNULL;
1165
1166    domain->metas.push_back(TMetaDescriptor(id, var, opt));
1167    domain->domainHasChanged();
1168    RETURN_NONE;
1169  PyCATCH
1170}
1171
1172
1173bool convertMetasFromPython(PyObject *dict, TMetaVector &metas)
1174{
1175  Py_ssize_t pos = 0;
1176  PyObject *pykey, *pyvalue;
1177  while (PyDict_Next(dict, &pos, &pykey, &pyvalue)) {
1178    if (!PyOrVariable_Check(pyvalue)) {
1179      PyErr_Format(PyExc_TypeError, "parsing meta attributes: dictionary value at position '%i' should be 'Variable', not '%s'", pos-1, pyvalue->ob_type->tp_name);
1180      return false;
1181    }
1182    if (!PyInt_Check(pykey) || (PyInt_AsLong(pykey)>=0))
1183      PYERROR(PyExc_TypeError, "parsing meta attributes: dictionary keys should be meta-ids (negative integers)", false);
1184
1185    metas.push_back(TMetaDescriptor((int)PyInt_AsLong(pykey), PyOrange_AsVariable(pyvalue)));
1186  }
1187
1188  return true;
1189}
1190
1191
1192PyObject *Domain_addmetasLow(TDomain &domain, PyObject *dict, const int opt = 0)
1193{
1194  TMetaVector metas;
1195  if (!convertMetasFromPython(dict, metas))
1196    return PYNULL;
1197
1198  ITERATE(TMetaVector, mi, metas) {
1199    (*mi).optional = opt;
1200    domain.metas.push_back(*mi);
1201  }
1202
1203  domain.domainHasChanged();
1204
1205  RETURN_NONE;
1206}
1207
1208
1209PyObject *Domain_add_metas(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "({id: descriptor, id: descriptor, ...}[, optional]) -> None")
1210{ PyTRY
1211    PyObject *pymetadict;
1212    int opt = 0;
1213    if (!PyArg_ParseTuple(args, "O|i", &pymetadict, &opt))
1214      PYERROR(PyExc_AttributeError, "Domain.addmetas expects a dictionary with id's and descriptors, optionally follow by an int flag 'optional'", PYNULL);
1215
1216    return Domain_addmetasLow(SELF_AS(TDomain), pymetadict, opt);
1217  PyCATCH
1218}
1219
1220
1221bool removeMeta(PyObject *rar, TMetaVector &metas)
1222{ TMetaVector::iterator mvi(metas.begin()), mve(metas.end());
1223
1224  if (PyInt_Check(rar)) {
1225    int id = PyInt_AsLong(rar);
1226    while((mvi!=mve) && ((*mvi).id!=id))
1227      mvi++;
1228  }
1229  else if (PyOrVariable_Check(rar))
1230    while((mvi!=mve) && ((*mvi).variable!=PyOrange_AsVariable(rar)))
1231      mvi++;
1232  else if (PyString_Check(rar)) {
1233    char *metaname = PyString_AsString(rar);
1234    while((mvi!=mve) && ((*mvi).variable->get_name()!=metaname))
1235      mvi++;
1236  }
1237  else
1238    mvi=mve;
1239
1240  if (mvi==mve)
1241    PYERROR(PyExc_AttributeError, "meta value not found", false);
1242
1243  metas.erase(mvi);
1244  return true;
1245}
1246
1247
1248PyObject *Domain_remove_meta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "({id0:desc0, id1:desc1, ...}) | ([id0|desc0, id1|desc1, ...]) -> None")
1249{ PyTRY
1250    CAST_TO(TDomain, domain);
1251
1252    if (PyDict_Check(rar)) {
1253      Py_ssize_t pos=0;
1254      PyObject *key, *value;
1255      TMetaVector newMetas=domain->metas;
1256      TMetaVector::iterator mve=domain->metas.end();
1257
1258      while (PyDict_Next(rar, &pos, &key, &value)) {
1259        if (!PyInt_Check(key) || !PyOrVariable_Check(value))
1260          PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
1261
1262        long idx=PyInt_AsLong(key);
1263        TMetaVector::iterator mvi(newMetas.begin());
1264        for(; (mvi!=mve) && ( ((*mvi).id!=idx) || (*mvi).variable!=PyOrange_AsVariable(value)); mvi++);
1265        if (mvi==mve)
1266          PYERROR(PyExc_AttributeError, "meta not found", PYNULL);
1267
1268        newMetas.erase(mvi);
1269      }
1270      domain->metas=newMetas;
1271      domain->domainHasChanged();
1272    }
1273
1274    else if (PyList_Check(rar)) {
1275      TMetaVector newMetas=domain->metas;
1276      for(Py_ssize_t pos=0, noel=PyList_Size(rar); pos!=noel; pos++)
1277        if (!removeMeta(PyList_GetItem(rar, pos), newMetas))
1278          return PYNULL;
1279      domain->metas=newMetas;
1280      domain->domainHasChanged();
1281    }
1282
1283    else if (!removeMeta(rar, domain->metas))
1284      return PYNULL;
1285
1286    RETURN_NONE;
1287  PyCATCH
1288}
1289
1290
1291PyObject *Domain_hasDiscreteAttributes(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(includeClass=0) -> int")
1292{
1293  PyTRY
1294      PyObject *includeClass = PYNULL;
1295      if (!PyArg_ParseTuple(args, "|O:Domain.hasDiscreteAttributes", &includeClass))
1296        return PYNULL;
1297
1298      return PyInt_FromLong(SELF_AS(TDomain).hasDiscreteAttributes(!includeClass || PyObject_IsTrue(includeClass)!=0) ? 1 : 0);
1299  PyCATCH
1300}
1301
1302
1303PyObject *Domain_hasContinuousAttributes(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(includeClass=0) -> int")
1304{
1305  PyTRY
1306      PyObject *includeClass = PYNULL;
1307      if (!PyArg_ParseTuple(args, "|O:Domain.hasContinuousAttributes", &includeClass))
1308        return PYNULL;
1309
1310      return PyInt_FromLong(SELF_AS(TDomain).hasContinuousAttributes(!includeClass || PyObject_IsTrue(includeClass)!=0) ? 1 : 0);
1311  PyCATCH
1312}
1313
1314
1315PyObject *Domain_hasOtherAttributes(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(includeClass=0) -> int")
1316{
1317  PyTRY
1318      PyObject *includeClass = PYNULL;
1319      if (!PyArg_ParseTuple(args, "|O:Domain.hasOtherAttributes", &includeClass))
1320        return PYNULL;
1321
1322      return PyInt_FromLong(SELF_AS(TDomain).hasOtherAttributes(!includeClass || PyObject_IsTrue(includeClass)!=0) ? 1 : 0);
1323  PyCATCH
1324}
1325
1326
1327Py_ssize_t Domain_len(TPyOrange *self)
1328{ PyTRY
1329    CAST_TO_err(TDomain, domain, -1);
1330    return domain->variables->size();
1331  PyCATCH_1
1332}
1333
1334
1335PyObject *Domain_index(PyObject *self, PyObject *arg) PYARGS(METH_O, "(variable) -> int")
1336{
1337  PyTRY
1338    CAST_TO(TDomain, domain);
1339
1340    PVariable variable = varFromArg_byDomain(arg, domain, true);
1341    return variable ? PyInt_FromLong(domain->getVarNum(variable)) : PYNULL;
1342  PyCATCH
1343}
1344
1345
1346int Domain_contains(PyObject *self, PyObject *arg)
1347{
1348  PyTRY
1349    CAST_TO_err(TDomain, domain, -1);
1350
1351    PVariable variable = varFromArg_byDomain(arg, domain, true);
1352    PyErr_Clear();
1353    return variable ? 1 : 0;
1354  PyCATCH_1
1355}
1356
1357CONSTRUCTOR_KEYWORDS(Domain, "source class_vars")
1358
1359PyObject *Domain_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange - Orange.data.Domain, "(list-of-attrs | domain [, hasClass | classVar | None] [,domain | list-of-attrs | source=domain])")
1360{ PyTRY
1361    PyObject *list;
1362    PyObject *arg1 = PYNULL;
1363    PyObject *arg2 = PYNULL;
1364    PyObject *pyclassvars = PYNULL;
1365
1366    if (PyArg_ParseTuple(args, "O|OO", &list, &arg1, &arg2)) {
1367
1368      if (keywds) {
1369          PyObject *key, *value;
1370          Py_ssize_t pos = 0;
1371          while (PyDict_Next(keywds, &pos, &key, &value)) {
1372              if (!PyString_Check(key)) {
1373                  Py_XDECREF(pyclassvars);
1374                  PYERROR(PyExc_TypeError, "keyword argument name must be a string", PYNULL);
1375              }
1376              if (!strcmp(PyString_AS_STRING(key), "source")) {
1377                  if (arg1 && arg2) {
1378                      Py_XDECREF(pyclassvars);
1379                      PYERROR(PyExc_TypeError, "Domain: too many arguments", PYNULL);
1380                  }
1381                  Py_INCREF(value);
1382                  if (!arg1) {
1383                      arg1 = value;
1384                  }
1385                  else {
1386                      arg2 = value;
1387                  }
1388              }
1389              else if (!strcmp(PyString_AS_STRING(key), "class_vars")) {
1390                  Py_INCREF(value);
1391                  pyclassvars = value;
1392              }
1393              else {
1394                  Py_XDECREF(pyclassvars);
1395                  PyErr_Format(PyExc_ValueError, "unexpected keyword argument '%s'", PyString_AS_STRING(key));
1396                  return PYNULL;
1397              }
1398          }
1399      }
1400
1401      if (PyOrDomain_Check(list)) {
1402
1403        PDomain dom = PyOrange_AsDomain(list);
1404        TDomain *newdomain = NULL;
1405
1406        if (arg1) {
1407          if (PyString_Check(arg1) || PyOrVariable_Check(arg1)) {
1408            PVariable classVar = varFromArg_byDomain(arg1, dom, false);
1409            if (!classVar) {
1410                Py_XDECREF(pyclassvars);
1411                return PYNULL;
1412            }
1413            TVarList attributes = dom->variables.getReference();
1414            int vnumint = dom->getVarNum(classVar, false);
1415            if (vnumint>=0) {
1416                attributes.erase(attributes.begin()+vnumint);
1417            }
1418            newdomain = mlnew TDomain(classVar, attributes);
1419          }
1420          else if (PyInt_Check(arg1) || (arg1==Py_None)) {
1421            TVarList attributes = dom->variables.getReference();
1422            if (PyObject_IsTrue(arg1))
1423                newdomain = CLONE(TDomain, dom), type;
1424            else
1425                newdomain = mlnew TDomain(PVariable(), dom->variables.getReference());
1426          }
1427          else {
1428              Py_XDECREF(pyclassvars);
1429              PYERROR(PyExc_TypeError, "Domain: invalid arguments for constructor (I'm unable to guess what you meant)", PYNULL);
1430          }
1431        }
1432        else {
1433           newdomain = CLONE(TDomain, dom);
1434        }
1435        if (pyclassvars) {
1436            if (!varListFromVarList(pyclassvars, dom->variables, newdomain->classVars.getReference(), false, false)) {
1437                Py_DECREF(pyclassvars);
1438                mldelete newdomain;
1439                return PYNULL;
1440            }
1441            Py_DECREF(pyclassvars);
1442        }
1443        return WrapNewOrange(newdomain, type);
1444      }
1445
1446      /* Now, arg1 can be either
1447           - NULL
1448           - source (i.e. Domain or list of variables)
1449           - boolean that tells whether we have a class
1450           - class variable
1451         If arg1 is present but is not source, arg2 can be source
1452      */
1453
1454      PVarList source;
1455      PVariable classVar;
1456      bool hasClass = true;
1457
1458      if (arg1) {
1459        if (PyOrDomain_Check(arg1))
1460          source = PyOrange_AsDomain(arg1)->variables;
1461        else if (PyOrVarList_Check(arg1))
1462          source = PyOrange_AsVarList(arg1);
1463        else if (PyList_Check(arg1))
1464          source = PVarList_FromArguments(arg1);
1465        else if (PyOrVariable_Check(arg1))
1466          classVar = PyOrange_AsVariable(arg1);
1467        else
1468          hasClass = (PyObject_IsTrue(arg1) != 0);
1469      }
1470      if (arg2) {
1471        if (source) {
1472          PYERROR(PyExc_TypeError, "Domain: invalid argument 3", PYNULL);
1473        }
1474        else
1475          if (PyOrDomain_Check(arg2)) {
1476            PDomain sourceDomain = PyOrange_AsDomain(arg2);
1477            source = mlnew TVarList(sourceDomain->variables.getReference());
1478            ITERATE(TMetaVector, mi, sourceDomain->metas)
1479              source->push_back((*mi).variable);
1480          }
1481
1482          else if (PyOrVarList_Check(arg2))
1483            source = PyOrange_AsVarList(arg2);
1484          else if (PyList_Check(arg2))
1485            source = PVarList_FromArguments(arg2);
1486      }
1487
1488      TVarList variables;
1489      if (!varListFromVarList(list, source, variables, true, false))
1490        return PYNULL;
1491
1492      if (hasClass && !classVar && variables.size()) {
1493        classVar = variables.back();
1494        variables.erase(variables.end()-1);
1495      }
1496
1497      TDomain *newdomain = mlnew TDomain(classVar, variables);
1498      if (pyclassvars) {
1499          if (!varListFromVarList(pyclassvars, source, newdomain->classVars.getReference(), false, false)) {
1500              Py_DECREF(pyclassvars);
1501              mldelete newdomain;
1502              return PYNULL;
1503          }
1504          Py_DECREF(pyclassvars);
1505      }
1506      return WrapNewOrange(newdomain, type);
1507    }
1508
1509    PYERROR(PyExc_TypeError, "invalid parameters (list of 'Variable' expected)", PYNULL);
1510
1511  PyCATCH
1512}
1513
1514
1515PyObject *Domain__reduce__(PyObject *self)
1516{
1517  CAST_TO(TDomain, domain)
1518
1519
1520  return Py_BuildValue("O(ONNNNN)N", getExportedFunction("__pickleLoaderDomain"),
1521                                   self->ob_type,
1522                                   WrapOrange(domain->attributes),
1523                                   WrapOrange(domain->classVar),
1524                                   WrapOrange(domain->classVars),
1525                                   Domain_getmetasLow(SELF_AS(TDomain), false),
1526                                   Domain_getmetasLow(SELF_AS(TDomain), true),
1527                                   packOrangeDictionary(self));
1528}
1529
1530PyObject *__pickleLoaderDomain(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, attributes, classVar, classVars, req_metas, opt_metas)")
1531{
1532  PyTRY {
1533    if (!args || !PyTuple_Check(args))
1534        PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL)
1535
1536    int arg_size = PyTuple_Size(args);
1537
1538    if (!(arg_size == 6 || arg_size == 5))
1539        PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL);
1540
1541    PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
1542    PyObject *attributes = PyTuple_GET_ITEM(args, 1);
1543    PyObject *classVar = PyTuple_GET_ITEM(args, 2);
1544
1545    PyObject *classVars = NULL;
1546    PyObject *req_metas = NULL;
1547    PyObject *opt_metas = NULL;
1548
1549    if (arg_size == 5)
1550    {
1551        // Old tuple format (pre multiclass support)
1552        req_metas = PyTuple_GET_ITEM(args, 3);
1553        opt_metas = PyTuple_GET_ITEM(args, 4);
1554
1555    }
1556    else
1557    {
1558        classVars = PyTuple_GET_ITEM(args, 3);
1559        req_metas = PyTuple_GET_ITEM(args, 4);
1560        opt_metas = PyTuple_GET_ITEM(args, 5);
1561    }
1562
1563    if (!PyOrVarList_Check(attributes) || (classVars && !PyOrVarList_Check(classVars)) || !PyDict_Check(req_metas) || !PyDict_Check(opt_metas))
1564      PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL);
1565
1566
1567    TDomain *domain = NULL;
1568    if (classVar == Py_None)
1569      domain = new TDomain(PVariable(), PyOrange_AsVarList(attributes).getReference());
1570    else if (PyOrVariable_Check(classVar))
1571      domain = new TDomain(PyOrange_AsVariable(classVar), PyOrange_AsVarList(attributes).getReference());
1572    else
1573      PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL);
1574
1575    if (classVars != NULL)
1576        domain->classVars = PyOrange_AsVarList(classVars);
1577    else
1578        domain->classVars = PVarList(new TVarList());
1579
1580
1581    PyObject *pydomain = WrapNewOrange(domain, type);
1582
1583    PyObject *res;
1584    res = Domain_addmetasLow(*domain, req_metas, false);
1585    if (!res) {
1586      Py_DECREF(pydomain);
1587      return NULL;
1588    }
1589    Py_DECREF(res);
1590
1591    res = Domain_addmetasLow(*domain, opt_metas, true);
1592    if (!res) {
1593      Py_DECREF(pydomain);
1594      return NULL;
1595    }
1596    Py_DECREF(res);
1597
1598    return pydomain;
1599  }
1600  PyCATCH
1601}
1602
1603
1604PyObject *Domain_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(example) -> Example")
1605{ PyTRY
1606    NO_KEYWORDS
1607
1608    TExample *ex;
1609    if (!PyArg_ParseTuple(args, "O&", ptr_Example, &ex))
1610      PYERROR(PyExc_TypeError, "invalid parameters (Example expected)", PYNULL);
1611
1612    return Example_FromWrappedExample(PExample(mlnew TExample(PyOrange_AsDomain(self), *ex)));
1613  PyCATCH
1614}
1615
1616
1617PyObject *Domain_getitem(TPyOrange *self, PyObject *index)
1618{ PyTRY
1619    PVariable var = varFromArg_byDomain(index, PyOrange_AsDomain(self), true);
1620    return var ? WrapOrange(var) : PYNULL;
1621  PyCATCH
1622}
1623
1624
1625PyObject *Domain_getitem_sq(TPyOrange *self, Py_ssize_t index)
1626{ PyTRY
1627    CAST_TO(TDomain, domain)
1628    if ((index<0) || (index>=domain->variables->size()))
1629      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
1630    return WrapOrange(domain->getVar(index));
1631  PyCATCH
1632}
1633
1634
1635PyObject *Domain_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
1636{
1637  PyTRY
1638    CAST_TO(TDomain, domain);
1639
1640    int ds=domain->variables->size();
1641    if (start>ds)
1642      start=ds;
1643    else if (start<0)
1644      start=0;
1645
1646    if (stop>ds) stop=ds;
1647    else if (stop<0) stop=0;
1648    stop-=start;
1649    PyObject *list=PyList_New(stop);
1650    if (!list)
1651      return NULL;
1652    TVarList::iterator vi(domain->variables->begin()+start);
1653    for(Py_ssize_t i=0; i<stop; i++)
1654      PyList_SetItem(list, i, WrapOrange(*(vi++)));
1655    return list;
1656  PyCATCH
1657}
1658
1659
1660const string &nonamevar = string("<noname>");
1661
1662inline const string &namefrom(const string &name)
1663{ return name.length() ? name : nonamevar; }
1664
1665string TDomain2string(TPyOrange *self)
1666{ CAST_TO_err(TDomain, domain, "<invalid domain>")
1667
1668  string res;
1669
1670  int added=0;
1671  PITERATE(TVarList, vi, domain->variables)
1672    res+=(added++ ? ", " : "[") + namefrom((*vi)->get_name());
1673
1674  if (added) {
1675    res+="]";
1676    if (domain->metas.size())
1677      res+=", {";
1678  }
1679  else
1680    if (domain->metas.size())
1681      res+="{";
1682
1683  added=0;
1684  ITERATE(TMetaVector, mi, domain->metas) {
1685    char pls[256];
1686    sprintf(pls, "%s%i:%s", (added++) ? ", " : "", int((*mi).id), namefrom((*mi).variable->get_name()).c_str());
1687    res+=pls;
1688  }
1689  if (added)
1690    res+="}";
1691
1692  return res;
1693}
1694
1695
1696
1697PyObject *Domain_repr(TPyOrange *pex)
1698{ PyTRY
1699    PyObject *result = callbackOutput((PyObject *)pex, NULL, NULL, "repr", "str");
1700    if (result)
1701      return result;
1702
1703    return PyString_FromString(TDomain2string(pex).c_str());
1704  PyCATCH
1705}
1706
1707
1708PyObject *Domain_str(TPyOrange *pex)
1709{ PyTRY
1710    PyObject *result = callbackOutput((PyObject *)pex, NULL, NULL, "str", "repr");
1711    if (result)
1712      return result;
1713
1714    return PyString_FromString(TDomain2string(pex).c_str());
1715  PyCATCH
1716}
1717
1718
1719int Domain_set_classVar(PyObject *self, PyObject *arg) PYDOC("Domain's class attribute")
1720{
1721  PyTRY
1722    CAST_TO_err(TDomain, domain, -1);
1723
1724    if (arg==Py_None)
1725      domain->removeClass();
1726    else
1727      if (PyOrVariable_Check(arg))
1728        domain->changeClass(PyOrange_AsVariable(arg));
1729      else PYERROR(PyExc_AttributeError, "invalid type for class", -1)
1730
1731    return 0;
1732  PyCATCH_1
1733}
1734
1735PyObject *Domain_checksum(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
1736{ return PyInt_FromLong(SELF_AS(TDomain).sumValues()); }
1737
1738
1739/* ************ RANDOM GENERATORS ************** */
1740
1741#include "random.hpp"
1742
1743C_UNNAMED(RandomGenerator, Orange, "() -> 32-bit random int")
1744
1745PyObject *RandomGenerator_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange, "([int])")
1746{ PyTRY
1747      int i = 0;
1748      if (!PyArg_ParseTuple(args, "|i:RandomGenerator.__new__", &i))
1749        return PYNULL;
1750
1751      return WrapNewOrange(mlnew TRandomGenerator(i), type);
1752  PyCATCH
1753}
1754
1755
1756PyObject *RandomGenerator__reduce__(PyObject *self)
1757{
1758  cMersenneTwister &mt = SELF_AS(TRandomGenerator).mt;
1759
1760  return Py_BuildValue("O(Os#ii)N", getExportedFunction("__pickleLoaderRandomGenerator"),
1761                                    self->ob_type,
1762                                    (char *)(mt.state), 625 * sizeof(long),
1763                                    mt.next - mt.state,
1764                                    mt.left,
1765                                    packOrangeDictionary(self));
1766}
1767
1768
1769PyObject *__pickleLoaderRandomGenerator(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, state, next_offset, left)")
1770{
1771  PyTypeObject *type;
1772  int offs;
1773  int left;
1774  char *buff;
1775  int bufsize;
1776  if (!PyArg_ParseTuple(args, "Os#ii", &type, &buff, &bufsize, &offs, &left))
1777    return PYNULL;
1778
1779  TRandomGenerator *rg = new TRandomGenerator;
1780
1781  cMersenneTwister &mt = rg->mt;
1782  memcpy(mt.state, buff, bufsize);
1783  mt.next = mt.state + offs;
1784  mt.left = left;
1785
1786  return WrapNewOrange(rg, type);
1787}
1788
1789
1790PyObject *RandomGenerator_reset(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([new_seed]) -> None")
1791{ PyTRY
1792    int seed = numeric_limits<int>::min();
1793    if (!PyArg_ParseTuple(args, "|i:RandomGenerator.reset", &seed))
1794      return PYNULL;
1795
1796    if (seed != numeric_limits<int>::min())
1797      SELF_AS(TRandomGenerator).initseed = seed;
1798
1799    SELF_AS(TRandomGenerator).reset();
1800    RETURN_NONE;
1801  PyCATCH
1802}
1803
1804PyObject *RandomGenerator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("() -> 32-bit random int")
1805{ PyTRY
1806    NO_KEYWORDS
1807
1808    if (args) {
1809      if (PyTuple_Size(args) == 1) {
1810        return PyInt_FromLong((long)SELF_AS(TRandomGenerator).randlong(PyInt_AsLong(PyTuple_GET_ITEM(args, 0))));
1811      }
1812      PYERROR(PyExc_TypeError, "zero or one argument expected", PYNULL);
1813    }
1814
1815    return PyInt_FromLong((long)SELF_AS(TRandomGenerator)());
1816  PyCATCH
1817}
1818
1819
1820PyObject *stdRandomGenerator()
1821{ return WrapOrange(globalRandom); }
1822
1823PYCONSTANTFUNC(globalRandom, stdRandomGenerator)
1824
1825
1826/* ************ EXAMPLE GENERATOR ************ */
1827
1828TFiletypeDefinition::TFiletypeDefinition(const char *an, PyObject *al, PyObject *as)
1829: name(an),
1830  loader(al),
1831  saver(as)
1832{
1833  if (loader == Py_None)
1834    loader = PYNULL;
1835  else
1836    Py_INCREF(loader);
1837
1838  if (saver == Py_None)
1839    saver = PYNULL;
1840  else
1841    Py_INCREF(saver);
1842}
1843
1844
1845TFiletypeDefinition::TFiletypeDefinition(const TFiletypeDefinition &other)
1846: name(other.name),
1847  extensions(other.extensions),
1848  loader(other.loader),
1849  saver(other.saver)
1850{
1851  Py_XINCREF(loader);
1852  Py_XINCREF(saver);
1853}
1854
1855
1856TFiletypeDefinition::~TFiletypeDefinition()
1857{
1858  Py_XDECREF(loader);
1859  Py_XDECREF(saver);
1860}
1861
1862
1863class GlobalFiletypeDefinitionVector: public vector<TFiletypeDefinition>
1864{
1865public:
1866  ~GlobalFiletypeDefinitionVector()
1867  {
1868    /*
1869     * The 'filetypeDefinitions' below will be (and should be)
1870     * the only instance and it will outlive the Python interpreter.
1871     * This destructor will be called in clib's exit() and at that time the
1872     * 'saver' and 'loader' pointers in TFiletypeDefinition are no
1873     * longer valid so we set them to NULL so Py_XDECREF macro in
1874     * TFiletypeDefinition destructor does nothing.
1875     */
1876    for (GlobalFiletypeDefinitionVector::iterator iter = begin();
1877         iter != end();
1878         iter++)
1879    {
1880      iter->loader = NULL;
1881      iter->saver = NULL;
1882    }
1883  }
1884};
1885
1886GlobalFiletypeDefinitionVector filetypeDefinitions;
1887
1888
1889/* lower case to avoid any ambiguity problems (don't know how various compilers can react when
1890   registerFiletype is cast by the code produced by pyxtract */
1891ORANGE_API void registerFiletype(const char *name, const vector<string> &extensions, PyObject *loader, PyObject *saver)
1892{
1893  TFiletypeDefinition ftd(name, loader, saver);
1894  ftd.extensions = extensions;
1895  filetypeDefinitions.push_back(ftd);
1896}
1897
1898bool fileExists(const string &s);
1899const char *getExtension(const char *name);
1900
1901
1902vector<TFiletypeDefinition>::iterator findFiletypeByExtension(const char *name, bool needLoader, bool needSaver, bool exhaustive)
1903{
1904  const char *extension = getExtension(name);
1905
1906  if (extension) {
1907    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1908      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1909        ITERATE(TStringList, ei, (*fi).extensions)
1910          if (*ei == extension)
1911            return fi;
1912  }
1913
1914  else if (exhaustive) {
1915    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1916      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1917        ITERATE(TStringList, ei, (*fi).extensions)
1918          if (fileExists(name + *ei))
1919            return fi;
1920  }
1921
1922  return filetypeDefinitions.end();
1923}
1924
1925
1926PyObject *registerFileType(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(name, extensions, loader, saver) -> None")
1927{
1928  char *name;
1929  PyObject *pyextensions, *loader, *saver;
1930  if (!PyArg_ParseTuple(args, "sOOO:registerFiletype", &name, &loader, &saver, &pyextensions))
1931    return PYNULL;
1932
1933  TFiletypeDefinition ftd(name, loader, saver);
1934
1935  if (PyString_Check(pyextensions))
1936    ftd.extensions.push_back(PyString_AsString(pyextensions));
1937  else {
1938    PStringList extensions = PStringList_FromArguments(pyextensions);
1939    if (!extensions)
1940      return PYNULL;
1941    ftd.extensions = extensions.getReference();
1942  }
1943
1944  vector<TFiletypeDefinition>::iterator fi(filetypeDefinitions.begin()), fe(filetypeDefinitions.begin());
1945  for(; (fi != fe) && ((*fi).name != name); fi++);
1946
1947  if (fi==fe)
1948    filetypeDefinitions.push_back(ftd);
1949  else
1950    *fi = ftd;
1951
1952  RETURN_NONE;
1953}
1954
1955
1956extern char *fileTypes[][2];
1957
1958PyObject *getRegisteredFileTypes(PyObject *, PyObject *, PyObject *) PYARGS(METH_NOARGS, "() -> ((extension, description, loader, saver), ...)")
1959{
1960  char *(*t)[2] = fileTypes;
1961  while(**t)
1962    t++;
1963
1964  int builtIns = t-fileTypes;
1965  int i = 0;
1966  PyObject *types = PyTuple_New(builtIns + filetypeDefinitions.size());
1967  for(t = fileTypes; **t; t++)
1968    PyTuple_SetItem(types, i++, Py_BuildValue("ss", (*t)[0], (*t)[1]));
1969
1970  ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions) {
1971    string exts;
1972    ITERATE(TStringList, ei, (*fi).extensions)
1973      exts += (exts.size() ? " *" : "*") + *ei;
1974
1975    PyObject *ploader = (*fi).loader, *psaver = (*fi).saver;
1976    if (!ploader) {
1977      ploader = Py_None;
1978      Py_INCREF(Py_None);
1979    }
1980    if (!psaver) {
1981      psaver = Py_None;
1982      Py_INCREF(Py_None);
1983    }
1984    PyTuple_SetItem(types, i++, Py_BuildValue("ssOO", (*fi).name.c_str(), exts.c_str(), ploader, psaver));
1985  }
1986
1987  return types;
1988}
1989
1990#include "examplegen.hpp"
1991#include "table.hpp"
1992#include "filter.hpp"
1993
1994
1995PyObject *loadDataByPython(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool exhaustiveFilesearch, bool &fileFound)
1996{
1997  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, true, false, exhaustiveFilesearch);
1998  fileFound = fi!=filetypeDefinitions.end();
1999
2000  if (!fileFound)
2001    return PYNULL;
2002
2003  PyObject *res = PyObject_Call((*fi).loader, argstuple, keywords);
2004  if (!res)
2005    throw pyexception();
2006  if (res == Py_None)
2007    return res;
2008
2009  bool gotTuple = PyTuple_Check(res);
2010  PyObject *res1 = gotTuple ? PyTuple_GET_ITEM(res, 0) : res;
2011
2012  if (PyOrExampleTable_Check(res1))
2013    return res;
2014
2015  PExampleGenerator gen;
2016  if (!exampleGenFromParsedArgs(res1, gen)) {
2017    Py_DECREF(res);
2018    return PYNULL;
2019  }
2020
2021  TExampleTable *table = gen.AS(TExampleTable);
2022  if (!table) {
2023    Py_DECREF(res);
2024    return PYNULL;
2025  }
2026
2027  if (gotTuple) {
2028    PyObject *nres = PyTuple_New(PyTuple_Size(res));
2029    PyTuple_SetItem(nres, 0, WrapNewOrange(table, type));
2030    for(Py_ssize_t i = 1; i < PyTuple_Size(res); i++)
2031      PyTuple_SetItem(nres, i, PyTuple_GET_ITEM(res, i));
2032
2033    Py_DECREF(res);
2034    return nres;
2035  }
2036  else {
2037    Py_DECREF(res);
2038    return WrapNewOrange(table, type);
2039  }
2040}
2041
2042bool readUndefinedSpecs(PyObject *keyws, char *&DK, char *&DC);
2043
2044
2045bool readBoolFlag(PyObject *keywords, char *flag)
2046{
2047  PyObject *pyflag = keywords ? PyDict_GetItemString(keywords, flag) : PYNULL;
2048  return pyflag && PyObject_IsTrue(pyflag);
2049}
2050
2051bool hasFlag(PyObject *keywords, char *flag)
2052{
2053  return keywords && (PyDict_GetItemString(keywords, flag) != PYNULL);
2054}
2055
2056
2057TExampleTable         *readTable(char *filename, const int createNewOn, vector<int> &status, vector<pair<int, int> > &metaStatus, const char *DK, const char *DC, bool noExcOnUnknown = false, bool noCodedDiscrete = false, bool noClass = false);
2058TExampleGenerator *readGenerator(char *filename, const int createNewOn, vector<int> &status, vector<pair<int, int> > &metaStatus, const char *DK, const char *DC, bool noExcOnUnknown = false, bool noCodedDiscrete = false, bool noClass = false);
2059
2060PyObject *encodeStatus(const vector<int> &status);
2061PyObject *encodeStatus(const vector<pair<int, int> > &metaStatus);
2062
2063char *obsoleteFlags[] = {"dontCheckStored", "dontStore", "use", "useMetas", "domain", 0 };
2064
2065
2066PyObject *loadDataFromFileNoSearch(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2067{
2068  PyObject *res;
2069
2070  bool pythonFileFound;
2071  res = loadDataByPython(type, filename, argstuple, keywords, false, pythonFileFound);
2072  if (res) {
2073    if (res != Py_None) {
2074      if (!PyTuple_Check(res))
2075        return res;
2076
2077      PyObject *pygen = PyTuple_GetItem(res, 0);
2078      Py_INCREF(pygen);
2079
2080      if (PyTuple_Size(res) >= 2) {
2081        Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", PyTuple_GET_ITEM(res, 1), false);
2082        Orange_setattrDictionary((TPyOrange *)pygen, "attribute_load_status", PyTuple_GET_ITEM(res, 1), false);
2083      }
2084      if (PyTuple_Size(res) >= 3) {
2085        Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", PyTuple_GET_ITEM(res, 2), false);
2086        Orange_setattrDictionary((TPyOrange *)pygen, "meta_attribute_load_status", PyTuple_GET_ITEM(res, 2), false);
2087      }
2088      return pygen;
2089    }
2090
2091    else
2092      Py_DECREF(Py_None);
2093  }
2094
2095  PyErr_Clear();
2096
2097  for(char * const *of = obsoleteFlags; *of; of++)
2098    if (hasFlag(keywords, *of))
2099      raiseWarning("flag '%s' is not supported any longer", *of);
2100
2101  int createNewOn = TVariable::Incompatible;
2102  if (hasFlag(keywords, "createNewOn"))
2103    convertFromPython(PyDict_GetItemString(keywords, "createNewOn"), createNewOn);
2104
2105  char *DK = NULL, *DC = NULL;
2106  if (!readUndefinedSpecs(keywords, DK, DC))
2107    return PYNULL;
2108
2109  char *errs = NULL;
2110  vector<int> status;
2111  vector<pair<int, int> > metaStatus;
2112  try {
2113    TExampleGenerator *generator =
2114      generatorOnly ? readGenerator(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"))
2115                    : readTable(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"));
2116    if (generator) {
2117      PyObject *pygen = WrapNewOrange(generator, type);
2118      PyObject *pystatus = encodeStatus(status);
2119      PyObject *pymetastatus = encodeStatus(metaStatus);
2120      Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", pystatus, false);
2121      Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", pymetastatus, false);
2122      Py_DECREF(pystatus);
2123      Py_DECREF(pymetastatus);
2124      return pygen;
2125    }
2126  }
2127  catch (mlexception err) {
2128    errs = strdup(err.what());
2129  }
2130
2131  res = loadDataByPython(type, filename, argstuple, keywords, true, pythonFileFound);
2132  if (res)
2133    return res;
2134
2135  if (pythonFileFound) {
2136    PYERROR(PyExc_SystemError, "cannot load the file", PYNULL);
2137  }
2138  else {
2139    PyErr_SetString(PyExc_SystemError, errs);
2140    free(errs);
2141    return PYNULL;
2142  }
2143}
2144
2145PyObject *loadDataFromFilePath(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly, const char *path)
2146{
2147  if (!path) {
2148    return NULL;
2149  }
2150
2151  #if defined _WIN32
2152  const char sep = ';';
2153  const char pathsep = '\\';
2154  #else
2155  const char sep = ':';
2156  const char pathsep = '/';
2157  #endif
2158  const int flen = strlen(filename);
2159
2160  for(const char *pi = path, *pe=pi; *pi; pi = pe+1) {
2161    for(pe = pi; *pe && *pe != sep; pe++);
2162    const int plen = pe-pi;
2163    char *npath = new char[plen + flen + 2];
2164    strncpy(npath, pi, pe - pi);
2165    if (!plen || (pi[plen] != pathsep)) {
2166      npath[plen] = pathsep;
2167      strcpy(npath+plen+1, filename);
2168    }
2169    else {
2170      strcpy(npath+plen, filename);
2171    }
2172    PyObject *res = loadDataFromFileNoSearch(type, npath, argstuple, keywords, generatorOnly);
2173    delete[] npath;
2174
2175    PyErr_Clear();
2176    if (res) {
2177      return res;
2178    }
2179    if (!*pe)
2180      break;
2181  }
2182
2183  return NULL;
2184}
2185
2186PyObject *loadDataFromFile(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2187{
2188  PyObject *ptype, *pvalue, *ptraceback;
2189  PyObject *res;
2190
2191  res = loadDataFromFileNoSearch(type, filename, argstuple, keywords, generatorOnly);
2192  if (res) {
2193    return res;
2194  }
2195
2196  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
2197
2198  // Try to find the file in the doc/datasets directory
2199  PyObject *configurationModule = PyImport_ImportModule("orngConfiguration");
2200  if (configurationModule) {
2201    PyObject *datasetsPath = PyDict_GetItemString(PyModule_GetDict(configurationModule), "datasetsPath");
2202    if (datasetsPath)
2203      res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, PyString_AsString(datasetsPath));
2204    Py_DECREF(configurationModule);
2205  }
2206  else {
2207    PyErr_Clear();
2208  }
2209
2210  if (!res) {
2211      // Try fo find the file using Orange.data.io.find_file
2212      PyObject *ioModule = PyImport_ImportModule("Orange.data.io");
2213      if (ioModule) {
2214          PyObject *find_file = PyObject_GetAttrString(ioModule, "find_file");
2215          if (find_file){
2216              PyObject *py_args = Py_BuildValue("(s)", filename);
2217              PyObject *ex_filename = PyObject_Call(find_file, py_args, NULL);
2218              if (ex_filename && PyString_Check(ex_filename)){
2219                  res = loadDataFromFileNoSearch(type, PyString_AsString(ex_filename), argstuple, keywords, generatorOnly);
2220                  Py_DECREF(ex_filename);
2221              }
2222              PyErr_Clear();
2223              Py_DECREF(py_args);
2224              Py_DECREF(find_file);
2225          }
2226          Py_DECREF(ioModule);
2227      }
2228  }
2229  if (!res)
2230      PyErr_Clear();
2231
2232  if (!res) {
2233    res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, getenv("ORANGE_DATA_PATH"));
2234  }
2235
2236  if (res) {
2237    Py_XDECREF(ptype);
2238    Py_XDECREF(pvalue);
2239    Py_XDECREF(ptraceback);
2240    return res;
2241  }
2242
2243  PyErr_Restore(ptype, pvalue, ptraceback);
2244  return PYNULL;
2245}
2246
2247
2248int pt_ExampleGenerator(PyObject *args, void *egen)
2249{
2250  *(PExampleGenerator *)(egen) = PyOrExampleGenerator_Check(args) ? PyOrange_AsExampleGenerator(args)
2251                                                                  : PExampleGenerator(readListOfExamples(args));
2252
2253  if (!*(PExampleGenerator *)(egen))
2254    PYERROR(PyExc_TypeError, "invalid example generator", 0)
2255  else
2256    return 1;
2257}
2258
2259
2260static PDomain ptd_domain;
2261
2262int ptdf_ExampleGenerator(PyObject *args, void *egen)
2263{
2264  egen = NULL;
2265
2266  try {
2267    if (PyOrExampleGenerator_Check(args)) {
2268      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
2269      if (gen->domain == ptd_domain)
2270        *(PExampleGenerator *)(egen) = gen;
2271      else
2272        *(PExampleGenerator *)(egen) = mlnew TExampleTable(ptd_domain, gen);
2273    }
2274    else
2275      *(PExampleGenerator *)(egen) = PExampleGenerator(readListOfExamples(args, ptd_domain));
2276
2277    ptd_domain = PDomain();
2278
2279    if (!*(PExampleGenerator *)(egen))
2280      PYERROR(PyExc_TypeError, "invalid example generator", 0)
2281    else
2282      return 1;
2283  }
2284
2285  catch (...) {
2286    ptd_domain = PDomain();
2287    throw;
2288  }
2289}
2290
2291
2292converter ptd_ExampleGenerator(PDomain domain)
2293{
2294  ptd_domain = domain;
2295  return ptdf_ExampleGenerator;
2296}
2297
2298
2299CONSTRUCTOR_KEYWORDS(ExampleGenerator, "domain use useMetas dontCheckStored dontStore filterMetas DC DK NA noClass noCodedDiscrete")
2300
2301// Class ExampleGenerator is abstract in C++; this constructor returns the derived classes
2302
2303NO_PICKLE(ExampleGenerator)
2304
2305PyObject *ExampleGenerator_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(Orange, "(filename)")
2306{
2307  PyTRY
2308    char *filename = NULL;
2309    if (PyArg_ParseTuple(argstuple, "s", &filename))
2310      return loadDataFromFile(type, filename, argstuple, keywords, true);
2311    else
2312      return PYNULL;
2313  PyCATCH;
2314}
2315
2316
2317PExampleGenerator exampleGenFromParsedArgs(PyObject *args)
2318{
2319 if (PyOrOrange_Check(args)) {
2320   if (PyOrExampleGenerator_Check(args))
2321      return PyOrange_AsExampleGenerator(args);
2322    else
2323      PYERROR(PyExc_TypeError, "example generator expected", NULL);
2324  }
2325  return PExampleGenerator(readListOfExamples(args));
2326}
2327
2328
2329PExampleGenerator exampleGenFromArgs(PyObject *args, int &weightID)
2330{
2331  PyObject *examples, *pyweight = NULL;
2332  if (!PyArg_UnpackTuple(args, "exampleGenFromArgs", 1, 2, &examples, &pyweight))
2333    return PExampleGenerator();
2334
2335  PExampleGenerator egen = exampleGenFromParsedArgs(examples);
2336  if (!egen || !weightFromArg_byDomain(pyweight, egen->domain, weightID))
2337    return PExampleGenerator();
2338
2339  return egen;
2340}
2341
2342
2343PExampleGenerator exampleGenFromArgs(PyObject *args)
2344{
2345  if (PyTuple_GET_SIZE(args) != 1)
2346    PYERROR(PyExc_TypeError, "exampleGenFromArgs: examples expected", PExampleGenerator())
2347
2348  return exampleGenFromParsedArgs(PyTuple_GET_ITEM(args, 0));
2349}
2350
2351
2352PyObject *ExampleGenerator_native(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
2353{ PyTRY
2354    bool tuples = false;
2355    PyObject *forDC = NULL;
2356    PyObject *forDK = NULL;
2357    PyObject *forSpecial = NULL;
2358    if (keyws) {
2359      PyObject *pytuples = PyDict_GetItemString(keyws, "tuple");
2360      tuples = pytuples && (PyObject_IsTrue(pytuples) != 0);
2361
2362      forDC = PyDict_GetItemString(keyws, "substitute_DC");
2363      if (!forDC) {
2364          forDC = PyDict_GetItemString(keyws, "substituteDC");
2365      }
2366      forDC = PyDict_GetItemString(keyws, "substitute_DK");
2367      if (!forDC) {
2368          forDC = PyDict_GetItemString(keyws, "substituteDK");
2369      }
2370      forDC = PyDict_GetItemString(keyws, "substitute_other");
2371      if (!forDC) {
2372          forDC = PyDict_GetItemString(keyws, "substituteOther");
2373      }
2374    }
2375
2376    int natvt=2;
2377    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=2)))
2378      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2379    CAST_TO(TExampleGenerator, eg);
2380
2381    PyObject *list=PyList_New(0);
2382    EITERATE(ei, *eg)
2383      if (natvt<=1) {
2384        PyObject *obj=convertToPythonNative(*ei, natvt, tuples, forDK, forDC, forSpecial);
2385        PyList_Append(list, obj);
2386        Py_DECREF(obj);
2387      }
2388        // What happens with: convertToPythonNative((*ei, natvt, tuples))? Funny.
2389      else {
2390        PyObject *example=Example_FromExampleCopyRef(*ei);
2391        if (!example) {
2392          PyMem_DEL(list);
2393          PYERROR(PyExc_SystemError, "out of memory", PYNULL);
2394        }
2395        PyList_Append(list, example);
2396        Py_DECREF(example);
2397      }
2398
2399    return list;
2400  PyCATCH
2401}
2402
2403
2404PVariableFilterMap PVariableFilterMap_FromArguments(PyObject *arg);
2405
2406int VariableFilterMap_setitemlow(TVariableFilterMap *aMap, PVariable var, PyObject *pyvalue);
2407
2408inline PVariableFilterMap sameValuesMap(PyObject *dict, PDomain dom)
2409{ TVariableFilterMap *vfm = mlnew TVariableFilterMap;
2410  PVariableFilterMap wvfm = vfm;
2411
2412  Py_ssize_t pos=0;
2413  PyObject *pykey, *pyvalue;
2414  while (PyDict_Next(dict, &pos, &pykey, &pyvalue)) {
2415    PVariable var = varFromArg_byDomain(pykey, dom, true);
2416    if (!var || (VariableFilterMap_setitemlow(vfm, var, pyvalue) < 0))
2417      return PVariableFilterMap();
2418  }
2419
2420  return wvfm;
2421}
2422
2423inline PPreprocessor pp_sameValues(PyObject *dict, PDomain dom)
2424{ PVariableFilterMap vfm = sameValuesMap(dict, dom);
2425  return vfm ? mlnew TPreprocessor_take(vfm) : PPreprocessor();
2426}
2427
2428inline PFilter filter_sameValues(PyObject *dict, PDomain domain, PyObject *kwds = PYNULL)
2429{ PVariableFilterMap svm = sameValuesMap(dict, domain);
2430  if (!svm)
2431    return PFilter();
2432
2433  PyObject *pyneg = kwds ? PyDict_GetItemString(kwds, "negate") : NULL;
2434  return TPreprocessor_take::constructFilter(svm, domain, true, pyneg && PyObject_IsTrue(pyneg));
2435}
2436
2437PyObject *applyPreprocessor(PPreprocessor preprocessor, PExampleGenerator gen, bool weightGiven, int weightID)
2438{ if (!preprocessor)
2439    return PYNULL;
2440
2441  int newWeight;
2442  PExampleGenerator newGen = preprocessor->call(gen, weightID, newWeight);
2443  return weightGiven ? Py_BuildValue("Ni", WrapOrange(newGen), newWeight) : WrapOrange(newGen);
2444}
2445
2446
2447
2448PyObject *applyFilter(PFilter filter, PExampleGenerator gen, bool weightGiven, int weightID);
2449
2450PyObject *ExampleGenerator_select(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
2451/* This function is a spaghetti for compatibility reasons. Most of its functionality
2452   has been moved to specialized functions (changeDomain, filter). The only two
2453   functions that 'select' should be used for is selection of examples by vector
2454   of bools or indices (LongList) */
2455{
2456  PyTRY
2457    CAST_TO(TExampleGenerator, eg);
2458    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2459
2460    /* ***** SELECTION BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
2461    /* Deprecated: use method 'filter' instead */
2462    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2463      return applyPreprocessor(pp_sameValues(keywords, eg->domain), weg, false, 0);
2464    }
2465
2466
2467    PyObject *mplier;
2468    PyObject *pyweight = NULL;
2469    if (PyArg_ParseTuple(args, "O|O", &mplier, &pyweight)) {
2470      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
2471      bool negate = pyneg && PyObject_IsTrue(pyneg);
2472      bool secondArgGiven = (pyweight != NULL);
2473
2474      /* ***** SELECTION BY VECTOR OF BOOLS ****** */
2475      if (PyList_Check(mplier) && PyList_Size(mplier) && PyInt_Check(PyList_GetItem(mplier, 0))) {
2476        Py_ssize_t nole = PyList_Size(mplier);
2477
2478        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2479        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2480        Py_ssize_t i = 0;
2481
2482        if (secondArgGiven) {
2483          if (PyInt_Check(pyweight)) {
2484            int compVal = (int)PyInt_AsLong(pyweight);
2485            TExampleIterator ei = eg->begin();
2486            for(; ei && (i<nole); ++ei) {
2487              PyObject *lel = PyList_GetItem(mplier, i++);
2488              if (!PyInt_Check(lel))
2489                break;
2490
2491              if (negate != (PyInt_AsLong(lel)==compVal))
2492                newTable->addExample(*ei);
2493            }
2494
2495            if ((i==nole) && !ei)
2496              return WrapOrange(newGen);
2497          }
2498        }
2499        else {
2500          TExampleIterator ei = eg->begin();
2501          for(; ei && (i<nole); ++ei) {
2502            PyObject *lel = PyList_GetItem(mplier, i++);
2503            if (negate != (PyObject_IsTrue(lel) != 0))
2504              newTable->addExample(*ei);
2505          }
2506
2507          if ((i==nole) && !ei)
2508            return WrapOrange(newGen);
2509        }
2510      }
2511
2512      PyErr_Clear();
2513
2514
2515      /* ***** SELECTION BY LONGLIST ****** */
2516      if (PyOrLongList_Check(mplier)) {
2517        PLongList llist = PyOrange_AsLongList(mplier);
2518        TLongList::iterator lli(llist->begin()), lle(llist->end());
2519
2520        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2521        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2522
2523        TExampleIterator ei = eg->begin();
2524
2525        if (secondArgGiven) {
2526          if (!PyInt_Check(pyweight))
2527            PYERROR(PyExc_AttributeError, "example selector must be an integer", PYNULL);
2528
2529          int compVal = (int)PyInt_AsLong(pyweight);
2530          for(; ei && (lli!=lle); ++ei, lli++)
2531            if (negate != (*lli==compVal))
2532              newTable->addExample(*ei);
2533        }
2534        else {
2535          for(; ei && (lli != lle); ++ei, lli++)
2536            if (negate != (*lli != 0))
2537              newTable->addExample(*ei);
2538        }
2539
2540        if ((lli==lle) && !ei)
2541          return WrapOrange(newGen);
2542
2543        PYERROR(PyExc_IndexError, "ExampleGenerator.select: invalid list size", PYNULL)
2544      }
2545
2546      PyErr_Clear();
2547
2548      /* ***** CHANGING DOMAIN ***** */
2549      /* Deprecated: use method 'translate' instead. */
2550      if (PyOrDomain_Check(mplier)) {
2551        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(PyOrange_AsDomain(mplier), weg)));
2552        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2553      }
2554
2555
2556      /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2557      /* Deprecated: use method 'translate' instead. */
2558      TVarList attributes;
2559      if (varListFromDomain(mplier, eg->domain, attributes, true, false)) {
2560        PDomain newDomain;
2561        TVarList::iterator vi, ve;
2562        for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2563        if (vi==ve)
2564          newDomain = mlnew TDomain(PVariable(), attributes);
2565        else {
2566          attributes.erase(vi);
2567          newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2568        }
2569
2570        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2571        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2572      }
2573
2574      PyErr_Clear();
2575
2576
2577      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
2578      /* Deprecated: use method 'filter' instead. */
2579      if (PyDict_Check(mplier)) {
2580        int weightID;
2581        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2582          return applyFilter(filter_sameValues(mplier, eg->domain), weg, secondArgGiven, weightID);
2583      }
2584
2585
2586      /* ***** PREPROCESSING ***** */
2587      /* Deprecated: call preprocessor instead. */
2588      if (PyOrPreprocessor_Check(mplier)) {
2589        int weightID;
2590        if (weightFromArg_byDomain(pyweight, eg->domain, weightID)) {
2591
2592          PExampleGenerator res;
2593          int newWeight;
2594          PyTRY
2595            NAME_CAST_TO(TPreprocessor, mplier, pp);
2596            if (!pp)
2597              PYERROR(PyExc_TypeError, "invalid object type (preprocessor announced, but not passed)", PYNULL)
2598            res = (*pp)(weg, weightID, newWeight);
2599          PyCATCH
2600
2601          return secondArgGiven ? Py_BuildValue("Ni", WrapOrange(res), newWeight) : WrapOrange(res);
2602        }
2603      }
2604
2605      /* ***** APPLY FILTER ***** */
2606      /* Deprecated: use method 'filter' instead. */
2607      if (PyOrFilter_Check(mplier)) {
2608        int weightID;
2609        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2610          return applyFilter(PyOrange_AsFilter(mplier), weg, secondArgGiven, weightID);
2611      }
2612    }
2613    PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2614  PyCATCH
2615}
2616
2617
2618PyObject *ExampleGenerator_filter(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
2619{
2620  PyTRY
2621    CAST_TO(TExampleGenerator, eg);
2622    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2623
2624    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2625      return applyFilter(filter_sameValues(keywords, eg->domain, keywords), weg, false, 0);
2626    }
2627
2628    if (PyTuple_Size(args)==1) {
2629      PyObject *arg = PyTuple_GET_ITEM(args, 0);
2630
2631      if (PyDict_Check(arg))
2632        return applyFilter(filter_sameValues(arg, eg->domain, keywords), weg, false, 0);
2633
2634      if (PyOrFilter_Check(arg))
2635          return applyFilter(PyOrange_AsFilter(arg), weg, false, 0);
2636    }
2637
2638    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter expects a list of conditions or orange.Filter", PYNULL)
2639  PyCATCH
2640}
2641
2642
2643PyObject *ExampleGenerator_translate(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "translate(domain | list-of-attributes) -> ExampleTable")
2644{
2645  PyTRY
2646    CAST_TO(TExampleGenerator, eg);
2647    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2648
2649    PDomain domain;
2650    if (PyArg_ParseTuple(args, "O&|i", cc_Domain, &domain))
2651      return WrapOrange(PExampleTable(mlnew TExampleTable(domain, weg)));
2652
2653    PyObject *pargs, *guard = NULL;
2654    int keepMeta = 0;
2655    if (args && ((PyTuple_Size(args)==1) || ((PyTuple_Size(args)==2) && PyInt_Check(PyTuple_GET_ITEM(args, 1))))) {
2656      pargs = guard = PyTuple_GET_ITEM(args, 0);
2657      if (PyTuple_Size(args)==2) {
2658        keepMeta = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
2659      }
2660    }
2661    else
2662      pargs = args;
2663
2664    /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2665    TVarList attributes;
2666    if (varListFromDomain(pargs, eg->domain, attributes, true, false)) {
2667      PDomain newDomain;
2668      TVarList::iterator vi, ve;
2669      for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2670      if (vi==ve)
2671        newDomain = mlnew TDomain(PVariable(), attributes);
2672      else {
2673        attributes.erase(vi);
2674        newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2675      }
2676     
2677      if (keepMeta) {
2678        newDomain->metas = eg->domain->metas;
2679      }
2680
2681      Py_XDECREF(guard);
2682      return WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2683    }
2684
2685    PYERROR(PyExc_AttributeError, "ExampleGenerator.translate expects a list of attributes or orange.Domain", PYNULL)
2686 PyCATCH
2687}
2688
2689
2690PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference)
2691{ PyTRY
2692    if (!PyList_Check(pylist))
2693      PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2694
2695    vector<int> indices;
2696    Py_ssize_t i, sze = PyList_Size(pylist);
2697    for(i = 0; i<sze; i++) {
2698      PyObject *lel = PyList_GetItem(pylist, i);
2699      if (!PyInt_Check(lel))
2700        PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2701      indices.push_back(int(PyInt_AsLong(lel)));
2702    }
2703    sort(indices.begin(), indices.end());
2704
2705    CAST_TO(TExampleGenerator, eg);
2706    TExampleTable *newTable = reference ? mlnew TExampleTable(eg, (int)0)
2707                                        : mlnew TExampleTable(eg->domain);
2708    PExampleGenerator newGen(newTable);
2709
2710    TExampleGenerator::iterator ei(eg->begin());
2711    vector<int>::iterator ii(indices.begin()), iie(indices.end());
2712    i = 0;
2713    while(ei && (ii!=iie)) {
2714      if (*ii == i) {
2715        newTable->addExample(*ei);
2716        ii++;
2717      }
2718      else {
2719        i++;
2720        ++ei;
2721      }
2722    }
2723
2724    if (ii!=iie)
2725      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
2726
2727    return WrapOrange(newGen);
2728  PyCATCH
2729}
2730
2731
2732PyObject *ExampleGenerator_get_items(TPyOrange *self, PyObject *pylist)  PYARGS(METH_O, "(indices) -> ExampleTable")
2733{ return multipleSelectLow(self, pylist, false); }
2734
2735
2736PyObject *ExampleGenerator_checksum(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
2737{ PyTRY
2738    return PyInt_FromLong(SELF_AS(TExampleGenerator).checkSum());
2739  PyCATCH
2740}
2741
2742
2743const char *getExtension(const char *name);
2744char *getFileSystemEncoding(); // defined in lib_io.cpp
2745
2746PyObject *saveTabDelimited(PyObject *, PyObject *args, PyObject *keyws);
2747PyObject *saveC45(PyObject *, PyObject *args);
2748PyObject *saveTxt(PyObject *, PyObject *args, PyObject *keyws);
2749PyObject *saveCsv(PyObject *, PyObject *args, PyObject *keyws);
2750PyObject *saveBasket(PyObject *, PyObject *args);
2751
2752PyObject *ExampleGenerator_save(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "(filename) -> None")
2753{
2754  char *filename;
2755  bool free_filename = false;
2756  if (!PyArg_ParseTuple(args, "s:ExampleGenerator.save", &filename))
2757  {
2758      // Try again, this time with the fs encoding.
2759      char *encoding = getFileSystemEncoding();
2760      if (!PyArg_ParseTuple(args, "es:ExampleGenerator.save", encoding, &filename))
2761          return PYNULL;
2762      free_filename = true;
2763      PyErr_Clear();
2764  }
2765
2766  const char *extension = getExtension(filename);
2767  if (!extension)
2768  {
2769    if (free_filename)
2770        PyMem_Free(filename);
2771    PYERROR(PyExc_TypeError, "file name must have an extension", PYNULL);
2772  }
2773
2774
2775  PyObject *newargs = PyTuple_New(PyTuple_Size(args) + 1);
2776  PyObject *el;
2777
2778  el = PyTuple_GET_ITEM(args, 0);
2779  Py_INCREF(el);
2780  PyTuple_SetItem(newargs, 0, el);
2781
2782  Py_INCREF(self);
2783  PyTuple_SetItem(newargs, 1, self);
2784
2785  for(Py_ssize_t i = 1, e = PyTuple_Size(args); i < e; i++) {
2786    el = PyTuple_GET_ITEM(args, i);
2787    Py_INCREF(el);
2788    PyTuple_SetItem(newargs, i+1, el);
2789  }
2790
2791  PyObject *res = PYNULL;
2792
2793  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, false, true, false);
2794  if (fi != filetypeDefinitions.end())
2795    res = PyObject_Call((*fi).saver, newargs, keyws);
2796  else if (!strcmp(extension, ".tab"))
2797    res = saveTabDelimited(NULL, newargs, keyws);
2798  else if (!strcmp(extension, ".txt"))
2799    res = saveTxt(NULL, newargs, keyws);
2800  else if (!strcmp(extension, ".csv"))
2801    res = saveCsv(NULL, newargs, keyws);
2802  else if (!strcmp(extension, ".names") || !strcmp(extension, ".data") || !strcmp(extension, ".test"))
2803    res = saveC45(NULL, newargs);
2804  else if (!strcmp(extension, ".basket"))
2805    res = saveBasket(NULL, newargs);
2806  else
2807    PyErr_Format(PyExc_AttributeError, "unknown file format (%s)", extension);
2808
2809  Py_DECREF(newargs);
2810
2811  if (free_filename)
2812      PyMem_Free(filename);
2813
2814  return res;
2815}
2816
2817
2818PyObject *ExampleGenerator_weight(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(weightID)")
2819{
2820  PyObject *pyw = PYNULL;
2821  if (!PyArg_ParseTuple(args, "|O:ExampleGenerator.weight", &pyw))
2822    return PYNULL;
2823
2824  CAST_TO(TExampleGenerator, egen)
2825  if (!pyw)
2826    return PyInt_FromLong(egen->numberOfExamples());
2827
2828  int weightID;
2829  if (!varNumFromVarDom(pyw, egen->domain, weightID))
2830    return PYNULL;
2831
2832  float weight = 0.0;
2833  PEITERATE(ei, egen)
2834    weight += WEIGHT(*ei);
2835
2836  return PyFloat_FromDouble(weight);
2837}
2838
2839
2840PExampleGeneratorList PExampleGeneratorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::P_FromArguments(arg); }
2841PyObject *ExampleGeneratorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_FromArguments(type, arg); }
2842PyObject *ExampleGeneratorList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of ExampleGenerator>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_new(type, arg, kwds); }
2843PyObject *ExampleGeneratorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getitem(self, index); }
2844int       ExampleGeneratorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setitem(self, index, item); }
2845PyObject *ExampleGeneratorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getslice(self, start, stop); }
2846int       ExampleGeneratorList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setslice(self, start, stop, item); }
2847Py_ssize_t       ExampleGeneratorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_len(self); }
2848PyObject *ExampleGeneratorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_richcmp(self, object, op); }
2849PyObject *ExampleGeneratorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_concat(self, obj); }
2850PyObject *ExampleGeneratorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_repeat(self, times); }
2851PyObject *ExampleGeneratorList_str(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2852PyObject *ExampleGeneratorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2853int       ExampleGeneratorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_contains(self, obj); }
2854PyObject *ExampleGeneratorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_append(self, item); }
2855PyObject *ExampleGeneratorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_extend(self, obj); }
2856PyObject *ExampleGeneratorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_count(self, obj); }
2857PyObject *ExampleGeneratorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ExampleGeneratorList") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_filter(self, args); }
2858PyObject *ExampleGeneratorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_index(self, obj); }
2859PyObject *ExampleGeneratorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_insert(self, args); }
2860PyObject *ExampleGeneratorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_native(self); }
2861PyObject *ExampleGeneratorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ExampleGenerator") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_pop(self, args); }
2862PyObject *ExampleGeneratorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_remove(self, obj); }
2863PyObject *ExampleGeneratorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reverse(self); }
2864PyObject *ExampleGeneratorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_sort(self, args); }
2865PyObject *ExampleGeneratorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reduce(self); }
2866
2867
2868/* ************ EXAMPLE TABLE ************ */
2869
2870#include "table.hpp"
2871#include "numeric_interface.hpp"
2872
2873TExampleTable *readListOfExamples(PyObject *args)
2874{
2875    if (isSomeNumeric_wPrecheck(args) || isSomeMaskedNumeric_wPrecheck(args))
2876      return readListOfExamples(args, PDomain(), false);
2877
2878
2879  if (PySequence_Check(args)) {
2880    Py_ssize_t size=PySequence_Size(args);
2881    if (!size)
2882      PYERROR(PyExc_TypeError, "can't construct a table from an empty sequence", (TExampleTable *)NULL);
2883
2884    TExampleTable *table=NULL;
2885    PyObject *pex = NULL;
2886
2887    try {
2888      for(Py_ssize_t i=0; i<size; i++) {
2889        PyObject *pex = PySequence_GetItem(args, i);
2890        if (!pex || !PyOrExample_Check(pex)) {
2891          Py_XDECREF(pex);
2892          mldelete table;
2893          PyErr_Format(PyExc_TypeError, "invalid sequence element at %i", i);
2894          return NULL;
2895        }
2896        if (!i)
2897          table = mlnew TExampleTable(PyExample_AS_Example(pex)->domain);
2898        table->addExample(PyExample_AS_ExampleReference(pex));
2899        Py_DECREF(pex);
2900        pex = NULL;
2901      }
2902    }
2903    catch (...) {
2904      delete table;
2905      Py_XDECREF(pex);
2906      throw;
2907    }
2908
2909    return table;
2910  }
2911
2912  PYERROR(PyExc_TypeError, "a list of examples expected", NULL);
2913}
2914
2915
2916
2917template<typename T>
2918int to_int_value(T & value) {
2919    return (int)value;
2920}
2921
2922
2923template<>
2924int to_int_value<float>(float & value) {
2925    return (int)floor(0.5 + value);
2926}
2927
2928
2929template<>
2930int to_int_value<double>(double & value) {
2931    return (int)floor(0.5 + value);
2932}
2933
2934
2935template<typename T>
2936void init_value(TValue & target, TVariable & variable, T & value, bool masked=false) {
2937    if (variable.varType == TValue::INTVAR) {
2938        TEnumVariable * enumvar = dynamic_cast<TEnumVariable *>(&variable);
2939        int ivalue = to_int_value(value);
2940        if (enumvar) {
2941            if (!masked && (ivalue < 0 || ivalue >= enumvar->noOfValues())) {
2942                PyErr_Format(PyExc_ValueError, "Invalid value for a Discrete variable.");
2943                throw pyexception();
2944            }
2945        }
2946        intValInit(target, ivalue, masked ? valueDK : valueRegular);
2947    } else {
2948        floatValInit(target, (float)value,  masked ? valueDK : valueRegular);
2949    }
2950}
2951
2952
2953template<typename T>
2954void copy_strided_buffer_to_example(
2955        TExample & example,
2956        char * buffer, Py_ssize_t stride,
2957        char * mask_buffer, Py_ssize_t mask_stride) {
2958    PDomain domain = example.domain;
2959    PVarList vars = domain->variables, class_vars = domain->classVars;
2960    TVarList::iterator var_iter = vars->begin();
2961    TValue * value_iter = example.begin();
2962    int pos = 0;
2963
2964    // copy variables part
2965    for (; var_iter != vars->end();
2966            var_iter++, value_iter++, pos++) {
2967        init_value(*value_iter, var_iter->getReference(),
2968                   *((T *) buffer), mask_buffer && (*mask_buffer));
2969
2970        buffer += stride;
2971        if (mask_buffer) {
2972            mask_buffer += mask_stride;
2973        }
2974    }
2975
2976    // copy class vars part
2977    for (var_iter = class_vars->begin();
2978            var_iter != class_vars->end();
2979            var_iter++, value_iter++, pos++) {
2980        init_value(*value_iter, var_iter->getReference(),
2981                   *((T *) buffer), mask_buffer && (*mask_buffer));
2982
2983        buffer += stride;
2984        if (mask_buffer) {
2985        mask_buffer += mask_stride;
2986        }
2987    }
2988}
2989
2990
2991TExampleTable *readListOfExamples(PyObject *args, PDomain domain, bool filterMetas)
2992{
2993  PyArrayObject *array = NULL, *mask = NULL;
2994
2995  if (isSomeNumeric_wPrecheck(args)) {
2996    array = (PyArrayObject *)args;
2997  } else if (isSomeMaskedNumeric_wPrecheck(args)) {
2998    array = (PyArrayObject *)args;
2999    mask = (PyArrayObject *)PyObject_GetAttrString(args, "mask");
3000    if (!mask) {
3001        PyErr_Clear();
3002    } else if (!isSomeNumeric_wPrecheck((PyObject *)mask)) {
3003      Py_DECREF((PyObject *)mask);
3004      mask = NULL;
3005    }
3006  }
3007
3008  if (array) {
3009      if (array->nd != 2)
3010        PYERROR(PyExc_AttributeError, "two-dimensional array expected for an ExampleTable", NULL);
3011
3012      PVarList variables;
3013      TVarList::const_iterator vi;
3014
3015      if (!domain) {
3016        TVarList lvariables;
3017        char vbuf[20];
3018        for(int i = 0, e = array->dimensions[1]; i < e; i++) {
3019          sprintf(vbuf, "a%i", i+1);
3020          lvariables.push_back(mlnew TFloatVariable(vbuf));
3021        }
3022        domain = mlnew TDomain(PVariable(), lvariables);
3023        variables = domain->variables;
3024      }
3025
3026      else {
3027          int const nvars = domain->variables->size() + domain->classVars->size();
3028          if (array->dimensions[1] != nvars) {
3029              PyErr_Format(PyExc_AttributeError,
3030                  "the number of columns (%i) in the array doesn't match the number of attributes (%i)",
3031                  array->dimensions[1], nvars);
3032              return NULL;
3033          }
3034
3035       variables = domain->variables;
3036       for(vi = variables->begin(); vi!=variables->end(); vi++)
3037          if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
3038              PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
3039       
3040       for(vi = domain->classVars->begin(); vi!=domain->classVars->end(); vi++) 
3041          if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
3042              PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
3043      }
3044
3045      const char arrayType = getArrayType(array);
3046      if (!strchr(supportedNumericTypes, arrayType)) {
3047        PyErr_Format(PyExc_AttributeError, "Converting arrays of type '%c' is not supported (use one of '%s')", arrayType, supportedNumericTypes);
3048        return NULL;
3049      }
3050
3051      TExampleTable *table = mlnew TExampleTable(domain);
3052      TExample *nex = NULL;
3053      table->reserve(array->dimensions[0]);
3054
3055      const int &strideRow = array->strides[0];
3056      const int &strideCol = array->strides[1];
3057
3058      // If there's no mask, the mask pointers will equal the data pointer to avoid too many if's
3059      const int &strideMaskRow = mask ? mask->strides[0] : strideRow;
3060      const int &strideMaskCol = mask ? mask->strides[1] : strideCol;
3061
3062      try {
3063        TExample::iterator ei;
3064        char *rowPtr = array->data;
3065        char *maskRowPtr = mask ? mask->data : array->data;
3066
3067        for (int row = 0, rowe = array->dimensions[0];
3068             row < rowe;
3069             row++, rowPtr += strideRow, maskRowPtr += strideMaskRow) {
3070          TExample *nex = mlnew TExample(domain);
3071          char * maskPtr = mask ? maskRowPtr : NULL;
3072
3073          #define COPY_BUFFER(TYPE) \
3074                  copy_strided_buffer_to_example<TYPE>(*nex, rowPtr, strideCol, maskPtr, strideMaskCol); \
3075                  break;
3076
3077          switch (arrayType) {
3078            case 'c':
3079            case 'b': COPY_BUFFER(char)
3080            case 'B': COPY_BUFFER(unsigned char)
3081            case 'h': COPY_BUFFER(short)
3082            case 'H': COPY_BUFFER(unsigned short)
3083            case 'i': COPY_BUFFER(int)
3084            case 'I': COPY_BUFFER(unsigned int)
3085            case 'l': COPY_BUFFER(long)
3086            case 'L': COPY_BUFFER(unsigned long)
3087            case 'f': COPY_BUFFER(float)
3088            case 'd': COPY_BUFFER(double)
3089          }
3090
3091          #undef COPY_BUFFER
3092
3093          table->addExample(nex);
3094          nex = NULL;
3095        }
3096      }
3097      catch (...) {
3098        mldelete table;
3099        mldelete nex;
3100        throw;
3101      }
3102
3103      return table;
3104  }
3105
3106  if (PyList_Check(args)) {
3107    Py_ssize_t size=PyList_Size(args);
3108    if (!size)
3109      PYERROR(PyExc_TypeError, "can't construct a table from an empty list", (TExampleTable *)NULL);
3110
3111    TExampleTable *table = mlnew TExampleTable(domain);;
3112
3113    try {
3114      for(Py_ssize_t i=0; i<size; i++) {
3115        PyObject *pex = PyList_GetItem(args, i);
3116        if (PyOrExample_Check(pex))
3117          table->addExample(PyExample_AS_ExampleReference(pex), filterMetas);
3118        else {
3119          TExample example(domain);
3120          if (!convertFromPythonExisting(pex, example)) {
3121            mldelete table;
3122            PyObject *type, *value, *tracebk;
3123            PyErr_Fetch(&type, &value, &tracebk);
3124            if (type) {
3125              //PyErr_Restore(type, value, tracebk);
3126              const char *oldes = PyString_AsString(value);
3127              PyErr_Format(type, "%s (at example %i)", oldes, i);
3128              Py_DECREF(type);
3129              Py_XDECREF(value);
3130              Py_XDECREF(tracebk);
3131              return NULL;
3132            }
3133          }
3134          table->addExample(example);
3135        }
3136      }
3137
3138      return table;
3139    }
3140    catch (...) {
3141      mldelete table;
3142      throw;
3143    }
3144  }
3145
3146  PYERROR(PyExc_TypeError, "invalid arguments", NULL);
3147}
3148
3149CONSTRUCTOR_KEYWORDS(ExampleTable, "domain use useMetas dontCheckStored dontStore filterMetas filter_metas DC DK NA noClass noCodedDiscrete createNewOn")
3150
3151PyObject *ExampleTable_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(ExampleGenerator - Orange.data.Table, "(filename | domain[, examples] | examples)")
3152{
3153  PyTRY
3154
3155    char *filename = NULL;
3156    if (PyArg_ParseTuple(argstuple, "s", &filename))
3157        return loadDataFromFile(type, filename, argstuple, keywords, false);
3158
3159    PyErr_Clear();
3160
3161    /*For a case where the unicode can't be converted to a default
3162     * encoding (on most platforms this is ASCII)
3163     */
3164    char * coding = getFileSystemEncoding();
3165    if (PyArg_ParseTuple(argstuple, "es", coding, &filename))
3166    {
3167        PyObject *rval = loadDataFromFile(type, filename, argstuple, keywords, false);
3168        PyMem_Free(filename);
3169        return rval;
3170    }
3171
3172    PyErr_Clear();
3173
3174    PExampleGenerator egen;
3175    PyObject *args = PYNULL;
3176    if (PyArg_ParseTuple(argstuple, "O&|O", cc_ExampleTable, &egen, &args))
3177      return WrapNewOrange(mlnew TExampleTable(egen, !args || (PyObject_IsTrue(args) == 0)), type);
3178
3179    PyErr_Clear();
3180
3181    if (PyArg_ParseTuple(argstuple, "O", &args)) {
3182      if (PyOrDomain_Check(args))
3183        return WrapNewOrange(mlnew TExampleTable(PyOrange_AsDomain(args)), type);
3184
3185      TExampleTable *res = readListOfExamples(args);
3186      if (res)
3187        return WrapNewOrange(res, type);
3188      PyErr_Clear();
3189
3190      // check if it's a list of generators
3191      if (PyList_Check(args)) {
3192        TExampleGeneratorList eglist;
3193        PyObject *iterator = PyObject_GetIter(args);
3194        PyObject *item = PyIter_Next(iterator);
3195        for(; item; item = PyIter_Next(iterator)) {
3196          if (!PyOrExampleGenerator_Check(item)) {
3197            Py_DECREF(item);
3198            break;
3199          }
3200          eglist.push_back(PyOrange_AsExampleGenerator(item));
3201          Py_DECREF(item);
3202        }
3203        Py_DECREF(iterator);
3204        if (!item)
3205          return WrapNewOrange(mlnew TExampleTable(PExampleGeneratorList(eglist)), type);
3206      }
3207
3208      PYERROR(PyExc_TypeError, "invalid arguments for constructor (domain or examples or both expected)", PYNULL);
3209    }
3210
3211    PyErr_Clear();
3212
3213    PDomain domain;
3214    if (PyArg_ParseTuple(argstuple, "O&O", cc_Domain, &domain, &args)) {
3215      bool filterMetas = readBoolFlag(keywords, "filterMetas") || readBoolFlag(keywords, "filter_metas");
3216
3217      if (PyOrExampleGenerator_Check(args))
3218        return WrapNewOrange(mlnew TExampleTable(domain, PyOrange_AsExampleGenerator(args), filterMetas), type);
3219      else {
3220        TExampleTable *res = readListOfExamples(args, domain, filterMetas);
3221        return res ? WrapNewOrange(res, type) : PYNULL;
3222      }
3223    }
3224
3225    PYERROR(PyExc_TypeError, "invalid arguments for ExampleTable.__init__", PYNULL);
3226
3227  PyCATCH
3228}
3229
3230
3231PyObject *ExampleTable__reduce__(PyObject *self)
3232{
3233  CAST_TO(TExampleTable, table)
3234
3235  if (!table->ownsExamples || table->lock) {
3236    PExampleTable lock = table->lock;
3237    TCharBuffer buf(1024);
3238    const int lockSize = lock->size();
3239    buf.writeInt(table->size());
3240    PEITERATE(ei, table) {
3241      int index = 0;
3242      PEITERATE(li, lock) {
3243        if (&*li == &*ei)
3244          break;
3245        index++;
3246      }
3247      if (index == lockSize) {
3248        PYERROR(PyExc_SystemError, "invalid example reference discovered in the table", PYNULL);
3249      }
3250
3251      buf.writeInt(index);
3252    }
3253
3254    return Py_BuildValue("O(ONs#)O", getExportedFunction("__pickleLoaderExampleReferenceTable"),
3255                                      self->ob_type,
3256                                      WrapOrange(table->lock),
3257                                      buf.buf, buf.length(),
3258                                      packOrangeDictionary(self));
3259  }
3260
3261  else {
3262    TCharBuffer buf(1024);
3263    PyObject *otherValues = NULL;
3264
3265    buf.writeInt(table->size());
3266    PEITERATE(ei, table)
3267      Example_pack(*ei, buf, otherValues);
3268
3269    if (!otherValues) {
3270      otherValues = Py_None;
3271      Py_INCREF(otherValues);
3272    }
3273
3274    return Py_BuildValue("O(ONs#N)O", getExportedFunction("__pickleLoaderExampleTable"),
3275                                      self->ob_type,
3276                                      WrapOrange(table->domain),
3277                                      buf.buf, buf.length(),
3278                                      otherValues,
3279                                      packOrangeDictionary(self));
3280  }
3281}
3282
3283
3284PyObject *__pickleLoaderExampleTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, domain, packed_values, other_values)")
3285{
3286  PyTRY
3287    PyTypeObject *type;
3288    PDomain domain;
3289    char *buf;
3290    int bufSize;
3291    PyObject *otherValues;
3292
3293    if (!PyArg_ParseTuple(args, "OO&s#O:__pickleLoaderExampleTable", &type, cc_Domain, &domain, &buf, &bufSize, &otherValues))
3294      return NULL;
3295
3296    TCharBuffer cbuf(buf);
3297    int otherValuesIndex = 0;
3298
3299    int noOfEx = cbuf.readInt();
3300    TExampleTable *newTable = new TExampleTable(domain);
3301    try {
3302      newTable->reserve(noOfEx);
3303      for(int i = noOfEx; i--;)
3304        Example_unpack(newTable->new_example(), cbuf, otherValues, otherValuesIndex);
3305
3306      return WrapNewOrange(newTable, type);
3307    }
3308    catch (...) {
3309      delete newTable;
3310      throw;
3311    }
3312  PyCATCH
3313}
3314
3315
3316PyObject *__pickleLoaderExampleReferenceTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, lockedtable, indices)")
3317{
3318  PyTRY
3319    PyTypeObject *type;
3320    PExampleTable table;
3321    char *buf;
3322    int bufSize;
3323
3324    if (!PyArg_ParseTuple(args, "OO&s#:__pickleLoaderExampleReferenceTable", &type, cc_ExampleTable, &table, &buf, &bufSize))
3325      return NULL;
3326
3327
3328    TCharBuffer cbuf(buf);
3329    int noOfEx = cbuf.readInt();
3330
3331    TExampleTable *newTable = new TExampleTable(table, 1);
3332    try {
3333      newTable->reserve(noOfEx);
3334      for(int i = noOfEx; i--;)
3335        newTable->addExample(table->at(cbuf.readInt()));
3336      return WrapNewOrange(newTable, type);
3337    }
3338    catch (...) {
3339      delete newTable;
3340      throw;
3341    }
3342  PyCATCH
3343}
3344
3345
3346#define EXAMPLE_LOCK(tab) (((tab)->ownsExamples || !(tab)->lock) ? PExampleGenerator(tab) : (tab)->lock)
3347
3348PyObject *ExampleTable_native(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
3349{ PyTRY
3350    int natvt=2;
3351    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=3)))
3352      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
3353
3354    if (natvt<2)
3355      return ExampleGenerator_native(self, args, keywords);
3356
3357    CAST_TO(TExampleTable, table);
3358
3359    PyObject *list=PyList_New(table->numberOfExamples());
3360    Py_ssize_t i=0;
3361    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3362    EITERATE(ei, *table) {
3363      // here we wrap a reference to example, so we must pass a self's wrapper
3364      PyObject *example = Example_FromExampleRef(*ei, lock);
3365      if (!example) {
3366        PyMem_DEL(list);
3367        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3368      }
3369      PyList_SetItem(list, i++, example);
3370    }
3371
3372    return list;
3373  PyCATCH
3374}
3375
3376/*
3377PyTypeObject *gsl_matrixType = NULL;
3378
3379bool load_gsl()
3380{
3381  if (gsl_matrixType)
3382    return true;
3383
3384  PyObject *matrixModule = PyImport_ImportModule("pygsl.matrix");
3385  if (!matrixModule)
3386    return false;
3387
3388  gsl_matrixType = (PyTypeObject *)PyDict_GetItemString(PyModule_GetDict(matrixModule), "matrix");
3389  return gsl_matrixType != NULL;
3390}
3391*/
3392
3393
3394/* Not in .hpp (to be parsed by pyprops) since these only occur in arguments to numpy conversion function */
3395
3396PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Ignore, 0)
3397PYCLASSCONSTANT_INT(ExampleTable, Multinomial_AsOrdinal, 1)
3398PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Error, 2)
3399
3400
3401
3402PyObject *packMatrixTuple(PyObject *X, PyObject *y, PyObject *my, PyObject *w, char *contents)
3403{
3404  int left = (*contents && *contents != '/') ? 1 : 0;
3405
3406  char *cp = strchr(contents, '/');
3407  if (cp)
3408    cp++;
3409
3410  int right = cp ? strlen(cp) : 0;
3411
3412  PyObject *res = PyTuple_New(left + right);
3413  if (left) {
3414    Py_INCREF(X);
3415    PyTuple_SetItem(res, 0, X);
3416  }
3417
3418  if (cp)
3419    for(; *cp; cp++)
3420      if ((*cp == 'c') || (*cp == 'C')) {
3421        Py_INCREF(y);
3422        PyTuple_SetItem(res, left++, y);
3423      }
3424      else if ((*cp == 'w') || (*cp == 'W')) {
3425        Py_INCREF(w);
3426        PyTuple_SetItem(res, left++, w);
3427      }
3428      else {
3429        Py_INCREF(my);
3430        PyTuple_SetItem(res, left++, my);
3431      }
3432
3433  Py_DECREF(X);
3434  Py_DECREF(y);
3435  Py_DECREF(my);
3436  Py_DECREF(w);
3437  return res;
3438}
3439
3440
3441void parseMatrixContents(PExampleGenerator egen, const int &weightID, const char *contents, const int &multiTreatment,
3442                         bool &hasClass, bool &classVector, bool &multiclassVector, bool &weightVector, bool &classIsDiscrete, int &columns,
3443                         vector<bool> &include);
3444
3445
3446inline bool storeNumPyValue(double *&p, const TValue &val, signed char *&m, const PVariable attr, const int &row)
3447{
3448  if (val.isSpecial()) {
3449    if (m) {
3450      *p++ = 0;
3451      *m++ = 1;
3452    }
3453    else {
3454      PyErr_Format(PyExc_TypeError, "value of attribute '%s' in example '%i' is undefined", attr->get_name().c_str(), row);
3455      return false;
3456    }
3457  }
3458
3459  else if (val.varType == TValue::FLOATVAR) {
3460    *p++ = val.floatV;
3461    if (m)
3462      *m++ = 0;
3463  }
3464
3465  else if (val.varType == TValue::INTVAR) {
3466    *p++ = float(val.intV);
3467    if (m)
3468      *m++ = 0;
3469  }
3470
3471  else {
3472    *p++ = ILLEGAL_FLOAT;
3473    if (m)
3474      *m++ = 1;
3475  }
3476
3477  return true;
3478}
3479
3480
3481PyObject *ExampleTable_toNumericOrMA(PyObject *self, PyObject *args, PyObject *keywords, PyObject **module, PyObject **maskedArray = NULL)
3482{
3483  PyTRY
3484    prepareNumeric();
3485    if (!*module || maskedArray && !*maskedArray)
3486      PYERROR(PyExc_ImportError, "cannot import the necessary numeric module for conversion", PYNULL);
3487
3488    // These references are all borrowed
3489    PyObject *moduleDict = PyModule_GetDict(*module);
3490      PyObject *mzeros = PyDict_GetItemString(moduleDict, "zeros");
3491      if (!mzeros)
3492        PYERROR(PyExc_AttributeError, "numeric module has no function 'zeros'", PYNULL);
3493
3494    char *contents = NULL;
3495    int weightID = 0;
3496    int multinomialTreatment = 1;
3497    if (!PyArg_ParseTuple(args, "|sii:ExampleTable.toNumeric", &contents, &weightID, &multinomialTreatment))
3498      return PYNULL;
3499
3500    if (!contents)
3501      contents = "a/cw";
3502
3503    PExampleGenerator egen = PyOrange_AsExampleGenerator(self);
3504
3505    bool hasClass, classVector, weightVector, multiclassVector, classIsDiscrete;
3506    vector<bool> include;
3507    int columns;
3508    parseMatrixContents(egen, weightID, contents, multinomialTreatment,
3509                            hasClass, classVector, multiclassVector, weightVector,
3510                            classIsDiscrete, columns, include);
3511
3512    int rows = egen->numberOfExamples();
3513    PVariable classVar = egen->domain->classVar;
3514
3515    PyObject *X, *y, *w, *my, *mask = NULL, *masky = NULL, *maskmy = NULL;
3516    double *Xp, *yp, *myp, *wp;
3517    signed char *mp = NULL, *mpy = NULL, *mpmy = NULL;
3518    X = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "d");
3519    if (!X)
3520        return PYNULL;
3521    Xp = columns ? (double *)((PyArrayObject *)X)->data : NULL;
3522    if (maskedArray) {
3523        mask = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "b");
3524        mp = (signed char *)((PyArrayObject *)mask)->data;
3525    }
3526
3527    if (classVector) {
3528      y = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3529      if (!y)
3530        return PYNULL;
3531      yp = (double *)((PyArrayObject *)y)->data;
3532
3533      if (maskedArray) {
3534        masky = PyObject_CallFunction(mzeros, "(i)s", rows, "b");
3535        mpy = (signed char *)((PyArrayObject *)masky)->data;
3536      }
3537    }
3538    else {
3539      y = Py_None;
3540      Py_INCREF(y);
3541      yp = NULL;
3542    }
3543
3544    if (multiclassVector) {
3545      my = PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "d");
3546      if (!my)
3547        return PYNULL;
3548      myp = (double *)((PyArrayObject *)my)->data;
3549
3550      if (maskedArray) {
3551        maskmy= PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "b");
3552        mpmy = (signed char *)((PyArrayObject *)maskmy)->data;
3553      }
3554    }
3555    else {
3556      my = Py_None;
3557      Py_INCREF(my);
3558      myp = NULL;
3559    }
3560
3561    if (weightVector) {
3562      w = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3563      if (!w)
3564        return PYNULL;
3565      wp = (double *)((PyArrayObject *)w)->data;
3566    }
3567    else {
3568      w = Py_None;
3569      Py_INCREF(w);
3570      wp = NULL;
3571    }
3572
3573    try {
3574      int row = 0;
3575      TExampleGenerator::iterator ei(egen->begin());
3576      for(; ei; ++ei, row++) {
3577        int col = 0;
3578
3579        /* This is all optimized assuming that each symbol (A, C, W) only appears once.
3580           If it would be common for them to appear more than once, we could cache the
3581           values, but since this is unlikely, caching would only slow down the conversion */
3582        for(const char *cp = contents; *cp && (*cp!='/'); cp++) {
3583          switch (*cp) {
3584            case 'A':
3585            case 'a': {
3586              const TVarList &attributes = egen->domain->attributes.getReference();
3587              TVarList::const_iterator vi(attributes.begin()), ve(attributes.end());
3588              TExample::iterator eei((*ei).begin());
3589              vector<bool>::const_iterator bi(include.begin());
3590              for(; vi != ve; eei++, vi++, bi++)
3591                if (*bi && !storeNumPyValue(Xp, *eei, mp, *vi, row))
3592                  return PYNULL;
3593              break;
3594            }
3595
3596            case 'C':
3597            case 'c':
3598              if (hasClass && !storeNumPyValue(Xp, (*ei).getClass(), mp, classVar, row))
3599                return PYNULL;
3600              break;
3601
3602            case 'M':
3603            case 'm': {
3604              const TVarList &classes = egen->domain->classVars.getReference();
3605              TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3606              TValue *eei = (*ei).values_end;
3607              for(; vi != ve; eei++, vi++)
3608                if (!storeNumPyValue(Xp, *eei, mp, *vi, row))
3609                  return PYNULL;
3610              break;
3611            }
3612
3613            case 'W':
3614            case 'w':
3615              if (weightID)
3616                *Xp++ = WEIGHT(*ei);
3617                if (maskedArray)
3618                  *mp++ = 0;
3619              break;
3620
3621            case '0':
3622              *Xp++ = 0.0;
3623              if (maskedArray)
3624                *mp++ = 0;
3625              break;
3626
3627            case '1':
3628              *Xp++ = 1.0;
3629              if (maskedArray)
3630                *mp++ = 0;
3631              break;
3632          }
3633        }
3634
3635        if (yp && !storeNumPyValue(yp, (*ei).getClass(), mpy, classVar, row))
3636          return PYNULL;
3637
3638        if (wp)
3639          *wp++ = WEIGHT(*ei);
3640
3641        if (myp) {
3642            const TVarList &classes = egen->domain->classVars.getReference();
3643            TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3644            TValue *eei = (*ei).values_end;
3645            for(; vi != ve; eei++, vi++)
3646              if (!storeNumPyValue(myp, *eei, mpmy, *vi, row))
3647                return PYNULL;
3648        }
3649      }
3650
3651      if (maskedArray) {
3652        PyObject *args, *maskedX = NULL, *maskedy = NULL, *maskedmy = NULL;
3653
3654        bool err = false;
3655
3656        if (mask) {
3657          args = Py_BuildValue("OOiOO", X, Py_None, 1, Py_None, mask);
3658          maskedX = PyObject_CallObject(*maskedArray, args);
3659          Py_DECREF(args);
3660          if (!maskedX) {
3661            PyErr_Clear();
3662            args = Py_BuildValue("OOOi", X, mask, Py_None, 1);
3663            maskedX = PyObject_CallObject(*maskedArray, args);
3664            Py_DECREF(args);
3665          }
3666          err = !maskedX;
3667        }
3668
3669        if (!err && masky) {
3670          args = Py_BuildValue("OOiOO", y, Py_None, 1, Py_None, masky);
3671          maskedy = PyObject_CallObject(*maskedArray, args);
3672          Py_DECREF(args);
3673          if (!maskedy) {
3674            PyErr_Clear();
3675            args = Py_BuildValue("OOOi", y, masky, Py_None, 1);
3676            maskedy = PyObject_CallObject(*maskedArray, args);
3677            Py_DECREF(args);
3678          }
3679          err = !maskedy;
3680        }
3681
3682        if (!err && maskmy) {
3683          args = Py_BuildValue("OOiOO", my, Py_None, 1, Py_None, maskmy);
3684          maskedmy = PyObject_CallObject(*maskedArray, args);
3685          Py_DECREF(args);
3686          if (!maskedmy) {
3687            PyErr_Clear();
3688            args = Py_BuildValue("OOOi", my, maskmy, Py_None, 1);
3689            maskedmy = PyObject_CallObject(*maskedArray, args);
3690            Py_DECREF(args);
3691          }
3692          err = !maskedmy;
3693        }
3694
3695        if (err) {
3696          Py_DECREF(X);
3697          Py_DECREF(y);
3698          Py_DECREF(w);
3699          Py_XDECREF(maskedX);
3700          Py_XDECREF(mask);
3701          Py_XDECREF(masky);
3702          Py_XDECREF(maskmy);
3703          return PYNULL;
3704        }
3705
3706        if (mask) {
3707          Py_DECREF(X);
3708          Py_DECREF(mask);
3709          X = maskedX;
3710        }
3711
3712        if (masky) {
3713          Py_DECREF(y);
3714          Py_DECREF(masky);
3715          y = maskedy;
3716        }
3717
3718        if (maskmy) {
3719          Py_DECREF(my);
3720          Py_DECREF(maskmy);
3721          my = maskedmy;
3722        }
3723      }
3724
3725      return packMatrixTuple(X, y, my, w, contents);
3726    }
3727    catch (...) {
3728      Py_DECREF(X);
3729      Py_DECREF(y);
3730      Py_DECREF(w);
3731      Py_XDECREF(mask);
3732      Py_XDECREF(masky);
3733      Py_XDECREF(maskmy);
3734      throw;
3735    }
3736  PyCATCH
3737}
3738
3739
3740PyObject *ExampleTable_toNumeric(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3741{
3742  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric);
3743}
3744
3745
3746PyObject *ExampleTable_toNumericMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3747{
3748  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric, &numericMaskedArray);
3749}
3750
3751// this is for compatibility
3752PyObject *ExampleTable_toMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3753{
3754  return ExampleTable_toNumericMA(self, args, keywords);
3755}
3756
3757PyObject *ExampleTable_toNumarray(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3758{
3759  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray);
3760}
3761
3762
3763PyObject *ExampleTable_toNumarrayMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3764{
3765  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray, &numarrayMaskedArray);
3766}
3767
3768PyObject *ExampleTable_toNumpy(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3769{
3770  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy);
3771}
3772
3773
3774PyObject *ExampleTable_toNumpyMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3775{
3776  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy, &numpyMaskedArray);
3777}
3778
3779
3780
3781int ExampleTable_nonzero(PyObject *self)
3782{ PyTRY
3783    return SELF_AS(TExampleGenerator).numberOfExamples() ? 1 : 0;
3784  PyCATCH_1
3785}
3786
3787Py_ssize_t ExampleTable_len_sq(PyObject *self)
3788{ PyTRY
3789    return SELF_AS(TExampleGenerator).numberOfExamples();
3790  PyCATCH_1
3791}
3792
3793
3794PyObject *ExampleTable_append(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> None")
3795{ PyTRY
3796    CAST_TO(TExampleTable, table)
3797
3798    if (table->ownsExamples) {
3799      if (!convertFromPythonExisting(args, table->new_example())) {
3800        table->delete_last();
3801        return PYNULL;
3802      }
3803    }
3804    else {
3805      if (!PyOrExample_Check(args) || (((TPyExample *)(args))->lock != table->lock))
3806        PYERROR(PyExc_TypeError, "tables containing references to examples can only append examples from the same table", PYNULL);
3807
3808      table->addExample(PyExample_AS_ExampleReference(args));
3809    }
3810    RETURN_NONE;
3811  PyCATCH
3812}
3813
3814PyObject *ExampleTable_extend(PyObject *self, PyObject *args) PYARGS(METH_O, "(examples) -> None")
3815{ PyTRY
3816    CAST_TO(TExampleTable, table)
3817
3818    if (PyOrExampleGenerator_Check(args)) {
3819      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3820      if (args==self) {
3821        TExampleTable temp(gen, false);
3822        table->addExamples(PExampleGenerator(temp));
3823      }
3824      else {
3825        if (!table->ownsExamples
3826              && (table->lock != gen)
3827              && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3828            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3829        table->addExamples(gen);
3830      }
3831      RETURN_NONE;
3832    }
3833
3834    TExample example(table->domain);
3835    if (PyList_Check(args)) {
3836      Py_ssize_t i, size = PyList_Size(args);
3837
3838      // We won't append until we know we can append all
3839      // (don't want to leave the work half finished)
3840      if (!table->ownsExamples) {
3841        for (i = 0; i<size; i++) {
3842          PyObject *pyex = PyList_GET_ITEM(args, i);
3843          if (!PyOrExample_Check(pyex) || (((TPyExample *)(pyex))->lock != table->lock))
3844            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3845        }
3846      }
3847
3848      for(i = 0; i<size; i++) {
3849        PyObject *pex = PyList_GET_ITEM(args, i);
3850        if (!convertFromPythonExisting(pex, example))
3851          return PYNULL;
3852
3853        table->addExample(example);
3854      }
3855
3856      RETURN_NONE;
3857    }
3858
3859
3860    PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.extend", PYNULL);
3861  PyCATCH
3862}
3863
3864
3865PyObject *ExampleTable_getitem_sq(TPyOrange *self, Py_ssize_t idx)
3866{
3867  PyTRY
3868    CAST_TO(TExampleTable, table);
3869
3870    if (idx<0)
3871      idx += table->numberOfExamples();
3872
3873    if ((idx<0) || (idx>=table->numberOfExamples()))
3874      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
3875
3876    // here we wrap a reference to example, so we must pass self's wrapper
3877    return Example_FromExampleRef((*table)[idx], EXAMPLE_LOCK(PyOrange_AsExampleTable(self)));
3878  PyCATCH
3879}
3880
3881
3882int ExampleTable_setitem_sq(TPyOrange *self, Py_ssize_t idx, PyObject *pex)
3883{
3884  PyTRY
3885    CAST_TO_err(TExampleTable, table, -1);
3886
3887    if (idx>table->numberOfExamples())
3888      PYERROR(PyExc_IndexError, "index out of range", -1);
3889
3890    if (!pex) {
3891      table->erase(idx);
3892      return 0;
3893    }
3894
3895    if (!table->ownsExamples) {
3896      if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock))
3897        PYERROR(PyExc_TypeError, "tables containing references to examples can contain examples from the same table", -1);
3898
3899      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3900      return 0;
3901    }
3902
3903    if (PyOrExample_Check(pex)) {
3904      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3905      return 0;
3906    }
3907
3908    TExample example(table->domain);
3909    if (convertFromPythonExisting(pex, example)) {
3910      (*table)[idx] = example;
3911      return 0;
3912    }
3913
3914    PYERROR(PyExc_TypeError, "invalid parameter type (Example expected)", -1)
3915  PyCATCH_1
3916}
3917
3918
3919PyObject *ExampleTable_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
3920{
3921  PyTRY
3922    CAST_TO(TExampleTable, table);
3923
3924    if (stop>table->numberOfExamples())
3925      stop=table->numberOfExamples();
3926
3927    if (start>stop)
3928      start=stop;
3929
3930    PyObject *list=PyList_New(stop-start);
3931    Py_ssize_t i=0;
3932    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3933    while(start<stop) {
3934      // here we wrap a reference to example, so we must pass a self's wrapper
3935      PyObject *example=Example_FromExampleRef((*table)[start++], lock);
3936      if (!example) {
3937        PyMem_DEL(list);
3938        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3939      }
3940      PyList_SetItem(list, i++, (PyObject *)example);
3941    }
3942
3943    return list;
3944  PyCATCH
3945}
3946
3947
3948int ExampleTable_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *args)
3949{
3950  PyTRY
3951    CAST_TO_err(TExampleTable, table, -1);
3952
3953    if (stop>table->size())
3954      stop = table->size();
3955
3956    if (start>stop)
3957      PYERROR(PyExc_IndexError, "index out of range", -1);
3958
3959    int inspoint = stop;
3960
3961    try {
3962      if (PyOrExampleGenerator_Check(args)) {
3963        PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3964        if (args==(PyObject *)self) {
3965          TExampleTable tab(gen, false);
3966          EITERATE(ei, tab)
3967            table->insert(inspoint++, *ei);
3968        }
3969        else
3970          if (!table->ownsExamples
3971                && (table->lock != gen)
3972                && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3973              PYERROR(PyExc_TypeError, "tables containing references to examples can only contain examples from the same table", -1);
3974          PEITERATE(ei, gen)
3975            table->insert(inspoint++, *ei);
3976      }
3977
3978      else {
3979        TExample example(table->domain);
3980        if (PyList_Check(args)) {
3981          Py_ssize_t size = PyList_Size(args);
3982
3983          for(Py_ssize_t i = 0; i<size; i++) {
3984            PyObject *pex = PyList_GetItem(args, i);
3985
3986            if (table->ownsExamples) {
3987              if (!convertFromPythonExisting(pex, example)) {
3988                table->erase(stop, inspoint);
3989                return -1;
3990              }
3991              table->insert(inspoint++, example);
3992            }
3993            else {
3994              if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock)) {
3995                table->erase(stop, inspoint);
3996                PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", -1);
3997              }
3998              table->insert(inspoint++, PyExample_AS_ExampleReference(pex));
3999            }
4000          }
4001        }
4002        else
4003          PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.__setslice__", -1);
4004      }
4005    }
4006    catch (...) {
4007      table->erase(stop, inspoint);
4008      throw;
4009    }
4010
4011    table->erase(start, stop);
4012
4013    return 0;
4014  PyCATCH_1
4015}
4016
4017
4018PyObject *applyFilterL(PFilter filter, PExampleTable gen)
4019{ if (!filter)
4020    return PYNULL;
4021
4022  PyObject *list=PyList_New(0);
4023  filter->reset();
4024  PExampleGenerator lock = EXAMPLE_LOCK(gen);
4025  PEITERATE(ei, gen)
4026    if (filter->operator()(*ei)) {
4027      PyObject *obj=Example_FromExampleRef(*ei, lock);
4028      PyList_Append(list, obj);
4029      Py_DECREF(obj);
4030    }
4031
4032  return list;
4033}
4034
4035
4036PyObject *applyFilterP(PFilter filter, PExampleTable gen)
4037{ if (!filter)
4038    return PYNULL;
4039
4040  TExampleTable *newTable = mlnew TExampleTable(PExampleGenerator(gen), 1);
4041  PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4042  filter->reset();
4043  PEITERATE(ei, gen)
4044    if (filter->operator()(*ei))
4045      newTable->addExample(*ei);
4046
4047  return WrapOrange(newGen);
4048}
4049
4050
4051PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen);
4052
4053PyObject *applyFilterB(PFilter filter, PExampleTable gen)
4054{
4055  return filter ? filterSelectionVectorLow(filter.getReference(), gen) : PYNULL;
4056}
4057
4058
4059PyObject *ExampleTable_get_items_ref(TPyOrange *self, PyObject *pylist)   PYARGS(METH_O, "(indices) -> ExampleTable")
4060{ return multipleSelectLow(self, pylist, true); }
4061
4062
4063PyObject *ExampleTable_selectLow(TPyOrange *self, PyObject *args, PyObject *keywords, const int toList)
4064{
4065  PyTRY
4066    CAST_TO(TExampleTable, eg);
4067    PExampleGenerator weg = PExampleGenerator(PyOrange_AS_Orange(self));
4068    PExampleGenerator lock = EXAMPLE_LOCK(eg);
4069
4070    /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
4071    /* Deprecated: use 'filter' instead */
4072    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4073      switch (toList) {
4074        case 2: return applyFilterB(filter_sameValues(keywords, eg->domain), weg);
4075        case 1: return applyFilterL(filter_sameValues(keywords, eg->domain), weg);
4076        default: return applyFilterP(filter_sameValues(keywords, eg->domain), weg);
4077      }
4078    }
4079
4080    PyObject *mplier;
4081    int index;
4082    if (PyArg_ParseTuple(args, "O|i", &mplier, &index)) {
4083      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
4084      bool negate = pyneg && PyObject_IsTrue(pyneg);
4085      bool indexGiven = (PyTuple_Size(args)==2);
4086
4087      /* ***** SELECTION BY PYLIST ****** */
4088      if (PyList_Check(mplier)) {
4089        if (PyList_Size(mplier) != eg->numberOfExamples())
4090          PYERROR(PyExc_IndexError, "example selector of invalid length", PYNULL);
4091
4092        int i = 0;
4093        switch (toList) {
4094
4095          case 1: {
4096            PyObject *list = PyList_New(0);
4097
4098            if (indexGiven)
4099              EITERATE(ei, *eg) {
4100                PyObject *lel = PyList_GetItem(mplier, i++);
4101                if (!PyInt_Check(lel))
4102                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4103
4104                if (negate != (index==PyInt_AsLong(lel))) {
4105                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4106                  PyList_Append(list, pyex);
4107                  Py_DECREF(pyex);
4108                }
4109              }
4110            else
4111              EITERATE(ei, *eg)
4112                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0)) {
4113                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4114                  PyList_Append(list, pyex);
4115                  Py_DECREF(pyex);
4116                }
4117
4118            return list;
4119          }
4120
4121
4122          // this is a pervesion, but let's support it as a kind of syntactic sugar...
4123          case 2: {
4124            const Py_ssize_t lsize = PyList_Size(mplier);
4125            TBoolList *selection = new TBoolList(lsize);
4126            PBoolList pselection = selection;
4127            TBoolList::iterator si(selection->begin());
4128            if (indexGiven)
4129              for(Py_ssize_t i = 0; i < lsize; i++) {
4130                PyObject *lel = PyList_GetItem(mplier, i);
4131                if (!PyInt_Check(lel))
4132                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4133
4134                *si++ = negate != (index == PyInt_AsLong(lel));
4135              }
4136            else
4137              for(Py_ssize_t i = 0; i < lsize; *si++ = negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0));
4138
4139            return WrapOrange(pselection);
4140          }
4141
4142
4143          default: {
4144            TExampleTable *newTable = mlnew TExampleTable(lock, 1); //locks to weg but does not copy
4145            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4146
4147            if (indexGiven)
4148              EITERATE(ei, *eg) {
4149                PyObject *lel = PyList_GetItem(mplier, i++);
4150                if (!PyInt_Check(lel))
4151                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4152
4153                if (negate != (index==PyInt_AsLong(lel)))
4154                  newTable->addExample(*ei);
4155              }
4156            else
4157              EITERATE(ei, *eg)
4158                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0))
4159                  newTable->addExample(*ei);
4160
4161            return WrapOrange(newGen);
4162          }
4163        }
4164      }
4165
4166      /* ***** SELECTION BY LONGLIST ****** */
4167      else if (PyOrLongList_Check(mplier)) {
4168        PLongList llist = PyOrange_AsLongList(mplier);
4169        if (int(llist->size()) != eg->numberOfExamples())
4170          PYERROR(PyExc_IndexError, "select: invalid list size", PYNULL)
4171
4172        TLongList::iterator lli(llist->begin()), lle(llist->end());
4173        TExampleIterator ei = eg->begin();
4174
4175        switch (toList) {
4176          case 1: {
4177            PyObject *list = PyList_New(0);
4178            for(; ei && (lli!=lle); ++ei, lli++)
4179              if (negate != (indexGiven ? (*lli==index) : (*lli!=0))) {
4180                PyObject *pyex = Example_FromExampleRef(*ei, lock);
4181                PyList_Append(list, pyex);
4182                Py_DECREF(pyex);
4183              }
4184            return list;
4185          }
4186
4187          case 2: {
4188            TBoolList *selection = new TBoolList(llist->size());
4189            PBoolList pselection = selection;
4190            for(TBoolList::iterator si(selection->begin()); lli != lle; *si++ = negate != (indexGiven ? (*lli++ == index) : (*lli++ != 0)));
4191
4192            return WrapOrange(pselection);
4193          }
4194
4195          default: {
4196            TExampleTable *newTable = mlnew TExampleTable(lock, 1);
4197            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4198
4199            for(;ei && (lli!=lle); ++ei, lli++)
4200              if (negate != (indexGiven ? (*lli==index) : (*lli!=0)))
4201                newTable->addExample(*ei);
4202
4203            return WrapOrange(newGen);
4204          }
4205        }
4206      }
4207
4208      PyErr_Clear();
4209
4210
4211      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
4212      /* Deprecated: use method 'filter' instead. */
4213      if (PyDict_Check(mplier))
4214        switch (toList) {
4215          case 2: return applyFilterB(filter_sameValues(mplier, eg->domain), weg);
4216          case 1: return applyFilterL(filter_sameValues(mplier, eg->domain), weg);
4217          default: return applyFilterP(filter_sameValues(mplier, eg->domain), weg);
4218        }
4219
4220      else if (PyOrFilter_Check(mplier))
4221        switch (toList) {
4222          case 2: return applyFilterB(PyOrange_AsFilter(mplier), weg);
4223          case 1: return applyFilterL(PyOrange_AsFilter(mplier), weg);
4224          default: return applyFilterP(PyOrange_AsFilter(mplier), weg);
4225        }
4226    }
4227
4228  PYERROR(PyExc_TypeError, "invalid example selector type", PYNULL);
4229  PyCATCH
4230}
4231
4232
4233PyObject *ExampleTable_select_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4234{ PyTRY
4235    return ExampleTable_selectLow(self, args, keywords, 1);
4236  PyCATCH
4237}
4238
4239
4240PyObject *ExampleTable_select_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4241{ PyTRY
4242    return ExampleTable_selectLow(self, args, keywords, 0);
4243  PyCATCH
4244}
4245
4246
4247PyObject *ExampleTable_select_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4248{ PyTRY
4249    return ExampleTable_selectLow(self, args, keywords, 2);
4250  PyCATCH
4251}
4252
4253
4254PyObject *ExampleTable_filter_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4255{
4256  PyTRY
4257    CAST_TO(TExampleGenerator, eg);
4258    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4259
4260    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4261      return applyFilterL(filter_sameValues(keywords, eg->domain, keywords), weg);
4262    }
4263
4264    if (PyTuple_Size(args)==1) {
4265      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4266
4267      if (PyDict_Check(arg))
4268        return applyFilterL(filter_sameValues(arg, eg->domain, keywords), weg);
4269
4270      if (PyOrFilter_Check(arg))
4271          return applyFilterL(PyOrange_AsFilter(arg), weg);
4272    }
4273
4274    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_list expects a list of conditions or orange.Filter", PYNULL)
4275  PyCATCH
4276}
4277
4278
4279PyObject *ExampleTable_filter_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4280{
4281  PyTRY
4282    CAST_TO(TExampleGenerator, eg);
4283    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4284
4285    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4286      return applyFilterP(filter_sameValues(keywords, eg->domain, keywords), weg);
4287    }
4288
4289    if (PyTuple_Size(args)==1) {
4290      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4291
4292      if (PyDict_Check(arg))
4293        return applyFilterP(filter_sameValues(arg, eg->domain, keywords), weg);
4294
4295      if (PyOrFilter_Check(arg))
4296          return applyFilterP(PyOrange_AsFilter(arg), weg);
4297    }
4298
4299    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_ref expects a list of conditions or orange.Filter", PYNULL)
4300  PyCATCH
4301}
4302
4303
4304PyObject *ExampleTable_filter_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4305{
4306  PyTRY
4307    CAST_TO(TExampleGenerator, eg);
4308    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4309
4310    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4311      return applyFilterB(filter_sameValues(keywords, eg->domain, keywords), weg);
4312    }
4313
4314    if (PyTuple_Size(args)==1) {
4315      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4316
4317      if (PyDict_Check(arg))
4318        return applyFilterB(filter_sameValues(arg, eg->domain, keywords), weg);
4319
4320      if (PyOrFilter_Check(arg))
4321          return applyFilterB(PyOrange_AsFilter(arg), weg);
4322    }
4323
4324    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_bool expects a list of conditions or orange.Filter", PYNULL)
4325  PyCATCH
4326}
4327
4328
4329PyObject *ExampleTable_random_example(TPyOrange *self) PYARGS(0, "() -> Example")
4330{ PyTRY
4331    CAST_TO(TExampleTable, table);
4332    TExample example(table->domain);
4333    table->randomExample(example);
4334    return Example_FromExampleCopyRef(example);
4335  PyCATCH
4336}
4337
4338
4339PyObject *ExampleTable_removeDuplicates(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([weightID=0]]) -> None")
4340{ PyTRY
4341    if (PyTuple_Size(args) > 1)
4342      PYERROR(PyExc_AttributeError, "at most one argument (weight) expected", PYNULL);
4343
4344    CAST_TO(TExampleTable, table);
4345
4346    int weightID = 0;
4347    if (PyTuple_Size(args) && !weightFromArg_byDomain(PyTuple_GET_ITEM(args, 0), table->domain, weightID))
4348      return PYNULL;
4349
4350    table->removeDuplicates(weightID);
4351    RETURN_NONE;
4352  PyCATCH
4353}
4354
4355
4356PyObject *ExampleTable_shuffle(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None")
4357{
4358  PyTRY
4359    SELF_AS(TExampleTable).shuffle();
4360    RETURN_NONE;
4361  PyCATCH
4362}
4363
4364PyObject *ExampleTable_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
4365{ PyTRY
4366    CAST_TO(TExampleTable, table);
4367
4368    if (!args || !PyTuple_Size(args)) {
4369      table->sort();
4370      RETURN_NONE;
4371    }
4372
4373    PyObject *alist = PyTuple_GET_ITEM(args, 0);
4374    /* If the first argument is nor list nor tuple, the whole argument is taken as a list
4375       i.e., data.sort("age", "prescr") is interpreted the same as data.sort(["age", "prescr"])
4376       All references are borrowed. */
4377    if ((PyTuple_Size(args) > 1) || (!PyList_Check(alist) && !PyTuple_Check(alist)))
4378      alist = args;
4379
4380    TVarList attributes;
4381    if (varListFromDomain(alist, table->domain, attributes, true, true)) {
4382      vector<int> order;
4383      for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++)
4384        order.push_back(table->domain->getVarNum(*vi));
4385      table->sort(order);
4386      RETURN_NONE;
4387    }
4388
4389    PYERROR(PyExc_TypeError, "invalid arguments (none, or a list of attributes expected)", PYNULL);
4390
4391  PyCATCH
4392}
4393
4394
4395PyObject *ExampleTable_addMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id[, Value=1.0]) -> None")
4396{ PyTRY
4397    CAST_TO(TExampleTable, table);
4398
4399    PyObject *pyid;
4400    PyObject *pyvalue=PYNULL;
4401    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4402      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4403
4404    int id;
4405    PVariable metavariable;
4406    if (PyInt_Check(pyid)) {
4407      id = PyInt_AsLong(pyid);
4408      metavariable = table->domain->getMetaVar(id, false);
4409    }
4410    else if (PyString_Check(pyid)) {
4411      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4412      metavariable = table->domain->getMetaVar(id, false);
4413    }
4414    else if (PyOrVariable_Check(pyid)) {
4415      metavariable = PyOrange_AsVariable(pyid);
4416      id = table->domain->getMetaNum(metavariable);
4417    }
4418
4419    TValue value;
4420    if (!pyvalue)
4421      if (metavariable && metavariable->varType != TValue::FLOATVAR)
4422        value = metavariable->DK();
4423      else
4424        value = TValue(float(1.0));
4425    else if (!convertFromPython(pyvalue, value, metavariable))
4426      PYERROR(PyExc_AttributeError, "invalid value argument", PYNULL);
4427
4428    table->addMetaAttribute(id, value);
4429
4430    RETURN_NONE;
4431  PyCATCH
4432}
4433
4434
4435PyObject *ExampleTable_removeMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id) -> None")
4436{ PyTRY
4437    CAST_TO(TExampleTable, table);
4438
4439    PyObject *pyid;
4440    PyObject *pyvalue=PYNULL;
4441    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4442      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4443
4444    int id;
4445    if (PyInt_Check(pyid))
4446      id = PyInt_AsLong(pyid);
4447    else if (PyString_Check(pyid))
4448      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4449    else if (PyOrVariable_Check(pyid))
4450      id = table->domain->getMetaNum(PyOrange_AsVariable(pyid));
4451
4452    table->removeMetaAttribute(id);
4453
4454    RETURN_NONE;
4455  PyCATCH
4456}
4457
4458
4459PyObject *ExampleTable_changeDomain(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(Domain) -> None")
4460{ PyTRY
4461    CAST_TO(TExampleTable, table);
4462    if (!table->ownsExamples)
4463      PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4464
4465    PDomain domain;
4466    if (!PyArg_ParseTuple(args, "O&", cc_Domain, &domain))
4467      PYERROR(PyExc_AttributeError, "domain argument expected", PYNULL);
4468
4469    table->changeDomain(domain);
4470    RETURN_NONE;
4471  PyCATCH
4472}
4473
4474PyObject *ExampleTable_pickClass(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable | name) -> None")
4475{
4476    PyTRY
4477        CAST_TO(TExampleTable, table);
4478        if (!table->ownsExamples) {
4479            PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4480        }
4481        PVariable newClass;
4482        if (PyString_Check(obj)) {
4483            const char *attr = PyString_AS_STRING(obj);
4484            TVarList::const_iterator mci(table->domain->classVars->begin()), mce(table->domain->classVars->end());
4485            for(; (mci != mce) && ((*mci)->get_name() != attr); mci++);
4486            if (mci == mce) {
4487                PYERROR(PyExc_TypeError, "table does not have multiple classes", PYNULL);
4488            }
4489            newClass = *mci;
4490        }
4491        if (PyOrVariable_Check(obj)) {
4492            newClass = PyOrange_AsVariable(obj);
4493        }
4494        else if (obj != Py_None) {
4495            PYERROR(PyExc_TypeError, "class should be given as Variable, name or None", PYNULL);
4496        }
4497        table->pickClass(newClass);
4498        RETURN_NONE;
4499    PyCATCH;
4500}
4501
4502
4503
4504PyObject *ExampleTable_hasMissingValues(TPyOrange *self) PYARGS(0, "() -> bool")
4505{
4506  PyTRY
4507    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissing());
4508  PyCATCH
4509}
4510
4511
4512PyObject *ExampleTable_hasMissingClasses(TPyOrange *self) PYARGS(0, "() -> bool")
4513{
4514  PyTRY
4515    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissingClass());
4516  PyCATCH
4517}
4518/* ************ TRANSFORMVALUE ************ */
4519
4520#include "transval.hpp"
4521BASED_ON(TransformValue, Orange)
4522
4523PyObject *TransformValue_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
4524{ if (type == (PyTypeObject *)&PyOrTransformValue_Type)
4525    return setCallbackFunction(WrapNewOrange(mlnew TTransformValue_Python(), type), args);
4526  else
4527    return WrapNewOrange(mlnew TTransformValue_Python(), type);
4528}
4529
4530
4531PyObject *TransformValue__reduce__(PyObject *self)
4532{
4533  return callbackReduce(self, PyOrTransformValue_Type);
4534}
4535
4536
4537PyObject *TransformValue_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
4538{ PyTRY
4539    NO_KEYWORDS
4540
4541    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrTransformValue_Type) {
4542      PyErr_Format(PyExc_SystemError, "TransformValue.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
4543      return PYNULL;
4544    }
4545
4546    CAST_TO(TTransformValue, tv)
4547
4548    TPyValue *value;
4549    if (!convertFromPython(args, value))
4550      return PYNULL;
4551
4552    tv->transform(value->value);
4553    value->variable=PVariable();
4554    return (PyObject *)value;
4555  PyCATCH
4556}
4557
4558
4559/* ************ DISTRIBUTION ************ */
4560
4561#include "distvars.hpp"
4562
4563PyObject *convertToPythonNative(const TDiscDistribution &disc)
4564{ int e = disc.size();
4565  PyObject *pylist = PyList_New(e);
4566  for (Py_ssize_t i = 0; i<e; i++)
4567    PyList_SetItem(pylist, i, PyFloat_FromDouble((double)(disc[i])));
4568  return pylist;
4569}
4570
4571PyObject *convertToPythonNative(const TContDistribution &cont)
4572{ PyObject *pydict = PyDict_New();
4573  const_ITERATE(TContDistribution, ci, cont) {
4574    PyObject *key = PyFloat_FromDouble((double)((*ci).first));
4575    PyObject *val = PyFloat_FromDouble((double)((*ci).second));
4576    PyDict_SetItem(pydict, key, val);
4577    Py_DECREF(key);
4578    Py_DECREF(val);
4579  }
4580  return pydict;
4581}
4582
4583
4584bool convertFromPython(PyObject *pylist, TDiscDistribution &disc)
4585{
4586  if (!PyList_Check(pylist))
4587    PYERROR(PyExc_TypeError, "list expected", false);
4588
4589  disc.clear();
4590  float d;
4591  for(Py_ssize_t i = 0, e = PyList_Size(pylist); i!=e; i++) {
4592    if (!PyNumber_ToFloat(PyList_GET_ITEM(pylist, i), d))
4593      PYERROR(PyExc_TypeError, "non-number in DiscDistribution as list", false);
4594    disc.set(TValue((int)i), d);
4595  }
4596
4597  return true;
4598}
4599
4600
4601PyObject *convertToPythonNative(const TDistribution &dist, int)
4602{ const TDiscDistribution *disc = dynamic_cast<const TDiscDistribution *>(&dist);
4603  if (disc)
4604    return convertToPythonNative(*disc);
4605
4606  const TContDistribution *cont = dynamic_cast<const TContDistribution *>(&dist);
4607  if (cont)
4608    return convertToPythonNative(*cont);
4609
4610  PYERROR(PyExc_TypeError, "cannot convert to native python object", PYNULL);
4611}
4612
4613
4614/* Class Distribution has a constructor, but it constructs an instance of either DiscDistribution
4615   or ContDistribution. Class Distribution is thus essentially abstract for Python, although it has
4616   a constructor. */
4617
4618NO_PICKLE(Distribution)
4619
4620PyObject *Distribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.statistics.distribution.Distribution, "(attribute[, examples[, weightID]])")
4621{
4622  PyTRY
4623    PExampleGenerator gen;
4624    PyObject *pyvar;
4625    int weightID = 0;
4626    if (!PyArg_ParseTuple(args, "O|O&O&:Distribution.new", &pyvar, &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID))
4627      return PYNULL;
4628
4629    TDistribution *dist;
4630
4631    if (!gen) {
4632      if (PyOrVariable_Check(pyvar))
4633        dist = TDistribution::create(PyOrange_AsVariable(pyvar));
4634      else if (PyList_Check(pyvar)) {
4635        TDiscDistribution *ddist = mlnew TDiscDistribution();
4636        if (!convertFromPython(pyvar, *ddist)) {
4637          mldelete ddist;
4638          raiseError("invalid arguments");
4639        }
4640        else
4641          dist = ddist;
4642      }
4643      else
4644        raiseError("invalid arguments");
4645    }
4646    else {
4647      if (PyOrVariable_Check(pyvar))
4648        dist = TDistribution::fromGenerator(gen, PyOrange_AsVariable(pyvar), weightID);
4649      else {
4650        PVariable var = varFromArg_byDomain(pyvar, gen->domain, false);
4651        if (!var)
4652          return PYNULL;
4653
4654        dist = TDistribution::fromGenerator(gen, var, weightID);
4655      }
4656    }
4657
4658    /* We need to override the type (don't want to lie it's Distribution).
4659       The exception is if another type is prescribed. */
4660    return type==(PyTypeObject *)(&PyOrDistribution_Type) ? WrapOrange(PDistribution(dist)) : WrapNewOrange(dist, type);
4661  PyCATCH
4662}
4663
4664
4665PyObject *Distribution_native(PyObject *self, PyObject *) PYARGS(0, "() -> list | dictionary")
4666{
4667  PyTRY
4668    return convertToPythonNative(*PyOrange_AS_Orange(self).AS(TDistribution), 1);
4669  PyCATCH
4670}
4671
4672
4673TDiscDistribution *getDiscDistribution(PyObject *self)
4674{ TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4675  if (!disc)
4676    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected DiscDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4677  return disc;
4678}
4679
4680
4681TContDistribution *getContDistribution(PyObject *self)
4682{ TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4683  if (!cont)
4684    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected ContDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4685  return cont;
4686}
4687
4688
4689
4690float *Distribution_getItemRef(PyObject *self, PyObject *index, float *float_idx=NULL)
4691{
4692  TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4693  if (disc) {
4694    int ind=-1;
4695    if (PyInt_Check(index))
4696      ind = (int)PyInt_AsLong(index);
4697    else {
4698      if (!disc->variable)
4699        PYERROR(PyExc_SystemError, "invalid distribution (no variable)", (float *)NULL);
4700      TValue val;
4701      if (convertFromPython(index, val, disc->variable) && !val.isSpecial())
4702        ind=int(val);
4703    }
4704
4705    if (ind<0)
4706      PYERROR(PyExc_IndexError, "invalid index for distribution", (float *)NULL);
4707
4708    if (ind<int(disc->size()))
4709      return &disc->at(ind);
4710
4711    PyErr_Format(PyExc_IndexError, "index %i is out of range (0-%i)", ind, disc->size()-1);
4712    return (float *)NULL;
4713  }
4714
4715  TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4716  if (cont) {
4717    float ind;
4718    if (PyNumber_ToFloat(index, ind)) {
4719      if (float_idx)
4720        *float_idx = ind;
4721    }
4722    else {
4723      TValue val;
4724      if (convertFromPython(index, val, cont->variable) && !val.isSpecial()) {
4725        ind = float(val);
4726        if (float_idx)
4727          *float_idx = ind;
4728      }
4729      else
4730        PYERROR(PyExc_IndexError, "invalid index type (float expected)", NULL);
4731    }
4732
4733    TContDistribution::iterator mi=cont->find(ind);
4734    if (mi!=cont->end())
4735      return &(*mi).second;
4736  }
4737
4738  PYERROR(PyExc_IndexError, "invalid index", (float *)NULL);
4739}
4740
4741
4742PyObject *Distribution_getitem(PyObject *self, PyObject *index)
4743{ PyTRY
4744    float *prob=Distribution_getItemRef(self, index);
4745    return prob ? PyFloat_FromDouble(*prob) : PYNULL;
4746  PyCATCH
4747}
4748
4749
4750int Distribution_setitem(PyObject *self, PyObject *index, PyObject *item)
4751{ PyTRY
4752    PyObject *flt = PyNumber_Float(item);
4753    if (!flt)
4754      PYERROR(PyExc_TypeError, "float expected", -1);
4755
4756    float val=(float)PyFloat_AsDouble(flt);
4757    Py_DECREF(flt);
4758
4759    if (PyOrValue_Check(index)) {
4760      SELF_AS(TDistribution).set(PyValue_AS_Value(index), val);
4761      return 0;
4762    }
4763
4764    float *prob = Distribution_getItemRef(self, index);
4765    if (!prob)
4766      return -1;
4767
4768    *prob = val;
4769    return 0;
4770  PyCATCH_1
4771}
4772
4773
4774string convertToString(const PDistribution &distribution)
4775{
4776  const TDiscDistribution *disc = distribution.AS(TDiscDistribution);
4777  if (disc) {
4778    string res = "<";
4779    char buf[128];
4780    const_PITERATE(TDiscDistribution, di, disc) {
4781      if (res.size()>1)
4782        res += ", ";
4783      sprintf(buf, "%.3f", *di);
4784      res += buf;
4785    }
4786    return res+">";
4787  }
4788
4789  const TContDistribution *cont = distribution.AS(TContDistribution);
4790  if (cont) {
4791    string res = "<";
4792    char buf[128];
4793    const_PITERATE(TContDistribution, di, cont) {
4794      if (res.size()>1)
4795        res += ", ";
4796      sprintf(buf, "%.3f: %.3f", (*di).first, (*di).second);
4797      res += buf;
4798    }
4799    return res+">";
4800  }
4801
4802  raiseErrorWho("convertToString(PDistribution)", "invalid distribution");
4803  return string();
4804}
4805
4806
4807PyObject *Distribution_str(PyObject *self)
4808{ PyTRY
4809    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
4810    if (result)
4811      return result;
4812
4813    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4814  PyCATCH
4815}
4816
4817
4818PyObject *Distribution_repr(PyObject *self)
4819{ PyTRY
4820    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "repr", "str");
4821    if (result)
4822      return result;
4823
4824    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4825  PyCATCH
4826}
4827
4828
4829PyObject *Distribution_normalize(PyObject *self) PYARGS(0, "() -> None")
4830{ PyTRY
4831    SELF_AS(TDistribution).normalize();
4832    RETURN_NONE;
4833  PyCATCH
4834}
4835
4836
4837PyObject *Distribution_modus(PyObject *self) PYARGS(0, "() -> Value")
4838{ PyTRY
4839    CAST_TO(TDistribution, dist)
4840    return Value_FromVariableValue(dist->variable, dist->highestProbValue());
4841  PyCATCH
4842}
4843
4844
4845PyObject *Distribution_random(PyObject *self) PYARGS(0, "() -> Value")
4846{ PyTRY
4847    CAST_TO(TDistribution, dist)
4848    return Value_FromVariableValue(dist->variable, dist->randomValue());
4849  PyCATCH
4850}
4851
4852
4853
4854PDiscDistribution list2discdistr(PyObject *args, PyTypeObject *type = NULL)
4855{
4856  TDiscDistribution *udist = mlnew TDiscDistribution();
4857  PDiscDistribution disc = type ? PDistribution(udist) : PDistribution(udist, type);
4858  for(Py_ssize_t i = 0, e = PyList_Size(args); i<e; i++) {
4859    PyObject *flt = PyNumber_Float(PyList_GetItem(args, i));
4860    if (!flt) {
4861      PyErr_Format(PyExc_TypeError, "invalid element at index %i (float expected)", i);
4862      return PDiscDistribution();
4863    }
4864    udist->addint((int)i, (float)PyFloat_AsDouble(flt));
4865    Py_DECREF(flt);
4866  }
4867
4868  return disc;
4869}
4870
4871
4872PyObject *DiscDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Discrete, "[list of floats] | DiscDistribution")
4873{ PyTRY {
4874    if (!PyTuple_Size(targs)) {
4875      return WrapNewOrange(mlnew TDiscDistribution(), type);
4876    }
4877
4878    if (PyTuple_Size(targs)==1) {
4879      PyObject *args = PyTuple_GetItem(targs, 0);
4880
4881      if (PyList_Check(args)) {
4882        PDiscDistribution disc = list2discdistr(args, type);
4883        if (disc)
4884          return WrapOrange(disc);
4885      }
4886
4887      else if (PyOrDiscDistribution_Check(args)) {
4888        Py_INCREF(args);
4889        return args;
4890      }
4891
4892      else if (PyOrEnumVariable_Check(args))
4893        return WrapNewOrange(mlnew TDiscDistribution(PyOrange_AsVariable(args)), type);
4894    }
4895
4896    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
4897  }
4898  PyCATCH;
4899}
4900
4901
4902PyObject *DiscDistribution__reduce__(PyObject *self)
4903{
4904  PyTRY
4905    TDiscDistribution *disc = getDiscDistribution(self);
4906    TCharBuffer buf(sizeof(float)*(disc->size()+2));
4907    buf.writeFloatVector(disc->distribution);
4908
4909    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderDiscDistribution"),
4910                                    self->ob_type,
4911                                    buf.buf, buf.length(),
4912                                    packOrangeDictionary(self));
4913  PyCATCH
4914}
4915
4916
4917PyObject *__pickleLoaderDiscDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
4918{
4919  PyTRY
4920    PyTypeObject *type;
4921    char *buf;
4922    int bufSize;
4923    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &buf, &bufSize))
4924      return PYNULL;
4925
4926    const int &size = (int &)*buf;
4927    buf += sizeof(int);
4928
4929    return WrapNewOrange(new TDiscDistribution((float *)buf, size), type);
4930  PyCATCH
4931}
4932
4933
4934int pt_DiscDistribution(PyObject *args, void *dist)
4935{ if (PyOrDiscDistribution_Check(args)) {
4936    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4937    return 1;
4938  }
4939  else if (PyList_Check(args)) {
4940    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4941    if (dist)
4942      return 1;
4943  }
4944
4945  PYERROR(PyExc_TypeError, "invalid discrete distribution", 0)
4946}
4947
4948
4949PyObject *DiscDistribution_getitem_sq(PyObject *self, Py_ssize_t ind)
4950{
4951  PyTRY
4952    TDiscDistribution *disc = getDiscDistribution(self);
4953    if (!disc)
4954      return PYNULL;
4955
4956    if ((ind<0) || (ind>=disc->size()))
4957      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
4958
4959    return PyFloat_FromDouble(double(disc->at(ind)));
4960  PyCATCH
4961}
4962
4963
4964Py_ssize_t DiscDistribution_len(PyObject *self)
4965{ PyTRY
4966    TDiscDistribution *disc = getDiscDistribution(self);
4967    return disc ? disc->size() : -1;
4968  PyCATCH_1
4969}
4970
4971
4972PyObject *DiscDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
4973{ PyTRY
4974    TDiscDistribution *disc = getDiscDistribution(self);
4975    if (!disc)
4976      return PYNULL;
4977
4978    if (!disc->variable)
4979      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4980
4981    PyObject *nl=PyList_New(disc->variable->noOfValues());
4982    Py_ssize_t i=0;
4983    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4984    PITERATE(TStringList, ii, vals)
4985      PyList_SetItem(nl, i++, PyString_FromString((*ii).c_str()));
4986    return nl;
4987  PyCATCH
4988}
4989
4990
4991PyObject *DiscDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
4992{ PyTRY
4993    TDiscDistribution *disc = getDiscDistribution(self);
4994    if (!disc)
4995      return PYNULL;
4996
4997    if (!disc->variable)
4998      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4999
5000    PyObject *nl=PyList_New(disc->variable->noOfValues());
5001    TDiscDistribution::const_iterator ci(disc->begin());
5002    Py_ssize_t i=0;
5003    PStringList vals=disc->variable.AS(TEnumVariable)->values;
5004    PITERATE(TStringList, ii, vals)
5005      PyList_SetItem(nl, i++, Py_BuildValue("sf", (*ii).c_str(), *(ci++)));
5006    return nl;
5007  PyCATCH
5008}
5009
5010
5011PyObject *DiscDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5012{ PyTRY
5013    TDiscDistribution *disc = getDiscDistribution(self);
5014    if (!disc)
5015      return PYNULL;
5016
5017    PyObject *nl = PyList_New(disc->size());
5018    Py_ssize_t i = 0;
5019    const_PITERATE(TDiscDistribution, ci, disc)
5020      PyList_SetItem(nl, i++, PyFloat_FromDouble(*ci));
5021    return nl;
5022  PyCATCH
5023}
5024
5025
5026PyObject *DiscDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5027{ PyTRY
5028    CAST_TO(TDiscDistribution, dist)
5029
5030    PyObject *index;
5031    float weight = 1.0;
5032    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5033      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5034
5035    if (PyInt_Check(index)) {
5036      dist->addint(int(PyInt_AsLong(index)), weight);
5037      RETURN_NONE;
5038    }
5039
5040    TValue val;
5041    if (!dist->variable || !convertFromPython(index, val, dist->variable))
5042      PYERROR(PyExc_TypeError, "DiscDistriubtion.add: cannot convert the arguments to a Value", PYNULL);
5043
5044    dist->add(val, weight);
5045    RETURN_NONE;
5046  PyCATCH;
5047}
5048
5049
5050PyObject *ContDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Continuous, "[dist of float:float] | DiscDistribution")
5051{ PyTRY {
5052
5053    if (!PyTuple_Size(targs))
5054      return WrapNewOrange(mlnew TContDistribution(), type);
5055
5056    if (PyTuple_Size(targs) == 1) {
5057      PyObject *args = PyTuple_GetItem(targs, 0);
5058
5059      if (PyDict_Check(args)) {
5060        TContDistribution *udist = mlnew TContDistribution();
5061        PContDistribution cont = PDistribution(udist);
5062        PyObject *key, *value;
5063        Py_ssize_t pos = 0;
5064        while (PyDict_Next(args, &pos, &key, &value)) {
5065          PyObject *flt = PyNumber_Float(key);
5066          if (!flt) {
5067            PyErr_Format(PyExc_TypeError, "invalid key at index %i (float expected)", pos);
5068            return false;
5069          }
5070          float ind = (float) PyFloat_AsDouble(flt);
5071          Py_DECREF(flt);
5072
5073          flt = PyNumber_Float(value);
5074          if (!flt) {
5075            PyErr_Format(PyExc_TypeError, "invalid value at index %i (float expected)", pos);
5076            return false;
5077          }
5078
5079          udist->addfloat(ind, (float)PyFloat_AsDouble(flt));
5080          Py_DECREF(flt);
5081        }
5082
5083        return WrapOrange(cont);
5084      }
5085
5086      else if (PyOrDistribution_Check(args)) {
5087        Py_INCREF(args);
5088        return args;
5089      }
5090
5091      else if (PyOrFloatVariable_Check(args))
5092        return WrapNewOrange(mlnew TContDistribution(PyOrange_AsVariable(args)), type);
5093    }
5094
5095    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
5096
5097  }
5098  PyCATCH;
5099}
5100
5101
5102PyObject *ContDistribution__reduce__(PyObject *self)
5103{
5104  PyTRY
5105    TContDistribution *cont = getContDistribution(self);
5106    TCharBuffer buf(sizeof(float) * 2 * (cont->size()  +  5));
5107
5108    buf.writeInt(cont->size());
5109    PITERATE(TContDistribution, ci, cont) {
5110      buf.writeFloat((*ci).first);
5111      buf.writeFloat((*ci).second);
5112    }
5113
5114    buf.writeFloat(cont->sum);
5115    buf.writeFloat(cont->sum2);
5116
5117    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderContDistribution"),
5118                                    self->ob_type,
5119                                    buf.buf, buf.length(),
5120                                    packOrangeDictionary(self));
5121  PyCATCH
5122}
5123
5124
5125PyObject *__pickleLoaderContDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
5126{
5127  PyTRY
5128    PyTypeObject *type;
5129    char *pbuf;
5130    int bufSize;
5131    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &pbuf, &bufSize))
5132      return PYNULL;
5133
5134    TContDistribution *cdi = new TContDistribution();
5135
5136    TCharBuffer buf(pbuf);
5137    for(int size = buf.readInt(); size--; ) {
5138      // cannot call buf.readFloat() in the make_pair call since we're not sure about the
5139      // order in which the arguments are evaluated
5140      const float p1 = buf.readFloat();
5141      const float p2 = buf.readFloat();
5142      cdi->insert(cdi->end(), make_pair(p1, p2));
5143    }
5144
5145    cdi->sum = buf.readFloat();
5146    cdi->sum2 = buf.readFloat();
5147
5148    return WrapNewOrange(cdi, type);
5149  PyCATCH
5150}
5151
5152
5153Py_ssize_t ContDistribution_len(PyObject *self)
5154{ PyTRY
5155    TContDistribution *cont = getContDistribution(self);
5156    return cont ? cont->size() : -1;
5157  PyCATCH_1
5158}
5159
5160
5161PyObject *ContDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
5162{ PyTRY
5163    TContDistribution *cont = getContDistribution(self);
5164    if (!cont)
5165      return PYNULL;
5166
5167    PyObject *nl=PyList_New(cont->size());
5168    Py_ssize_t i=0;
5169    PITERATE(TContDistribution, ci, cont)
5170      PyList_SetItem(nl, i++, PyFloat_FromDouble((double)(*ci).first));
5171    return nl;
5172  PyCATCH
5173}
5174
5175
5176PyObject *ContDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
5177{ PyTRY
5178    TContDistribution *cont = getContDistribution(self);
5179    if (!cont)
5180      return PYNULL;
5181
5182    PyObject *nl=PyList_New(cont->size());
5183    Py_ssize_t i=0;
5184    PITERATE(TContDistribution, ci, cont)
5185      PyList_SetItem(nl, i++, Py_BuildValue("ff", (*ci).first, (*ci).second));
5186    return nl;
5187  PyCATCH
5188}
5189
5190
5191PyObject *ContDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5192{ PyTRY
5193    TContDistribution *cont = getContDistribution(self);
5194    if (!cont)
5195      return PYNULL;
5196
5197    PyObject *nl = PyList_New(cont->size());
5198    Py_ssize_t i = 0;
5199    const_PITERATE(TContDistribution, ci, cont)
5200      PyList_SetItem(nl, i++, PyFloat_FromDouble((*ci).second));
5201    return nl;
5202  PyCATCH
5203}
5204
5205
5206PyObject *ContDistribution_percentile(PyObject *self, PyObject *arg) PYARGS(METH_VARARGS, "(int) -> float")
5207{ PyTRY
5208    TContDistribution *cont = getContDistribution(self);
5209    if (!cont)
5210      return PYNULL;
5211
5212    float perc;
5213    if (!PyArg_ParseTuple(arg, "f:ContDistribution.percentile", &perc))
5214      return PYNULL;
5215
5216    return PyFloat_FromDouble(cont->percentile(perc));
5217  PyCATCH
5218}
5219
5220
5221PyObject *ContDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5222{ PyTRY
5223    CAST_TO(TContDistribution, dist)
5224
5225    PyObject *index;
5226    float weight = 1.0;
5227    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5228      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5229
5230    float f;
5231    if (PyNumber_ToFloat(index, f)) {
5232      dist->addfloat(f, weight);
5233      RETURN_NONE;
5234    }
5235
5236    TValue val;
5237    if (!convertFromPython(index, val, dist->variable))
5238      PYERROR(PyExc_TypeError, "ContDistriubtion.add: invalid arguments", PYNULL);
5239
5240    dist->add(val, weight);
5241    RETURN_NONE;
5242  PyCATCH;
5243}
5244
5245
5246PyObject *ContDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5247{ PyTRY
5248    TContDistribution *cont = getContDistribution(self);
5249    if (!cont)
5250      return PYNULL;
5251
5252    return PyFloat_FromDouble(cont->error());
5253  PyCATCH
5254}
5255
5256
5257PyObject *ContDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5258{ PyTRY
5259    TContDistribution *cont = getContDistribution(self);
5260    if (!cont)
5261      return PYNULL;
5262
5263    return PyFloat_FromDouble(cont->average());
5264  PyCATCH
5265}
5266
5267
5268PyObject *ContDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5269{ PyTRY
5270    TContDistribution *cont = getContDistribution(self);
5271    if (!cont)
5272      return PYNULL;
5273
5274    return PyFloat_FromDouble(cont->dev());
5275  PyCATCH
5276}
5277
5278
5279PyObject *ContDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5280{ PyTRY
5281    TContDistribution *cont = getContDistribution(self);
5282    if (!cont)
5283      return PYNULL;
5284
5285    return PyFloat_FromDouble(cont->var());
5286  PyCATCH
5287}
5288
5289
5290PyObject *ContDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5291{ PyTRY
5292    TContDistribution *cont = getContDistribution(self);
5293    float x;
5294    if (!cont || !PyArg_ParseTuple(args, "f:ContDistribution.density", &x))
5295      return PYNULL;
5296
5297    return PyFloat_FromDouble(cont->p(x));
5298  PyCATCH
5299}
5300
5301
5302PyObject *GaussianDistribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Gaussian, "(mean, sigma) | (distribution) | () -> distribution") ALLOWS_EMPTY
5303{ PyTRY
5304    float mean = 0.0, sigma = 1.0;
5305
5306    if (PyArg_ParseTuple(args, "|ff", &mean, &sigma))
5307      return WrapNewOrange(mlnew TGaussianDistribution(mean, sigma), type);
5308
5309    PyErr_Clear();
5310
5311    PDistribution dist;
5312    if (PyArg_ParseTuple(args, "O&", &cc_Distribution, &dist))
5313      return WrapNewOrange(mlnew TGaussianDistribution(dist), type);
5314
5315    PYERROR(PyExc_TypeError, "GaussianDistribution expects mean and sigma, or distribution or nothing", PYNULL)
5316
5317  PyCATCH
5318}
5319
5320
5321PyObject *GaussianDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5322{ PyTRY
5323    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).average());
5324  PyCATCH
5325}
5326
5327
5328PyObject *GaussianDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5329{ PyTRY
5330    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).error());
5331  PyCATCH
5332}
5333
5334
5335PyObject *GaussianDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5336{ PyTRY
5337    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).dev());
5338  PyCATCH
5339}
5340
5341
5342PyObject *GaussianDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5343{ PyTRY
5344    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).var());
5345  PyCATCH
5346}
5347
5348
5349PyObject *GaussianDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5350{ PyTRY
5351    float x;
5352    if (!PyArg_ParseTuple(args, "f:GaussianDistribution.density", &x))
5353      return PYNULL;
5354
5355    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).p(x));
5356  PyCATCH
5357}
5358
5359
5360/* We redefine new (removed from below!) and add mapping methods
5361*/
5362
5363PyObject *getClassDistribution(PyObject *type, PyObject *args) PYARGS(METH_VARARGS, "(examples[, weightID]) -> Distribution")
5364{ PyTRY
5365    int weightID;
5366    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
5367    if (!gen)
5368      return PYNULL;
5369    return WrapOrange(getClassDistribution(gen, weightID));
5370  PyCATCH
5371}
5372
5373
5374/* modified new (defined below), modified getitem, setitem */
5375
5376PDomainDistributions PDomainDistributions_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5377PyObject *DomainDistributions_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5378PyObject *DomainDistributions_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5379int       DomainDistributions_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setslice(self, start, stop, item); }
5380PyObject *DomainDistributions_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5381int       DomainDistributions_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5382Py_ssize_t       DomainDistributions_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_len(self); }
5383PyObject *DomainDistributions_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5384PyObject *DomainDistributions_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5385PyObject *DomainDistributions_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5386PyObject *DomainDistributions_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5387PyObject *DomainDistributions_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5388int       DomainDistributions_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5389PyObject *DomainDistributions_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5390PyObject *DomainDistributions_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5391PyObject *DomainDistributions_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5392PyObject *DomainDistributions_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainDistributions") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5393PyObject *DomainDistributions_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5394PyObject *DomainDistributions_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5395PyObject *DomainDistributions_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_native(self); }
5396PyObject *DomainDistributions_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5397PyObject *DomainDistributions_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5398PyObject *DomainDistributions_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5399PyObject *DomainDistributions_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5400PyObject *DomainDistributions__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5401
5402
5403/* Note that this is not like callable-constructors. They return different type when given
5404   parameters, while this one returns the same type, disregarding whether it was given examples or not.
5405*/
5406PyObject *DomainDistributions_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange - Orange.statistics.distribution.Domain, "(examples[, weightID, skipDiscrete, skipContinuous] | <list of Distribution>) -> DomainDistributions") ALLOWS_EMPTY
5407{ PyTRY
5408    if (!args || !PyTuple_Size(args))
5409      return WrapNewOrange(mlnew TDomainDistributions(), type);
5410
5411    int weightID = 0;
5412    PExampleGenerator gen;
5413    int skipDiscrete=0, skipContinuous=0;
5414    if (PyArg_ParseTuple(args, "O&|O&ii:Distribution.new", &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &skipDiscrete, &skipContinuous))
5415      return WrapNewOrange(mlnew TDomainDistributions(gen, weightID, skipDiscrete!=0, skipContinuous!=0), type);
5416
5417    PyErr_Clear();
5418
5419    PyObject *obj = ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_new(type, args, keywds);
5420    if (obj)
5421      if (obj!=Py_None)
5422        return obj;
5423      else
5424        Py_DECREF(obj);
5425
5426    PyErr_Clear();
5427    PYERROR(PyExc_TypeError, "DomainDistributions.__init__ expect examples or a list of Distributions", PYNULL);
5428
5429  PyCATCH
5430}
5431
5432
5433/* We keep the sequence methods and add mapping interface */
5434
5435int DomainDistributions_getItemIndex(PyObject *self, PyObject *args)
5436{ CAST_TO_err(TDomainDistributions, bas, -1);
5437
5438  if (PyInt_Check(args)) {
5439    int i=(int)PyInt_AsLong(args);
5440    if ((i>=0) && (i<int(bas->size())))
5441      return i;
5442    else
5443      PYERROR(PyExc_IndexError, "index out of range", -1);
5444  }
5445
5446  if (PyString_Check(args)) {
5447    char *s=PyString_AsString(args);
5448    PITERATE(TDomainDistributions, ci, bas)
5449      if ((*ci)->variable && ((*ci)->variable->get_name()==s))
5450        return ci - bas->begin();
5451
5452    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", s);
5453    return -1;
5454  }
5455
5456  if (PyOrVariable_Check(args)) {
5457    PVariable var = PyOrange_AsVariable(args);
5458    PITERATE(TDomainDistributions, ci, bas)
5459      if ((*ci)->variable && ((*ci)->variable==var))
5460        return ci - bas->begin();
5461
5462    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", var->get_name().length() ? var->get_name().c_str() : "<no name>");
5463    return -1;
5464  }
5465
5466  PYERROR(PyExc_IndexError, "invalid index type", -1);
5467}
5468
5469
5470PyObject *DomainDistributions_getitem(PyObject *self, PyObject *args)
5471{ PyTRY
5472    int index=DomainDistributions_getItemIndex(self, args);
5473    if (index<0)
5474      return PYNULL;
5475    return WrapOrange(POrange(SELF_AS(TDomainDistributions).at(index)));
5476  PyCATCH
5477}
5478
5479
5480int DomainDistributions_setitem(PyObject *self, PyObject *args, PyObject *obj)
5481{ PyTRY
5482    PDistribution bas;
5483
5484    if (!PyOrBasicAttrStat_Check(obj))
5485      PYERROR(PyExc_TypeError, "invalid Distribution object", -1);
5486
5487    int index=DomainDistributions_getItemIndex(self, args);
5488    if (index==-1)
5489      return -1;
5490
5491    SELF_AS(TDomainDistributions)[index] = PyOrange_AsDistribution(obj);
5492    return 0;
5493  PyCATCH_1
5494}
5495
5496
5497PDistributionList PDistributionList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5498PyObject *DistributionList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5499PyObject *DistributionList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of Distribution>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_new(type, arg, kwds); }
5500PyObject *DistributionList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5501int       DistributionList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5502PyObject *DistributionList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5503int       DistributionList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setslice(self, start, stop, item); }
5504Py_ssize_t       DistributionList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_len(self); }
5505PyObject *DistributionList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5506PyObject *DistributionList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5507PyObject *DistributionList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5508PyObject *DistributionList_str(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5509PyObject *DistributionList_repr(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5510int       DistributionList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5511PyObject *DistributionList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5512PyObject *DistributionList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5513PyObject *DistributionList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5514PyObject *DistributionList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DistributionList") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5515PyObject *DistributionList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5516PyObject *DistributionList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5517PyObject *DistributionList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_native(self); }
5518PyObject *DistributionList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5519PyObject *DistributionList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5520PyObject *DistributionList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5521PyObject *DistributionList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5522PyObject *DistributionList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5523
5524
5525
5526/* ************ LEARNER ************ */
5527
5528#include "classify.hpp"
5529#include "learn.hpp"
5530
5531BASED_ON(EFMDataDescription, Orange)
5532
5533PyObject *EFMDataDescription__reduce__(PyObject *self)
5534{
5535  CAST_TO(TEFMDataDescription, edd);
5536
5537  TCharBuffer buf(0);
5538  buf.writeFloatVector(edd->averages);
5539  buf.writeFloatVector(edd->matchProbabilities);
5540  buf.writeInt(edd->originalWeight);
5541  buf.writeInt(edd->missingWeight);
5542
5543  return Py_BuildValue("O(OOs#)N", getExportedFunction("__pickleLoaderEFMDataDescription"),
5544                                  WrapOrange(edd->domain),
5545                                  WrapOrange(edd->domainDistributions),
5546                                  buf.buf, buf.length(),
5547                                  packOrangeDictionary(self));
5548}
5549
5550
5551PyObject *__pickleLoaderEFMDataDescription(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, domainDistributions, packed_data)")
5552{
5553  PDomain domain;
5554  PDomainDistributions domainDistributions;
5555  char *pbuf;
5556  int bufSize;
5557
5558  if (!PyArg_ParseTuple(args, "O&O&s#", ccn_Domain, &domain, ccn_DomainDistributions, &domainDistributions, &pbuf, &bufSize))
5559    return PYNULL;
5560
5561  TEFMDataDescription *edd = new TEFMDataDescription(domain, domainDistributions);
5562  PEFMDataDescription wedd = edd;
5563
5564  TCharBuffer buf(pbuf);
5565  buf.readFloatVector(edd->averages);
5566  buf.readFloatVector(edd->matchProbabilities);
5567  edd->originalWeight = buf.readInt();
5568  edd->missingWeight = buf.readInt();
5569
5570  return WrapOrange(wedd);
5571}
5572
5573
5574ABSTRACT(LearnerFD - Orange.classification.LearnerFD, Learner)
5575
5576PyObject *Learner_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.classification.Learner, "<abstract>")
5577{ if (type == (PyTypeObject *)&PyOrLearner_Type)
5578    return setCallbackFunction(WrapNewOrange(mlnew TLearner_Python(), type), args);
5579  else
5580    return WrapNewOrange(mlnew TLearner_Python(), type);
5581}
5582
5583
5584PyObject *Learner__reduce__(PyObject *self)
5585{
5586  return callbackReduce(self, PyOrLearner_Type);
5587}
5588
5589
5590PyObject *Learner_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(examples) -> Classifier")
5591{
5592  PyTRY
5593    NO_KEYWORDS
5594
5595    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrLearner_Type) {
5596      PyErr_Format(PyExc_SystemError, "Learner.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
5597      return PYNULL;
5598    }
5599
5600    PExampleGenerator egen;
5601    int weight = 0;
5602    if (!PyArg_ParseTuple(targs, "O&|O&", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weight))
5603      PYERROR(PyExc_AttributeError, "Learner.__call__: examples and, optionally, weight attribute expected", PYNULL);
5604
5605    // Here for compatibility with obsolete scripts
5606/*    if (PyTuple_Size(targs)==1) {
5607      if (((TPyOrange *)self)->orange_dict) {
5608        PyObject *pyweight = PyDict_GetItemString(((TPyOrange *)self)->orange_dict, "weight");
5609        if (pyweight && PyInt_Check(pyweight))
5610          weight = (int)PyInt_AsLong(pyweight);
5611      }
5612    }
5613*/
5614    PClassifier classfr = SELF_AS(TLearner)(egen, weight);
5615    if (!classfr)
5616      PYERROR(PyExc_SystemError, "learning failed", PYNULL);
5617
5618    return WrapOrange(classfr);
5619  PyCATCH
5620}
5621
5622
5623
5624
5625/* ************ CLASSIFIERS ************ */
5626
5627#include "classify.hpp"
5628#include "majority.hpp"
5629
5630ABSTRACT(ClassifierFD - Orange.classification.ClassifierFD, Classifier)
5631
5632PyObject *DefaultClassifier_new(PyTypeObject *tpe, PyObject *args, PyObject *kw) BASED_ON(Classifier - Orange.classification.ConstantClassifier, "([defaultVal])") ALLOWS_EMPTY
5633{
5634  PyObject *arg1 = NULL, *arg2 = NULL;
5635  if (!PyArg_UnpackTuple(args, "DefaultClassifier.__new__", 0, 2, &arg1, &arg2))
5636    return PYNULL;
5637
5638  if (!arg1)
5639    return WrapNewOrange(mlnew TDefaultClassifier(), tpe);
5640
5641  if (!arg2) {
5642    if (PyOrVariable_Check(arg1))
5643      return WrapNewOrange(mlnew TDefaultClassifier(PyOrange_AsVariable(arg1)), tpe);
5644    TValue val;
5645    if (convertFromPython(arg1, val)) {
5646      PVariable var = PyOrValue_Check(arg1) ? PyValue_AS_Variable(arg1) : PVariable();
5647      return WrapNewOrange(mlnew TDefaultClassifier(var, val, PDistribution()), tpe);
5648    }
5649  }
5650
5651  else
5652    if (PyOrVariable_Check(arg1)) {
5653      PVariable classVar = PyOrange_AsVariable(arg1);
5654      TValue val;
5655      if (convertFromPython(arg2, val, classVar))
5656        return WrapNewOrange(mlnew TDefaultClassifier(classVar, val, PDistribution()), tpe);
5657    }
5658
5659  PYERROR(PyExc_TypeError, "DefaultClassifier's constructor expects a Variable, a Value or both", PYNULL);
5660}
5661
5662C_NAMED(RandomLearner - Orange.classification.RandomLearner, Learner, "([probabilities=])")
5663C_NAMED(RandomClassifier - Orange.classification.RandomClassifier, Classifier, "([probabilities=])")
5664
5665PClassifierList PClassifierList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::P_FromArguments(arg); }
5666PyObject *ClassifierList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_FromArguments(type, arg); }
5667PyObject *ClassifierList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange - Orange.classification.ClassifierList, "(<list of Classifier>)")  ALLOWS_EMPTY { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_new(type, arg, kwds); }
5668PyObject *ClassifierList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getitem(self, index); }
5669int       ClassifierList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_setitem(self, index, item); }
5670PyObject *ClassifierList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getslice(self, start, stop); }
5671int       ClassifierList_setslice(TPyOrange *self, Py_ssize_t start, P