source: orange/source/orange/lib_kernel.cpp @ 10606:4ea62a7a1910

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

Fixed construction of ExampleTables from masked arrays without a mask

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