source: orange/source/orange/lib_kernel.cpp @ 10568:83a026cffa47

Revision 10568:83a026cffa47, 208.3 KB checked in by Janez Demšar <janez.demsar@…>, 2 years ago (diff)

Fixed RandomGeneratorreduce (Mersenne twister leaves mt.next dangling until the first use, which caused reduce to miscalculate the buffer size)

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, ve;
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        ve = variables->end();
2941      }
2942
2943      else {
2944        if (array->dimensions[1] != domain->variables->size())
2945          PYERROR(PyExc_AttributeError, "the number of columns in the array doesn't match the number of attributes", NULL);
2946
2947       variables = domain->variables;
2948       ve = variables->end();
2949       for(vi = variables->begin(); vi!=ve; vi++)
2950                  if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
2951                      PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
2952            }
2953
2954      const char arrayType = getArrayType(array);
2955      if (!strchr(supportedNumericTypes, arrayType)) {
2956        PyErr_Format(PyExc_AttributeError, "Converting arrays of type '%c' is not supported (use one of '%s')", arrayType, supportedNumericTypes);
2957        return NULL;
2958      }
2959
2960      TExampleTable *table = mlnew TExampleTable(domain);
2961      TExample *nex = NULL;
2962      table->reserve(array->dimensions[0]);
2963
2964      const int &strideRow = array->strides[0];
2965      const int &strideCol = array->strides[1];
2966
2967      // If there's no mask, the mask pointers will equal the data pointer to avoid too many if's
2968      const int &strideMaskRow = mask ? mask->strides[0] : strideRow;
2969      const int &strideMaskCol = mask ? mask->strides[1] : strideCol;
2970
2971      try {
2972        TExample::iterator ei;
2973        char *rowPtr = array->data;
2974        char *maskRowPtr = mask ? mask->data : array->data;
2975
2976        for(int row = 0, rowe = array->dimensions[0]; row < rowe; row++, rowPtr += strideRow, maskRowPtr += strideMaskRow) {
2977          char *elPtr = rowPtr;
2978          char *maskPtr = maskRowPtr;
2979          TExample *nex = mlnew TExample(domain);
2980
2981          #define ARRAYTYPE(TYPE) \
2982            for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol) \
2983              if ((*vi)->varType == TValue::INTVAR) \
2984                intValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
2985              else \
2986                floatValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
2987            break;
2988
2989          switch (arrayType) {
2990            case 'c':
2991            case 'b': ARRAYTYPE(char)
2992            case 'B': ARRAYTYPE(unsigned char)
2993            case 'h': ARRAYTYPE(short)
2994            case 'H': ARRAYTYPE(unsigned short)
2995            case 'i': ARRAYTYPE(int)
2996            case 'I': ARRAYTYPE(unsigned int)
2997            case 'l': ARRAYTYPE(long)
2998            case 'L': ARRAYTYPE(unsigned long)
2999
3000            case 'f':
3001              for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
3002                if ((*vi)->varType == TValue::INTVAR)
3003                  intValInit(*ei, int(floor(0.5 + *(float *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
3004                else
3005                  floatValInit(*ei, *(float *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
3006              break;
3007
3008            case 'd':
3009              for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
3010                if ((*vi)->varType == TValue::INTVAR)
3011                  intValInit(*ei, int(floor(0.5 + *(double *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
3012                else
3013                  floatValInit(*ei, *(double *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
3014              break;
3015
3016          }
3017
3018          #undef ARRAYTYPE
3019
3020          table->addExample(nex);
3021          nex = NULL;
3022        }
3023      }
3024      catch (...) {
3025        mldelete table;
3026        mldelete nex;
3027        throw;
3028      }
3029
3030      return table;
3031  }
3032
3033  if (PyList_Check(args)) {
3034    Py_ssize_t size=PyList_Size(args);
3035    if (!size)
3036      PYERROR(PyExc_TypeError, "can't construct a table from an empty list", (TExampleTable *)NULL);
3037
3038    TExampleTable *table = mlnew TExampleTable(domain);;
3039
3040    try {
3041      for(Py_ssize_t i=0; i<size; i++) {
3042        PyObject *pex = PyList_GetItem(args, i);
3043        if (PyOrExample_Check(pex))
3044          table->addExample(PyExample_AS_ExampleReference(pex), filterMetas);
3045        else {
3046          TExample example(domain);
3047          if (!convertFromPythonExisting(pex, example)) {
3048            mldelete table;
3049            PyObject *type, *value, *tracebk;
3050            PyErr_Fetch(&type, &value, &tracebk);
3051            if (type) {
3052              //PyErr_Restore(type, value, tracebk);
3053              const char *oldes = PyString_AsString(value);
3054              PyErr_Format(type, "%s (at example %i)", oldes, i);
3055              Py_DECREF(type);
3056              Py_XDECREF(value);
3057              Py_XDECREF(tracebk);
3058              return NULL;
3059            }
3060          }
3061          table->addExample(example);
3062        }
3063      }
3064
3065      return table;
3066    }
3067    catch (...) {
3068      mldelete table;
3069      throw;
3070    }
3071  }
3072
3073  PYERROR(PyExc_TypeError, "invalid arguments", NULL);
3074}
3075
3076CONSTRUCTOR_KEYWORDS(ExampleTable, "domain use useMetas dontCheckStored dontStore filterMetas filter_metas DC DK NA noClass noCodedDiscrete createNewOn")
3077
3078PyObject *ExampleTable_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(ExampleGenerator - Orange.data.Table, "(filename | domain[, examples] | examples)")
3079{
3080  PyTRY
3081
3082    char *filename = NULL;
3083    if (PyArg_ParseTuple(argstuple, "s", &filename))
3084        return loadDataFromFile(type, filename, argstuple, keywords, false);
3085
3086    PyErr_Clear();
3087
3088    /*For a case where the unicode can't be converted to a default
3089     * encoding (on most platforms this is ASCII)
3090     */
3091    char * coding = getFileSystemEncoding();
3092    if (PyArg_ParseTuple(argstuple, "es", coding, &filename))
3093    {
3094        PyObject *rval = loadDataFromFile(type, filename, argstuple, keywords, false);
3095        PyMem_Free(filename);
3096        return rval;
3097    }
3098
3099    PyErr_Clear();
3100
3101    PExampleGenerator egen;
3102    PyObject *args = PYNULL;
3103    if (PyArg_ParseTuple(argstuple, "O&|O", cc_ExampleTable, &egen, &args))
3104      return WrapNewOrange(mlnew TExampleTable(egen, !args || (PyObject_IsTrue(args) == 0)), type);
3105
3106    PyErr_Clear();
3107
3108    if (PyArg_ParseTuple(argstuple, "O", &args)) {
3109      if (PyOrDomain_Check(args))
3110        return WrapNewOrange(mlnew TExampleTable(PyOrange_AsDomain(args)), type);
3111
3112      TExampleTable *res = readListOfExamples(args);
3113      if (res)
3114        return WrapNewOrange(res, type);
3115      PyErr_Clear();
3116
3117      // check if it's a list of generators
3118      if (PyList_Check(args)) {
3119        TExampleGeneratorList eglist;
3120        PyObject *iterator = PyObject_GetIter(args);
3121        PyObject *item = PyIter_Next(iterator);
3122        for(; item; item = PyIter_Next(iterator)) {
3123          if (!PyOrExampleGenerator_Check(item)) {
3124            Py_DECREF(item);
3125            break;
3126          }
3127          eglist.push_back(PyOrange_AsExampleGenerator(item));
3128          Py_DECREF(item);
3129        }
3130        Py_DECREF(iterator);
3131        if (!item)
3132          return WrapNewOrange(mlnew TExampleTable(PExampleGeneratorList(eglist)), type);
3133      }
3134
3135      PYERROR(PyExc_TypeError, "invalid arguments for constructor (domain or examples or both expected)", PYNULL);
3136    }
3137
3138    PyErr_Clear();
3139
3140    PDomain domain;
3141    if (PyArg_ParseTuple(argstuple, "O&O", cc_Domain, &domain, &args)) {
3142      bool filterMetas = readBoolFlag(keywords, "filterMetas") || readBoolFlag(keywords, "filter_metas");
3143
3144      if (PyOrExampleGenerator_Check(args))
3145        return WrapNewOrange(mlnew TExampleTable(domain, PyOrange_AsExampleGenerator(args), filterMetas), type);
3146      else {
3147        TExampleTable *res = readListOfExamples(args, domain, filterMetas);
3148        return res ? WrapNewOrange(res, type) : PYNULL;
3149      }
3150    }
3151
3152    PYERROR(PyExc_TypeError, "invalid arguments for ExampleTable.__init__", PYNULL);
3153
3154  PyCATCH
3155}
3156
3157
3158PyObject *ExampleTable__reduce__(PyObject *self)
3159{
3160  CAST_TO(TExampleTable, table)
3161
3162  if (!table->ownsExamples || table->lock) {
3163    PExampleTable lock = table->lock;
3164    TCharBuffer buf(1024);
3165    const int lockSize = lock->size();
3166    buf.writeInt(table->size());
3167    PEITERATE(ei, table) {
3168      int index = 0;
3169      PEITERATE(li, lock) {
3170        if (&*li == &*ei)
3171          break;
3172        index++;
3173      }
3174      if (index == lockSize) {
3175        PYERROR(PyExc_SystemError, "invalid example reference discovered in the table", PYNULL);
3176      }
3177
3178      buf.writeInt(index);
3179    }
3180
3181    return Py_BuildValue("O(ONs#)O", getExportedFunction("__pickleLoaderExampleReferenceTable"),
3182                                      self->ob_type,
3183                                      WrapOrange(table->lock),
3184                                      buf.buf, buf.length(),
3185                                      packOrangeDictionary(self));
3186  }
3187
3188  else {
3189    TCharBuffer buf(1024);
3190    PyObject *otherValues = NULL;
3191
3192    buf.writeInt(table->size());
3193    PEITERATE(ei, table)
3194      Example_pack(*ei, buf, otherValues);
3195
3196    if (!otherValues) {
3197      otherValues = Py_None;
3198      Py_INCREF(otherValues);
3199    }
3200
3201    return Py_BuildValue("O(ONs#N)O", getExportedFunction("__pickleLoaderExampleTable"),
3202                                      self->ob_type,
3203                                      WrapOrange(table->domain),
3204                                      buf.buf, buf.length(),
3205                                      otherValues,
3206                                      packOrangeDictionary(self));
3207  }
3208}
3209
3210
3211PyObject *__pickleLoaderExampleTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, domain, packed_values, other_values)")
3212{
3213  PyTRY
3214    PyTypeObject *type;
3215    PDomain domain;
3216    char *buf;
3217    int bufSize;
3218    PyObject *otherValues;
3219
3220    if (!PyArg_ParseTuple(args, "OO&s#O:__pickleLoaderExampleTable", &type, cc_Domain, &domain, &buf, &bufSize, &otherValues))
3221      return NULL;
3222
3223    TCharBuffer cbuf(buf);
3224    int otherValuesIndex = 0;
3225
3226    int noOfEx = cbuf.readInt();
3227    TExampleTable *newTable = new TExampleTable(domain);
3228    try {
3229      newTable->reserve(noOfEx);
3230      for(int i = noOfEx; i--;)
3231        Example_unpack(newTable->new_example(), cbuf, otherValues, otherValuesIndex);
3232
3233      return WrapNewOrange(newTable, type);
3234    }
3235    catch (...) {
3236      delete newTable;
3237      throw;
3238    }
3239  PyCATCH
3240}
3241
3242
3243PyObject *__pickleLoaderExampleReferenceTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, lockedtable, indices)")
3244{
3245  PyTRY
3246    PyTypeObject *type;
3247    PExampleTable table;
3248    char *buf;
3249    int bufSize;
3250
3251    if (!PyArg_ParseTuple(args, "OO&s#:__pickleLoaderExampleReferenceTable", &type, cc_ExampleTable, &table, &buf, &bufSize))
3252      return NULL;
3253
3254
3255    TCharBuffer cbuf(buf);
3256    int noOfEx = cbuf.readInt();
3257
3258    TExampleTable *newTable = new TExampleTable(table, 1);
3259    try {
3260      newTable->reserve(noOfEx);
3261      for(int i = noOfEx; i--;)
3262        newTable->addExample(table->at(cbuf.readInt()));
3263      return WrapNewOrange(newTable, type);
3264    }
3265    catch (...) {
3266      delete newTable;
3267      throw;
3268    }
3269  PyCATCH
3270}
3271
3272
3273#define EXAMPLE_LOCK(tab) (((tab)->ownsExamples || !(tab)->lock) ? PExampleGenerator(tab) : (tab)->lock)
3274
3275PyObject *ExampleTable_native(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
3276{ PyTRY
3277    int natvt=2;
3278    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=3)))
3279      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
3280
3281    if (natvt<2)
3282      return ExampleGenerator_native(self, args, keywords);
3283
3284    CAST_TO(TExampleTable, table);
3285
3286    PyObject *list=PyList_New(table->numberOfExamples());
3287    Py_ssize_t i=0;
3288    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3289    EITERATE(ei, *table) {
3290      // here we wrap a reference to example, so we must pass a self's wrapper
3291      PyObject *example = Example_FromExampleRef(*ei, lock);
3292      if (!example) {
3293        PyMem_DEL(list);
3294        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3295      }
3296      PyList_SetItem(list, i++, example);
3297    }
3298
3299    return list;
3300  PyCATCH
3301}
3302
3303/*
3304PyTypeObject *gsl_matrixType = NULL;
3305
3306bool load_gsl()
3307{
3308  if (gsl_matrixType)
3309    return true;
3310
3311  PyObject *matrixModule = PyImport_ImportModule("pygsl.matrix");
3312  if (!matrixModule)
3313    return false;
3314
3315  gsl_matrixType = (PyTypeObject *)PyDict_GetItemString(PyModule_GetDict(matrixModule), "matrix");
3316  return gsl_matrixType != NULL;
3317}
3318*/
3319
3320
3321/* Not in .hpp (to be parsed by pyprops) since these only occur in arguments to numpy conversion function */
3322
3323PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Ignore, 0)
3324PYCLASSCONSTANT_INT(ExampleTable, Multinomial_AsOrdinal, 1)
3325PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Error, 2)
3326
3327
3328
3329PyObject *packMatrixTuple(PyObject *X, PyObject *y, PyObject *my, PyObject *w, char *contents)
3330{
3331  int left = (*contents && *contents != '/') ? 1 : 0;
3332
3333  char *cp = strchr(contents, '/');
3334  if (cp)
3335    cp++;
3336
3337  int right = cp ? strlen(cp) : 0;
3338
3339  PyObject *res = PyTuple_New(left + right);
3340  if (left) {
3341    Py_INCREF(X);
3342    PyTuple_SetItem(res, 0, X);
3343  }
3344
3345  if (cp)
3346    for(; *cp; cp++)
3347      if ((*cp == 'c') || (*cp == 'C')) {
3348        Py_INCREF(y);
3349        PyTuple_SetItem(res, left++, y);
3350      }
3351      else if ((*cp == 'w') || (*cp == 'W')) {
3352        Py_INCREF(w);
3353        PyTuple_SetItem(res, left++, w);
3354      }
3355      else {
3356        Py_INCREF(my);
3357        PyTuple_SetItem(res, left++, my);
3358      }
3359
3360  Py_DECREF(X);
3361  Py_DECREF(y);
3362  Py_DECREF(my);
3363  Py_DECREF(w);
3364  return res;
3365}
3366
3367
3368void parseMatrixContents(PExampleGenerator egen, const int &weightID, const char *contents, const int &multiTreatment,
3369                         bool &hasClass, bool &classVector, bool &multiclassVector, bool &weightVector, bool &classIsDiscrete, int &columns,
3370                         vector<bool> &include);
3371
3372
3373inline bool storeNumPyValue(double *&p, const TValue &val, signed char *&m, const PVariable attr, const int &row)
3374{
3375  if (val.isSpecial()) {
3376    if (m) {
3377      *p++ = 0;
3378      *m++ = 1;
3379    }
3380    else {
3381      PyErr_Format(PyExc_TypeError, "value of attribute '%s' in example '%i' is undefined", attr->get_name().c_str(), row);
3382      return false;
3383    }
3384  }
3385
3386  else if (val.varType == TValue::FLOATVAR) {
3387    *p++ = val.floatV;
3388    if (m)
3389      *m++ = 0;
3390  }
3391
3392  else if (val.varType == TValue::INTVAR) {
3393    *p++ = float(val.intV);
3394    if (m)
3395      *m++ = 0;
3396  }
3397
3398  else {
3399    *p++ = ILLEGAL_FLOAT;
3400    if (m)
3401      *m++ = 1;
3402  }
3403
3404  return true;
3405}
3406
3407
3408PyObject *ExampleTable_toNumericOrMA(PyObject *self, PyObject *args, PyObject *keywords, PyObject **module, PyObject **maskedArray = NULL)
3409{
3410  PyTRY
3411    prepareNumeric();
3412    if (!*module || maskedArray && !*maskedArray)
3413      PYERROR(PyExc_ImportError, "cannot import the necessary numeric module for conversion", PYNULL);
3414
3415    // These references are all borrowed
3416    PyObject *moduleDict = PyModule_GetDict(*module);
3417      PyObject *mzeros = PyDict_GetItemString(moduleDict, "zeros");
3418      if (!mzeros)
3419        PYERROR(PyExc_AttributeError, "numeric module has no function 'zeros'", PYNULL);
3420
3421    char *contents = NULL;
3422    int weightID = 0;
3423    int multinomialTreatment = 1;
3424    if (!PyArg_ParseTuple(args, "|sii:ExampleTable.toNumeric", &contents, &weightID, &multinomialTreatment))
3425      return PYNULL;
3426
3427    if (!contents)
3428      contents = "a/cw";
3429
3430    PExampleGenerator egen = PyOrange_AsExampleGenerator(self);
3431
3432    bool hasClass, classVector, weightVector, multiclassVector, classIsDiscrete;
3433    vector<bool> include;
3434    int columns;
3435    parseMatrixContents(egen, weightID, contents, multinomialTreatment,
3436                            hasClass, classVector, multiclassVector, weightVector,
3437                            classIsDiscrete, columns, include);
3438
3439    int rows = egen->numberOfExamples();
3440    PVariable classVar = egen->domain->classVar;
3441
3442    PyObject *X, *y, *w, *my, *mask = NULL, *masky = NULL, *maskmy = NULL;
3443    double *Xp, *yp, *myp, *wp;
3444    signed char *mp = NULL, *mpy = NULL, *mpmy = NULL;
3445    if (columns) {
3446      X = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "d");
3447      if (!X)
3448        return PYNULL;
3449
3450      Xp = (double *)((PyArrayObject *)X)->data;
3451
3452      if (maskedArray) {
3453        mask = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "b");
3454        mp = (signed char *)((PyArrayObject *)mask)->data;
3455      }
3456    }
3457    else {
3458      X = Py_None;
3459      Py_INCREF(X);
3460      Xp = NULL;
3461    }
3462
3463    if (classVector) {
3464      y = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3465      if (!y)
3466        return PYNULL;
3467      yp = (double *)((PyArrayObject *)y)->data;
3468
3469      if (maskedArray) {
3470        masky = PyObject_CallFunction(mzeros, "(i)s", rows, "b");
3471        mpy = (signed char *)((PyArrayObject *)masky)->data;
3472      }
3473    }
3474    else {
3475      y = Py_None;
3476      Py_INCREF(y);
3477      yp = NULL;
3478    }
3479
3480    if (multiclassVector) {
3481      my = PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "d");
3482      if (!my)
3483        return PYNULL;
3484      myp = (double *)((PyArrayObject *)my)->data;
3485
3486      if (maskedArray) {
3487        maskmy= PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "b");
3488        mpmy = (signed char *)((PyArrayObject *)maskmy)->data;
3489      }
3490    }
3491    else {
3492      my = Py_None;
3493      Py_INCREF(my);
3494      myp = NULL;
3495    }
3496
3497    if (weightVector) {
3498      w = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3499      if (!w)
3500        return PYNULL;
3501      wp = (double *)((PyArrayObject *)w)->data;
3502    }
3503    else {
3504      w = Py_None;
3505      Py_INCREF(w);
3506      wp = NULL;
3507    }
3508
3509    try {
3510      int row = 0;
3511      TExampleGenerator::iterator ei(egen->begin());
3512      for(; ei; ++ei, row++) {
3513        int col = 0;
3514
3515        /* This is all optimized assuming that each symbol (A, C, W) only appears once.
3516           If it would be common for them to appear more than once, we could cache the
3517           values, but since this is unlikely, caching would only slow down the conversion */
3518        for(const char *cp = contents; *cp && (*cp!='/'); cp++) {
3519          switch (*cp) {
3520            case 'A':
3521            case 'a': {
3522              const TVarList &attributes = egen->domain->attributes.getReference();
3523              TVarList::const_iterator vi(attributes.begin()), ve(attributes.end());
3524              TExample::iterator eei((*ei).begin());
3525              vector<bool>::const_iterator bi(include.begin());
3526              for(; vi != ve; eei++, vi++, bi++)
3527                if (*bi && !storeNumPyValue(Xp, *eei, mp, *vi, row))
3528                  return PYNULL;
3529              break;
3530            }
3531
3532            case 'C':
3533            case 'c':
3534              if (hasClass && !storeNumPyValue(Xp, (*ei).getClass(), mp, classVar, row))
3535                return PYNULL;
3536              break;
3537
3538            case 'M':
3539            case 'm': {
3540              const TVarList &classes = egen->domain->classVars.getReference();
3541              TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3542              TValue *eei = (*ei).values_end;
3543              for(; vi != ve; eei++, vi++)
3544                if (!storeNumPyValue(Xp, *eei, mp, *vi, row))
3545                  return PYNULL;
3546              break;
3547            }
3548
3549            case 'W':
3550            case 'w':
3551              if (weightID)
3552                *Xp++ = WEIGHT(*ei);
3553                if (maskedArray)
3554                  *mp++ = 0;
3555              break;
3556
3557            case '0':
3558              *Xp++ = 0.0;
3559              if (maskedArray)
3560                *mp++ = 0;
3561              break;
3562
3563            case '1':
3564              *Xp++ = 1.0;
3565              if (maskedArray)
3566                *mp++ = 0;
3567              break;
3568          }
3569        }
3570
3571        if (yp && !storeNumPyValue(yp, (*ei).getClass(), mpy, classVar, row))
3572          return PYNULL;
3573
3574        if (wp)
3575          *wp++ = WEIGHT(*ei);
3576
3577        if (myp) {
3578            const TVarList &classes = egen->domain->classVars.getReference();
3579            TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3580            TValue *eei = (*ei).values_end;
3581            for(; vi != ve; eei++, vi++)
3582              if (!storeNumPyValue(myp, *eei, mpmy, *vi, row))
3583                return PYNULL;
3584        }
3585      }
3586
3587      if (maskedArray) {
3588        PyObject *args, *maskedX = NULL, *maskedy = NULL, *maskedmy = NULL;
3589
3590        bool err = false;
3591
3592        if (mask) {
3593          args = Py_BuildValue("OOiOO", X, Py_None, 1, Py_None, mask);
3594          maskedX = PyObject_CallObject(*maskedArray, args);
3595          Py_DECREF(args);
3596          if (!maskedX) {
3597            PyErr_Clear();
3598            args = Py_BuildValue("OOOi", X, mask, Py_None, 1);
3599            maskedX = PyObject_CallObject(*maskedArray, args);
3600            Py_DECREF(args);
3601          }
3602          err = !maskedX;
3603        }
3604
3605        if (!err && masky) {
3606          args = Py_BuildValue("OOiOO", y, Py_None, 1, Py_None, masky);
3607          maskedy = PyObject_CallObject(*maskedArray, args);
3608          Py_DECREF(args);
3609          if (!maskedy) {
3610            PyErr_Clear();
3611            args = Py_BuildValue("OOOi", y, masky, Py_None, 1);
3612            maskedy = PyObject_CallObject(*maskedArray, args);
3613            Py_DECREF(args);
3614          }
3615          err = !maskedy;
3616        }
3617
3618        if (!err && maskmy) {
3619          args = Py_BuildValue("OOiOO", my, Py_None, 1, Py_None, maskmy);
3620          maskedmy = PyObject_CallObject(*maskedArray, args);
3621          Py_DECREF(args);
3622          if (!maskedmy) {
3623            PyErr_Clear();
3624            args = Py_BuildValue("OOOi", my, maskmy, Py_None, 1);
3625            maskedmy = PyObject_CallObject(*maskedArray, args);
3626            Py_DECREF(args);
3627          }
3628          err = !maskedmy;
3629        }
3630
3631        if (err) {
3632          Py_DECREF(X);
3633          Py_DECREF(y);
3634          Py_DECREF(w);
3635          Py_XDECREF(maskedX);
3636          Py_XDECREF(mask);
3637          Py_XDECREF(masky);
3638          Py_XDECREF(maskmy);
3639          return PYNULL;
3640        }
3641
3642        if (mask) {
3643          Py_DECREF(X);
3644          Py_DECREF(mask);
3645          X = maskedX;
3646        }
3647
3648        if (masky) {
3649          Py_DECREF(y);
3650          Py_DECREF(masky);
3651          y = maskedy;
3652        }
3653
3654        if (maskmy) {
3655          Py_DECREF(my);
3656          Py_DECREF(maskmy);
3657          my = maskedmy;
3658        }
3659      }
3660
3661      return packMatrixTuple(X, y, my, w, contents);
3662    }
3663    catch (...) {
3664      Py_DECREF(X);
3665      Py_DECREF(y);
3666      Py_DECREF(w);
3667      Py_XDECREF(mask);
3668      Py_XDECREF(masky);
3669      Py_XDECREF(maskmy);
3670      throw;
3671    }
3672  PyCATCH
3673}
3674
3675
3676PyObject *ExampleTable_toNumeric(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3677{
3678  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric);
3679}
3680
3681
3682PyObject *ExampleTable_toNumericMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3683{
3684  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric, &numericMaskedArray);
3685}
3686
3687// this is for compatibility
3688PyObject *ExampleTable_toMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3689{
3690  return ExampleTable_toNumericMA(self, args, keywords);
3691}
3692
3693PyObject *ExampleTable_toNumarray(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3694{
3695  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray);
3696}
3697
3698
3699PyObject *ExampleTable_toNumarrayMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3700{
3701  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray, &numarrayMaskedArray);
3702}
3703
3704PyObject *ExampleTable_toNumpy(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3705{
3706  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy);
3707}
3708
3709
3710PyObject *ExampleTable_toNumpyMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3711{
3712  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy, &numpyMaskedArray);
3713}
3714
3715
3716
3717int ExampleTable_nonzero(PyObject *self)
3718{ PyTRY
3719    return SELF_AS(TExampleGenerator).numberOfExamples() ? 1 : 0;
3720  PyCATCH_1
3721}
3722
3723Py_ssize_t ExampleTable_len_sq(PyObject *self)
3724{ PyTRY
3725    return SELF_AS(TExampleGenerator).numberOfExamples();
3726  PyCATCH_1
3727}
3728
3729
3730PyObject *ExampleTable_append(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> None")
3731{ PyTRY
3732    CAST_TO(TExampleTable, table)
3733
3734    if (table->ownsExamples) {
3735      if (!convertFromPythonExisting(args, table->new_example())) {
3736        table->delete_last();
3737        return PYNULL;
3738      }
3739    }
3740    else {
3741      if (!PyOrExample_Check(args) || (((TPyExample *)(args))->lock != table->lock))
3742        PYERROR(PyExc_TypeError, "tables containing references to examples can only append examples from the same table", PYNULL);
3743
3744      table->addExample(PyExample_AS_ExampleReference(args));
3745    }
3746    RETURN_NONE;
3747  PyCATCH
3748}
3749
3750PyObject *ExampleTable_extend(PyObject *self, PyObject *args) PYARGS(METH_O, "(examples) -> None")
3751{ PyTRY
3752    CAST_TO(TExampleTable, table)
3753
3754    if (PyOrExampleGenerator_Check(args)) {
3755      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3756      if (args==self) {
3757        TExampleTable temp(gen, false);
3758        table->addExamples(PExampleGenerator(temp));
3759      }
3760      else {
3761        if (!table->ownsExamples
3762              && (table->lock != gen)
3763              && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3764            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3765        table->addExamples(gen);
3766      }
3767      RETURN_NONE;
3768    }
3769
3770    TExample example(table->domain);
3771    if (PyList_Check(args)) {
3772      Py_ssize_t i, size = PyList_Size(args);
3773
3774      // We won't append until we know we can append all
3775      // (don't want to leave the work half finished)
3776      if (!table->ownsExamples) {
3777        for (i = 0; i<size; i++) {
3778          PyObject *pyex = PyList_GET_ITEM(args, i);
3779          if (!PyOrExample_Check(pyex) || (((TPyExample *)(pyex))->lock != table->lock))
3780            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3781        }
3782      }
3783
3784      for(i = 0; i<size; i++) {
3785        PyObject *pex = PyList_GET_ITEM(args, i);
3786        if (!convertFromPythonExisting(pex, example))
3787          return PYNULL;
3788
3789        table->addExample(example);
3790      }
3791
3792      RETURN_NONE;
3793    }
3794
3795
3796    PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.extend", PYNULL);
3797  PyCATCH
3798}
3799
3800
3801PyObject *ExampleTable_getitem_sq(TPyOrange *self, Py_ssize_t idx)
3802{
3803  PyTRY
3804    CAST_TO(TExampleTable, table);
3805
3806    if (idx<0)
3807      idx += table->numberOfExamples();
3808
3809    if ((idx<0) || (idx>=table->numberOfExamples()))
3810      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
3811
3812    // here we wrap a reference to example, so we must pass self's wrapper
3813    return Example_FromExampleRef((*table)[idx], EXAMPLE_LOCK(PyOrange_AsExampleTable(self)));
3814  PyCATCH
3815}
3816
3817
3818int ExampleTable_setitem_sq(TPyOrange *self, Py_ssize_t idx, PyObject *pex)
3819{
3820  PyTRY
3821    CAST_TO_err(TExampleTable, table, -1);
3822
3823    if (idx>table->numberOfExamples())
3824      PYERROR(PyExc_IndexError, "index out of range", -1);
3825
3826    if (!pex) {
3827      table->erase(idx);
3828      return 0;
3829    }
3830
3831    if (!table->ownsExamples) {
3832      if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock))
3833        PYERROR(PyExc_TypeError, "tables containing references to examples can contain examples from the same table", -1);
3834
3835      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3836      return 0;
3837    }
3838
3839    if (PyOrExample_Check(pex)) {
3840      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3841      return 0;
3842    }
3843
3844    TExample example(table->domain);
3845    if (convertFromPythonExisting(pex, example)) {
3846      (*table)[idx] = example;
3847      return 0;
3848    }
3849
3850    PYERROR(PyExc_TypeError, "invalid parameter type (Example expected)", -1)
3851  PyCATCH_1
3852}
3853
3854
3855PyObject *ExampleTable_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
3856{
3857  PyTRY
3858    CAST_TO(TExampleTable, table);
3859
3860    if (stop>table->numberOfExamples())
3861      stop=table->numberOfExamples();
3862
3863    if (start>stop)
3864      start=stop;
3865
3866    PyObject *list=PyList_New(stop-start);
3867    Py_ssize_t i=0;
3868    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3869    while(start<stop) {
3870      // here we wrap a reference to example, so we must pass a self's wrapper
3871      PyObject *example=Example_FromExampleRef((*table)[start++], lock);
3872      if (!example) {
3873        PyMem_DEL(list);
3874        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3875      }
3876      PyList_SetItem(list, i++, (PyObject *)example);
3877    }
3878
3879    return list;
3880  PyCATCH
3881}
3882
3883
3884int ExampleTable_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *args)
3885{
3886  PyTRY
3887    CAST_TO_err(TExampleTable, table, -1);
3888
3889    if (stop>table->size())
3890      stop = table->size();
3891
3892    if (start>stop)
3893      PYERROR(PyExc_IndexError, "index out of range", -1);
3894
3895    int inspoint = stop;
3896
3897    try {
3898      if (PyOrExampleGenerator_Check(args)) {
3899        PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3900        if (args==(PyObject *)self) {
3901          TExampleTable tab(gen, false);
3902          EITERATE(ei, tab)
3903            table->insert(inspoint++, *ei);
3904        }
3905        else
3906          if (!table->ownsExamples
3907                && (table->lock != gen)
3908                && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3909              PYERROR(PyExc_TypeError, "tables containing references to examples can only contain examples from the same table", -1);
3910          PEITERATE(ei, gen)
3911            table->insert(inspoint++, *ei);
3912      }
3913
3914      else {
3915        TExample example(table->domain);
3916        if (PyList_Check(args)) {
3917          Py_ssize_t size = PyList_Size(args);
3918
3919          for(Py_ssize_t i = 0; i<size; i++) {
3920            PyObject *pex = PyList_GetItem(args, i);
3921
3922            if (table->ownsExamples) {
3923              if (!convertFromPythonExisting(pex, example)) {
3924                table->erase(stop, inspoint);
3925                return -1;
3926              }
3927              table->insert(inspoint++, example);
3928            }
3929            else {
3930              if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock)) {
3931                table->erase(stop, inspoint);
3932                PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", -1);
3933              }
3934              table->insert(inspoint++, PyExample_AS_ExampleReference(pex));
3935            }
3936          }
3937        }
3938        else
3939          PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.__setslice__", -1);
3940      }
3941    }
3942    catch (...) {
3943      table->erase(stop, inspoint);
3944      throw;
3945    }
3946
3947    table->erase(start, stop);
3948
3949    return 0;
3950  PyCATCH_1
3951}
3952
3953
3954PyObject *applyFilterL(PFilter filter, PExampleTable gen)
3955{ if (!filter)
3956    return PYNULL;
3957
3958  PyObject *list=PyList_New(0);
3959  filter->reset();
3960  PExampleGenerator lock = EXAMPLE_LOCK(gen);
3961  PEITERATE(ei, gen)
3962    if (filter->operator()(*ei)) {
3963      PyObject *obj=Example_FromExampleRef(*ei, lock);
3964      PyList_Append(list, obj);
3965      Py_DECREF(obj);
3966    }
3967
3968  return list;
3969}
3970
3971
3972PyObject *applyFilterP(PFilter filter, PExampleTable gen)
3973{ if (!filter)
3974    return PYNULL;
3975
3976  TExampleTable *newTable = mlnew TExampleTable(PExampleGenerator(gen), 1);
3977  PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
3978  filter->reset();
3979  PEITERATE(ei, gen)
3980    if (filter->operator()(*ei))
3981      newTable->addExample(*ei);
3982
3983  return WrapOrange(newGen);
3984}
3985
3986
3987PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen);
3988
3989PyObject *applyFilterB(PFilter filter, PExampleTable gen)
3990{
3991  return filter ? filterSelectionVectorLow(filter.getReference(), gen) : PYNULL;
3992}
3993
3994
3995PyObject *ExampleTable_get_items_ref(TPyOrange *self, PyObject *pylist)   PYARGS(METH_O, "(indices) -> ExampleTable")
3996{ return multipleSelectLow(self, pylist, true); }
3997
3998
3999PyObject *ExampleTable_selectLow(TPyOrange *self, PyObject *args, PyObject *keywords, const int toList)
4000{
4001  PyTRY
4002    CAST_TO(TExampleTable, eg);
4003    PExampleGenerator weg = PExampleGenerator(PyOrange_AS_Orange(self));
4004    PExampleGenerator lock = EXAMPLE_LOCK(eg);
4005
4006    /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
4007    /* Deprecated: use 'filter' instead */
4008    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4009      switch (toList) {
4010        case 2: return applyFilterB(filter_sameValues(keywords, eg->domain), weg);
4011        case 1: return applyFilterL(filter_sameValues(keywords, eg->domain), weg);
4012        default: return applyFilterP(filter_sameValues(keywords, eg->domain), weg);
4013      }
4014    }
4015
4016    PyObject *mplier;
4017    int index;
4018    if (PyArg_ParseTuple(args, "O|i", &mplier, &index)) {
4019      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
4020      bool negate = pyneg && PyObject_IsTrue(pyneg);
4021      bool indexGiven = (PyTuple_Size(args)==2);
4022
4023      /* ***** SELECTION BY PYLIST ****** */
4024      if (PyList_Check(mplier)) {
4025        if (PyList_Size(mplier) != eg->numberOfExamples())
4026          PYERROR(PyExc_IndexError, "example selector of invalid length", PYNULL);
4027
4028        int i = 0;
4029        switch (toList) {
4030
4031          case 1: {
4032            PyObject *list = PyList_New(0);
4033
4034            if (indexGiven)
4035              EITERATE(ei, *eg) {
4036                PyObject *lel = PyList_GetItem(mplier, i++);
4037                if (!PyInt_Check(lel))
4038                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4039
4040                if (negate != (index==PyInt_AsLong(lel))) {
4041                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4042                  PyList_Append(list, pyex);
4043                  Py_DECREF(pyex);
4044                }
4045              }
4046            else
4047              EITERATE(ei, *eg)
4048                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0)) {
4049                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4050                  PyList_Append(list, pyex);
4051                  Py_DECREF(pyex);
4052                }
4053
4054            return list;
4055          }
4056
4057
4058          // this is a pervesion, but let's support it as a kind of syntactic sugar...
4059          case 2: {
4060            const Py_ssize_t lsize = PyList_Size(mplier);
4061            TBoolList *selection = new TBoolList(lsize);
4062            PBoolList pselection = selection;
4063            TBoolList::iterator si(selection->begin());
4064            if (indexGiven)
4065              for(Py_ssize_t i = 0; i < lsize; i++) {
4066                PyObject *lel = PyList_GetItem(mplier, i);
4067                if (!PyInt_Check(lel))
4068                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4069
4070                *si++ = negate != (index == PyInt_AsLong(lel));
4071              }
4072            else
4073              for(Py_ssize_t i = 0; i < lsize; *si++ = negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0));
4074
4075            return WrapOrange(pselection);
4076          }
4077
4078
4079          default: {
4080            TExampleTable *newTable = mlnew TExampleTable(lock, 1); //locks to weg but does not copy
4081            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4082
4083            if (indexGiven)
4084              EITERATE(ei, *eg) {
4085                PyObject *lel = PyList_GetItem(mplier, i++);
4086                if (!PyInt_Check(lel))
4087                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4088
4089                if (negate != (index==PyInt_AsLong(lel)))
4090                  newTable->addExample(*ei);
4091              }
4092            else
4093              EITERATE(ei, *eg)
4094                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0))
4095                  newTable->addExample(*ei);
4096
4097            return WrapOrange(newGen);
4098          }
4099        }
4100      }
4101
4102      /* ***** SELECTION BY LONGLIST ****** */
4103      else if (PyOrLongList_Check(mplier)) {
4104        PLongList llist = PyOrange_AsLongList(mplier);
4105        if (int(llist->size()) != eg->numberOfExamples())
4106          PYERROR(PyExc_IndexError, "select: invalid list size", PYNULL)
4107
4108        TLongList::iterator lli(llist->begin()), lle(llist->end());
4109        TExampleIterator ei = eg->begin();
4110
4111        switch (toList) {
4112          case 1: {
4113            PyObject *list = PyList_New(0);
4114            for(; ei && (lli!=lle); ++ei, lli++)
4115              if (negate != (indexGiven ? (*lli==index) : (*lli!=0))) {
4116                PyObject *pyex = Example_FromExampleRef(*ei, lock);
4117                PyList_Append(list, pyex);
4118                Py_DECREF(pyex);
4119              }
4120            return list;
4121          }
4122
4123          case 2: {
4124            TBoolList *selection = new TBoolList(llist->size());
4125            PBoolList pselection = selection;
4126            for(TBoolList::iterator si(selection->begin()); lli != lle; *si++ = negate != (indexGiven ? (*lli++ == index) : (*lli++ != 0)));
4127
4128            return WrapOrange(pselection);
4129          }
4130
4131          default: {
4132            TExampleTable *newTable = mlnew TExampleTable(lock, 1);
4133            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4134
4135            for(;ei && (lli!=lle); ++ei, lli++)
4136              if (negate != (indexGiven ? (*lli==index) : (*lli!=0)))
4137                newTable->addExample(*ei);
4138
4139            return WrapOrange(newGen);
4140          }
4141        }
4142      }
4143
4144      PyErr_Clear();
4145
4146
4147      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
4148      /* Deprecated: use method 'filter' instead. */
4149      if (PyDict_Check(mplier))
4150        switch (toList) {
4151          case 2: return applyFilterB(filter_sameValues(mplier, eg->domain), weg);
4152          case 1: return applyFilterL(filter_sameValues(mplier, eg->domain), weg);
4153          default: return applyFilterP(filter_sameValues(mplier, eg->domain), weg);
4154        }
4155
4156      else if (PyOrFilter_Check(mplier))
4157        switch (toList) {
4158          case 2: return applyFilterB(PyOrange_AsFilter(mplier), weg);
4159          case 1: return applyFilterL(PyOrange_AsFilter(mplier), weg);
4160          default: return applyFilterP(PyOrange_AsFilter(mplier), weg);
4161        }
4162    }
4163
4164  PYERROR(PyExc_TypeError, "invalid example selector type", PYNULL);
4165  PyCATCH
4166}
4167
4168
4169PyObject *ExampleTable_select_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4170{ PyTRY
4171    return ExampleTable_selectLow(self, args, keywords, 1);
4172  PyCATCH
4173}
4174
4175
4176PyObject *ExampleTable_select_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4177{ PyTRY
4178    return ExampleTable_selectLow(self, args, keywords, 0);
4179  PyCATCH
4180}
4181
4182
4183PyObject *ExampleTable_select_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4184{ PyTRY
4185    return ExampleTable_selectLow(self, args, keywords, 2);
4186  PyCATCH
4187}
4188
4189
4190PyObject *ExampleTable_filter_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4191{
4192  PyTRY
4193    CAST_TO(TExampleGenerator, eg);
4194    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4195
4196    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4197      return applyFilterL(filter_sameValues(keywords, eg->domain, keywords), weg);
4198    }
4199
4200    if (PyTuple_Size(args)==1) {
4201      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4202
4203      if (PyDict_Check(arg))
4204        return applyFilterL(filter_sameValues(arg, eg->domain, keywords), weg);
4205
4206      if (PyOrFilter_Check(arg))
4207          return applyFilterL(PyOrange_AsFilter(arg), weg);
4208    }
4209
4210    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_list expects a list of conditions or orange.Filter", PYNULL)
4211  PyCATCH
4212}
4213
4214
4215PyObject *ExampleTable_filter_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4216{
4217  PyTRY
4218    CAST_TO(TExampleGenerator, eg);
4219    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4220
4221    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4222      return applyFilterP(filter_sameValues(keywords, eg->domain, keywords), weg);
4223    }
4224
4225    if (PyTuple_Size(args)==1) {
4226      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4227
4228      if (PyDict_Check(arg))
4229        return applyFilterP(filter_sameValues(arg, eg->domain, keywords), weg);
4230
4231      if (PyOrFilter_Check(arg))
4232          return applyFilterP(PyOrange_AsFilter(arg), weg);
4233    }
4234
4235    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_ref expects a list of conditions or orange.Filter", PYNULL)
4236  PyCATCH
4237}
4238
4239
4240PyObject *ExampleTable_filter_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4241{
4242  PyTRY
4243    CAST_TO(TExampleGenerator, eg);
4244    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4245
4246    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4247      return applyFilterB(filter_sameValues(keywords, eg->domain, keywords), weg);
4248    }
4249
4250    if (PyTuple_Size(args)==1) {
4251      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4252
4253      if (PyDict_Check(arg))
4254        return applyFilterB(filter_sameValues(arg, eg->domain, keywords), weg);
4255
4256      if (PyOrFilter_Check(arg))
4257          return applyFilterB(PyOrange_AsFilter(arg), weg);
4258    }
4259
4260    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_bool expects a list of conditions or orange.Filter", PYNULL)
4261  PyCATCH
4262}
4263
4264
4265PyObject *ExampleTable_random_example(TPyOrange *self) PYARGS(0, "() -> Example")
4266{ PyTRY
4267    CAST_TO(TExampleTable, table);
4268    TExample example(table->domain);
4269    table->randomExample(example);
4270    return Example_FromExampleCopyRef(example);
4271  PyCATCH
4272}
4273
4274
4275PyObject *ExampleTable_removeDuplicates(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([weightID=0]]) -> None")
4276{ PyTRY
4277    if (PyTuple_Size(args) > 1)
4278      PYERROR(PyExc_AttributeError, "at most one argument (weight) expected", PYNULL);
4279
4280    CAST_TO(TExampleTable, table);
4281
4282    int weightID = 0;
4283    if (PyTuple_Size(args) && !weightFromArg_byDomain(PyTuple_GET_ITEM(args, 0), table->domain, weightID))
4284      return PYNULL;
4285
4286    table->removeDuplicates(weightID);
4287    RETURN_NONE;
4288  PyCATCH
4289}
4290
4291
4292PyObject *ExampleTable_shuffle(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None")
4293{
4294  PyTRY
4295    SELF_AS(TExampleTable).shuffle();
4296    RETURN_NONE;
4297  PyCATCH
4298}
4299
4300PyObject *ExampleTable_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
4301{ PyTRY
4302    CAST_TO(TExampleTable, table);
4303
4304    if (!args || !PyTuple_Size(args)) {
4305      table->sort();
4306      RETURN_NONE;
4307    }
4308
4309    PyObject *alist = PyTuple_GET_ITEM(args, 0);
4310    /* If the first argument is nor list nor tuple, the whole argument is taken as a list
4311       i.e., data.sort("age", "prescr") is interpreted the same as data.sort(["age", "prescr"])
4312       All references are borrowed. */
4313    if ((PyTuple_Size(args) > 1) || (!PyList_Check(alist) && !PyTuple_Check(alist)))
4314      alist = args;
4315
4316    TVarList attributes;
4317    if (varListFromDomain(alist, table->domain, attributes, true, true)) {
4318      vector<int> order;
4319      for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++)
4320        order.push_back(table->domain->getVarNum(*vi));
4321      table->sort(order);
4322      RETURN_NONE;
4323    }
4324
4325    PYERROR(PyExc_TypeError, "invalid arguments (none, or a list of attributes expected)", PYNULL);
4326
4327  PyCATCH
4328}
4329
4330
4331PyObject *ExampleTable_addMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id[, Value=1.0]) -> None")
4332{ PyTRY
4333    CAST_TO(TExampleTable, table);
4334
4335    PyObject *pyid;
4336    PyObject *pyvalue=PYNULL;
4337    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4338      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4339
4340    int id;
4341    PVariable metavariable;
4342    if (PyInt_Check(pyid)) {
4343      id = PyInt_AsLong(pyid);
4344      metavariable = table->domain->getMetaVar(id, false);
4345    }
4346    else if (PyString_Check(pyid)) {
4347      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4348      metavariable = table->domain->getMetaVar(id, false);
4349    }
4350    else if (PyOrVariable_Check(pyid)) {
4351      metavariable = PyOrange_AsVariable(pyid);
4352      id = table->domain->getMetaNum(metavariable);
4353    }
4354
4355    TValue value;
4356    if (!pyvalue)
4357      if (metavariable && metavariable->varType != TValue::FLOATVAR)
4358        value = metavariable->DK();
4359      else
4360        value = TValue(float(1.0));
4361    else if (!convertFromPython(pyvalue, value, metavariable))
4362      PYERROR(PyExc_AttributeError, "invalid value argument", PYNULL);
4363
4364    table->addMetaAttribute(id, value);
4365
4366    RETURN_NONE;
4367  PyCATCH
4368}
4369
4370
4371PyObject *ExampleTable_removeMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id) -> None")
4372{ PyTRY
4373    CAST_TO(TExampleTable, table);
4374
4375    PyObject *pyid;
4376    PyObject *pyvalue=PYNULL;
4377    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4378      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4379
4380    int id;
4381    if (PyInt_Check(pyid))
4382      id = PyInt_AsLong(pyid);
4383    else if (PyString_Check(pyid))
4384      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4385    else if (PyOrVariable_Check(pyid))
4386      id = table->domain->getMetaNum(PyOrange_AsVariable(pyid));
4387
4388    table->removeMetaAttribute(id);
4389
4390    RETURN_NONE;
4391  PyCATCH
4392}
4393
4394
4395PyObject *ExampleTable_changeDomain(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(Domain) -> None")
4396{ PyTRY
4397    CAST_TO(TExampleTable, table);
4398    if (!table->ownsExamples)
4399      PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4400
4401    PDomain domain;
4402    if (!PyArg_ParseTuple(args, "O&", cc_Domain, &domain))
4403      PYERROR(PyExc_AttributeError, "domain argument expected", PYNULL);
4404
4405    table->changeDomain(domain);
4406    RETURN_NONE;
4407  PyCATCH
4408}
4409
4410PyObject *ExampleTable_pickClass(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable | name) -> None")
4411{
4412    PyTRY
4413        CAST_TO(TExampleTable, table);
4414        if (!table->ownsExamples) {
4415            PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4416        }
4417        PVariable newClass;
4418        if (PyString_Check(obj)) {
4419            const char *attr = PyString_AS_STRING(obj);
4420            TVarList::const_iterator mci(table->domain->classVars->begin()), mce(table->domain->classVars->end());
4421            for(; (mci != mce) && ((*mci)->get_name() != attr); mci++);
4422            if (mci == mce) {
4423                PYERROR(PyExc_TypeError, "table does not have multiple classes", PYNULL);
4424            }
4425            newClass = *mci;
4426        }
4427        if (PyOrVariable_Check(obj)) {
4428            newClass = PyOrange_AsVariable(obj);
4429        }
4430        else if (obj != Py_None) {
4431            PYERROR(PyExc_TypeError, "class should be given as Variable, name or None", PYNULL);
4432        }
4433        table->pickClass(newClass);
4434        RETURN_NONE;
4435    PyCATCH;
4436}
4437
4438
4439
4440PyObject *ExampleTable_hasMissingValues(TPyOrange *self) PYARGS(0, "() -> bool")
4441{
4442  PyTRY
4443    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissing());
4444  PyCATCH
4445}
4446
4447
4448PyObject *ExampleTable_hasMissingClasses(TPyOrange *self) PYARGS(0, "() -> bool")
4449{
4450  PyTRY
4451    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissingClass());
4452  PyCATCH
4453}
4454/* ************ TRANSFORMVALUE ************ */
4455
4456#include "transval.hpp"
4457BASED_ON(TransformValue, Orange)
4458
4459PyObject *TransformValue_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
4460{ if (type == (PyTypeObject *)&PyOrTransformValue_Type)
4461    return setCallbackFunction(WrapNewOrange(mlnew TTransformValue_Python(), type), args);
4462  else
4463    return WrapNewOrange(mlnew TTransformValue_Python(), type);
4464}
4465
4466
4467PyObject *TransformValue__reduce__(PyObject *self)
4468{
4469  return callbackReduce(self, PyOrTransformValue_Type);
4470}
4471
4472
4473PyObject *TransformValue_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
4474{ PyTRY
4475    NO_KEYWORDS
4476
4477    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrTransformValue_Type) {
4478      PyErr_Format(PyExc_SystemError, "TransformValue.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
4479      return PYNULL;
4480    }
4481
4482    CAST_TO(TTransformValue, tv)
4483
4484    TPyValue *value;
4485    if (!convertFromPython(args, value))
4486      return PYNULL;
4487
4488    tv->transform(value->value);
4489    value->variable=PVariable();
4490    return (PyObject *)value;
4491  PyCATCH
4492}
4493
4494
4495/* ************ DISTRIBUTION ************ */
4496
4497#include "distvars.hpp"
4498
4499PyObject *convertToPythonNative(const TDiscDistribution &disc)
4500{ int e = disc.size();
4501  PyObject *pylist = PyList_New(e);
4502  for (Py_ssize_t i = 0; i<e; i++)
4503    PyList_SetItem(pylist, i, PyFloat_FromDouble((double)(disc[i])));
4504  return pylist;
4505}
4506
4507PyObject *convertToPythonNative(const TContDistribution &cont)
4508{ PyObject *pydict = PyDict_New();
4509  const_ITERATE(TContDistribution, ci, cont) {
4510    PyObject *key = PyFloat_FromDouble((double)((*ci).first));
4511    PyObject *val = PyFloat_FromDouble((double)((*ci).second));
4512    PyDict_SetItem(pydict, key, val);
4513    Py_DECREF(key);
4514    Py_DECREF(val);
4515  }
4516  return pydict;
4517}
4518
4519
4520bool convertFromPython(PyObject *pylist, TDiscDistribution &disc)
4521{
4522  if (!PyList_Check(pylist))
4523    PYERROR(PyExc_TypeError, "list expected", false);
4524
4525  disc.clear();
4526  float d;
4527  for(Py_ssize_t i = 0, e = PyList_Size(pylist); i!=e; i++) {
4528    if (!PyNumber_ToFloat(PyList_GET_ITEM(pylist, i), d))
4529      PYERROR(PyExc_TypeError, "non-number in DiscDistribution as list", false);
4530    disc.set(TValue((int)i), d);
4531  }
4532
4533  return true;
4534}
4535
4536
4537PyObject *convertToPythonNative(const TDistribution &dist, int)
4538{ const TDiscDistribution *disc = dynamic_cast<const TDiscDistribution *>(&dist);
4539  if (disc)
4540    return convertToPythonNative(*disc);
4541
4542  const TContDistribution *cont = dynamic_cast<const TContDistribution *>(&dist);
4543  if (cont)
4544    return convertToPythonNative(*cont);
4545
4546  PYERROR(PyExc_TypeError, "cannot convert to native python object", PYNULL);
4547}
4548
4549
4550/* Class Distribution has a constructor, but it constructs an instance of either DiscDistribution
4551   or ContDistribution. Class Distribution is thus essentially abstract for Python, although it has
4552   a constructor. */
4553
4554NO_PICKLE(Distribution)
4555
4556PyObject *Distribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.statistics.distribution.Distribution, "(attribute[, examples[, weightID]])")
4557{
4558  PyTRY
4559    PExampleGenerator gen;
4560    PyObject *pyvar;
4561    int weightID = 0;
4562    if (!PyArg_ParseTuple(args, "O|O&O&:Distribution.new", &pyvar, &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID))
4563      return PYNULL;
4564
4565    TDistribution *dist;
4566
4567    if (!gen) {
4568      if (PyOrVariable_Check(pyvar))
4569        dist = TDistribution::create(PyOrange_AsVariable(pyvar));
4570      else if (PyList_Check(pyvar)) {
4571        TDiscDistribution *ddist = mlnew TDiscDistribution();
4572        if (!convertFromPython(pyvar, *ddist)) {
4573          mldelete ddist;
4574          raiseError("invalid arguments");
4575        }
4576        else
4577          dist = ddist;
4578      }
4579      else
4580        raiseError("invalid arguments");
4581    }
4582    else {
4583      if (PyOrVariable_Check(pyvar))
4584        dist = TDistribution::fromGenerator(gen, PyOrange_AsVariable(pyvar), weightID);
4585      else {
4586        PVariable var = varFromArg_byDomain(pyvar, gen->domain, false);
4587        if (!var)
4588          return PYNULL;
4589
4590        dist = TDistribution::fromGenerator(gen, var, weightID);
4591      }
4592    }
4593
4594    /* We need to override the type (don't want to lie it's Distribution).
4595       The exception is if another type is prescribed. */
4596    return type==(PyTypeObject *)(&PyOrDistribution_Type) ? WrapOrange(PDistribution(dist)) : WrapNewOrange(dist, type);
4597  PyCATCH
4598}
4599
4600
4601PyObject *Distribution_native(PyObject *self, PyObject *) PYARGS(0, "() -> list | dictionary")
4602{
4603  PyTRY
4604    return convertToPythonNative(*PyOrange_AS_Orange(self).AS(TDistribution), 1);
4605  PyCATCH
4606}
4607
4608
4609TDiscDistribution *getDiscDistribution(PyObject *self)
4610{ TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4611  if (!disc)
4612    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected DiscDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4613  return disc;
4614}
4615
4616
4617TContDistribution *getContDistribution(PyObject *self)
4618{ TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4619  if (!cont)
4620    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected ContDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4621  return cont;
4622}
4623
4624
4625
4626float *Distribution_getItemRef(PyObject *self, PyObject *index, float *float_idx=NULL)
4627{
4628  TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4629  if (disc) {
4630    int ind=-1;
4631    if (PyInt_Check(index))
4632      ind = (int)PyInt_AsLong(index);
4633    else {
4634      if (!disc->variable)
4635        PYERROR(PyExc_SystemError, "invalid distribution (no variable)", (float *)NULL);
4636      TValue val;
4637      if (convertFromPython(index, val, disc->variable) && !val.isSpecial())
4638        ind=int(val);
4639    }
4640
4641    if (ind<0)
4642      PYERROR(PyExc_IndexError, "invalid index for distribution", (float *)NULL);
4643
4644    if (ind<int(disc->size()))
4645      return &disc->at(ind);
4646
4647    PyErr_Format(PyExc_IndexError, "index %i is out of range (0-%i)", ind, disc->size()-1);
4648    return (float *)NULL;
4649  }
4650
4651  TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4652  if (cont) {
4653    float ind;
4654    if (PyNumber_ToFloat(index, ind)) {
4655      if (float_idx)
4656        *float_idx = ind;
4657    }
4658    else {
4659      TValue val;
4660      if (convertFromPython(index, val, cont->variable) && !val.isSpecial()) {
4661        ind = float(val);
4662        if (float_idx)
4663          *float_idx = ind;
4664      }
4665      else
4666        PYERROR(PyExc_IndexError, "invalid index type (float expected)", NULL);
4667    }
4668
4669    TContDistribution::iterator mi=cont->find(ind);
4670    if (mi!=cont->end())
4671      return &(*mi).second;
4672  }
4673
4674  PYERROR(PyExc_IndexError, "invalid index", (float *)NULL);
4675}
4676
4677
4678PyObject *Distribution_getitem(PyObject *self, PyObject *index)
4679{ PyTRY
4680    float *prob=Distribution_getItemRef(self, index);
4681    return prob ? PyFloat_FromDouble(*prob) : PYNULL;
4682  PyCATCH
4683}
4684
4685
4686int Distribution_setitem(PyObject *self, PyObject *index, PyObject *item)
4687{ PyTRY
4688    PyObject *flt = PyNumber_Float(item);
4689    if (!flt)
4690      PYERROR(PyExc_TypeError, "float expected", -1);
4691
4692    float val=(float)PyFloat_AsDouble(flt);
4693    Py_DECREF(flt);
4694
4695    if (PyOrValue_Check(index)) {
4696      SELF_AS(TDistribution).set(PyValue_AS_Value(index), val);
4697      return 0;
4698    }
4699
4700    float *prob = Distribution_getItemRef(self, index);
4701    if (!prob)
4702      return -1;
4703
4704    *prob = val;
4705    return 0;
4706  PyCATCH_1
4707}
4708
4709
4710string convertToString(const PDistribution &distribution)
4711{
4712  const TDiscDistribution *disc = distribution.AS(TDiscDistribution);
4713  if (disc) {
4714    string res = "<";
4715    char buf[128];
4716    const_PITERATE(TDiscDistribution, di, disc) {
4717      if (res.size()>1)
4718        res += ", ";
4719      sprintf(buf, "%.3f", *di);
4720      res += buf;
4721    }
4722    return res+">";
4723  }
4724
4725  const TContDistribution *cont = distribution.AS(TContDistribution);
4726  if (cont) {
4727    string res = "<";
4728    char buf[128];
4729    const_PITERATE(TContDistribution, di, cont) {
4730      if (res.size()>1)
4731        res += ", ";
4732      sprintf(buf, "%.3f: %.3f", (*di).first, (*di).second);
4733      res += buf;
4734    }
4735    return res+">";
4736  }
4737
4738  raiseErrorWho("convertToString(PDistribution)", "invalid distribution");
4739  return string();
4740}
4741
4742
4743PyObject *Distribution_str(PyObject *self)
4744{ PyTRY
4745    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
4746    if (result)
4747      return result;
4748
4749    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4750  PyCATCH
4751}
4752
4753
4754PyObject *Distribution_repr(PyObject *self)
4755{ PyTRY
4756    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "repr", "str");
4757    if (result)
4758      return result;
4759
4760    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4761  PyCATCH
4762}
4763
4764
4765PyObject *Distribution_normalize(PyObject *self) PYARGS(0, "() -> None")
4766{ PyTRY
4767    SELF_AS(TDistribution).normalize();
4768    RETURN_NONE;
4769  PyCATCH
4770}
4771
4772
4773PyObject *Distribution_modus(PyObject *self) PYARGS(0, "() -> Value")
4774{ PyTRY
4775    CAST_TO(TDistribution, dist)
4776    return Value_FromVariableValue(dist->variable, dist->highestProbValue());
4777  PyCATCH
4778}
4779
4780
4781PyObject *Distribution_random(PyObject *self) PYARGS(0, "() -> Value")
4782{ PyTRY
4783    CAST_TO(TDistribution, dist)
4784    return Value_FromVariableValue(dist->variable, dist->randomValue());
4785  PyCATCH
4786}
4787
4788
4789
4790PDiscDistribution list2discdistr(PyObject *args, PyTypeObject *type = NULL)
4791{
4792  TDiscDistribution *udist = mlnew TDiscDistribution();
4793  PDiscDistribution disc = type ? PDistribution(udist) : PDistribution(udist, type);
4794  for(Py_ssize_t i = 0, e = PyList_Size(args); i<e; i++) {
4795    PyObject *flt = PyNumber_Float(PyList_GetItem(args, i));
4796    if (!flt) {
4797      PyErr_Format(PyExc_TypeError, "invalid element at index %i (float expected)", i);
4798      return PDiscDistribution();
4799    }
4800    udist->addint((int)i, (float)PyFloat_AsDouble(flt));
4801    Py_DECREF(flt);
4802  }
4803
4804  return disc;
4805}
4806
4807
4808PyObject *DiscDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Discrete, "[list of floats] | DiscDistribution")
4809{ PyTRY {
4810    if (!PyTuple_Size(targs)) {
4811      return WrapNewOrange(mlnew TDiscDistribution(), type);
4812    }
4813
4814    if (PyTuple_Size(targs)==1) {
4815      PyObject *args = PyTuple_GetItem(targs, 0);
4816
4817      if (PyList_Check(args)) {
4818        PDiscDistribution disc = list2discdistr(args, type);
4819        if (disc)
4820          return WrapOrange(disc);
4821      }
4822
4823      else if (PyOrDiscDistribution_Check(args)) {
4824        Py_INCREF(args);
4825        return args;
4826      }
4827
4828      else if (PyOrEnumVariable_Check(args))
4829        return WrapNewOrange(mlnew TDiscDistribution(PyOrange_AsVariable(args)), type);
4830    }
4831
4832    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
4833  }
4834  PyCATCH;
4835}
4836
4837
4838PyObject *DiscDistribution__reduce__(PyObject *self)
4839{
4840  PyTRY
4841    TDiscDistribution *disc = getDiscDistribution(self);
4842    TCharBuffer buf(sizeof(float)*(disc->size()+2));
4843    buf.writeFloatVector(disc->distribution);
4844
4845    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderDiscDistribution"),
4846                                    self->ob_type,
4847                                    buf.buf, buf.length(),
4848                                    packOrangeDictionary(self));
4849  PyCATCH
4850}
4851
4852
4853PyObject *__pickleLoaderDiscDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
4854{
4855  PyTRY
4856    PyTypeObject *type;
4857    char *buf;
4858    int bufSize;
4859    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &buf, &bufSize))
4860      return PYNULL;
4861
4862    const int &size = (int &)*buf;
4863    buf += sizeof(int);
4864
4865    return WrapNewOrange(new TDiscDistribution((float *)buf, size), type);
4866  PyCATCH
4867}
4868
4869
4870int pt_DiscDistribution(PyObject *args, void *dist)
4871{ if (PyOrDiscDistribution_Check(args)) {
4872    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4873    return 1;
4874  }
4875  else if (PyList_Check(args)) {
4876    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4877    if (dist)
4878      return 1;
4879  }
4880
4881  PYERROR(PyExc_TypeError, "invalid discrete distribution", 0)
4882}
4883
4884
4885PyObject *DiscDistribution_getitem_sq(PyObject *self, Py_ssize_t ind)
4886{
4887  PyTRY
4888    TDiscDistribution *disc = getDiscDistribution(self);
4889    if (!disc)
4890      return PYNULL;
4891
4892    if ((ind<0) || (ind>=disc->size()))
4893      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
4894
4895    return PyFloat_FromDouble(double(disc->at(ind)));
4896  PyCATCH
4897}
4898
4899
4900Py_ssize_t DiscDistribution_len(PyObject *self)
4901{ PyTRY
4902    TDiscDistribution *disc = getDiscDistribution(self);
4903    return disc ? disc->size() : -1;
4904  PyCATCH_1
4905}
4906
4907
4908PyObject *DiscDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
4909{ PyTRY
4910    TDiscDistribution *disc = getDiscDistribution(self);
4911    if (!disc)
4912      return PYNULL;
4913
4914    if (!disc->variable)
4915      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4916
4917    PyObject *nl=PyList_New(disc->variable->noOfValues());
4918    Py_ssize_t i=0;
4919    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4920    PITERATE(TStringList, ii, vals)
4921      PyList_SetItem(nl, i++, PyString_FromString((*ii).c_str()));
4922    return nl;
4923  PyCATCH
4924}
4925
4926
4927PyObject *DiscDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
4928{ PyTRY
4929    TDiscDistribution *disc = getDiscDistribution(self);
4930    if (!disc)
4931      return PYNULL;
4932
4933    if (!disc->variable)
4934      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4935
4936    PyObject *nl=PyList_New(disc->variable->noOfValues());
4937    TDiscDistribution::const_iterator ci(disc->begin());
4938    Py_ssize_t i=0;
4939    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4940    PITERATE(TStringList, ii, vals)
4941      PyList_SetItem(nl, i++, Py_BuildValue("sf", (*ii).c_str(), *(ci++)));
4942    return nl;
4943  PyCATCH
4944}
4945
4946
4947PyObject *DiscDistribution_values(PyObject *self) PYARGS(0, "() -> list")
4948{ PyTRY
4949    TDiscDistribution *disc = getDiscDistribution(self);
4950    if (!disc)
4951      return PYNULL;
4952
4953    PyObject *nl = PyList_New(disc->size());
4954    Py_ssize_t i = 0;
4955    const_PITERATE(TDiscDistribution, ci, disc)
4956      PyList_SetItem(nl, i++, PyFloat_FromDouble(*ci));
4957    return nl;
4958  PyCATCH
4959}
4960
4961
4962PyObject *DiscDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
4963{ PyTRY
4964    CAST_TO(TDiscDistribution, dist)
4965
4966    PyObject *index;
4967    float weight = 1.0;
4968    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
4969      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
4970
4971    if (PyInt_Check(index)) {
4972      dist->addint(int(PyInt_AsLong(index)), weight);
4973      RETURN_NONE;
4974    }
4975
4976    TValue val;
4977    if (!dist->variable || !convertFromPython(index, val, dist->variable))
4978      PYERROR(PyExc_TypeError, "DiscDistriubtion.add: cannot convert the arguments to a Value", PYNULL);
4979
4980    dist->add(val, weight);
4981    RETURN_NONE;
4982  PyCATCH;
4983}
4984
4985
4986PyObject *ContDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Continuous, "[dist of float:float] | DiscDistribution")
4987{ PyTRY {
4988
4989    if (!PyTuple_Size(targs))
4990      return WrapNewOrange(mlnew TContDistribution(), type);
4991
4992    if (PyTuple_Size(targs) == 1) {
4993      PyObject *args = PyTuple_GetItem(targs, 0);
4994
4995      if (PyDict_Check(args)) {
4996        TContDistribution *udist = mlnew TContDistribution();
4997        PContDistribution cont = PDistribution(udist);
4998        PyObject *key, *value;
4999        Py_ssize_t pos = 0;
5000        while (PyDict_Next(args, &pos, &key, &value)) {
5001          PyObject *flt = PyNumber_Float(key);
5002          if (!flt) {
5003            PyErr_Format(PyExc_TypeError, "invalid key at index %i (float expected)", pos);
5004            return false;
5005          }
5006          float ind = (float) PyFloat_AsDouble(flt);
5007          Py_DECREF(flt);
5008
5009          flt = PyNumber_Float(value);
5010          if (!flt) {
5011            PyErr_Format(PyExc_TypeError, "invalid value at index %i (float expected)", pos);
5012            return false;
5013          }
5014
5015          udist->addfloat(ind, (float)PyFloat_AsDouble(flt));
5016          Py_DECREF(flt);
5017        }
5018
5019        return WrapOrange(cont);
5020      }
5021
5022      else if (PyOrDistribution_Check(args)) {
5023        Py_INCREF(args);
5024        return args;
5025      }
5026
5027      else if (PyOrFloatVariable_Check(args))
5028        return WrapNewOrange(mlnew TContDistribution(PyOrange_AsVariable(args)), type);
5029    }
5030
5031    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
5032
5033  }
5034  PyCATCH;
5035}
5036
5037
5038PyObject *ContDistribution__reduce__(PyObject *self)
5039{
5040  PyTRY
5041    TContDistribution *cont = getContDistribution(self);
5042    TCharBuffer buf(sizeof(float) * 2 * (cont->size()  +  5));
5043
5044    buf.writeInt(cont->size());
5045    PITERATE(TContDistribution, ci, cont) {
5046      buf.writeFloat((*ci).first);
5047      buf.writeFloat((*ci).second);
5048    }
5049
5050    buf.writeFloat(cont->sum);
5051    buf.writeFloat(cont->sum2);
5052
5053    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderContDistribution"),
5054                                    self->ob_type,
5055                                    buf.buf, buf.length(),
5056                                    packOrangeDictionary(self));
5057  PyCATCH
5058}
5059
5060
5061PyObject *__pickleLoaderContDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
5062{
5063  PyTRY
5064    PyTypeObject *type;
5065    char *pbuf;
5066    int bufSize;
5067    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &pbuf, &bufSize))
5068      return PYNULL;
5069
5070    TContDistribution *cdi = new TContDistribution();
5071
5072    TCharBuffer buf(pbuf);
5073    for(int size = buf.readInt(); size--; ) {
5074      // cannot call buf.readFloat() in the make_pair call since we're not sure about the
5075      // order in which the arguments are evaluated
5076      const float p1 = buf.readFloat();
5077      const float p2 = buf.readFloat();
5078      cdi->insert(cdi->end(), make_pair(p1, p2));
5079    }
5080
5081    cdi->sum = buf.readFloat();
5082    cdi->sum2 = buf.readFloat();
5083
5084    return WrapNewOrange(cdi, type);
5085  PyCATCH
5086}
5087
5088
5089Py_ssize_t ContDistribution_len(PyObject *self)
5090{ PyTRY
5091    TContDistribution *cont = getContDistribution(self);
5092    return cont ? cont->size() : -1;
5093  PyCATCH_1
5094}
5095
5096
5097PyObject *ContDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
5098{ PyTRY
5099    TContDistribution *cont = getContDistribution(self);
5100    if (!cont)
5101      return PYNULL;
5102
5103    PyObject *nl=PyList_New(cont->size());
5104    Py_ssize_t i=0;
5105    PITERATE(TContDistribution, ci, cont)
5106      PyList_SetItem(nl, i++, PyFloat_FromDouble((double)(*ci).first));
5107    return nl;
5108  PyCATCH
5109}
5110
5111
5112PyObject *ContDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
5113{ PyTRY
5114    TContDistribution *cont = getContDistribution(self);
5115    if (!cont)
5116      return PYNULL;
5117
5118    PyObject *nl=PyList_New(cont->size());
5119    Py_ssize_t i=0;
5120    PITERATE(TContDistribution, ci, cont)
5121      PyList_SetItem(nl, i++, Py_BuildValue("ff", (*ci).first, (*ci).second));
5122    return nl;
5123  PyCATCH
5124}
5125
5126
5127PyObject *ContDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5128{ PyTRY
5129    TContDistribution *cont = getContDistribution(self);
5130    if (!cont)
5131      return PYNULL;
5132
5133    PyObject *nl = PyList_New(cont->size());
5134    Py_ssize_t i = 0;
5135    const_PITERATE(TContDistribution, ci, cont)
5136      PyList_SetItem(nl, i++, PyFloat_FromDouble((*ci).second));
5137    return nl;
5138  PyCATCH
5139}
5140
5141
5142PyObject *ContDistribution_percentile(PyObject *self, PyObject *arg) PYARGS(METH_VARARGS, "(int) -> float")
5143{ PyTRY
5144    TContDistribution *cont = getContDistribution(self);
5145    if (!cont)
5146      return PYNULL;
5147
5148    float perc;
5149    if (!PyArg_ParseTuple(arg, "f:ContDistribution.percentile", &perc))
5150      return PYNULL;
5151
5152    return PyFloat_FromDouble(cont->percentile(perc));
5153  PyCATCH
5154}
5155
5156
5157PyObject *ContDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5158{ PyTRY
5159    CAST_TO(TContDistribution, dist)
5160
5161    PyObject *index;
5162    float weight = 1.0;
5163    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5164      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5165
5166    float f;
5167    if (PyNumber_ToFloat(index, f)) {
5168      dist->addfloat(f);
5169      RETURN_NONE;
5170    }
5171
5172    TValue val;
5173    if (!convertFromPython(index, val, dist->variable))
5174      PYERROR(PyExc_TypeError, "ContDistriubtion.add: invalid arguments", PYNULL);
5175
5176    dist->add(val, weight);
5177    RETURN_NONE;
5178  PyCATCH;
5179}
5180
5181
5182PyObject *ContDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5183{ PyTRY
5184    TContDistribution *cont = getContDistribution(self);
5185    if (!cont)
5186      return PYNULL;
5187
5188    return PyFloat_FromDouble(cont->error());
5189  PyCATCH
5190}
5191
5192
5193PyObject *ContDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5194{ PyTRY
5195    TContDistribution *cont = getContDistribution(self);
5196    if (!cont)
5197      return PYNULL;
5198
5199    return PyFloat_FromDouble(cont->average());
5200  PyCATCH
5201}
5202
5203
5204PyObject *ContDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5205{ PyTRY
5206    TContDistribution *cont = getContDistribution(self);
5207    if (!cont)
5208      return PYNULL;
5209
5210    return PyFloat_FromDouble(cont->dev());
5211  PyCATCH
5212}
5213
5214
5215PyObject *ContDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5216{ PyTRY
5217    TContDistribution *cont = getContDistribution(self);
5218    if (!cont)
5219      return PYNULL;
5220
5221    return PyFloat_FromDouble(cont->var());
5222  PyCATCH
5223}
5224
5225
5226PyObject *ContDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5227{ PyTRY
5228    TContDistribution *cont = getContDistribution(self);
5229    float x;
5230    if (!cont || !PyArg_ParseTuple(args, "f:ContDistribution.density", &x))
5231      return PYNULL;
5232
5233    return PyFloat_FromDouble(cont->p(x));
5234  PyCATCH
5235}
5236
5237
5238PyObject *GaussianDistribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Gaussian, "(mean, sigma) | (distribution) | () -> distribution") ALLOWS_EMPTY
5239{ PyTRY
5240    float mean = 0.0, sigma = 1.0;
5241
5242    if (PyArg_ParseTuple(args, "|ff", &mean, &sigma))
5243      return WrapNewOrange(mlnew TGaussianDistribution(mean, sigma), type);
5244
5245    PyErr_Clear();
5246
5247    PDistribution dist;
5248    if (PyArg_ParseTuple(args, "O&", &cc_Distribution, &dist))
5249      return WrapNewOrange(mlnew TGaussianDistribution(dist), type);
5250
5251    PYERROR(PyExc_TypeError, "GaussianDistribution expects mean and sigma, or distribution or nothing", PYNULL)
5252
5253  PyCATCH
5254}
5255
5256
5257PyObject *GaussianDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5258{ PyTRY
5259    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).average());
5260  PyCATCH
5261}
5262
5263
5264PyObject *GaussianDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5265{ PyTRY
5266    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).error());
5267  PyCATCH
5268}
5269
5270
5271PyObject *GaussianDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5272{ PyTRY
5273    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).dev());
5274  PyCATCH
5275}
5276
5277
5278PyObject *GaussianDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5279{ PyTRY
5280    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).var());
5281  PyCATCH
5282}
5283
5284
5285PyObject *GaussianDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5286{ PyTRY
5287    float x;
5288    if (!PyArg_ParseTuple(args, "f:GaussianDistribution.density", &x))
5289      return PYNULL;
5290
5291    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).p(x));
5292  PyCATCH
5293}
5294
5295
5296/* We redefine new (removed from below!) and add mapping methods
5297*/
5298
5299PyObject *getClassDistribution(PyObject *type, PyObject *args) PYARGS(METH_VARARGS, "(examples[, weightID]) -> Distribution")
5300{ PyTRY
5301    int weightID;
5302    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
5303    if (!gen)
5304      return PYNULL;
5305    return WrapOrange(getClassDistribution(gen, weightID));
5306  PyCATCH
5307}
5308
5309
5310/* modified new (defined below), modified getitem, setitem */
5311
5312PDomainDistributions PDomainDistributions_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5313PyObject *DomainDistributions_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5314PyObject *DomainDistributions_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5315int       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); }
5316PyObject *DomainDistributions_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5317int       DomainDistributions_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5318Py_ssize_t       DomainDistributions_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_len(self); }
5319PyObject *DomainDistributions_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5320PyObject *DomainDistributions_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5321PyObject *DomainDistributions_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5322PyObject *DomainDistributions_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5323PyObject *DomainDistributions_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5324int       DomainDistributions_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5325PyObject *DomainDistributions_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5326PyObject *DomainDistributions_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5327PyObject *DomainDistributions_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5328PyObject *DomainDistributions_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainDistributions") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5329PyObject *DomainDistributions_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5330PyObject *DomainDistributions_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5331PyObject *DomainDistributions_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_native(self); }
5332PyObject *DomainDistributions_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5333PyObject *DomainDistributions_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5334PyObject *DomainDistributions_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5335PyObject *DomainDistributions_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5336PyObject *DomainDistributions__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5337
5338
5339/* Note that this is not like callable-constructors. They return different type when given
5340   parameters, while this one returns the same type, disregarding whether it was given examples or not.
5341*/
5342PyObject *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
5343{ PyTRY
5344    if (!args || !PyTuple_Size(args))
5345      return WrapNewOrange(mlnew TDomainDistributions(), type);
5346
5347    int weightID = 0;
5348    PExampleGenerator gen;
5349    int skipDiscrete=0, skipContinuous=0;
5350    if (PyArg_ParseTuple(args, "O&|O&ii:Distribution.new", &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &skipDiscrete, &skipContinuous))
5351      return WrapNewOrange(mlnew TDomainDistributions(gen, weightID, skipDiscrete!=0, skipContinuous!=0), type);
5352
5353    PyErr_Clear();
5354
5355    PyObject *obj = ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_new(type, args, keywds);
5356    if (obj)
5357      if (obj!=Py_None)
5358        return obj;
5359      else
5360        Py_DECREF(obj);
5361
5362    PyErr_Clear();
5363    PYERROR(PyExc_TypeError, "DomainDistributions.__init__ expect examples or a list of Distributions", PYNULL);
5364
5365  PyCATCH
5366}
5367
5368
5369/* We keep the sequence methods and add mapping interface */
5370
5371int DomainDistributions_getItemIndex(PyObject *self, PyObject *args)
5372{ CAST_TO_err(TDomainDistributions, bas, -1);
5373
5374  if (PyInt_Check(args)) {
5375    int i=(int)PyInt_AsLong(args);
5376    if ((i>=0) && (i<int(bas->size())))
5377      return i;
5378    else
5379      PYERROR(PyExc_IndexError, "index out of range", -1);
5380  }
5381
5382  if (PyString_Check(args)) {
5383    char *s=PyString_AsString(args);
5384    PITERATE(TDomainDistributions, ci, bas)
5385      if ((*ci)->variable && ((*ci)->variable->get_name()==s))
5386        return ci - bas->begin();
5387
5388    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", s);
5389    return -1;
5390  }
5391
5392  if (PyOrVariable_Check(args)) {
5393    PVariable var = PyOrange_AsVariable(args);
5394    PITERATE(TDomainDistributions, ci, bas)
5395      if ((*ci)->variable && ((*ci)->variable==var))
5396        return ci - bas->begin();
5397
5398    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", var->get_name().length() ? var->get_name().c_str() : "<no name>");
5399    return -1;
5400  }
5401
5402  PYERROR(PyExc_IndexError, "invalid index type", -1);
5403}
5404
5405
5406PyObject *DomainDistributions_getitem(PyObject *self, PyObject *args)
5407{ PyTRY
5408    int index=DomainDistributions_getItemIndex(self, args);
5409    if (index<0)
5410      return PYNULL;
5411    return WrapOrange(POrange(SELF_AS(TDomainDistributions).at(index)));
5412  PyCATCH
5413}
5414
5415
5416int DomainDistributions_setitem(PyObject *self, PyObject *args, PyObject *obj)
5417{ PyTRY
5418    PDistribution bas;
5419
5420    if (!PyOrBasicAttrStat_Check(obj))
5421      PYERROR(PyExc_TypeError, "invalid Distribution object", -1);
5422
5423    int index=DomainDistributions_getItemIndex(self, args);
5424    if (index==-1)
5425      return -1;
5426
5427    SELF_AS(TDomainDistributions)[index] = PyOrange_AsDistribution(obj);
5428    return 0;
5429  PyCATCH_1
5430}
5431
5432
5433PDistributionList PDistributionList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5434PyObject *DistributionList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5435PyObject *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); }
5436PyObject *DistributionList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5437int       DistributionList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5438PyObject *DistributionList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5439int       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); }
5440Py_ssize_t       DistributionList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_len(self); }
5441PyObject *DistributionList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5442PyObject *DistributionList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5443PyObject *DistributionList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5444PyObject *DistributionList_str(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5445PyObject *DistributionList_repr(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5446int       DistributionList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5447PyObject *DistributionList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5448PyObject *DistributionList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5449PyObject *DistributionList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5450PyObject *DistributionList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DistributionList") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5451PyObject *DistributionList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5452PyObject *DistributionList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5453PyObject *DistributionList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_native(self); }
5454PyObject *DistributionList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5455PyObject *DistributionList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5456PyObject *DistributionList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5457PyObject *DistributionList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5458PyObject *DistributionList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5459
5460
5461
5462/* ************ LEARNER ************ */
5463
5464#include "classify.hpp"
5465#include "learn.hpp"
5466
5467BASED_ON(EFMDataDescription, Orange)
5468
5469PyObject *EFMDataDescription__reduce__(PyObject *self)
5470{
5471  CAST_TO(TEFMDataDescription, edd);
5472
5473  TCharBuffer buf(0);
5474  buf.writeFloatVector(edd->averages);
5475  buf.writeFloatVector(edd->matchProbabilities);
5476  buf.writeInt(edd->originalWeight);
5477  buf.writeInt(edd->missingWeight);
5478
5479  return Py_BuildValue("O(OOs#)N", getExportedFunction("__pickleLoaderEFMDataDescription"),
5480                                  WrapOrange(edd->domain),
5481                                  WrapOrange(edd->domainDistributions),
5482                                  buf.buf, buf.length(),
5483                                  packOrangeDictionary(self));
5484}
5485
5486
5487PyObject *__pickleLoaderEFMDataDescription(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, domainDistributions, packed_data)")
5488{
5489  PDomain domain;
5490  PDomainDistributions domainDistributions;
5491  char *pbuf;
5492  int bufSize;
5493
5494  if (!PyArg_ParseTuple(args, "O&O&s#", ccn_Domain, &domain, ccn_DomainDistributions, &domainDistributions, &pbuf, &bufSize))
5495    return PYNULL;
5496
5497  TEFMDataDescription *edd = new TEFMDataDescription(domain, domainDistributions);
5498  PEFMDataDescription wedd = edd;
5499
5500  TCharBuffer buf(pbuf);
5501  buf.readFloatVector(edd->averages);
5502  buf.readFloatVector(edd->matchProbabilities);
5503  edd->originalWeight = buf.readInt();
5504  edd->missingWeight = buf.readInt();
5505
5506  return WrapOrange(wedd);
5507}
5508
5509
5510ABSTRACT(LearnerFD - Orange.classification.LearnerFD, Learner)
5511
5512PyObject *Learner_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.classification.Learner, "<abstract>")
5513{ if (type == (PyTypeObject *)&PyOrLearner_Type)
5514    return setCallbackFunction(WrapNewOrange(mlnew TLearner_Python(), type), args);
5515  else
5516    return WrapNewOrange(mlnew TLearner_Python(), type);
5517}
5518
5519
5520PyObject *Learner__reduce__(PyObject *self)
5521{
5522  return callbackReduce(self, PyOrLearner_Type);
5523}
5524
5525
5526PyObject *Learner_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(examples) -> Classifier")
5527{
5528  PyTRY
5529    NO_KEYWORDS
5530
5531    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrLearner_Type) {
5532      PyErr_Format(PyExc_SystemError, "Learner.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
5533      return PYNULL;
5534    }
5535
5536    PExampleGenerator egen;
5537    int weight = 0;
5538    if (!PyArg_ParseTuple(targs, "O&|O&", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weight))
5539      PYERROR(PyExc_AttributeError, "Learner.__call__: examples and, optionally, weight attribute expected", PYNULL);
5540
5541    // Here for compatibility with obsolete scripts
5542/*    if (PyTuple_Size(targs)==1) {
5543      if (((TPyOrange *)self)->orange_dict) {
5544        PyObject *pyweight = PyDict_GetItemString(((TPyOrange *)self)->orange_dict, "weight");
5545        if (pyweight && PyInt_Check(pyweight))
5546          weight = (int)PyInt_AsLong(pyweight);
5547      }
5548    }
5549*/
5550    PClassifier classfr = SELF_AS(TLearner)(egen, weight);
5551    if (!classfr)
5552      PYERROR(PyExc_SystemError, "learning failed", PYNULL);
5553
5554    return WrapOrange(classfr);
5555  PyCATCH
5556}
5557
5558
5559
5560
5561/* ************ CLASSIFIERS ************ */
5562
5563#include "classify.hpp"
5564#include "majority.hpp"
5565
5566ABSTRACT(ClassifierFD - Orange.classification.ClassifierFD, Classifier)
5567
5568PyObject *DefaultClassifier_new(PyTypeObject *tpe, PyObject *args, PyObject *kw) BASED_ON(Classifier - Orange.classification.ConstantClassifier, "([defaultVal])") ALLOWS_EMPTY
5569{
5570  PyObject *arg1 = NULL, *arg2 = NULL;
5571  if (!PyArg_UnpackTuple(args, "DefaultClassifier.__new__", 0, 2, &arg1, &arg2))
5572    return PYNULL;
5573
5574  if (!arg1)
5575    return WrapNewOrange(mlnew TDefaultClassifier(), tpe);
5576
5577  if (!arg2) {
5578    if (PyOrVariable_Check(arg1))
5579      return WrapNewOrange(mlnew TDefaultClassifier(PyOrange_AsVariable(arg1)), tpe);
5580    TValue val;
5581    if (convertFromPython(arg1, val)) {
5582      PVariable var = PyOrValue_Check(arg1) ? PyValue_AS_Variable(arg1) : PVariable();
5583      return WrapNewOrange(mlnew TDefaultClassifier(var, val, PDistribution()), tpe);
5584    }
5585  }
5586
5587  else
5588    if (PyOrVariable_Check(arg1)) {
5589      PVariable classVar = PyOrange_AsVariable(arg1);
5590      TValue val;
5591      if (convertFromPython(arg2, val, classVar))
5592        return WrapNewOrange(mlnew TDefaultClassifier(classVar, val, PDistribution()), tpe);
5593    }
5594
5595  PYERROR(PyExc_TypeError, "DefaultClassifier's constructor expects a Variable, a Value or both", PYNULL);
5596}
5597
5598C_NAMED(RandomLearner - Orange.classification.RandomLearner, Learner, "([probabilities=])")
5599C_NAMED(RandomClassifier - Orange.classification.RandomClassifier, Classifier, "([probabilities=])")
5600
5601PClassifierList PClassifierList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::P_FromArguments(arg); }
5602PyObject *ClassifierList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_FromArguments(type, arg); }
5603PyObject *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); }
5604PyObject *ClassifierList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getitem(self, index); }
5605int       ClassifierList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_setitem(self, index, item); }
5606PyObject *ClassifierList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getslice(self, start, stop); }
5607int       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); }
5608Py_ssize_t       ClassifierList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_len(self); }
5609PyObject *ClassifierList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_richcmp(self, object, op); }
5610PyObject *ClassifierList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_concat(self, obj); }
5611PyObject *ClassifierList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_repeat(self, times); }
5612PyObject *ClassifierList_str(TPyOrange *self) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_str(self); }
5613PyObject *ClassifierList_repr(TPyOrange *self) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_str(self); }
5614int       ClassifierList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_contains(self, obj); }
5615PyObject *ClassifierList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Classifier) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_append(self, item); }
5616PyObject *ClassifierList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_extend(self, obj); }
5617PyObject *ClassifierList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Classifier) -> int") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_count(self, obj); }
5618PyObject *ClassifierList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ClassifierList") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_filter(self, args); }
5619PyObject *ClassifierList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Classifier) -> int") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_index(self, obj); }
5620PyObject *ClassifierList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_insert(self, args); }