source: orange/source/orange/lib_kernel.cpp @ 9415:b8c964fe3d51

Revision 9415:b8c964fe3d51, 204.5 KB checked in by janezd <janez.demsar@…>, 2 years ago (diff)

Fixed multiple classes: pickling, conversion between domains, printing

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