source: orange/source/orange/lib_kernel.cpp @ 7715:1b96a16d0b01

Revision 7715:1b96a16d0b01, 199.9 KB checked in by janezd <janez.demsar@…>, 3 years ago (diff)

Most C++ classes which are exported through the new modules now show the "correct" names.

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