source: orange/source/orange/lib_kernel.cpp @ 11704:02de8bb41dec

Revision 11704:02de8bb41dec, 212.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Added dedicated get/set for 'attributes' property of feature descriptors.

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