source: orange/source/orange/lib_kernel.cpp @ 11742:0141e039adf1

Revision 11742:0141e039adf1, 212.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 6 months ago (diff)

Accept an empty instances list in Orange.data.Table(domain, instances) constructor.

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