source: orange/source/orange/lib_kernel.cpp @ 10588:5ea62b7b37bc

Revision 10588:5ea62b7b37bc, 210.1 KB checked in by Janez Demšar <janez.demsar@…>, 2 years ago (diff)

Fixed conversion of Examples from lists and of ExampleTables from numpy arrays to work for domains with multiple classes (fixes #1145)

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