source: orange/source/orange/lib_kernel.cpp @ 11603:57399ad8c343

Revision 11603:57399ad8c343, 213.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 10 months ago (diff)

Fixed two memory leaks.

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
1883class GlobalFiletypeDefinitionVector: public vector<TFiletypeDefinition>
1884{
1885public:
1886  ~GlobalFiletypeDefinitionVector()
1887  {
1888    /*
1889     * The 'filetypeDefinitions' below will be (and should be)
1890     * the only instance and it will outlive the Python interpreter.
1891     * This destructor will be called in clib's exit() and at that time the
1892     * 'saver' and 'loader' pointers in TFiletypeDefinition are no
1893     * longer valid so we set them to NULL so Py_XDECREF macro in
1894     * TFiletypeDefinition destructor does nothing.
1895     */
1896    for (GlobalFiletypeDefinitionVector::iterator iter = begin();
1897         iter != end();
1898         iter++)
1899    {
1900      iter->loader = NULL;
1901      iter->saver = NULL;
1902    }
1903  }
1904};
1905
1906GlobalFiletypeDefinitionVector filetypeDefinitions;
1907
1908
1909/* lower case to avoid any ambiguity problems (don't know how various compilers can react when
1910   registerFiletype is cast by the code produced by pyxtract */
1911ORANGE_API void registerFiletype(const char *name, const vector<string> &extensions, PyObject *loader, PyObject *saver)
1912{
1913  TFiletypeDefinition ftd(name, loader, saver);
1914  ftd.extensions = extensions;
1915  filetypeDefinitions.push_back(ftd);
1916}
1917
1918bool fileExists(const string &s);
1919const char *getExtension(const char *name);
1920
1921
1922vector<TFiletypeDefinition>::iterator findFiletypeByExtension(const char *name, bool needLoader, bool needSaver, bool exhaustive)
1923{
1924  const char *extension = getExtension(name);
1925
1926  if (extension) {
1927    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1928      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1929        ITERATE(TStringList, ei, (*fi).extensions)
1930          if (*ei == extension)
1931            return fi;
1932  }
1933
1934  else if (exhaustive) {
1935    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1936      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1937        ITERATE(TStringList, ei, (*fi).extensions)
1938          if (fileExists(name + *ei))
1939            return fi;
1940  }
1941
1942  return filetypeDefinitions.end();
1943}
1944
1945
1946PyObject *registerFileType(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(name, extensions, loader, saver) -> None")
1947{
1948  char *name;
1949  PyObject *pyextensions, *loader, *saver;
1950  if (!PyArg_ParseTuple(args, "sOOO:registerFiletype", &name, &loader, &saver, &pyextensions))
1951    return PYNULL;
1952
1953  TFiletypeDefinition ftd(name, loader, saver);
1954
1955  if (PyString_Check(pyextensions))
1956    ftd.extensions.push_back(PyString_AsString(pyextensions));
1957  else {
1958    PStringList extensions = PStringList_FromArguments(pyextensions);
1959    if (!extensions)
1960      return PYNULL;
1961    ftd.extensions = extensions.getReference();
1962  }
1963
1964  vector<TFiletypeDefinition>::iterator fi(filetypeDefinitions.begin()), fe(filetypeDefinitions.begin());
1965  for(; (fi != fe) && ((*fi).name != name); fi++);
1966
1967  if (fi==fe)
1968    filetypeDefinitions.push_back(ftd);
1969  else
1970    *fi = ftd;
1971
1972  RETURN_NONE;
1973}
1974
1975
1976extern char *fileTypes[][2];
1977
1978PyObject *getRegisteredFileTypes(PyObject *, PyObject *, PyObject *) PYARGS(METH_NOARGS, "() -> ((extension, description, loader, saver), ...)")
1979{
1980  char *(*t)[2] = fileTypes;
1981  while(**t)
1982    t++;
1983
1984  int builtIns = t-fileTypes;
1985  int i = 0;
1986  PyObject *types = PyTuple_New(builtIns + filetypeDefinitions.size());
1987  for(t = fileTypes; **t; t++)
1988    PyTuple_SetItem(types, i++, Py_BuildValue("ss", (*t)[0], (*t)[1]));
1989
1990  ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions) {
1991    string exts;
1992    ITERATE(TStringList, ei, (*fi).extensions)
1993      exts += (exts.size() ? " *" : "*") + *ei;
1994
1995    PyObject *ploader = (*fi).loader, *psaver = (*fi).saver;
1996    if (!ploader) {
1997      ploader = Py_None;
1998      Py_INCREF(Py_None);
1999    }
2000    if (!psaver) {
2001      psaver = Py_None;
2002      Py_INCREF(Py_None);
2003    }
2004    PyTuple_SetItem(types, i++, Py_BuildValue("ssOO", (*fi).name.c_str(), exts.c_str(), ploader, psaver));
2005  }
2006
2007  return types;
2008}
2009
2010#include "examplegen.hpp"
2011#include "table.hpp"
2012#include "filter.hpp"
2013
2014
2015PyObject *loadDataByPython(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool exhaustiveFilesearch, bool &fileFound)
2016{
2017  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, true, false, exhaustiveFilesearch);
2018  fileFound = fi!=filetypeDefinitions.end();
2019
2020  if (!fileFound)
2021    return PYNULL;
2022
2023  PyObject *res = PyObject_Call((*fi).loader, argstuple, keywords);
2024  if (!res)
2025    throw pyexception();
2026  if (res == Py_None)
2027    return res;
2028
2029  bool gotTuple = PyTuple_Check(res);
2030  PyObject *res1 = gotTuple ? PyTuple_GET_ITEM(res, 0) : res;
2031
2032  if (PyOrExampleTable_Check(res1))
2033    return res;
2034
2035  PExampleGenerator gen;
2036  if (!exampleGenFromParsedArgs(res1, gen)) {
2037    Py_DECREF(res);
2038    return PYNULL;
2039  }
2040
2041  TExampleTable *table = gen.AS(TExampleTable);
2042  if (!table) {
2043    Py_DECREF(res);
2044    return PYNULL;
2045  }
2046
2047  if (gotTuple) {
2048    PyObject *nres = PyTuple_New(PyTuple_Size(res));
2049    PyTuple_SetItem(nres, 0, WrapNewOrange(table, type));
2050    for(Py_ssize_t i = 1; i < PyTuple_Size(res); i++)
2051      PyTuple_SetItem(nres, i, PyTuple_GET_ITEM(res, i));
2052
2053    Py_DECREF(res);
2054    return nres;
2055  }
2056  else {
2057    Py_DECREF(res);
2058    return WrapNewOrange(table, type);
2059  }
2060}
2061
2062bool readUndefinedSpecs(PyObject *keyws, char *&DK, char *&DC);
2063
2064
2065bool readBoolFlag(PyObject *keywords, char *flag)
2066{
2067  PyObject *pyflag = keywords ? PyDict_GetItemString(keywords, flag) : PYNULL;
2068  return pyflag && PyObject_IsTrue(pyflag);
2069}
2070
2071bool hasFlag(PyObject *keywords, char *flag)
2072{
2073  return keywords && (PyDict_GetItemString(keywords, flag) != PYNULL);
2074}
2075
2076
2077TExampleTable         *readTable(char *filename, const int createNewOn, vector<int> &status, vector<pair<int, int> > &metaStatus, const char *DK, const char *DC, bool noExcOnUnknown = false, bool noCodedDiscrete = false, bool noClass = false);
2078TExampleGenerator *readGenerator(char *filename, const int createNewOn, vector<int> &status, vector<pair<int, int> > &metaStatus, const char *DK, const char *DC, bool noExcOnUnknown = false, bool noCodedDiscrete = false, bool noClass = false);
2079
2080PyObject *encodeStatus(const vector<int> &status);
2081PyObject *encodeStatus(const vector<pair<int, int> > &metaStatus);
2082
2083char *obsoleteFlags[] = {"dontCheckStored", "dontStore", "use", "useMetas", "domain", 0 };
2084
2085
2086PyObject *loadDataFromFileNoSearch(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2087{
2088  PyObject *res;
2089
2090  bool pythonFileFound;
2091  res = loadDataByPython(type, filename, argstuple, keywords, false, pythonFileFound);
2092  if (res) {
2093    if (res != Py_None) {
2094      if (!PyTuple_Check(res))
2095        return res;
2096
2097      PyObject *pygen = PyTuple_GetItem(res, 0);
2098      Py_INCREF(pygen);
2099
2100      if (PyTuple_Size(res) >= 2) {
2101        Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", PyTuple_GET_ITEM(res, 1), false);
2102        Orange_setattrDictionary((TPyOrange *)pygen, "attribute_load_status", PyTuple_GET_ITEM(res, 1), false);
2103      }
2104      if (PyTuple_Size(res) >= 3) {
2105        Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", PyTuple_GET_ITEM(res, 2), false);
2106        Orange_setattrDictionary((TPyOrange *)pygen, "meta_attribute_load_status", PyTuple_GET_ITEM(res, 2), false);
2107      }
2108      return pygen;
2109    }
2110
2111    else
2112      Py_DECREF(Py_None);
2113  }
2114
2115  PyErr_Clear();
2116
2117  for(char * const *of = obsoleteFlags; *of; of++)
2118    if (hasFlag(keywords, *of))
2119      raiseWarning("flag '%s' is not supported any longer", *of);
2120
2121  int createNewOn = TVariable::Incompatible;
2122  if (hasFlag(keywords, "createNewOn"))
2123    convertFromPython(PyDict_GetItemString(keywords, "createNewOn"), createNewOn);
2124
2125  char *DK = NULL, *DC = NULL;
2126  if (!readUndefinedSpecs(keywords, DK, DC))
2127    return PYNULL;
2128
2129  char *errs = NULL;
2130  vector<int> status;
2131  vector<pair<int, int> > metaStatus;
2132  try {
2133    TExampleGenerator *generator =
2134      generatorOnly ? readGenerator(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"))
2135                    : readTable(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"));
2136    if (generator) {
2137      PyObject *pygen = WrapNewOrange(generator, type);
2138      PyObject *pystatus = encodeStatus(status);
2139      PyObject *pymetastatus = encodeStatus(metaStatus);
2140      Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", pystatus, false);
2141      Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", pymetastatus, false);
2142      Py_DECREF(pystatus);
2143      Py_DECREF(pymetastatus);
2144      return pygen;
2145    }
2146  }
2147  catch (mlexception err) {
2148    errs = strdup(err.what());
2149  }
2150
2151  res = loadDataByPython(type, filename, argstuple, keywords, true, pythonFileFound);
2152  if (res)
2153    return res;
2154
2155  if (pythonFileFound) {
2156    PYERROR(PyExc_SystemError, "cannot load the file", PYNULL);
2157  }
2158  else {
2159    PyErr_SetString(PyExc_SystemError, errs);
2160    free(errs);
2161    return PYNULL;
2162  }
2163}
2164
2165PyObject *loadDataFromFilePath(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly, const char *path)
2166{
2167  if (!path) {
2168    return NULL;
2169  }
2170
2171  #if defined _WIN32
2172  const char sep = ';';
2173  const char pathsep = '\\';
2174  #else
2175  const char sep = ':';
2176  const char pathsep = '/';
2177  #endif
2178  const int flen = strlen(filename);
2179
2180  for(const char *pi = path, *pe=pi; *pi; pi = pe+1) {
2181    for(pe = pi; *pe && *pe != sep; pe++);
2182    const int plen = pe-pi;
2183    char *npath = new char[plen + flen + 2];
2184    strncpy(npath, pi, pe - pi);
2185    if (!plen || (pi[plen] != pathsep)) {
2186      npath[plen] = pathsep;
2187      strcpy(npath+plen+1, filename);
2188    }
2189    else {
2190      strcpy(npath+plen, filename);
2191    }
2192    PyObject *res = loadDataFromFileNoSearch(type, npath, argstuple, keywords, generatorOnly);
2193    delete[] npath;
2194
2195    PyErr_Clear();
2196    if (res) {
2197      return res;
2198    }
2199    if (!*pe)
2200      break;
2201  }
2202
2203  return NULL;
2204}
2205
2206PyObject *loadDataFromFile(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2207{
2208  PyObject *ptype, *pvalue, *ptraceback;
2209  PyObject *res;
2210
2211  res = loadDataFromFileNoSearch(type, filename, argstuple, keywords, generatorOnly);
2212  if (res) {
2213    return res;
2214  }
2215
2216  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
2217
2218  // Try to find the file in the doc/datasets directory
2219  PyObject *configurationModule = PyImport_ImportModule("orngConfiguration");
2220  if (configurationModule) {
2221    PyObject *datasetsPath = PyDict_GetItemString(PyModule_GetDict(configurationModule), "datasetsPath");
2222    if (datasetsPath)
2223      res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, PyString_AsString(datasetsPath));
2224    Py_DECREF(configurationModule);
2225  }
2226  else {
2227    PyErr_Clear();
2228  }
2229
2230  if (!res) {
2231      // Try fo find the file using Orange.data.io.find_file
2232      PyObject *ioModule = PyImport_ImportModule("Orange.data.io");
2233      if (ioModule) {
2234          PyObject *find_file = PyObject_GetAttrString(ioModule, "find_file");
2235          if (find_file){
2236              PyObject *py_args = Py_BuildValue("(s)", filename);
2237              PyObject *ex_filename = PyObject_Call(find_file, py_args, NULL);
2238              if (ex_filename && PyString_Check(ex_filename)){
2239                  res = loadDataFromFileNoSearch(type, PyString_AsString(ex_filename), argstuple, keywords, generatorOnly);
2240                  Py_DECREF(ex_filename);
2241              }
2242              PyErr_Clear();
2243              Py_DECREF(py_args);
2244              Py_DECREF(find_file);
2245          }
2246          Py_DECREF(ioModule);
2247      }
2248  }
2249  if (!res)
2250      PyErr_Clear();
2251
2252  if (!res) {
2253    res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, getenv("ORANGE_DATA_PATH"));
2254  }
2255
2256  if (res) {
2257    Py_XDECREF(ptype);
2258    Py_XDECREF(pvalue);
2259    Py_XDECREF(ptraceback);
2260    return res;
2261  }
2262
2263  PyErr_Restore(ptype, pvalue, ptraceback);
2264  return PYNULL;
2265}
2266
2267
2268int pt_ExampleGenerator(PyObject *args, void *egen)
2269{
2270  *(PExampleGenerator *)(egen) = PyOrExampleGenerator_Check(args) ? PyOrange_AsExampleGenerator(args)
2271                                                                  : PExampleGenerator(readListOfExamples(args));
2272
2273  if (!*(PExampleGenerator *)(egen))
2274    PYERROR(PyExc_TypeError, "invalid example generator", 0)
2275  else
2276    return 1;
2277}
2278
2279
2280static PDomain ptd_domain;
2281
2282int ptdf_ExampleGenerator(PyObject *args, void *egen)
2283{
2284  egen = NULL;
2285
2286  try {
2287    if (PyOrExampleGenerator_Check(args)) {
2288      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
2289      if (gen->domain == ptd_domain)
2290        *(PExampleGenerator *)(egen) = gen;
2291      else
2292        *(PExampleGenerator *)(egen) = mlnew TExampleTable(ptd_domain, gen);
2293    }
2294    else
2295      *(PExampleGenerator *)(egen) = PExampleGenerator(readListOfExamples(args, ptd_domain));
2296
2297    ptd_domain = PDomain();
2298
2299    if (!*(PExampleGenerator *)(egen))
2300      PYERROR(PyExc_TypeError, "invalid example generator", 0)
2301    else
2302      return 1;
2303  }
2304
2305  catch (...) {
2306    ptd_domain = PDomain();
2307    throw;
2308  }
2309}
2310
2311
2312converter ptd_ExampleGenerator(PDomain domain)
2313{
2314  ptd_domain = domain;
2315  return ptdf_ExampleGenerator;
2316}
2317
2318
2319CONSTRUCTOR_KEYWORDS(ExampleGenerator, "domain use useMetas dontCheckStored dontStore filterMetas DC DK NA noClass noCodedDiscrete")
2320
2321// Class ExampleGenerator is abstract in C++; this constructor returns the derived classes
2322
2323NO_PICKLE(ExampleGenerator)
2324
2325PyObject *ExampleGenerator_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(Orange, "(filename)")
2326{
2327  PyTRY
2328    char *filename = NULL;
2329    if (PyArg_ParseTuple(argstuple, "s", &filename))
2330      return loadDataFromFile(type, filename, argstuple, keywords, true);
2331    else
2332      return PYNULL;
2333  PyCATCH;
2334}
2335
2336
2337PExampleGenerator exampleGenFromParsedArgs(PyObject *args)
2338{
2339 if (PyOrOrange_Check(args)) {
2340   if (PyOrExampleGenerator_Check(args))
2341      return PyOrange_AsExampleGenerator(args);
2342    else
2343      PYERROR(PyExc_TypeError, "example generator expected", NULL);
2344  }
2345  return PExampleGenerator(readListOfExamples(args));
2346}
2347
2348
2349PExampleGenerator exampleGenFromArgs(PyObject *args, int &weightID)
2350{
2351  PyObject *examples, *pyweight = NULL;
2352  if (!PyArg_UnpackTuple(args, "exampleGenFromArgs", 1, 2, &examples, &pyweight))
2353    return PExampleGenerator();
2354
2355  PExampleGenerator egen = exampleGenFromParsedArgs(examples);
2356  if (!egen || !weightFromArg_byDomain(pyweight, egen->domain, weightID))
2357    return PExampleGenerator();
2358
2359  return egen;
2360}
2361
2362
2363PExampleGenerator exampleGenFromArgs(PyObject *args)
2364{
2365  if (PyTuple_GET_SIZE(args) != 1)
2366    PYERROR(PyExc_TypeError, "exampleGenFromArgs: examples expected", PExampleGenerator())
2367
2368  return exampleGenFromParsedArgs(PyTuple_GET_ITEM(args, 0));
2369}
2370
2371
2372PyObject *ExampleGenerator_native(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
2373{ PyTRY
2374    bool tuples = false;
2375    PyObject *forDC = NULL;
2376    PyObject *forDK = NULL;
2377    PyObject *forSpecial = NULL;
2378    if (keyws) {
2379      PyObject *pytuples = PyDict_GetItemString(keyws, "tuple");
2380      tuples = pytuples && (PyObject_IsTrue(pytuples) != 0);
2381
2382      forDC = PyDict_GetItemString(keyws, "substitute_DC");
2383      if (!forDC) {
2384          forDC = PyDict_GetItemString(keyws, "substituteDC");
2385      }
2386      forDC = PyDict_GetItemString(keyws, "substitute_DK");
2387      if (!forDC) {
2388          forDC = PyDict_GetItemString(keyws, "substituteDK");
2389      }
2390      forDC = PyDict_GetItemString(keyws, "substitute_other");
2391      if (!forDC) {
2392          forDC = PyDict_GetItemString(keyws, "substituteOther");
2393      }
2394    }
2395
2396    int natvt=2;
2397    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=2)))
2398      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2399    CAST_TO(TExampleGenerator, eg);
2400
2401    PyObject *list=PyList_New(0);
2402    EITERATE(ei, *eg)
2403      if (natvt<=1) {
2404        PyObject *obj=convertToPythonNative(*ei, natvt, tuples, forDK, forDC, forSpecial);
2405        PyList_Append(list, obj);
2406        Py_DECREF(obj);
2407      }
2408        // What happens with: convertToPythonNative((*ei, natvt, tuples))? Funny.
2409      else {
2410        PyObject *example=Example_FromExampleCopyRef(*ei);
2411        if (!example) {
2412          PyMem_DEL(list);
2413          PYERROR(PyExc_SystemError, "out of memory", PYNULL);
2414        }
2415        PyList_Append(list, example);
2416        Py_DECREF(example);
2417      }
2418
2419    return list;
2420  PyCATCH
2421}
2422
2423
2424PVariableFilterMap PVariableFilterMap_FromArguments(PyObject *arg);
2425
2426int VariableFilterMap_setitemlow(TVariableFilterMap *aMap, PVariable var, PyObject *pyvalue);
2427
2428inline PVariableFilterMap sameValuesMap(PyObject *dict, PDomain dom)
2429{ TVariableFilterMap *vfm = mlnew TVariableFilterMap;
2430  PVariableFilterMap wvfm = vfm;
2431
2432  Py_ssize_t pos=0;
2433  PyObject *pykey, *pyvalue;
2434  while (PyDict_Next(dict, &pos, &pykey, &pyvalue)) {
2435    PVariable var = varFromArg_byDomain(pykey, dom, true);
2436    if (!var || (VariableFilterMap_setitemlow(vfm, var, pyvalue) < 0))
2437      return PVariableFilterMap();
2438  }
2439
2440  return wvfm;
2441}
2442
2443inline PPreprocessor pp_sameValues(PyObject *dict, PDomain dom)
2444{ PVariableFilterMap vfm = sameValuesMap(dict, dom);
2445  return vfm ? mlnew TPreprocessor_take(vfm) : PPreprocessor();
2446}
2447
2448inline PFilter filter_sameValues(PyObject *dict, PDomain domain, PyObject *kwds = PYNULL)
2449{ PVariableFilterMap svm = sameValuesMap(dict, domain);
2450  if (!svm)
2451    return PFilter();
2452
2453  PyObject *pyneg = kwds ? PyDict_GetItemString(kwds, "negate") : NULL;
2454  return TPreprocessor_take::constructFilter(svm, domain, true, pyneg && PyObject_IsTrue(pyneg));
2455}
2456
2457PyObject *applyPreprocessor(PPreprocessor preprocessor, PExampleGenerator gen, bool weightGiven, int weightID)
2458{ if (!preprocessor)
2459    return PYNULL;
2460
2461  int newWeight;
2462  PExampleGenerator newGen = preprocessor->call(gen, weightID, newWeight);
2463  return weightGiven ? Py_BuildValue("Ni", WrapOrange(newGen), newWeight) : WrapOrange(newGen);
2464}
2465
2466
2467
2468PyObject *applyFilter(PFilter filter, PExampleGenerator gen, bool weightGiven, int weightID);
2469
2470PyObject *ExampleGenerator_select(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
2471/* This function is a spaghetti for compatibility reasons. Most of its functionality
2472   has been moved to specialized functions (changeDomain, filter). The only two
2473   functions that 'select' should be used for is selection of examples by vector
2474   of bools or indices (LongList) */
2475{
2476  PyTRY
2477    CAST_TO(TExampleGenerator, eg);
2478    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2479
2480    /* ***** SELECTION BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
2481    /* Deprecated: use method 'filter' instead */
2482    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2483      return applyPreprocessor(pp_sameValues(keywords, eg->domain), weg, false, 0);
2484    }
2485
2486
2487    PyObject *mplier;
2488    PyObject *pyweight = NULL;
2489    if (PyArg_ParseTuple(args, "O|O", &mplier, &pyweight)) {
2490      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
2491      bool negate = pyneg && PyObject_IsTrue(pyneg);
2492      bool secondArgGiven = (pyweight != NULL);
2493
2494      /* ***** SELECTION BY VECTOR OF BOOLS ****** */
2495      if (PyList_Check(mplier) && PyList_Size(mplier) && PyInt_Check(PyList_GetItem(mplier, 0))) {
2496        Py_ssize_t nole = PyList_Size(mplier);
2497
2498        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2499        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2500        Py_ssize_t i = 0;
2501
2502        if (secondArgGiven) {
2503          if (PyInt_Check(pyweight)) {
2504            int compVal = (int)PyInt_AsLong(pyweight);
2505            TExampleIterator ei = eg->begin();
2506            for(; ei && (i<nole); ++ei) {
2507              PyObject *lel = PyList_GetItem(mplier, i++);
2508              if (!PyInt_Check(lel))
2509                break;
2510
2511              if (negate != (PyInt_AsLong(lel)==compVal))
2512                newTable->addExample(*ei);
2513            }
2514
2515            if ((i==nole) && !ei)
2516              return WrapOrange(newGen);
2517          }
2518        }
2519        else {
2520          TExampleIterator ei = eg->begin();
2521          for(; ei && (i<nole); ++ei) {
2522            PyObject *lel = PyList_GetItem(mplier, i++);
2523            if (negate != (PyObject_IsTrue(lel) != 0))
2524              newTable->addExample(*ei);
2525          }
2526
2527          if ((i==nole) && !ei)
2528            return WrapOrange(newGen);
2529        }
2530      }
2531
2532      PyErr_Clear();
2533
2534
2535      /* ***** SELECTION BY LONGLIST ****** */
2536      if (PyOrLongList_Check(mplier)) {
2537        PLongList llist = PyOrange_AsLongList(mplier);
2538        TLongList::iterator lli(llist->begin()), lle(llist->end());
2539
2540        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2541        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2542
2543        TExampleIterator ei = eg->begin();
2544
2545        if (secondArgGiven) {
2546          if (!PyInt_Check(pyweight))
2547            PYERROR(PyExc_AttributeError, "example selector must be an integer", PYNULL);
2548
2549          int compVal = (int)PyInt_AsLong(pyweight);
2550          for(; ei && (lli!=lle); ++ei, lli++)
2551            if (negate != (*lli==compVal))
2552              newTable->addExample(*ei);
2553        }
2554        else {
2555          for(; ei && (lli != lle); ++ei, lli++)
2556            if (negate != (*lli != 0))
2557              newTable->addExample(*ei);
2558        }
2559
2560        if ((lli==lle) && !ei)
2561          return WrapOrange(newGen);
2562
2563        PYERROR(PyExc_IndexError, "ExampleGenerator.select: invalid list size", PYNULL)
2564      }
2565
2566      PyErr_Clear();
2567
2568      /* ***** CHANGING DOMAIN ***** */
2569      /* Deprecated: use method 'translate' instead. */
2570      if (PyOrDomain_Check(mplier)) {
2571        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(PyOrange_AsDomain(mplier), weg)));
2572        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2573      }
2574
2575
2576      /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2577      /* Deprecated: use method 'translate' instead. */
2578      TVarList attributes;
2579      if (varListFromDomain(mplier, eg->domain, attributes, true, false)) {
2580        PDomain newDomain;
2581        TVarList::iterator vi, ve;
2582        for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2583        if (vi==ve)
2584          newDomain = mlnew TDomain(PVariable(), attributes);
2585        else {
2586          attributes.erase(vi);
2587          newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2588        }
2589
2590        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2591        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2592      }
2593
2594      PyErr_Clear();
2595
2596
2597      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
2598      /* Deprecated: use method 'filter' instead. */
2599      if (PyDict_Check(mplier)) {
2600        int weightID;
2601        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2602          return applyFilter(filter_sameValues(mplier, eg->domain), weg, secondArgGiven, weightID);
2603      }
2604
2605
2606      /* ***** PREPROCESSING ***** */
2607      /* Deprecated: call preprocessor instead. */
2608      if (PyOrPreprocessor_Check(mplier)) {
2609        int weightID;
2610        if (weightFromArg_byDomain(pyweight, eg->domain, weightID)) {
2611
2612          PExampleGenerator res;
2613          int newWeight;
2614          PyTRY
2615            NAME_CAST_TO(TPreprocessor, mplier, pp);
2616            if (!pp)
2617              PYERROR(PyExc_TypeError, "invalid object type (preprocessor announced, but not passed)", PYNULL)
2618            res = (*pp)(weg, weightID, newWeight);
2619          PyCATCH
2620
2621          return secondArgGiven ? Py_BuildValue("Ni", WrapOrange(res), newWeight) : WrapOrange(res);
2622        }
2623      }
2624
2625      /* ***** APPLY FILTER ***** */
2626      /* Deprecated: use method 'filter' instead. */
2627      if (PyOrFilter_Check(mplier)) {
2628        int weightID;
2629        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2630          return applyFilter(PyOrange_AsFilter(mplier), weg, secondArgGiven, weightID);
2631      }
2632    }
2633    PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2634  PyCATCH
2635}
2636
2637
2638PyObject *ExampleGenerator_filter(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
2639{
2640  PyTRY
2641    CAST_TO(TExampleGenerator, eg);
2642    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2643
2644    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2645      return applyFilter(filter_sameValues(keywords, eg->domain, keywords), weg, false, 0);
2646    }
2647
2648    if (PyTuple_Size(args)==1) {
2649      PyObject *arg = PyTuple_GET_ITEM(args, 0);
2650
2651      if (PyDict_Check(arg))
2652        return applyFilter(filter_sameValues(arg, eg->domain, keywords), weg, false, 0);
2653
2654      if (PyOrFilter_Check(arg))
2655          return applyFilter(PyOrange_AsFilter(arg), weg, false, 0);
2656    }
2657
2658    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter expects a list of conditions or orange.Filter", PYNULL)
2659  PyCATCH
2660}
2661
2662
2663PyObject *ExampleGenerator_translate(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "translate(domain | list-of-attributes) -> ExampleTable")
2664{
2665  PyTRY
2666    CAST_TO(TExampleGenerator, eg);
2667    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2668
2669    PDomain domain;
2670    if (PyArg_ParseTuple(args, "O&|i", cc_Domain, &domain))
2671      return WrapOrange(PExampleTable(mlnew TExampleTable(domain, weg)));
2672
2673    PyObject *pargs, *guard = NULL;
2674    int keepMeta = 0;
2675    if (args && ((PyTuple_Size(args)==1) || ((PyTuple_Size(args)==2) && PyInt_Check(PyTuple_GET_ITEM(args, 1))))) {
2676      pargs = guard = PyTuple_GET_ITEM(args, 0);
2677      if (PyTuple_Size(args)==2) {
2678        keepMeta = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
2679      }
2680    }
2681    else
2682      pargs = args;
2683
2684    /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2685    TVarList attributes;
2686    if (varListFromDomain(pargs, eg->domain, attributes, true, false)) {
2687      PDomain newDomain;
2688      TVarList::iterator vi, ve;
2689      for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2690      if (vi==ve)
2691        newDomain = mlnew TDomain(PVariable(), attributes);
2692      else {
2693        attributes.erase(vi);
2694        newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2695      }
2696     
2697      if (keepMeta) {
2698        newDomain->metas = eg->domain->metas;
2699      }
2700
2701      Py_XDECREF(guard);
2702      return WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2703    }
2704
2705    PYERROR(PyExc_AttributeError, "ExampleGenerator.translate expects a list of attributes or orange.Domain", PYNULL)
2706 PyCATCH
2707}
2708
2709
2710PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference)
2711{ PyTRY
2712    if (!PyList_Check(pylist))
2713      PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2714
2715    vector<int> indices;
2716    Py_ssize_t i, sze = PyList_Size(pylist);
2717    for(i = 0; i<sze; i++) {
2718      PyObject *lel = PyList_GetItem(pylist, i);
2719      if (!PyInt_Check(lel))
2720        PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2721      indices.push_back(int(PyInt_AsLong(lel)));
2722    }
2723    sort(indices.begin(), indices.end());
2724
2725    CAST_TO(TExampleGenerator, eg);
2726    TExampleTable *newTable = reference ? mlnew TExampleTable(eg, (int)0)
2727                                        : mlnew TExampleTable(eg->domain);
2728    PExampleGenerator newGen(newTable);
2729
2730    TExampleGenerator::iterator ei(eg->begin());
2731    vector<int>::iterator ii(indices.begin()), iie(indices.end());
2732    i = 0;
2733    while(ei && (ii!=iie)) {
2734      if (*ii == i) {
2735        newTable->addExample(*ei);
2736        ii++;
2737      }
2738      else {
2739        i++;
2740        ++ei;
2741      }
2742    }
2743
2744    if (ii!=iie)
2745      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
2746
2747    return WrapOrange(newGen);
2748  PyCATCH
2749}
2750
2751
2752PyObject *ExampleGenerator_get_items(TPyOrange *self, PyObject *pylist)  PYARGS(METH_O, "(indices) -> ExampleTable")
2753{ return multipleSelectLow(self, pylist, false); }
2754
2755
2756PyObject *ExampleGenerator_checksum(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
2757{ PyTRY
2758    return PyInt_FromLong(SELF_AS(TExampleGenerator).checkSum());
2759  PyCATCH
2760}
2761
2762
2763const char *getExtension(const char *name);
2764char *getFileSystemEncoding(); // defined in lib_io.cpp
2765
2766PyObject *saveTabDelimited(PyObject *, PyObject *args, PyObject *keyws);
2767PyObject *saveC45(PyObject *, PyObject *args);
2768PyObject *saveTxt(PyObject *, PyObject *args, PyObject *keyws);
2769PyObject *saveCsv(PyObject *, PyObject *args, PyObject *keyws);
2770PyObject *saveBasket(PyObject *, PyObject *args);
2771
2772PyObject *ExampleGenerator_save(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "(filename) -> None")
2773{
2774  char *filename;
2775  bool free_filename = false;
2776  if (!PyArg_ParseTuple(args, "s:ExampleGenerator.save", &filename))
2777  {
2778      // Try again, this time with the fs encoding.
2779      char *encoding = getFileSystemEncoding();
2780      if (!PyArg_ParseTuple(args, "es:ExampleGenerator.save", encoding, &filename))
2781          return PYNULL;
2782      free_filename = true;
2783      PyErr_Clear();
2784  }
2785
2786  const char *extension = getExtension(filename);
2787  if (!extension)
2788  {
2789    if (free_filename)
2790        PyMem_Free(filename);
2791    PYERROR(PyExc_TypeError, "file name must have an extension", PYNULL);
2792  }
2793
2794
2795  PyObject *newargs = PyTuple_New(PyTuple_Size(args) + 1);
2796  PyObject *el;
2797
2798  el = PyTuple_GET_ITEM(args, 0);
2799  Py_INCREF(el);
2800  PyTuple_SetItem(newargs, 0, el);
2801
2802  Py_INCREF(self);
2803  PyTuple_SetItem(newargs, 1, self);
2804
2805  for(Py_ssize_t i = 1, e = PyTuple_Size(args); i < e; i++) {
2806    el = PyTuple_GET_ITEM(args, i);
2807    Py_INCREF(el);
2808    PyTuple_SetItem(newargs, i+1, el);
2809  }
2810
2811  PyObject *res = PYNULL;
2812
2813  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, false, true, false);
2814  if (fi != filetypeDefinitions.end())
2815    res = PyObject_Call((*fi).saver, newargs, keyws);
2816  else if (!strcmp(extension, ".tab"))
2817    res = saveTabDelimited(NULL, newargs, keyws);
2818  else if (!strcmp(extension, ".txt"))
2819    res = saveTxt(NULL, newargs, keyws);
2820  else if (!strcmp(extension, ".csv"))
2821    res = saveCsv(NULL, newargs, keyws);
2822  else if (!strcmp(extension, ".names") || !strcmp(extension, ".data") || !strcmp(extension, ".test"))
2823    res = saveC45(NULL, newargs);
2824  else if (!strcmp(extension, ".basket"))
2825    res = saveBasket(NULL, newargs);
2826  else
2827    PyErr_Format(PyExc_AttributeError, "unknown file format (%s)", extension);
2828
2829  Py_DECREF(newargs);
2830
2831  if (free_filename)
2832      PyMem_Free(filename);
2833
2834  return res;
2835}
2836
2837
2838PyObject *ExampleGenerator_weight(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(weightID)")
2839{
2840  PyObject *pyw = PYNULL;
2841  if (!PyArg_ParseTuple(args, "|O:ExampleGenerator.weight", &pyw))
2842    return PYNULL;
2843
2844  CAST_TO(TExampleGenerator, egen)
2845  if (!pyw)
2846    return PyInt_FromLong(egen->numberOfExamples());
2847
2848  int weightID;
2849  if (!varNumFromVarDom(pyw, egen->domain, weightID))
2850    return PYNULL;
2851
2852  float weight = 0.0;
2853  PEITERATE(ei, egen)
2854    weight += WEIGHT(*ei);
2855
2856  return PyFloat_FromDouble(weight);
2857}
2858
2859
2860PExampleGeneratorList PExampleGeneratorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::P_FromArguments(arg); }
2861PyObject *ExampleGeneratorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_FromArguments(type, arg); }
2862PyObject *ExampleGeneratorList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of ExampleGenerator>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_new(type, arg, kwds); }
2863PyObject *ExampleGeneratorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getitem(self, index); }
2864int       ExampleGeneratorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setitem(self, index, item); }
2865PyObject *ExampleGeneratorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getslice(self, start, stop); }
2866int       ExampleGeneratorList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setslice(self, start, stop, item); }
2867Py_ssize_t       ExampleGeneratorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_len(self); }
2868PyObject *ExampleGeneratorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_richcmp(self, object, op); }
2869PyObject *ExampleGeneratorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_concat(self, obj); }
2870PyObject *ExampleGeneratorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_repeat(self, times); }
2871PyObject *ExampleGeneratorList_str(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2872PyObject *ExampleGeneratorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2873int       ExampleGeneratorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_contains(self, obj); }
2874PyObject *ExampleGeneratorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_append(self, item); }
2875PyObject *ExampleGeneratorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_extend(self, obj); }
2876PyObject *ExampleGeneratorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_count(self, obj); }
2877PyObject *ExampleGeneratorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ExampleGeneratorList") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_filter(self, args); }
2878PyObject *ExampleGeneratorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_index(self, obj); }
2879PyObject *ExampleGeneratorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_insert(self, args); }
2880PyObject *ExampleGeneratorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_native(self); }
2881PyObject *ExampleGeneratorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ExampleGenerator") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_pop(self, args); }
2882PyObject *ExampleGeneratorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_remove(self, obj); }
2883PyObject *ExampleGeneratorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reverse(self); }
2884PyObject *ExampleGeneratorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_sort(self, args); }
2885PyObject *ExampleGeneratorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reduce(self); }
2886
2887
2888/* ************ EXAMPLE TABLE ************ */
2889
2890#include "table.hpp"
2891#include "numeric_interface.hpp"
2892
2893TExampleTable *readListOfExamples(PyObject *args)
2894{
2895    if (isSomeNumeric_wPrecheck(args))
2896      return readListOfExamples(args, PDomain(), false);
2897
2898
2899  if (PySequence_Check(args)) {
2900    Py_ssize_t size=PySequence_Size(args);
2901    if (!size)
2902      PYERROR(PyExc_TypeError, "can't construct a table from an empty sequence", (TExampleTable *)NULL);
2903
2904    TExampleTable *table=NULL;
2905    PyObject *pex = NULL;
2906
2907    try {
2908      for(Py_ssize_t i=0; i<size; i++) {
2909        PyObject *pex = PySequence_GetItem(args, i);
2910        if (!pex || !PyOrExample_Check(pex)) {
2911          Py_XDECREF(pex);
2912          mldelete table;
2913          PyErr_Format(PyExc_TypeError, "invalid sequence element at %i", i);
2914          return NULL;
2915        }
2916        if (!i)
2917          table = mlnew TExampleTable(PyExample_AS_Example(pex)->domain);
2918        table->addExample(PyExample_AS_ExampleReference(pex));
2919        Py_DECREF(pex);
2920        pex = NULL;
2921      }
2922    }
2923    catch (...) {
2924      delete table;
2925      Py_XDECREF(pex);
2926      throw;
2927    }
2928
2929    return table;
2930  }
2931
2932  PYERROR(PyExc_TypeError, "a list of examples expected", NULL);
2933}
2934
2935
2936TExampleTable *readListOfExamples(PyObject *args, PDomain domain, bool filterMetas)
2937{
2938  PyArrayObject *array = NULL, *mask = NULL;
2939
2940  if (isSomeNumeric_wPrecheck(args)) {
2941    array = (PyArrayObject *)(args);
2942  }
2943  else if (isSomeMaskedNumeric_wPrecheck(args)) {
2944    array = (PyArrayObject *)(args);
2945    mask = (PyArrayObject *)PyObject_GetAttrString(args, "mask");
2946    if (!mask) {
2947        PyErr_Clear();
2948    }
2949    else if (!isSomeNumeric_wPrecheck((PyObject *)mask)) {
2950      Py_DECREF((PyObject *)mask);
2951      mask = NULL;
2952    }
2953  }
2954
2955  if (array) {
2956      if (array->nd != 2)
2957        PYERROR(PyExc_AttributeError, "two-dimensional array expected for an ExampleTable", NULL);
2958
2959      PVarList variables;
2960      TVarList::const_iterator vi;
2961
2962      if (!domain) {
2963        TVarList lvariables;
2964        char vbuf[20];
2965        for(int i = 0, e = array->dimensions[1]; i < e; i++) {
2966          sprintf(vbuf, "a%i", i+1);
2967          lvariables.push_back(mlnew TFloatVariable(vbuf));
2968        }
2969        domain = mlnew TDomain(PVariable(), lvariables);
2970        variables = domain->variables;
2971      }
2972
2973      else {
2974          int const nvars = domain->variables->size() + domain->classVars->size();
2975          if (array->dimensions[1] != nvars) {
2976              PyErr_Format(PyExc_AttributeError,
2977                  "the number of columns (%i) in the array doesn't match the number of attributes (%i)",
2978                  array->dimensions[1], nvars);
2979              return NULL;
2980          }
2981
2982       variables = domain->variables;
2983       for(vi = variables->begin(); vi!=variables->end(); vi++)
2984          if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
2985              PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
2986       
2987       for(vi = domain->classVars->begin(); vi!=domain->classVars->end(); vi++) 
2988          if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
2989              PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
2990      }
2991
2992      const char arrayType = getArrayType(array);
2993      if (!strchr(supportedNumericTypes, arrayType)) {
2994        PyErr_Format(PyExc_AttributeError, "Converting arrays of type '%c' is not supported (use one of '%s')", arrayType, supportedNumericTypes);
2995        return NULL;
2996      }
2997
2998      TExampleTable *table = mlnew TExampleTable(domain);
2999      TExample *nex = NULL;
3000      table->reserve(array->dimensions[0]);
3001
3002      const int &strideRow = array->strides[0];
3003      const int &strideCol = array->strides[1];
3004
3005      // If there's no mask, the mask pointers will equal the data pointer to avoid too many if's
3006      const int &strideMaskRow = mask ? mask->strides[0] : strideRow;
3007      const int &strideMaskCol = mask ? mask->strides[1] : strideCol;
3008
3009      TVarList::const_iterator const vb(variables->begin());
3010      TVarList::const_iterator const ve(variables->end());
3011      TVarList::const_iterator const cb(domain->classVars->begin());
3012      TVarList::const_iterator const ce(domain->classVars->end());
3013
3014      try {
3015        TExample::iterator ei;
3016        char *rowPtr = array->data;
3017        char *maskRowPtr = mask ? mask->data : array->data;
3018
3019        for(int row = 0, rowe = array->dimensions[0]; row < rowe; row++, rowPtr += strideRow, maskRowPtr += strideMaskRow) {
3020          char *elPtr = rowPtr;
3021          char *maskPtr = maskRowPtr;
3022          TExample *nex = mlnew TExample(domain);
3023
3024          #define ARRAYTYPE(TYPE) \
3025            for(ei = nex->begin(), vi = vb; vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol) \
3026              if ((*vi)->varType == TValue::INTVAR) \
3027                intValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
3028              else \
3029                floatValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
3030            for(vi = cb; vi!=ce; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol) \
3031              if ((*vi)->varType == TValue::INTVAR) \
3032                intValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
3033              else \
3034                floatValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
3035            break;
3036
3037          switch (arrayType) {
3038            case 'c':
3039            case 'b': ARRAYTYPE(char)
3040            case 'B': ARRAYTYPE(unsigned char)
3041            case 'h': ARRAYTYPE(short)
3042            case 'H': ARRAYTYPE(unsigned short)
3043            case 'i': ARRAYTYPE(int)
3044            case 'I': ARRAYTYPE(unsigned int)
3045            case 'l': ARRAYTYPE(long)
3046            case 'L': ARRAYTYPE(unsigned long)
3047
3048            case 'f':
3049              for(ei = nex->begin(), vi = vb; vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
3050                if ((*vi)->varType == TValue::INTVAR)
3051                  intValInit(*ei, int(floor(0.5 + *(float *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
3052                else
3053                  floatValInit(*ei, *(float *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
3054              for(vi = cb; vi!=ce; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
3055                if ((*vi)->varType == TValue::INTVAR)
3056                  intValInit(*ei, int(floor(0.5 + *(float *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
3057                else
3058                  floatValInit(*ei, *(float *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
3059              break;
3060
3061            case 'd':
3062              for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
3063                if ((*vi)->varType == TValue::INTVAR)
3064                  intValInit(*ei, int(floor(0.5 + *(double *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
3065                else
3066                  floatValInit(*ei, *(double *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
3067              for(vi = cb; vi!=ce; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
3068                if ((*vi)->varType == TValue::INTVAR)
3069                  intValInit(*ei, int(floor(0.5 + *(double *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
3070                else
3071                  floatValInit(*ei, *(double *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
3072              break;
3073
3074          }
3075
3076          #undef ARRAYTYPE
3077
3078          table->addExample(nex);
3079          nex = NULL;
3080        }
3081      }
3082      catch (...) {
3083        mldelete table;
3084        mldelete nex;
3085        throw;
3086      }
3087
3088      return table;
3089  }
3090
3091  if (PyList_Check(args)) {
3092    Py_ssize_t size=PyList_Size(args);
3093    if (!size)
3094      PYERROR(PyExc_TypeError, "can't construct a table from an empty list", (TExampleTable *)NULL);
3095
3096    TExampleTable *table = mlnew TExampleTable(domain);;
3097
3098    try {
3099      for(Py_ssize_t i=0; i<size; i++) {
3100        PyObject *pex = PyList_GetItem(args, i);
3101        if (PyOrExample_Check(pex))
3102          table->addExample(PyExample_AS_ExampleReference(pex), filterMetas);
3103        else {
3104          TExample example(domain);
3105          if (!convertFromPythonExisting(pex, example)) {
3106            mldelete table;
3107            PyObject *type, *value, *tracebk;
3108            PyErr_Fetch(&type, &value, &tracebk);
3109            if (type) {
3110              //PyErr_Restore(type, value, tracebk);
3111              const char *oldes = PyString_AsString(value);
3112              PyErr_Format(type, "%s (at example %i)", oldes, i);
3113              Py_DECREF(type);
3114              Py_XDECREF(value);
3115              Py_XDECREF(tracebk);
3116              return NULL;
3117            }
3118          }
3119          table->addExample(example);
3120        }
3121      }
3122
3123      return table;
3124    }
3125    catch (...) {
3126      mldelete table;
3127      throw;
3128    }
3129  }
3130
3131  PYERROR(PyExc_TypeError, "invalid arguments", NULL);
3132}
3133
3134CONSTRUCTOR_KEYWORDS(ExampleTable, "domain use useMetas dontCheckStored dontStore filterMetas filter_metas DC DK NA noClass noCodedDiscrete createNewOn")
3135
3136PyObject *ExampleTable_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(ExampleGenerator - Orange.data.Table, "(filename | domain[, examples] | examples)")
3137{
3138  PyTRY
3139
3140    char *filename = NULL;
3141    if (PyArg_ParseTuple(argstuple, "s", &filename))
3142        return loadDataFromFile(type, filename, argstuple, keywords, false);
3143
3144    PyErr_Clear();
3145
3146    /*For a case where the unicode can't be converted to a default
3147     * encoding (on most platforms this is ASCII)
3148     */
3149    char * coding = getFileSystemEncoding();
3150    if (PyArg_ParseTuple(argstuple, "es", coding, &filename))
3151    {
3152        PyObject *rval = loadDataFromFile(type, filename, argstuple, keywords, false);
3153        PyMem_Free(filename);
3154        return rval;
3155    }
3156
3157    PyErr_Clear();
3158
3159    PExampleGenerator egen;
3160    PyObject *args = PYNULL;
3161    if (PyArg_ParseTuple(argstuple, "O&|O", cc_ExampleTable, &egen, &args))
3162      return WrapNewOrange(mlnew TExampleTable(egen, !args || (PyObject_IsTrue(args) == 0)), type);
3163
3164    PyErr_Clear();
3165
3166    if (PyArg_ParseTuple(argstuple, "O", &args)) {
3167      if (PyOrDomain_Check(args))
3168        return WrapNewOrange(mlnew TExampleTable(PyOrange_AsDomain(args)), type);
3169
3170      TExampleTable *res = readListOfExamples(args);
3171      if (res)
3172        return WrapNewOrange(res, type);
3173      PyErr_Clear();
3174
3175      // check if it's a list of generators
3176      if (PyList_Check(args)) {
3177        TExampleGeneratorList eglist;
3178        PyObject *iterator = PyObject_GetIter(args);
3179        PyObject *item = PyIter_Next(iterator);
3180        for(; item; item = PyIter_Next(iterator)) {
3181          if (!PyOrExampleGenerator_Check(item)) {
3182            Py_DECREF(item);
3183            break;
3184          }
3185          eglist.push_back(PyOrange_AsExampleGenerator(item));
3186          Py_DECREF(item);
3187        }
3188        Py_DECREF(iterator);
3189        if (!item)
3190          return WrapNewOrange(mlnew TExampleTable(PExampleGeneratorList(eglist)), type);
3191      }
3192
3193      PYERROR(PyExc_TypeError, "invalid arguments for constructor (domain or examples or both expected)", PYNULL);
3194    }
3195
3196    PyErr_Clear();
3197
3198    PDomain domain;
3199    if (PyArg_ParseTuple(argstuple, "O&O", cc_Domain, &domain, &args)) {
3200      bool filterMetas = readBoolFlag(keywords, "filterMetas") || readBoolFlag(keywords, "filter_metas");
3201
3202      if (PyOrExampleGenerator_Check(args))
3203        return WrapNewOrange(mlnew TExampleTable(domain, PyOrange_AsExampleGenerator(args), filterMetas), type);
3204      else {
3205        TExampleTable *res = readListOfExamples(args, domain, filterMetas);
3206        return res ? WrapNewOrange(res, type) : PYNULL;
3207      }
3208    }
3209
3210    PYERROR(PyExc_TypeError, "invalid arguments for ExampleTable.__init__", PYNULL);
3211
3212  PyCATCH
3213}
3214
3215
3216PyObject *ExampleTable__reduce__(PyObject *self)
3217{
3218  CAST_TO(TExampleTable, table)
3219
3220  if (!table->ownsExamples || table->lock) {
3221    PExampleTable lock = table->lock;
3222    TCharBuffer buf(1024);
3223    const int lockSize = lock->size();
3224    buf.writeInt(table->size());
3225    PEITERATE(ei, table) {
3226      int index = 0;
3227      PEITERATE(li, lock) {
3228        if (&*li == &*ei)
3229          break;
3230        index++;
3231      }
3232      if (index == lockSize) {
3233        PYERROR(PyExc_SystemError, "invalid example reference discovered in the table", PYNULL);
3234      }
3235
3236      buf.writeInt(index);
3237    }
3238
3239    return Py_BuildValue("O(ONs#)O", getExportedFunction("__pickleLoaderExampleReferenceTable"),
3240                                      self->ob_type,
3241                                      WrapOrange(table->lock),
3242                                      buf.buf, buf.length(),
3243                                      packOrangeDictionary(self));
3244  }
3245
3246  else {
3247    TCharBuffer buf(1024);
3248    PyObject *otherValues = NULL;
3249
3250    buf.writeInt(table->size());
3251    PEITERATE(ei, table)
3252      Example_pack(*ei, buf, otherValues);
3253
3254    if (!otherValues) {
3255      otherValues = Py_None;
3256      Py_INCREF(otherValues);
3257    }
3258
3259    return Py_BuildValue("O(ONs#N)O", getExportedFunction("__pickleLoaderExampleTable"),
3260                                      self->ob_type,
3261                                      WrapOrange(table->domain),
3262                                      buf.buf, buf.length(),
3263                                      otherValues,
3264                                      packOrangeDictionary(self));
3265  }
3266}
3267
3268
3269PyObject *__pickleLoaderExampleTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, domain, packed_values, other_values)")
3270{
3271  PyTRY
3272    PyTypeObject *type;
3273    PDomain domain;
3274    char *buf;
3275    int bufSize;
3276    PyObject *otherValues;
3277
3278    if (!PyArg_ParseTuple(args, "OO&s#O:__pickleLoaderExampleTable", &type, cc_Domain, &domain, &buf, &bufSize, &otherValues))
3279      return NULL;
3280
3281    TCharBuffer cbuf(buf);
3282    int otherValuesIndex = 0;
3283
3284    int noOfEx = cbuf.readInt();
3285    TExampleTable *newTable = new TExampleTable(domain);
3286    try {
3287      newTable->reserve(noOfEx);
3288      for(int i = noOfEx; i--;)
3289        Example_unpack(newTable->new_example(), cbuf, otherValues, otherValuesIndex);
3290
3291      return WrapNewOrange(newTable, type);
3292    }
3293    catch (...) {
3294      delete newTable;
3295      throw;
3296    }
3297  PyCATCH
3298}
3299
3300
3301PyObject *__pickleLoaderExampleReferenceTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, lockedtable, indices)")
3302{
3303  PyTRY
3304    PyTypeObject *type;
3305    PExampleTable table;
3306    char *buf;
3307    int bufSize;
3308
3309    if (!PyArg_ParseTuple(args, "OO&s#:__pickleLoaderExampleReferenceTable", &type, cc_ExampleTable, &table, &buf, &bufSize))
3310      return NULL;
3311
3312
3313    TCharBuffer cbuf(buf);
3314    int noOfEx = cbuf.readInt();
3315
3316    TExampleTable *newTable = new TExampleTable(table, 1);
3317    try {
3318      newTable->reserve(noOfEx);
3319      for(int i = noOfEx; i--;)
3320        newTable->addExample(table->at(cbuf.readInt()));
3321      return WrapNewOrange(newTable, type);
3322    }
3323    catch (...) {
3324      delete newTable;
3325      throw;
3326    }
3327  PyCATCH
3328}
3329
3330
3331#define EXAMPLE_LOCK(tab) (((tab)->ownsExamples || !(tab)->lock) ? PExampleGenerator(tab) : (tab)->lock)
3332
3333PyObject *ExampleTable_native(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
3334{ PyTRY
3335    int natvt=2;
3336    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=3)))
3337      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
3338
3339    if (natvt<2)
3340      return ExampleGenerator_native(self, args, keywords);
3341
3342    CAST_TO(TExampleTable, table);
3343
3344    PyObject *list=PyList_New(table->numberOfExamples());
3345    Py_ssize_t i=0;
3346    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3347    EITERATE(ei, *table) {
3348      // here we wrap a reference to example, so we must pass a self's wrapper
3349      PyObject *example = Example_FromExampleRef(*ei, lock);
3350      if (!example) {
3351        PyMem_DEL(list);
3352        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3353      }
3354      PyList_SetItem(list, i++, example);
3355    }
3356
3357    return list;
3358  PyCATCH
3359}
3360
3361/*
3362PyTypeObject *gsl_matrixType = NULL;
3363
3364bool load_gsl()
3365{
3366  if (gsl_matrixType)
3367    return true;
3368
3369  PyObject *matrixModule = PyImport_ImportModule("pygsl.matrix");
3370  if (!matrixModule)
3371    return false;
3372
3373  gsl_matrixType = (PyTypeObject *)PyDict_GetItemString(PyModule_GetDict(matrixModule), "matrix");
3374  return gsl_matrixType != NULL;
3375}
3376*/
3377
3378
3379/* Not in .hpp (to be parsed by pyprops) since these only occur in arguments to numpy conversion function */
3380
3381PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Ignore, 0)
3382PYCLASSCONSTANT_INT(ExampleTable, Multinomial_AsOrdinal, 1)
3383PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Error, 2)
3384
3385
3386
3387PyObject *packMatrixTuple(PyObject *X, PyObject *y, PyObject *my, PyObject *w, char *contents)
3388{
3389  int left = (*contents && *contents != '/') ? 1 : 0;
3390
3391  char *cp = strchr(contents, '/');
3392  if (cp)
3393    cp++;
3394
3395  int right = cp ? strlen(cp) : 0;
3396
3397  PyObject *res = PyTuple_New(left + right);
3398  if (left) {
3399    Py_INCREF(X);
3400    PyTuple_SetItem(res, 0, X);
3401  }
3402
3403  if (cp)
3404    for(; *cp; cp++)
3405      if ((*cp == 'c') || (*cp == 'C')) {
3406        Py_INCREF(y);
3407        PyTuple_SetItem(res, left++, y);
3408      }
3409      else if ((*cp == 'w') || (*cp == 'W')) {
3410        Py_INCREF(w);
3411        PyTuple_SetItem(res, left++, w);
3412      }
3413      else {
3414        Py_INCREF(my);
3415        PyTuple_SetItem(res, left++, my);
3416      }
3417
3418  Py_DECREF(X);
3419  Py_DECREF(y);
3420  Py_DECREF(my);
3421  Py_DECREF(w);
3422  return res;
3423}
3424
3425
3426void parseMatrixContents(PExampleGenerator egen, const int &weightID, const char *contents, const int &multiTreatment,
3427                         bool &hasClass, bool &classVector, bool &multiclassVector, bool &weightVector, bool &classIsDiscrete, int &columns,
3428                         vector<bool> &include);
3429
3430
3431inline bool storeNumPyValue(double *&p, const TValue &val, signed char *&m, const PVariable attr, const int &row)
3432{
3433  if (val.isSpecial()) {
3434    if (m) {
3435      *p++ = 0;
3436      *m++ = 1;
3437    }
3438    else {
3439      PyErr_Format(PyExc_TypeError, "value of attribute '%s' in example '%i' is undefined", attr->get_name().c_str(), row);
3440      return false;
3441    }
3442  }
3443
3444  else if (val.varType == TValue::FLOATVAR) {
3445    *p++ = val.floatV;
3446    if (m)
3447      *m++ = 0;
3448  }
3449
3450  else if (val.varType == TValue::INTVAR) {
3451    *p++ = float(val.intV);
3452    if (m)
3453      *m++ = 0;
3454  }
3455
3456  else {
3457    *p++ = ILLEGAL_FLOAT;
3458    if (m)
3459      *m++ = 1;
3460  }
3461
3462  return true;
3463}
3464
3465
3466PyObject *ExampleTable_toNumericOrMA(PyObject *self, PyObject *args, PyObject *keywords, PyObject **module, PyObject **maskedArray = NULL)
3467{
3468  PyTRY
3469    prepareNumeric();
3470    if (!*module || maskedArray && !*maskedArray)
3471      PYERROR(PyExc_ImportError, "cannot import the necessary numeric module for conversion", PYNULL);
3472
3473    // These references are all borrowed
3474    PyObject *moduleDict = PyModule_GetDict(*module);
3475      PyObject *mzeros = PyDict_GetItemString(moduleDict, "zeros");
3476      if (!mzeros)
3477        PYERROR(PyExc_AttributeError, "numeric module has no function 'zeros'", PYNULL);
3478
3479    char *contents = NULL;
3480    int weightID = 0;
3481    int multinomialTreatment = 1;
3482    if (!PyArg_ParseTuple(args, "|sii:ExampleTable.toNumeric", &contents, &weightID, &multinomialTreatment))
3483      return PYNULL;
3484
3485    if (!contents)
3486      contents = "a/cw";
3487
3488    PExampleGenerator egen = PyOrange_AsExampleGenerator(self);
3489
3490    bool hasClass, classVector, weightVector, multiclassVector, classIsDiscrete;
3491    vector<bool> include;
3492    int columns;
3493    parseMatrixContents(egen, weightID, contents, multinomialTreatment,
3494                            hasClass, classVector, multiclassVector, weightVector,
3495                            classIsDiscrete, columns, include);
3496
3497    int rows = egen->numberOfExamples();
3498    PVariable classVar = egen->domain->classVar;
3499
3500    PyObject *X, *y, *w, *my, *mask = NULL, *masky = NULL, *maskmy = NULL;
3501    double *Xp, *yp, *myp, *wp;
3502    signed char *mp = NULL, *mpy = NULL, *mpmy = NULL;
3503    X = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "d");
3504    if (!X)
3505        return PYNULL;
3506    Xp = columns ? (double *)((PyArrayObject *)X)->data : NULL;
3507    if (maskedArray) {
3508        mask = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "b");
3509        mp = (signed char *)((PyArrayObject *)mask)->data;
3510    }
3511
3512    if (classVector) {
3513      y = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3514      if (!y)
3515        return PYNULL;
3516      yp = (double *)((PyArrayObject *)y)->data;
3517
3518      if (maskedArray) {
3519        masky = PyObject_CallFunction(mzeros, "(i)s", rows, "b");
3520        mpy = (signed char *)((PyArrayObject *)masky)->data;
3521      }
3522    }
3523    else {
3524      y = Py_None;
3525      Py_INCREF(y);
3526      yp = NULL;
3527    }
3528
3529    if (multiclassVector) {
3530      my = PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "d");
3531      if (!my)
3532        return PYNULL;
3533      myp = (double *)((PyArrayObject *)my)->data;
3534
3535      if (maskedArray) {
3536        maskmy= PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "b");
3537        mpmy = (signed char *)((PyArrayObject *)maskmy)->data;
3538      }
3539    }
3540    else {
3541      my = Py_None;
3542      Py_INCREF(my);
3543      myp = NULL;
3544    }
3545
3546    if (weightVector) {
3547      w = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3548      if (!w)
3549        return PYNULL;
3550      wp = (double *)((PyArrayObject *)w)->data;
3551    }
3552    else {
3553      w = Py_None;
3554      Py_INCREF(w);
3555      wp = NULL;
3556    }
3557
3558    try {
3559      int row = 0;
3560      TExampleGenerator::iterator ei(egen->begin());
3561      for(; ei; ++ei, row++) {
3562        int col = 0;
3563
3564        /* This is all optimized assuming that each symbol (A, C, W) only appears once.
3565           If it would be common for them to appear more than once, we could cache the
3566           values, but since this is unlikely, caching would only slow down the conversion */
3567        for(const char *cp = contents; *cp && (*cp!='/'); cp++) {
3568          switch (*cp) {
3569            case 'A':
3570            case 'a': {
3571              const TVarList &attributes = egen->domain->attributes.getReference();
3572              TVarList::const_iterator vi(attributes.begin()), ve(attributes.end());
3573              TExample::iterator eei((*ei).begin());
3574              vector<bool>::const_iterator bi(include.begin());
3575              for(; vi != ve; eei++, vi++, bi++)
3576                if (*bi && !storeNumPyValue(Xp, *eei, mp, *vi, row))
3577                  return PYNULL;
3578              break;
3579            }
3580
3581            case 'C':
3582            case 'c':
3583              if (hasClass && !storeNumPyValue(Xp, (*ei).getClass(), mp, classVar, row))
3584                return PYNULL;
3585              break;
3586
3587            case 'M':
3588            case 'm': {
3589              const TVarList &classes = egen->domain->classVars.getReference();
3590              TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3591              TValue *eei = (*ei).values_end;
3592              for(; vi != ve; eei++, vi++)
3593                if (!storeNumPyValue(Xp, *eei, mp, *vi, row))
3594                  return PYNULL;
3595              break;
3596            }
3597
3598            case 'W':
3599            case 'w':
3600              if (weightID)
3601                *Xp++ = WEIGHT(*ei);
3602                if (maskedArray)
3603                  *mp++ = 0;
3604              break;
3605
3606            case '0':
3607              *Xp++ = 0.0;
3608              if (maskedArray)
3609                *mp++ = 0;
3610              break;
3611
3612            case '1':
3613              *Xp++ = 1.0;
3614              if (maskedArray)
3615                *mp++ = 0;
3616              break;
3617          }
3618        }
3619
3620        if (yp && !storeNumPyValue(yp, (*ei).getClass(), mpy, classVar, row))
3621          return PYNULL;
3622
3623        if (wp)
3624          *wp++ = WEIGHT(*ei);
3625
3626        if (myp) {
3627            const TVarList &classes = egen->domain->classVars.getReference();
3628            TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3629            TValue *eei = (*ei).values_end;
3630            for(; vi != ve; eei++, vi++)
3631              if (!storeNumPyValue(myp, *eei, mpmy, *vi, row))
3632                return PYNULL;
3633        }
3634      }
3635
3636      if (maskedArray) {
3637        PyObject *args, *maskedX = NULL, *maskedy = NULL, *maskedmy = NULL;
3638
3639        bool err = false;
3640
3641        if (mask) {
3642          args = Py_BuildValue("OOiOO", X, Py_None, 1, Py_None, mask);
3643          maskedX = PyObject_CallObject(*maskedArray, args);
3644          Py_DECREF(args);
3645          if (!maskedX) {
3646            PyErr_Clear();
3647            args = Py_BuildValue("OOOi", X, mask, Py_None, 1);
3648            maskedX = PyObject_CallObject(*maskedArray, args);
3649            Py_DECREF(args);
3650          }
3651          err = !maskedX;
3652        }
3653
3654        if (!err && masky) {
3655          args = Py_BuildValue("OOiOO", y, Py_None, 1, Py_None, masky);
3656          maskedy = PyObject_CallObject(*maskedArray, args);
3657          Py_DECREF(args);
3658          if (!maskedy) {
3659            PyErr_Clear();
3660            args = Py_BuildValue("OOOi", y, masky, Py_None, 1);
3661            maskedy = PyObject_CallObject(*maskedArray, args);
3662            Py_DECREF(args);
3663          }
3664          err = !maskedy;
3665        }
3666
3667        if (!err && maskmy) {
3668          args = Py_BuildValue("OOiOO", my, Py_None, 1, Py_None, maskmy);
3669          maskedmy = PyObject_CallObject(*maskedArray, args);
3670          Py_DECREF(args);
3671          if (!maskedmy) {
3672            PyErr_Clear();
3673            args = Py_BuildValue("OOOi", my, maskmy, Py_None, 1);
3674            maskedmy = PyObject_CallObject(*maskedArray, args);
3675            Py_DECREF(args);
3676          }
3677          err = !maskedmy;
3678        }
3679
3680        if (err) {
3681          Py_DECREF(X);
3682          Py_DECREF(y);
3683          Py_DECREF(w);
3684          Py_XDECREF(maskedX);
3685          Py_XDECREF(mask);
3686          Py_XDECREF(masky);
3687          Py_XDECREF(maskmy);
3688          return PYNULL;
3689        }
3690
3691        if (mask) {
3692          Py_DECREF(X);
3693          Py_DECREF(mask);
3694          X = maskedX;
3695        }
3696
3697        if (masky) {
3698          Py_DECREF(y);
3699          Py_DECREF(masky);
3700          y = maskedy;
3701        }
3702
3703        if (maskmy) {
3704          Py_DECREF(my);
3705          Py_DECREF(maskmy);
3706          my = maskedmy;
3707        }
3708      }
3709
3710      return packMatrixTuple(X, y, my, w, contents);
3711    }
3712    catch (...) {
3713      Py_DECREF(X);
3714      Py_DECREF(y);
3715      Py_DECREF(w);
3716      Py_XDECREF(mask);
3717      Py_XDECREF(masky);
3718      Py_XDECREF(maskmy);
3719      throw;
3720    }
3721  PyCATCH
3722}
3723
3724
3725PyObject *ExampleTable_toNumeric(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3726{
3727  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric);
3728}
3729
3730
3731PyObject *ExampleTable_toNumericMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3732{
3733  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric, &numericMaskedArray);
3734}
3735
3736// this is for compatibility
3737PyObject *ExampleTable_toMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3738{
3739  return ExampleTable_toNumericMA(self, args, keywords);
3740}
3741
3742PyObject *ExampleTable_toNumarray(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3743{
3744  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray);
3745}
3746
3747
3748PyObject *ExampleTable_toNumarrayMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3749{
3750  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray, &numarrayMaskedArray);
3751}
3752
3753PyObject *ExampleTable_toNumpy(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3754{
3755  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy);
3756}
3757
3758
3759PyObject *ExampleTable_toNumpyMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3760{
3761  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy, &numpyMaskedArray);
3762}
3763
3764
3765
3766int ExampleTable_nonzero(PyObject *self)
3767{ PyTRY
3768    return SELF_AS(TExampleGenerator).numberOfExamples() ? 1 : 0;
3769  PyCATCH_1
3770}
3771
3772Py_ssize_t ExampleTable_len_sq(PyObject *self)
3773{ PyTRY
3774    return SELF_AS(TExampleGenerator).numberOfExamples();
3775  PyCATCH_1
3776}
3777
3778
3779PyObject *ExampleTable_append(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> None")
3780{ PyTRY
3781    CAST_TO(TExampleTable, table)
3782
3783    if (table->ownsExamples) {
3784      if (!convertFromPythonExisting(args, table->new_example())) {
3785        table->delete_last();
3786        return PYNULL;
3787      }
3788    }
3789    else {
3790      if (!PyOrExample_Check(args) || (((TPyExample *)(args))->lock != table->lock))
3791        PYERROR(PyExc_TypeError, "tables containing references to examples can only append examples from the same table", PYNULL);
3792
3793      table->addExample(PyExample_AS_ExampleReference(args));
3794    }
3795    RETURN_NONE;
3796  PyCATCH
3797}
3798
3799PyObject *ExampleTable_extend(PyObject *self, PyObject *args) PYARGS(METH_O, "(examples) -> None")
3800{ PyTRY
3801    CAST_TO(TExampleTable, table)
3802
3803    if (PyOrExampleGenerator_Check(args)) {
3804      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3805      if (args==self) {
3806        TExampleTable temp(gen, false);
3807        table->addExamples(PExampleGenerator(temp));
3808      }
3809      else {
3810        if (!table->ownsExamples
3811              && (table->lock != gen)
3812              && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3813            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3814        table->addExamples(gen);
3815      }
3816      RETURN_NONE;
3817    }
3818
3819    TExample example(table->domain);
3820    if (PyList_Check(args)) {
3821      Py_ssize_t i, size = PyList_Size(args);
3822
3823      // We won't append until we know we can append all
3824      // (don't want to leave the work half finished)
3825      if (!table->ownsExamples) {
3826        for (i = 0; i<size; i++) {
3827          PyObject *pyex = PyList_GET_ITEM(args, i);
3828          if (!PyOrExample_Check(pyex) || (((TPyExample *)(pyex))->lock != table->lock))
3829            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3830        }
3831      }
3832
3833      for(i = 0; i<size; i++) {
3834        PyObject *pex = PyList_GET_ITEM(args, i);
3835        if (!convertFromPythonExisting(pex, example))
3836          return PYNULL;
3837
3838        table->addExample(example);
3839      }
3840
3841      RETURN_NONE;
3842    }
3843
3844
3845    PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.extend", PYNULL);
3846  PyCATCH
3847}
3848
3849
3850PyObject *ExampleTable_getitem_sq(TPyOrange *self, Py_ssize_t idx)
3851{
3852  PyTRY
3853    CAST_TO(TExampleTable, table);
3854
3855    if (idx<0)
3856      idx += table->numberOfExamples();
3857
3858    if ((idx<0) || (idx>=table->numberOfExamples()))
3859      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
3860
3861    // here we wrap a reference to example, so we must pass self's wrapper
3862    return Example_FromExampleRef((*table)[idx], EXAMPLE_LOCK(PyOrange_AsExampleTable(self)));
3863  PyCATCH
3864}
3865
3866
3867int ExampleTable_setitem_sq(TPyOrange *self, Py_ssize_t idx, PyObject *pex)
3868{
3869  PyTRY
3870    CAST_TO_err(TExampleTable, table, -1);
3871
3872    if (idx>table->numberOfExamples())
3873      PYERROR(PyExc_IndexError, "index out of range", -1);
3874
3875    if (!pex) {
3876      table->erase(idx);
3877      return 0;
3878    }
3879
3880    if (!table->ownsExamples) {
3881      if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock))
3882        PYERROR(PyExc_TypeError, "tables containing references to examples can contain examples from the same table", -1);
3883
3884      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3885      return 0;
3886    }
3887
3888    if (PyOrExample_Check(pex)) {
3889      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3890      return 0;
3891    }
3892
3893    TExample example(table->domain);
3894    if (convertFromPythonExisting(pex, example)) {
3895      (*table)[idx] = example;
3896      return 0;
3897    }
3898
3899    PYERROR(PyExc_TypeError, "invalid parameter type (Example expected)", -1)
3900  PyCATCH_1
3901}
3902
3903
3904PyObject *ExampleTable_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
3905{
3906  PyTRY
3907    CAST_TO(TExampleTable, table);
3908
3909    if (stop>table->numberOfExamples())
3910      stop=table->numberOfExamples();
3911
3912    if (start>stop)
3913      start=stop;
3914
3915    PyObject *list=PyList_New(stop-start);
3916    Py_ssize_t i=0;
3917    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3918    while(start<stop) {
3919      // here we wrap a reference to example, so we must pass a self's wrapper
3920      PyObject *example=Example_FromExampleRef((*table)[start++], lock);
3921      if (!example) {
3922        PyMem_DEL(list);
3923        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3924      }
3925      PyList_SetItem(list, i++, (PyObject *)example);
3926    }
3927
3928    return list;
3929  PyCATCH
3930}
3931
3932
3933int ExampleTable_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *args)
3934{
3935  PyTRY
3936    CAST_TO_err(TExampleTable, table, -1);
3937
3938    if (stop>table->size())
3939      stop = table->size();
3940
3941    if (start>stop)
3942      PYERROR(PyExc_IndexError, "index out of range", -1);
3943
3944    int inspoint = stop;
3945
3946    try {
3947      if (PyOrExampleGenerator_Check(args)) {
3948        PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3949        if (args==(PyObject *)self) {
3950          TExampleTable tab(gen, false);
3951          EITERATE(ei, tab)
3952            table->insert(inspoint++, *ei);
3953        }
3954        else
3955          if (!table->ownsExamples
3956                && (table->lock != gen)
3957                && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3958              PYERROR(PyExc_TypeError, "tables containing references to examples can only contain examples from the same table", -1);
3959          PEITERATE(ei, gen)
3960            table->insert(inspoint++, *ei);
3961      }
3962
3963      else {
3964        TExample example(table->domain);
3965        if (PyList_Check(args)) {
3966          Py_ssize_t size = PyList_Size(args);
3967
3968          for(Py_ssize_t i = 0; i<size; i++) {
3969            PyObject *pex = PyList_GetItem(args, i);
3970
3971            if (table->ownsExamples) {
3972              if (!convertFromPythonExisting(pex, example)) {
3973                table->erase(stop, inspoint);
3974                return -1;
3975              }
3976              table->insert(inspoint++, example);
3977            }
3978            else {
3979              if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock)) {
3980                table->erase(stop, inspoint);
3981                PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", -1);
3982              }
3983              table->insert(inspoint++, PyExample_AS_ExampleReference(pex));
3984            }
3985          }
3986        }
3987        else
3988          PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.__setslice__", -1);
3989      }
3990    }
3991    catch (...) {
3992      table->erase(stop, inspoint);
3993      throw;
3994    }
3995
3996    table->erase(start, stop);
3997
3998    return 0;
3999  PyCATCH_1
4000}
4001
4002
4003PyObject *applyFilterL(PFilter filter, PExampleTable gen)
4004{ if (!filter)
4005    return PYNULL;
4006
4007  PyObject *list=PyList_New(0);
4008  filter->reset();
4009  PExampleGenerator lock = EXAMPLE_LOCK(gen);
4010  PEITERATE(ei, gen)
4011    if (filter->operator()(*ei)) {
4012      PyObject *obj=Example_FromExampleRef(*ei, lock);
4013      PyList_Append(list, obj);
4014      Py_DECREF(obj);
4015    }
4016
4017  return list;
4018}
4019
4020
4021PyObject *applyFilterP(PFilter filter, PExampleTable gen)
4022{ if (!filter)
4023    return PYNULL;
4024
4025  TExampleTable *newTable = mlnew TExampleTable(PExampleGenerator(gen), 1);
4026  PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4027  filter->reset();
4028  PEITERATE(ei, gen)
4029    if (filter->operator()(*ei))
4030      newTable->addExample(*ei);
4031
4032  return WrapOrange(newGen);
4033}
4034
4035
4036PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen);
4037
4038PyObject *applyFilterB(PFilter filter, PExampleTable gen)
4039{
4040  return filter ? filterSelectionVectorLow(filter.getReference(), gen) : PYNULL;
4041}
4042
4043
4044PyObject *ExampleTable_get_items_ref(TPyOrange *self, PyObject *pylist)   PYARGS(METH_O, "(indices) -> ExampleTable")
4045{ return multipleSelectLow(self, pylist, true); }
4046
4047
4048PyObject *ExampleTable_selectLow(TPyOrange *self, PyObject *args, PyObject *keywords, const int toList)
4049{
4050  PyTRY
4051    CAST_TO(TExampleTable, eg);
4052    PExampleGenerator weg = PExampleGenerator(PyOrange_AS_Orange(self));
4053    PExampleGenerator lock = EXAMPLE_LOCK(eg);
4054
4055    /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
4056    /* Deprecated: use 'filter' instead */
4057    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4058      switch (toList) {
4059        case 2: return applyFilterB(filter_sameValues(keywords, eg->domain), weg);
4060        case 1: return applyFilterL(filter_sameValues(keywords, eg->domain), weg);
4061        default: return applyFilterP(filter_sameValues(keywords, eg->domain), weg);
4062      }
4063    }
4064
4065    PyObject *mplier;
4066    int index;
4067    if (PyArg_ParseTuple(args, "O|i", &mplier, &index)) {
4068      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
4069      bool negate = pyneg && PyObject_IsTrue(pyneg);
4070      bool indexGiven = (PyTuple_Size(args)==2);
4071
4072      /* ***** SELECTION BY PYLIST ****** */
4073      if (PyList_Check(mplier)) {
4074        if (PyList_Size(mplier) != eg->numberOfExamples())
4075          PYERROR(PyExc_IndexError, "example selector of invalid length", PYNULL);
4076
4077        int i = 0;
4078        switch (toList) {
4079
4080          case 1: {
4081            PyObject *list = PyList_New(0);
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                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4091                  PyList_Append(list, pyex);
4092                  Py_DECREF(pyex);
4093                }
4094              }
4095            else
4096              EITERATE(ei, *eg)
4097                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0)) {
4098                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4099                  PyList_Append(list, pyex);
4100                  Py_DECREF(pyex);
4101                }
4102
4103            return list;
4104          }
4105
4106
4107          // this is a pervesion, but let's support it as a kind of syntactic sugar...
4108          case 2: {
4109            const Py_ssize_t lsize = PyList_Size(mplier);
4110            TBoolList *selection = new TBoolList(lsize);
4111            PBoolList pselection = selection;
4112            TBoolList::iterator si(selection->begin());
4113            if (indexGiven)
4114              for(Py_ssize_t i = 0; i < lsize; i++) {
4115                PyObject *lel = PyList_GetItem(mplier, i);
4116                if (!PyInt_Check(lel))
4117                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4118
4119                *si++ = negate != (index == PyInt_AsLong(lel));
4120              }
4121            else
4122              for(Py_ssize_t i = 0; i < lsize; *si++ = negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0));
4123
4124            return WrapOrange(pselection);
4125          }
4126
4127
4128          default: {
4129            TExampleTable *newTable = mlnew TExampleTable(lock, 1); //locks to weg but does not copy
4130            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4131
4132            if (indexGiven)
4133              EITERATE(ei, *eg) {
4134                PyObject *lel = PyList_GetItem(mplier, i++);
4135                if (!PyInt_Check(lel))
4136                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4137
4138                if (negate != (index==PyInt_AsLong(lel)))
4139                  newTable->addExample(*ei);
4140              }
4141            else
4142              EITERATE(ei, *eg)
4143                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0))
4144                  newTable->addExample(*ei);
4145
4146            return WrapOrange(newGen);
4147          }
4148        }
4149      }
4150
4151      /* ***** SELECTION BY LONGLIST ****** */
4152      else if (PyOrLongList_Check(mplier)) {
4153        PLongList llist = PyOrange_AsLongList(mplier);
4154        if (int(llist->size()) != eg->numberOfExamples())
4155          PYERROR(PyExc_IndexError, "select: invalid list size", PYNULL)
4156
4157        TLongList::iterator lli(llist->begin()), lle(llist->end());
4158        TExampleIterator ei = eg->begin();
4159
4160        switch (toList) {
4161          case 1: {
4162            PyObject *list = PyList_New(0);
4163            for(; ei && (lli!=lle); ++ei, lli++)
4164              if (negate != (indexGiven ? (*lli==index) : (*lli!=0))) {
4165                PyObject *pyex = Example_FromExampleRef(*ei, lock);
4166                PyList_Append(list, pyex);
4167                Py_DECREF(pyex);
4168              }
4169            return list;
4170          }
4171
4172          case 2: {
4173            TBoolList *selection = new TBoolList(llist->size());
4174            PBoolList pselection = selection;
4175            for(TBoolList::iterator si(selection->begin()); lli != lle; *si++ = negate != (indexGiven ? (*lli++ == index) : (*lli++ != 0)));
4176
4177            return WrapOrange(pselection);
4178          }
4179
4180          default: {
4181            TExampleTable *newTable = mlnew TExampleTable(lock, 1);
4182            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4183
4184            for(;ei && (lli!=lle); ++ei, lli++)
4185              if (negate != (indexGiven ? (*lli==index) : (*lli!=0)))
4186                newTable->addExample(*ei);
4187
4188            return WrapOrange(newGen);
4189          }
4190        }
4191      }
4192
4193      PyErr_Clear();
4194
4195
4196      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
4197      /* Deprecated: use method 'filter' instead. */
4198      if (PyDict_Check(mplier))
4199        switch (toList) {
4200          case 2: return applyFilterB(filter_sameValues(mplier, eg->domain), weg);
4201          case 1: return applyFilterL(filter_sameValues(mplier, eg->domain), weg);
4202          default: return applyFilterP(filter_sameValues(mplier, eg->domain), weg);
4203        }
4204
4205      else if (PyOrFilter_Check(mplier))
4206        switch (toList) {
4207          case 2: return applyFilterB(PyOrange_AsFilter(mplier), weg);
4208          case 1: return applyFilterL(PyOrange_AsFilter(mplier), weg);
4209          default: return applyFilterP(PyOrange_AsFilter(mplier), weg);
4210        }
4211    }
4212
4213  PYERROR(PyExc_TypeError, "invalid example selector type", PYNULL);
4214  PyCATCH
4215}
4216
4217
4218PyObject *ExampleTable_select_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4219{ PyTRY
4220    return ExampleTable_selectLow(self, args, keywords, 1);
4221  PyCATCH
4222}
4223
4224
4225PyObject *ExampleTable_select_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4226{ PyTRY
4227    return ExampleTable_selectLow(self, args, keywords, 0);
4228  PyCATCH
4229}
4230
4231
4232PyObject *ExampleTable_select_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4233{ PyTRY
4234    return ExampleTable_selectLow(self, args, keywords, 2);
4235  PyCATCH
4236}
4237
4238
4239PyObject *ExampleTable_filter_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4240{
4241  PyTRY
4242    CAST_TO(TExampleGenerator, eg);
4243    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4244
4245    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4246      return applyFilterL(filter_sameValues(keywords, eg->domain, keywords), weg);
4247    }
4248
4249    if (PyTuple_Size(args)==1) {
4250      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4251
4252      if (PyDict_Check(arg))
4253        return applyFilterL(filter_sameValues(arg, eg->domain, keywords), weg);
4254
4255      if (PyOrFilter_Check(arg))
4256          return applyFilterL(PyOrange_AsFilter(arg), weg);
4257    }
4258
4259    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_list expects a list of conditions or orange.Filter", PYNULL)
4260  PyCATCH
4261}
4262
4263
4264PyObject *ExampleTable_filter_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4265{
4266  PyTRY
4267    CAST_TO(TExampleGenerator, eg);
4268    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4269
4270    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4271      return applyFilterP(filter_sameValues(keywords, eg->domain, keywords), weg);
4272    }
4273
4274    if (PyTuple_Size(args)==1) {
4275      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4276
4277      if (PyDict_Check(arg))
4278        return applyFilterP(filter_sameValues(arg, eg->domain, keywords), weg);
4279
4280      if (PyOrFilter_Check(arg))
4281          return applyFilterP(PyOrange_AsFilter(arg), weg);
4282    }
4283
4284    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_ref expects a list of conditions or orange.Filter", PYNULL)
4285  PyCATCH
4286}
4287
4288
4289PyObject *ExampleTable_filter_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4290{
4291  PyTRY
4292    CAST_TO(TExampleGenerator, eg);
4293    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4294
4295    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4296      return applyFilterB(filter_sameValues(keywords, eg->domain, keywords), weg);
4297    }
4298
4299    if (PyTuple_Size(args)==1) {
4300      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4301
4302      if (PyDict_Check(arg))
4303        return applyFilterB(filter_sameValues(arg, eg->domain, keywords), weg);
4304
4305      if (PyOrFilter_Check(arg))
4306          return applyFilterB(PyOrange_AsFilter(arg), weg);
4307    }
4308
4309    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_bool expects a list of conditions or orange.Filter", PYNULL)
4310  PyCATCH
4311}
4312
4313
4314PyObject *ExampleTable_random_example(TPyOrange *self) PYARGS(0, "() -> Example")
4315{ PyTRY
4316    CAST_TO(TExampleTable, table);
4317    TExample example(table->domain);
4318    table->randomExample(example);
4319    return Example_FromExampleCopyRef(example);
4320  PyCATCH
4321}
4322
4323
4324PyObject *ExampleTable_removeDuplicates(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([weightID=0]]) -> None")
4325{ PyTRY
4326    if (PyTuple_Size(args) > 1)
4327      PYERROR(PyExc_AttributeError, "at most one argument (weight) expected", PYNULL);
4328
4329    CAST_TO(TExampleTable, table);
4330
4331    int weightID = 0;
4332    if (PyTuple_Size(args) && !weightFromArg_byDomain(PyTuple_GET_ITEM(args, 0), table->domain, weightID))
4333      return PYNULL;
4334
4335    table->removeDuplicates(weightID);
4336    RETURN_NONE;
4337  PyCATCH
4338}
4339
4340
4341PyObject *ExampleTable_shuffle(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None")
4342{
4343  PyTRY
4344    SELF_AS(TExampleTable).shuffle();
4345    RETURN_NONE;
4346  PyCATCH
4347}
4348
4349PyObject *ExampleTable_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
4350{ PyTRY
4351    CAST_TO(TExampleTable, table);
4352
4353    if (!args || !PyTuple_Size(args)) {
4354      table->sort();
4355      RETURN_NONE;
4356    }
4357
4358    PyObject *alist = PyTuple_GET_ITEM(args, 0);
4359    /* If the first argument is nor list nor tuple, the whole argument is taken as a list
4360       i.e., data.sort("age", "prescr") is interpreted the same as data.sort(["age", "prescr"])
4361       All references are borrowed. */
4362    if ((PyTuple_Size(args) > 1) || (!PyList_Check(alist) && !PyTuple_Check(alist)))
4363      alist = args;
4364
4365    TVarList attributes;
4366    if (varListFromDomain(alist, table->domain, attributes, true, true)) {
4367      vector<int> order;
4368      for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++)
4369        order.push_back(table->domain->getVarNum(*vi));
4370      table->sort(order);
4371      RETURN_NONE;
4372    }
4373
4374    PYERROR(PyExc_TypeError, "invalid arguments (none, or a list of attributes expected)", PYNULL);
4375
4376  PyCATCH
4377}
4378
4379
4380PyObject *ExampleTable_addMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id[, Value=1.0]) -> None")
4381{ PyTRY
4382    CAST_TO(TExampleTable, table);
4383
4384    PyObject *pyid;
4385    PyObject *pyvalue=PYNULL;
4386    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4387      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4388
4389    int id;
4390    PVariable metavariable;
4391    if (PyInt_Check(pyid)) {
4392      id = PyInt_AsLong(pyid);
4393      metavariable = table->domain->getMetaVar(id, false);
4394    }
4395    else if (PyString_Check(pyid)) {
4396      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4397      metavariable = table->domain->getMetaVar(id, false);
4398    }
4399    else if (PyOrVariable_Check(pyid)) {
4400      metavariable = PyOrange_AsVariable(pyid);
4401      id = table->domain->getMetaNum(metavariable);
4402    }
4403
4404    TValue value;
4405    if (!pyvalue)
4406      if (metavariable && metavariable->varType != TValue::FLOATVAR)
4407        value = metavariable->DK();
4408      else
4409        value = TValue(float(1.0));
4410    else if (!convertFromPython(pyvalue, value, metavariable))
4411      PYERROR(PyExc_AttributeError, "invalid value argument", PYNULL);
4412
4413    table->addMetaAttribute(id, value);
4414
4415    RETURN_NONE;
4416  PyCATCH
4417}
4418
4419
4420PyObject *ExampleTable_removeMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id) -> None")
4421{ PyTRY
4422    CAST_TO(TExampleTable, table);
4423
4424    PyObject *pyid;
4425    PyObject *pyvalue=PYNULL;
4426    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4427      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4428
4429    int id;
4430    if (PyInt_Check(pyid))
4431      id = PyInt_AsLong(pyid);
4432    else if (PyString_Check(pyid))
4433      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4434    else if (PyOrVariable_Check(pyid))
4435      id = table->domain->getMetaNum(PyOrange_AsVariable(pyid));
4436
4437    table->removeMetaAttribute(id);
4438
4439    RETURN_NONE;
4440  PyCATCH
4441}
4442
4443
4444PyObject *ExampleTable_changeDomain(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(Domain) -> None")
4445{ PyTRY
4446    CAST_TO(TExampleTable, table);
4447    if (!table->ownsExamples)
4448      PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4449
4450    PDomain domain;
4451    if (!PyArg_ParseTuple(args, "O&", cc_Domain, &domain))
4452      PYERROR(PyExc_AttributeError, "domain argument expected", PYNULL);
4453
4454    table->changeDomain(domain);
4455    RETURN_NONE;
4456  PyCATCH
4457}
4458
4459PyObject *ExampleTable_pickClass(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable | name) -> None")
4460{
4461    PyTRY
4462        CAST_TO(TExampleTable, table);
4463        if (!table->ownsExamples) {
4464            PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4465        }
4466        PVariable newClass;
4467        if (PyString_Check(obj)) {
4468            const char *attr = PyString_AS_STRING(obj);
4469            TVarList::const_iterator mci(table->domain->classVars->begin()), mce(table->domain->classVars->end());
4470            for(; (mci != mce) && ((*mci)->get_name() != attr); mci++);
4471            if (mci == mce) {
4472                PYERROR(PyExc_TypeError, "table does not have multiple classes", PYNULL);
4473            }
4474            newClass = *mci;
4475        }
4476        if (PyOrVariable_Check(obj)) {
4477            newClass = PyOrange_AsVariable(obj);
4478        }
4479        else if (obj != Py_None) {
4480            PYERROR(PyExc_TypeError, "class should be given as Variable, name or None", PYNULL);
4481        }
4482        table->pickClass(newClass);
4483        RETURN_NONE;
4484    PyCATCH;
4485}
4486
4487
4488
4489PyObject *ExampleTable_hasMissingValues(TPyOrange *self) PYARGS(0, "() -> bool")
4490{
4491  PyTRY
4492    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissing());
4493  PyCATCH
4494}
4495
4496
4497PyObject *ExampleTable_hasMissingClasses(TPyOrange *self) PYARGS(0, "() -> bool")
4498{
4499  PyTRY
4500    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissingClass());
4501  PyCATCH
4502}
4503/* ************ TRANSFORMVALUE ************ */
4504
4505#include "transval.hpp"
4506BASED_ON(TransformValue, Orange)
4507
4508PyObject *TransformValue_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
4509{ if (type == (PyTypeObject *)&PyOrTransformValue_Type)
4510    return setCallbackFunction(WrapNewOrange(mlnew TTransformValue_Python(), type), args);
4511  else
4512    return WrapNewOrange(mlnew TTransformValue_Python(), type);
4513}
4514
4515
4516PyObject *TransformValue__reduce__(PyObject *self)
4517{
4518  return callbackReduce(self, PyOrTransformValue_Type);
4519}
4520
4521
4522PyObject *TransformValue_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
4523{ PyTRY
4524    NO_KEYWORDS
4525
4526    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrTransformValue_Type) {
4527      PyErr_Format(PyExc_SystemError, "TransformValue.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
4528      return PYNULL;
4529    }
4530
4531    CAST_TO(TTransformValue, tv)
4532
4533    TPyValue *value;
4534    if (!convertFromPython(args, value))
4535      return PYNULL;
4536
4537    tv->transform(value->value);
4538    value->variable=PVariable();
4539    return (PyObject *)value;
4540  PyCATCH
4541}
4542
4543
4544/* ************ DISTRIBUTION ************ */
4545
4546#include "distvars.hpp"
4547
4548PyObject *convertToPythonNative(const TDiscDistribution &disc)
4549{ int e = disc.size();
4550  PyObject *pylist = PyList_New(e);
4551  for (Py_ssize_t i = 0; i<e; i++)
4552    PyList_SetItem(pylist, i, PyFloat_FromDouble((double)(disc[i])));
4553  return pylist;
4554}
4555
4556PyObject *convertToPythonNative(const TContDistribution &cont)
4557{ PyObject *pydict = PyDict_New();
4558  const_ITERATE(TContDistribution, ci, cont) {
4559    PyObject *key = PyFloat_FromDouble((double)((*ci).first));
4560    PyObject *val = PyFloat_FromDouble((double)((*ci).second));
4561    PyDict_SetItem(pydict, key, val);
4562    Py_DECREF(key);
4563    Py_DECREF(val);
4564  }
4565  return pydict;
4566}
4567
4568
4569bool convertFromPython(PyObject *pylist, TDiscDistribution &disc)
4570{
4571  if (!PyList_Check(pylist))
4572    PYERROR(PyExc_TypeError, "list expected", false);
4573
4574  disc.clear();
4575  float d;
4576  for(Py_ssize_t i = 0, e = PyList_Size(pylist); i!=e; i++) {
4577    if (!PyNumber_ToFloat(PyList_GET_ITEM(pylist, i), d))
4578      PYERROR(PyExc_TypeError, "non-number in DiscDistribution as list", false);
4579    disc.set(TValue((int)i), d);
4580  }
4581
4582  return true;
4583}
4584
4585
4586PyObject *convertToPythonNative(const TDistribution &dist, int)
4587{ const TDiscDistribution *disc = dynamic_cast<const TDiscDistribution *>(&dist);
4588  if (disc)
4589    return convertToPythonNative(*disc);
4590
4591  const TContDistribution *cont = dynamic_cast<const TContDistribution *>(&dist);
4592  if (cont)
4593    return convertToPythonNative(*cont);
4594
4595  PYERROR(PyExc_TypeError, "cannot convert to native python object", PYNULL);
4596}
4597
4598
4599/* Class Distribution has a constructor, but it constructs an instance of either DiscDistribution
4600   or ContDistribution. Class Distribution is thus essentially abstract for Python, although it has
4601   a constructor. */
4602
4603NO_PICKLE(Distribution)
4604
4605PyObject *Distribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.statistics.distribution.Distribution, "(attribute[, examples[, weightID]])")
4606{
4607  PyTRY
4608    PExampleGenerator gen;
4609    PyObject *pyvar;
4610    int weightID = 0;
4611    if (!PyArg_ParseTuple(args, "O|O&O&:Distribution.new", &pyvar, &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID))
4612      return PYNULL;
4613
4614    TDistribution *dist;
4615
4616    if (!gen) {
4617      if (PyOrVariable_Check(pyvar))
4618        dist = TDistribution::create(PyOrange_AsVariable(pyvar));
4619      else if (PyList_Check(pyvar)) {
4620        TDiscDistribution *ddist = mlnew TDiscDistribution();
4621        if (!convertFromPython(pyvar, *ddist)) {
4622          mldelete ddist;
4623          raiseError("invalid arguments");
4624        }
4625        else
4626          dist = ddist;
4627      }
4628      else
4629        raiseError("invalid arguments");
4630    }
4631    else {
4632      if (PyOrVariable_Check(pyvar))
4633        dist = TDistribution::fromGenerator(gen, PyOrange_AsVariable(pyvar), weightID);
4634      else {
4635        PVariable var = varFromArg_byDomain(pyvar, gen->domain, false);
4636        if (!var)
4637          return PYNULL;
4638
4639        dist = TDistribution::fromGenerator(gen, var, weightID);
4640      }
4641    }
4642
4643    /* We need to override the type (don't want to lie it's Distribution).
4644       The exception is if another type is prescribed. */
4645    return type==(PyTypeObject *)(&PyOrDistribution_Type) ? WrapOrange(PDistribution(dist)) : WrapNewOrange(dist, type);
4646  PyCATCH
4647}
4648
4649
4650PyObject *Distribution_native(PyObject *self, PyObject *) PYARGS(0, "() -> list | dictionary")
4651{
4652  PyTRY
4653    return convertToPythonNative(*PyOrange_AS_Orange(self).AS(TDistribution), 1);
4654  PyCATCH
4655}
4656
4657
4658TDiscDistribution *getDiscDistribution(PyObject *self)
4659{ TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4660  if (!disc)
4661    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected DiscDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4662  return disc;
4663}
4664
4665
4666TContDistribution *getContDistribution(PyObject *self)
4667{ TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4668  if (!cont)
4669    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected ContDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4670  return cont;
4671}
4672
4673
4674
4675float *Distribution_getItemRef(PyObject *self, PyObject *index, float *float_idx=NULL)
4676{
4677  TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4678  if (disc) {
4679    int ind=-1;
4680    if (PyInt_Check(index))
4681      ind = (int)PyInt_AsLong(index);
4682    else {
4683      if (!disc->variable)
4684        PYERROR(PyExc_SystemError, "invalid distribution (no variable)", (float *)NULL);
4685      TValue val;
4686      if (convertFromPython(index, val, disc->variable) && !val.isSpecial())
4687        ind=int(val);
4688    }
4689
4690    if (ind<0)
4691      PYERROR(PyExc_IndexError, "invalid index for distribution", (float *)NULL);
4692
4693    if (ind<int(disc->size()))
4694      return &disc->at(ind);
4695
4696    PyErr_Format(PyExc_IndexError, "index %i is out of range (0-%i)", ind, disc->size()-1);
4697    return (float *)NULL;
4698  }
4699
4700  TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4701  if (cont) {
4702    float ind;
4703    if (PyNumber_ToFloat(index, ind)) {
4704      if (float_idx)
4705        *float_idx = ind;
4706    }
4707    else {
4708      TValue val;
4709      if (convertFromPython(index, val, cont->variable) && !val.isSpecial()) {
4710        ind = float(val);
4711        if (float_idx)
4712          *float_idx = ind;
4713      }
4714      else
4715        PYERROR(PyExc_IndexError, "invalid index type (float expected)", NULL);
4716    }
4717
4718    TContDistribution::iterator mi=cont->find(ind);
4719    if (mi!=cont->end())
4720      return &(*mi).second;
4721  }
4722
4723  PYERROR(PyExc_IndexError, "invalid index", (float *)NULL);
4724}
4725
4726
4727PyObject *Distribution_getitem(PyObject *self, PyObject *index)
4728{ PyTRY
4729    float *prob=Distribution_getItemRef(self, index);
4730    return prob ? PyFloat_FromDouble(*prob) : PYNULL;
4731  PyCATCH
4732}
4733
4734
4735int Distribution_setitem(PyObject *self, PyObject *index, PyObject *item)
4736{ PyTRY
4737    PyObject *flt = PyNumber_Float(item);
4738    if (!flt)
4739      PYERROR(PyExc_TypeError, "float expected", -1);
4740
4741    float val=(float)PyFloat_AsDouble(flt);
4742    Py_DECREF(flt);
4743
4744    if (PyOrValue_Check(index)) {
4745      SELF_AS(TDistribution).set(PyValue_AS_Value(index), val);
4746      return 0;
4747    }
4748
4749    float *prob = Distribution_getItemRef(self, index);
4750    if (!prob)
4751      return -1;
4752
4753    *prob = val;
4754    return 0;
4755  PyCATCH_1
4756}
4757
4758
4759string convertToString(const PDistribution &distribution)
4760{
4761  const TDiscDistribution *disc = distribution.AS(TDiscDistribution);
4762  if (disc) {
4763    string res = "<";
4764    char buf[128];
4765    const_PITERATE(TDiscDistribution, di, disc) {
4766      if (res.size()>1)
4767        res += ", ";
4768      sprintf(buf, "%.3f", *di);
4769      res += buf;
4770    }
4771    return res+">";
4772  }
4773
4774  const TContDistribution *cont = distribution.AS(TContDistribution);
4775  if (cont) {
4776    string res = "<";
4777    char buf[128];
4778    const_PITERATE(TContDistribution, di, cont) {
4779      if (res.size()>1)
4780        res += ", ";
4781      sprintf(buf, "%.3f: %.3f", (*di).first, (*di).second);
4782      res += buf;
4783    }
4784    return res+">";
4785  }
4786
4787  raiseErrorWho("convertToString(PDistribution)", "invalid distribution");
4788  return string();
4789}
4790
4791
4792PyObject *Distribution_str(PyObject *self)
4793{ PyTRY
4794    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
4795    if (result)
4796      return result;
4797
4798    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4799  PyCATCH
4800}
4801
4802
4803PyObject *Distribution_repr(PyObject *self)
4804{ PyTRY
4805    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "repr", "str");
4806    if (result)
4807      return result;
4808
4809    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4810  PyCATCH
4811}
4812
4813
4814PyObject *Distribution_normalize(PyObject *self) PYARGS(0, "() -> None")
4815{ PyTRY
4816    SELF_AS(TDistribution).normalize();
4817    RETURN_NONE;
4818  PyCATCH
4819}
4820
4821
4822PyObject *Distribution_modus(PyObject *self) PYARGS(0, "() -> Value")
4823{ PyTRY
4824    CAST_TO(TDistribution, dist)
4825    return Value_FromVariableValue(dist->variable, dist->highestProbValue());
4826  PyCATCH
4827}
4828
4829
4830PyObject *Distribution_random(PyObject *self) PYARGS(0, "() -> Value")
4831{ PyTRY
4832    CAST_TO(TDistribution, dist)
4833    return Value_FromVariableValue(dist->variable, dist->randomValue());
4834  PyCATCH
4835}
4836
4837
4838
4839PDiscDistribution list2discdistr(PyObject *args, PyTypeObject *type = NULL)
4840{
4841  TDiscDistribution *udist = mlnew TDiscDistribution();
4842  PDiscDistribution disc = type ? PDistribution(udist) : PDistribution(udist, type);
4843  for(Py_ssize_t i = 0, e = PyList_Size(args); i<e; i++) {
4844    PyObject *flt = PyNumber_Float(PyList_GetItem(args, i));
4845    if (!flt) {
4846      PyErr_Format(PyExc_TypeError, "invalid element at index %i (float expected)", i);
4847      return PDiscDistribution();
4848    }
4849    udist->addint((int)i, (float)PyFloat_AsDouble(flt));
4850    Py_DECREF(flt);
4851  }
4852
4853  return disc;
4854}
4855
4856
4857PyObject *DiscDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Discrete, "[list of floats] | DiscDistribution")
4858{ PyTRY {
4859    if (!PyTuple_Size(targs)) {
4860      return WrapNewOrange(mlnew TDiscDistribution(), type);
4861    }
4862
4863    if (PyTuple_Size(targs)==1) {
4864      PyObject *args = PyTuple_GetItem(targs, 0);
4865
4866      if (PyList_Check(args)) {
4867        PDiscDistribution disc = list2discdistr(args, type);
4868        if (disc)
4869          return WrapOrange(disc);
4870      }
4871
4872      else if (PyOrDiscDistribution_Check(args)) {
4873        Py_INCREF(args);
4874        return args;
4875      }
4876
4877      else if (PyOrEnumVariable_Check(args))
4878        return WrapNewOrange(mlnew TDiscDistribution(PyOrange_AsVariable(args)), type);
4879    }
4880
4881    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
4882  }
4883  PyCATCH;
4884}
4885
4886
4887PyObject *DiscDistribution__reduce__(PyObject *self)
4888{
4889  PyTRY
4890    TDiscDistribution *disc = getDiscDistribution(self);
4891    TCharBuffer buf(sizeof(float)*(disc->size()+2));
4892    buf.writeFloatVector(disc->distribution);
4893
4894    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderDiscDistribution"),
4895                                    self->ob_type,
4896                                    buf.buf, buf.length(),
4897                                    packOrangeDictionary(self));
4898  PyCATCH
4899}
4900
4901
4902PyObject *__pickleLoaderDiscDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
4903{
4904  PyTRY
4905    PyTypeObject *type;
4906    char *buf;
4907    int bufSize;
4908    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &buf, &bufSize))
4909      return PYNULL;
4910
4911    const int &size = (int &)*buf;
4912    buf += sizeof(int);
4913
4914    return WrapNewOrange(new TDiscDistribution((float *)buf, size), type);
4915  PyCATCH
4916}
4917
4918
4919int pt_DiscDistribution(PyObject *args, void *dist)
4920{ if (PyOrDiscDistribution_Check(args)) {
4921    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4922    return 1;
4923  }
4924  else if (PyList_Check(args)) {
4925    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4926    if (dist)
4927      return 1;
4928  }
4929
4930  PYERROR(PyExc_TypeError, "invalid discrete distribution", 0)
4931}
4932
4933
4934PyObject *DiscDistribution_getitem_sq(PyObject *self, Py_ssize_t ind)
4935{
4936  PyTRY
4937    TDiscDistribution *disc = getDiscDistribution(self);
4938    if (!disc)
4939      return PYNULL;
4940
4941    if ((ind<0) || (ind>=disc->size()))
4942      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
4943
4944    return PyFloat_FromDouble(double(disc->at(ind)));
4945  PyCATCH
4946}
4947
4948
4949Py_ssize_t DiscDistribution_len(PyObject *self)
4950{ PyTRY
4951    TDiscDistribution *disc = getDiscDistribution(self);
4952    return disc ? disc->size() : -1;
4953  PyCATCH_1
4954}
4955
4956
4957PyObject *DiscDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
4958{ PyTRY
4959    TDiscDistribution *disc = getDiscDistribution(self);
4960    if (!disc)
4961      return PYNULL;
4962
4963    if (!disc->variable)
4964      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4965
4966    PyObject *nl=PyList_New(disc->variable->noOfValues());
4967    Py_ssize_t i=0;
4968    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4969    PITERATE(TStringList, ii, vals)
4970      PyList_SetItem(nl, i++, PyString_FromString((*ii).c_str()));
4971    return nl;
4972  PyCATCH
4973}
4974
4975
4976PyObject *DiscDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
4977{ PyTRY
4978    TDiscDistribution *disc = getDiscDistribution(self);
4979    if (!disc)
4980      return PYNULL;
4981
4982    if (!disc->variable)
4983      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4984
4985    PyObject *nl=PyList_New(disc->variable->noOfValues());
4986    TDiscDistribution::const_iterator ci(disc->begin());
4987    Py_ssize_t i=0;
4988    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4989    PITERATE(TStringList, ii, vals)
4990      PyList_SetItem(nl, i++, Py_BuildValue("sf", (*ii).c_str(), *(ci++)));
4991    return nl;
4992  PyCATCH
4993}
4994
4995
4996PyObject *DiscDistribution_values(PyObject *self) PYARGS(0, "() -> list")
4997{ PyTRY
4998    TDiscDistribution *disc = getDiscDistribution(self);
4999    if (!disc)
5000      return PYNULL;
5001
5002    PyObject *nl = PyList_New(disc->size());
5003    Py_ssize_t i = 0;
5004    const_PITERATE(TDiscDistribution, ci, disc)
5005      PyList_SetItem(nl, i++, PyFloat_FromDouble(*ci));
5006    return nl;
5007  PyCATCH
5008}
5009
5010
5011PyObject *DiscDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5012{ PyTRY
5013    CAST_TO(TDiscDistribution, dist)
5014
5015    PyObject *index;
5016    float weight = 1.0;
5017    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5018      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5019
5020    if (PyInt_Check(index)) {
5021      dist->addint(int(PyInt_AsLong(index)), weight);
5022      RETURN_NONE;
5023    }
5024
5025    TValue val;
5026    if (!dist->variable || !convertFromPython(index, val, dist->variable))
5027      PYERROR(PyExc_TypeError, "DiscDistriubtion.add: cannot convert the arguments to a Value", PYNULL);
5028
5029    dist->add(val, weight);
5030    RETURN_NONE;
5031  PyCATCH;
5032}
5033
5034
5035PyObject *ContDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Continuous, "[dist of float:float] | DiscDistribution")
5036{ PyTRY {
5037
5038    if (!PyTuple_Size(targs))
5039      return WrapNewOrange(mlnew TContDistribution(), type);
5040
5041    if (PyTuple_Size(targs) == 1) {
5042      PyObject *args = PyTuple_GetItem(targs, 0);
5043
5044      if (PyDict_Check(args)) {
5045        TContDistribution *udist = mlnew TContDistribution();
5046        PContDistribution cont = PDistribution(udist);
5047        PyObject *key, *value;
5048        Py_ssize_t pos = 0;
5049        while (PyDict_Next(args, &pos, &key, &value)) {
5050          PyObject *flt = PyNumber_Float(key);
5051          if (!flt) {
5052            PyErr_Format(PyExc_TypeError, "invalid key at index %i (float expected)", pos);
5053            return false;
5054          }
5055          float ind = (float) PyFloat_AsDouble(flt);
5056          Py_DECREF(flt);
5057
5058          flt = PyNumber_Float(value);
5059          if (!flt) {
5060            PyErr_Format(PyExc_TypeError, "invalid value at index %i (float expected)", pos);
5061            return false;
5062          }
5063
5064          udist->addfloat(ind, (float)PyFloat_AsDouble(flt));
5065          Py_DECREF(flt);
5066        }
5067
5068        return WrapOrange(cont);
5069      }
5070
5071      else if (PyOrDistribution_Check(args)) {
5072        Py_INCREF(args);
5073        return args;
5074      }
5075
5076      else if (PyOrFloatVariable_Check(args))
5077        return WrapNewOrange(mlnew TContDistribution(PyOrange_AsVariable(args)), type);
5078    }
5079
5080    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
5081
5082  }
5083  PyCATCH;
5084}
5085
5086
5087PyObject *ContDistribution__reduce__(PyObject *self)
5088{
5089  PyTRY
5090    TContDistribution *cont = getContDistribution(self);
5091    TCharBuffer buf(sizeof(float) * 2 * (cont->size()  +  5));
5092
5093    buf.writeInt(cont->size());
5094    PITERATE(TContDistribution, ci, cont) {
5095      buf.writeFloat((*ci).first);
5096      buf.writeFloat((*ci).second);
5097    }
5098
5099    buf.writeFloat(cont->sum);
5100    buf.writeFloat(cont->sum2);
5101
5102    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderContDistribution"),
5103                                    self->ob_type,
5104                                    buf.buf, buf.length(),
5105                                    packOrangeDictionary(self));
5106  PyCATCH
5107}
5108
5109
5110PyObject *__pickleLoaderContDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
5111{
5112  PyTRY
5113    PyTypeObject *type;
5114    char *pbuf;
5115    int bufSize;
5116    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &pbuf, &bufSize))
5117      return PYNULL;
5118
5119    TContDistribution *cdi = new TContDistribution();
5120
5121    TCharBuffer buf(pbuf);
5122    for(int size = buf.readInt(); size--; ) {
5123      // cannot call buf.readFloat() in the make_pair call since we're not sure about the
5124      // order in which the arguments are evaluated
5125      const float p1 = buf.readFloat();
5126      const float p2 = buf.readFloat();
5127      cdi->insert(cdi->end(), make_pair(p1, p2));
5128    }
5129
5130    cdi->sum = buf.readFloat();
5131    cdi->sum2 = buf.readFloat();
5132
5133    return WrapNewOrange(cdi, type);
5134  PyCATCH
5135}
5136
5137
5138Py_ssize_t ContDistribution_len(PyObject *self)
5139{ PyTRY
5140    TContDistribution *cont = getContDistribution(self);
5141    return cont ? cont->size() : -1;
5142  PyCATCH_1
5143}
5144
5145
5146PyObject *ContDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
5147{ PyTRY
5148    TContDistribution *cont = getContDistribution(self);
5149    if (!cont)
5150      return PYNULL;
5151
5152    PyObject *nl=PyList_New(cont->size());
5153    Py_ssize_t i=0;
5154    PITERATE(TContDistribution, ci, cont)
5155      PyList_SetItem(nl, i++, PyFloat_FromDouble((double)(*ci).first));
5156    return nl;
5157  PyCATCH
5158}
5159
5160
5161PyObject *ContDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
5162{ PyTRY
5163    TContDistribution *cont = getContDistribution(self);
5164    if (!cont)
5165      return PYNULL;
5166
5167    PyObject *nl=PyList_New(cont->size());
5168    Py_ssize_t i=0;
5169    PITERATE(TContDistribution, ci, cont)
5170      PyList_SetItem(nl, i++, Py_BuildValue("ff", (*ci).first, (*ci).second));
5171    return nl;
5172  PyCATCH
5173}
5174
5175
5176PyObject *ContDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5177{ PyTRY
5178    TContDistribution *cont = getContDistribution(self);
5179    if (!cont)
5180      return PYNULL;
5181
5182    PyObject *nl = PyList_New(cont->size());
5183    Py_ssize_t i = 0;
5184    const_PITERATE(TContDistribution, ci, cont)
5185      PyList_SetItem(nl, i++, PyFloat_FromDouble((*ci).second));
5186    return nl;
5187  PyCATCH
5188}
5189
5190
5191PyObject *ContDistribution_percentile(PyObject *self, PyObject *arg) PYARGS(METH_VARARGS, "(int) -> float")
5192{ PyTRY
5193    TContDistribution *cont = getContDistribution(self);
5194    if (!cont)
5195      return PYNULL;
5196
5197    float perc;
5198    if (!PyArg_ParseTuple(arg, "f:ContDistribution.percentile", &perc))
5199      return PYNULL;
5200
5201    return PyFloat_FromDouble(cont->percentile(perc));
5202  PyCATCH
5203}
5204
5205
5206PyObject *ContDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5207{ PyTRY
5208    CAST_TO(TContDistribution, dist)
5209
5210    PyObject *index;
5211    float weight = 1.0;
5212    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5213      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5214
5215    float f;
5216    if (PyNumber_ToFloat(index, f)) {
5217      dist->addfloat(f);
5218      RETURN_NONE;
5219    }
5220
5221    TValue val;
5222    if (!convertFromPython(index, val, dist->variable))
5223      PYERROR(PyExc_TypeError, "ContDistriubtion.add: invalid arguments", PYNULL);
5224
5225    dist->add(val, weight);
5226    RETURN_NONE;
5227  PyCATCH;
5228}
5229
5230
5231PyObject *ContDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5232{ PyTRY
5233    TContDistribution *cont = getContDistribution(self);
5234    if (!cont)
5235      return PYNULL;
5236
5237    return PyFloat_FromDouble(cont->error());
5238  PyCATCH
5239}
5240
5241
5242PyObject *ContDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5243{ PyTRY
5244    TContDistribution *cont = getContDistribution(self);
5245    if (!cont)
5246      return PYNULL;
5247
5248    return PyFloat_FromDouble(cont->average());
5249  PyCATCH
5250}
5251
5252
5253PyObject *ContDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5254{ PyTRY
5255    TContDistribution *cont = getContDistribution(self);
5256    if (!cont)
5257      return PYNULL;
5258
5259    return PyFloat_FromDouble(cont->dev());
5260  PyCATCH
5261}
5262
5263
5264PyObject *ContDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5265{ PyTRY
5266    TContDistribution *cont = getContDistribution(self);
5267    if (!cont)
5268      return PYNULL;
5269
5270    return PyFloat_FromDouble(cont->var());
5271  PyCATCH
5272}
5273
5274
5275PyObject *ContDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5276{ PyTRY
5277    TContDistribution *cont = getContDistribution(self);
5278    float x;
5279    if (!cont || !PyArg_ParseTuple(args, "f:ContDistribution.density", &x))
5280      return PYNULL;
5281
5282    return PyFloat_FromDouble(cont->p(x));
5283  PyCATCH
5284}
5285
5286
5287PyObject *GaussianDistribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Gaussian, "(mean, sigma) | (distribution) | () -> distribution") ALLOWS_EMPTY
5288{ PyTRY
5289    float mean = 0.0, sigma = 1.0;
5290
5291    if (PyArg_ParseTuple(args, "|ff", &mean, &sigma))
5292      return WrapNewOrange(mlnew TGaussianDistribution(mean, sigma), type);
5293
5294    PyErr_Clear();
5295
5296    PDistribution dist;
5297    if (PyArg_ParseTuple(args, "O&", &cc_Distribution, &dist))
5298      return WrapNewOrange(mlnew TGaussianDistribution(dist), type);
5299
5300    PYERROR(PyExc_TypeError, "GaussianDistribution expects mean and sigma, or distribution or nothing", PYNULL)
5301
5302  PyCATCH
5303}
5304
5305
5306PyObject *GaussianDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5307{ PyTRY
5308    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).average());
5309  PyCATCH
5310}
5311
5312
5313PyObject *GaussianDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5314{ PyTRY
5315    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).error());
5316  PyCATCH
5317}
5318
5319
5320PyObject *GaussianDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5321{ PyTRY
5322    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).dev());
5323  PyCATCH
5324}
5325
5326
5327PyObject *GaussianDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5328{ PyTRY
5329    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).var());
5330  PyCATCH
5331}
5332
5333
5334PyObject *GaussianDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5335{ PyTRY
5336    float x;
5337    if (!PyArg_ParseTuple(args, "f:GaussianDistribution.density", &x))
5338      return PYNULL;
5339
5340    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).p(x));
5341  PyCATCH
5342}
5343
5344
5345/* We redefine new (removed from below!) and add mapping methods
5346*/
5347
5348PyObject *getClassDistribution(PyObject *type, PyObject *args) PYARGS(METH_VARARGS, "(examples[, weightID]) -> Distribution")
5349{ PyTRY
5350    int weightID;
5351    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
5352    if (!gen)
5353      return PYNULL;
5354    return WrapOrange(getClassDistribution(gen, weightID));
5355  PyCATCH
5356}
5357
5358
5359/* modified new (defined below), modified getitem, setitem */
5360
5361PDomainDistributions PDomainDistributions_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5362PyObject *DomainDistributions_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5363PyObject *DomainDistributions_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5364int       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); }
5365PyObject *DomainDistributions_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5366int       DomainDistributions_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5367Py_ssize_t       DomainDistributions_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_len(self); }
5368PyObject *DomainDistributions_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5369PyObject *DomainDistributions_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5370PyObject *DomainDistributions_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5371PyObject *DomainDistributions_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5372PyObject *DomainDistributions_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5373int       DomainDistributions_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5374PyObject *DomainDistributions_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5375PyObject *DomainDistributions_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5376PyObject *DomainDistributions_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5377PyObject *DomainDistributions_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainDistributions") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5378PyObject *DomainDistributions_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5379PyObject *DomainDistributions_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5380PyObject *DomainDistributions_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_native(self); }
5381PyObject *DomainDistributions_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5382PyObject *DomainDistributions_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5383PyObject *DomainDistributions_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5384PyObject *DomainDistributions_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5385PyObject *DomainDistributions__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5386
5387
5388/* Note that this is not like callable-constructors. They return different type when given
5389   parameters, while this one returns the same type, disregarding whether it was given examples or not.
5390*/
5391PyObject *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
5392{ PyTRY
5393    if (!args || !PyTuple_Size(args))
5394      return WrapNewOrange(mlnew TDomainDistributions(), type);
5395
5396    int weightID = 0;
5397    PExampleGenerator gen;
5398    int skipDiscrete=0, skipContinuous=0;
5399    if (PyArg_ParseTuple(args, "O&|O&ii:Distribution.new", &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &skipDiscrete, &skipContinuous))
5400      return WrapNewOrange(mlnew TDomainDistributions(gen, weightID, skipDiscrete!=0, skipContinuous!=0), type);
5401
5402    PyErr_Clear();
5403
5404    PyObject *obj = ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_new(type, args, keywds);
5405    if (obj)
5406      if (obj!=Py_None)
5407        return obj;
5408      else
5409        Py_DECREF(obj);
5410
5411    PyErr_Clear();
5412    PYERROR(PyExc_TypeError, "DomainDistributions.__init__ expect examples or a list of Distributions", PYNULL);
5413
5414  PyCATCH
5415}
5416
5417
5418/* We keep the sequence methods and add mapping interface */
5419
5420int DomainDistributions_getItemIndex(PyObject *self, PyObject *args)
5421{ CAST_TO_err(TDomainDistributions, bas, -1);
5422
5423  if (PyInt_Check(args)) {
5424    int i=(int)PyInt_AsLong(args);
5425    if ((i>=0) && (i<int(bas->size())))
5426      return i;
5427    else
5428      PYERROR(PyExc_IndexError, "index out of range", -1);
5429  }
5430
5431  if (PyString_Check(args)) {
5432    char *s=PyString_AsString(args);
5433    PITERATE(TDomainDistributions, ci, bas)
5434      if ((*ci)->variable && ((*ci)->variable->get_name()==s))
5435        return ci - bas->begin();
5436
5437    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", s);
5438    return -1;
5439  }
5440
5441  if (PyOrVariable_Check(args)) {
5442    PVariable var = PyOrange_AsVariable(args);
5443    PITERATE(TDomainDistributions, ci, bas)
5444      if ((*ci)->variable && ((*ci)->variable==var))
5445        return ci - bas->begin();
5446
5447    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", var->get_name().length() ? var->get_name().c_str() : "<no name>");
5448    return -1;
5449  }
5450
5451  PYERROR(PyExc_IndexError, "invalid index type", -1);
5452}
5453
5454
5455PyObject *DomainDistributions_getitem(PyObject *self, PyObject *args)
5456{ PyTRY
5457    int index=DomainDistributions_getItemIndex(self, args);
5458    if (index<0)
5459      return PYNULL;
5460    return WrapOrange(POrange(SELF_AS(TDomainDistributions).at(index)));
5461  PyCATCH
5462}
5463
5464
5465int DomainDistributions_setitem(PyObject *self, PyObject *args, PyObject *obj)
5466{ PyTRY
5467    PDistribution bas;
5468
5469    if (!PyOrBasicAttrStat_Check(obj))
5470      PYERROR(PyExc_TypeError, "invalid Distribution object", -1);
5471
5472    int index=DomainDistributions_getItemIndex(self, args);
5473    if (index==-1)
5474      return -1;
5475
5476    SELF_AS(TDomainDistributions)[index] = PyOrange_AsDistribution(obj);
5477    return 0;
5478  PyCATCH_1
5479}
5480
5481
5482PDistributionList PDistributionList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5483PyObject *DistributionList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5484PyObject *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); }
5485PyObject *DistributionList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5486int       DistributionList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5487PyObject *DistributionList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5488int       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); }
5489Py_ssize_t       DistributionList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_len(self); }
5490PyObject *DistributionList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5491PyObject *DistributionList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5492PyObject *DistributionList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5493PyObject *DistributionList_str(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5494PyObject *DistributionList_repr(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5495int       DistributionList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5496PyObject *DistributionList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5497PyObject *DistributionList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5498PyObject *DistributionList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5499PyObject *DistributionList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DistributionList") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5500PyObject *DistributionList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5501PyObject *DistributionList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5502PyObject *DistributionList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_native(self); }
5503PyObject *DistributionList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5504PyObject *DistributionList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5505PyObject *DistributionList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5506PyObject *DistributionList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5507PyObject *DistributionList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5508
5509
5510
5511/* ************ LEARNER ************ */
5512
5513#include "classify.hpp"
5514#include "learn.hpp"
5515
5516BASED_ON(EFMDataDescription, Orange)
5517
5518PyObject *EFMDataDescription__reduce__(PyObject *self)
5519{
5520  CAST_TO(TEFMDataDescription, edd);
5521
5522  TCharBuffer buf(0);
5523  buf.writeFloatVector(edd->averages);
5524  buf.writeFloatVector(edd->matchProbabilities);
5525  buf.writeInt(edd->originalWeight);
5526  buf.writeInt(edd->missingWeight);
5527
5528  return Py_BuildValue("O(OOs#)N", getExportedFunction("__pickleLoaderEFMDataDescription"),
5529                                  WrapOrange(edd->domain),
5530                                  WrapOrange(edd->domainDistributions),
5531                                  buf.buf, buf.length(),
5532                                  packOrangeDictionary(self));
5533}
5534
5535
5536PyObject *__pickleLoaderEFMDataDescription(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, domainDistributions, packed_data)")
5537{
5538  PDomain domain;
5539  PDomainDistributions domainDistributions;
5540  char *pbuf;
5541  int bufSize;
5542
5543  if (!PyArg_ParseTuple(args, "O&O&s#", ccn_Domain, &domain, ccn_DomainDistributions, &domainDistributions, &pbuf, &bufSize))
5544    return PYNULL;
5545
5546  TEFMDataDescription *edd = new TEFMDataDescription(domain, domainDistributions);
5547  PEFMDataDescription wedd = edd;
5548
5549  TCharBuffer buf(pbuf);
5550  buf.readFloatVector(edd->averages);
5551  buf.readFloatVector(edd->matchProbabilities);
5552  edd->originalWeight = buf.readInt();
5553  edd->missingWeight = buf.readInt();
5554
5555  return WrapOrange(wedd);
5556}
5557
5558
5559ABSTRACT(LearnerFD - Orange.classification.LearnerFD, Learner)
5560
5561PyObject *Learner_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.classification.Learner, "<abstract>")
5562{ if (type == (PyTypeObject *)&PyOrLearner_Type)
5563    return setCallbackFunction(WrapNewOrange(mlnew TLearner_Python(), type), args);
5564  else
5565    return WrapNewOrange(mlnew TLearner_Python(), type);
5566}
5567
5568
5569PyObject *Learner__reduce__(PyObject *self)
5570{
5571  return callbackReduce(self, PyOrLearner_Type);
5572}
5573
5574
5575PyObject *Learner_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(examples) -> Classifier")
5576{
5577  PyTRY
5578    NO_KEYWORDS
5579
5580    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrLearner_Type) {
5581      PyErr_Format(PyExc_SystemError, "Learner.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
5582      return PYNULL;
5583    }
5584
5585    PExampleGenerator egen;
5586    int weight = 0;
5587    if (!PyArg_ParseTuple(targs, "O&|O&", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weight))
5588      PYERROR(PyExc_AttributeError, "Learner.__call__: examples and, optionally, weight attribute expected", PYNULL);
5589
5590    // Here for compatibility with obsolete scripts
5591/*    if (PyTuple_Size(targs)==1) {
5592      if (((TPyOrange *)self)->orange_dict) {
5593        PyObject *pyweight = PyDict_GetItemString(((TPyOrange *)self)->orange_dict, "weight");
5594        if (pyweight && PyInt_Check(pyweight))
5595          weight = (int)PyInt_AsLong(pyweight);
5596      }
5597    }
5598*/
5599    PClassifier classfr = SELF_AS(TLearner)(egen, weight);
5600    if (!classfr)
5601      PYERROR(PyExc_SystemError, "learning failed", PYNULL);
5602
5603    return WrapOrange(classfr);
5604  PyCATCH
5605}
5606
5607
5608
5609
5610/* ************ CLASSIFIERS ************ */
5611
5612#include "classify.hpp"
5613#include "majority.hpp"
5614
5615ABSTRACT(ClassifierFD - Orange.classification.ClassifierFD, Classifier)
5616
5617PyObject *DefaultClassifier_new(PyTypeObject *tpe, PyObject *args, PyObject *kw) BASED_ON(Classifier - Orange.classification.ConstantClassifier, "([defaultVal])") ALLOWS_EMPTY
5618{
5619  PyObject *arg1 = NULL, *arg2 = NULL;
5620  if (!PyArg_UnpackTuple(args, "DefaultClassifier.__new__", 0, 2, &arg1, &arg2))
5621    return PYNULL;
5622
5623  if (!arg1)
5624    return WrapNewOrange(mlnew TDefaultClassifier(), tpe);
5625
5626  if (!arg2) {
5627    if (PyOrVariable_Check(arg1))
5628      return WrapNewOrange(mlnew TDefaultClassifier(PyOrange_AsVariable(arg1)), tpe);
5629    TValue val;
5630    if (convertFromPython(arg1, val)) {
5631      PVariable var = PyOrValue_Check(arg1) ? PyValue_AS_Variable(arg1) : PVariable();
5632      return WrapNewOrange(mlnew TDefaultClassifier(var, val, PDistribution()), tpe);
5633    }
5634  }
5635
5636  else
5637    if (PyOrVariable_Check(arg1)) {
5638      PVariable classVar = PyOrange_AsVariable(arg1);
5639      TValue val;
5640      if (convertFromPython(arg2, val, classVar))
5641        return WrapNewOrange(mlnew TDefaultClassifier(classVar, val, PDistribution()), tpe);
5642    }
5643
5644  PYERROR(PyExc_TypeError, "DefaultClassifier's constructor expects a Variable, a Value or both", PYNULL);
5645}
5646
5647C_NAMED(RandomLearner - Orange.classification.RandomLearner, Learner, "([probabilities=])")
5648C_NAMED(RandomClassifier - Orange.classification.RandomClassifier, Classifier, "([probabilities=])")
5649
5650PClassifierList PClassifierList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::P_FromArguments(arg); }
5651PyObject *ClassifierList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_FromArguments(type, arg); }
5652PyObject *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); }
5653PyObject *ClassifierList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getitem(self, index); }
5654int       ClassifierList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_setitem(self, index, item); }
5655PyObject *ClassifierList_getslice(TPyOrange *self