source: orange/source/orange/cls_value.cpp @ 11724:e3921bbbecaa

Revision 11724:e3921bbbecaa, 35.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Changed the Value_richcmp function's handling of unknown values.

It is now more consistent with TValue.compare method.

Will now raise a TypeError when testing equality between unknown values
of a different type.

(fixes #1332)

Line 
1#ifdef _MSC_VER
2 #pragma warning (disable : 4786 4114 4018 4267 4244)
3#endif
4
5#include "cls_value.hpp"
6#include "cls_orange.hpp"
7#include "vars.hpp"
8#include "stringvars.hpp"
9#include "pythonvars.hpp"
10#include "values.hpp"
11
12#include "vectortemplates.hpp"
13
14#include "externs.px"
15
16
17#define CHECK_VARIABLE \
18  if (!self->variable) PYERROR(PyExc_TypeError, "'variable' not set", PYNULL);
19
20#define CHECK_SPECIAL_OTHER \
21  if (self->value.isSpecial()) \
22    PYERROR(PyExc_TypeError, "attribute value unknown", PYNULL); \
23  if ((self->value.varType!=TValue::INTVAR) && (self->value.varType!=TValue::FLOATVAR)) \
24    PYERROR(PyExc_TypeError, "attribute is not an ordinary discrete or continuous", PYNULL);
25
26
27
28DATASTRUCTURE(Value - Orange.data.Value, TPyValue, 0)
29ABSTRACT(SomeValue - Orange.core.SomeValue, Orange)
30
31/* Converts a value into an appropriate python variable.
32   Behaves as convertToPythonNative(const TValue &, PVariable)
33   when the variable is not given. */
34
35PyObject *convertToPythonNative(const TValue &val)
36{ return convertToPythonNative(val, PVariable()); }
37
38
39
40/* Converts a value into an appropriate python variable.
41   Behaves as convertToPythonNative(const TValue &, PVariable);
42   variable can be there or not. */
43
44PyObject *convertToPythonNative(const TPyValue *value)
45{ return convertToPythonNative(value->value, value->variable); }
46
47
48
49/* Converts a value into an appropriate python variable.
50   If value is known (e.g. not DC, DK...)
51    - continuous values are returned as ordinary python floats
52    - discrete are returned as strings (variable is required)
53    - string values are returned as strings
54    - other values are return as ordinary orange objects
55   If value is special
56    - if the variable is given, its val2str is used to get a string
57    - if the variable is not given, '?', '~' and '.' are returned
58      for DK, DC and other, respectively.
59
60   FAILS if the value is discrete and variable is not given
61*/
62
63PyObject *convertToPythonNative(const TValue &val, PVariable var)
64{
65  if ((val.varType==TValue::FLOATVAR) && !val.isSpecial())
66    return PyFloat_FromDouble(double(val.floatV));
67
68  if (val.varType == PYTHONVAR) {
69    PyObject *res = val.svalV ? ((TPythonValue &)(val.svalV.getReference())).value : Py_None;
70    Py_INCREF(res);
71    return res;
72  }
73
74  if ((val.varType == STRINGVAR) && val.svalV) {
75    string s;
76    val.svalV.AS(TStringValue)->val2str(s);
77    return PyString_FromString(s.c_str());
78  }
79
80  if ((val.varType!=TValue::INTVAR) && val.svalV)
81    return WrapOrange((const_cast<TValue &>(val)).svalV);
82
83  if (var) { // && (val.varType == TValue::INTVAR || val.isSpecial)
84    string vs;
85    var->val2str(val, vs);
86    return PyString_FromString(vs.c_str());
87  }
88
89  if (val.isSpecial())
90    if (val.isDK())
91      return PyString_FromString("?");
92    else if (val.isDC()) 
93      return PyString_FromString("~");
94    else
95      return PyString_FromString(".");
96
97  PYERROR(PyExc_TypeError, "unknown value type", PYNULL);
98}
99
100
101/* The main routine for converting values from python to TValue.
102   If arguments are given as a
103   - Value, it is simply copied.
104       The variable is checked if given.
105   - SomeValue, it is copied as such.
106       If the variable is discrete or continuous, SomeValue must
107       be DiscDistribution or ContDistribution.
108   - string, we convert it to a value
109       The variable must be given unless the string is '?', '~'
110       (in this case INTVAR is ocnstructed)
111       We could return a StringValue here, but if user passes a
112       string without descriptor it is more probable that he just
113       forgot it. I doubt that many would construct StringValues.)
114   - int - if variable is given and is discrete, an integer value
115           is constructed. If the variable is derived from
116           EnumVariable the range is also tested
117         - if variable is given and is continuous, a continuous
118           value is constructed
119         - if variable is given and is of other type, an error is
120           raised
121         - if the variable is not given, an integer value is constructed
122   - float - a continuous value is constructed.
123       If the variable is given, it is checked that it is continuous
124   - other types: if it can be converted to float and the variable is
125       given and is continuous, a continuous value is constructed.
126       Otherwise, an exception is raised.         
127*/
128
129bool convertFromPython(PyObject *args, TValue &value, PVariable var)
130{
131  if (PyOrValue_Check(args)) {
132    if (var && PyValue_AS_Variable(args) && (PyValue_AS_Variable(args)!=var)) {
133      PyErr_Format(PyExc_TypeError, "wrong attribute value (expected value of '%s', got value of '%s')", var->get_name().c_str(), PyValue_AS_Variable(args)->get_name().c_str());
134      return false;
135    }
136    else
137      value = PyValue_AS_Value(args);
138    return true;
139  }
140
141  if (PyOrSomeValue_Check(args)) {
142    if (var) {
143      if ((var->varType==TValue::INTVAR) && !PyOrDiscDistribution_Check(args)) {
144        PyErr_Format(PyExc_TypeError, "attribute '%s' expects DiscDistribution, '%s' given", var->get_name().c_str(), args->ob_type->tp_name);
145        return false;
146      }
147      if ((var->varType==TValue::FLOATVAR) && !PyOrContDistribution_Check(args)) {
148        PyErr_Format(PyExc_TypeError, "attribute '%s' expects ContDistribution, '%s' given", var->get_name().c_str(), args->ob_type->tp_name);
149        return false;
150      }
151    }
152    int vtype;
153    if (PyOrDiscDistribution_Check(args))
154      vtype = TValue::INTVAR;
155    else if (PyOrContDistribution_Check(args))
156      vtype = TValue::FLOATVAR;
157    else if (PyOrStringValue_Check(args))
158      vtype = STRINGVAR;
159    else if (PyOrPythonValue_Check(args))
160      vtype = PYTHONVAR;
161    else
162      raiseError("unknovn variable type");
163
164    value = TValue(PyOrange_AsSomeValue(args), vtype);
165    return true;
166  }
167 
168  if (PyString_Check(args)) {
169    char *str = PyString_AsString(args);
170    if (var)
171      var->str2val(str, value);
172    else
173      if (!strcmp(str, "?"))
174        value = TValue(TValue::INTVAR, valueDK);
175      else if (!strcmp(str, "~"))
176        value = TValue(TValue::INTVAR, valueDC);
177      else {
178        PyErr_Format(PyExc_TypeError, "cannot convert '%s' to a value of an unknown attribute", str);
179        return false;
180      }
181    return true;
182  }
183 
184  if (var && var->varType == PYTHONVAR) {
185    value = TValue(mlnew TPythonValue(args), PYTHONVAR);
186    return true;
187  }
188 
189  if (args == Py_None) {
190    value = var ? var->DK() : TValue(TValue::INTVAR, valueDK);
191    return true;
192  }
193
194  if (PyInt_Check(args)) {
195    int ii = int(PyInt_AsLong(args));
196
197    if (var) {
198      if (var->varType == TValue::FLOATVAR) {
199        value = TValue(float(ii));
200        return true;
201      }
202
203      if (var->varType == TValue::INTVAR) {
204        if (var.is_derived_from(TEnumVariable)) {
205          int nv = var.AS(TEnumVariable)->noOfValues();
206          if (ii >= nv) {
207            PyErr_Format(PyExc_TypeError, "value index %i out of range (0 - %i)", ii, nv-1);
208            return false;
209          }
210        }
211
212        value = TValue(ii);
213        return true;
214      }
215
216      PyErr_Format(PyExc_TypeError,  "cannot convert an integer to a value of attribute '%s'", var->get_name().c_str());
217      return false;
218    }
219
220    value = TValue(ii);
221    return true;
222  }
223
224  if (PyFloat_Check(args)) {
225    if (var && (var->varType != TValue::FLOATVAR)) {
226      PyErr_Format(PyExc_TypeError,  "cannot convert a float to a value of attribute '%s'", var->get_name().c_str());
227      return false;
228    }
229
230    value = TValue(float(PyFloat_AsDouble(args)));
231    return true;
232  }
233
234  if (var && (var->varType == TValue::FLOATVAR)) {
235    PyObject *pyfloat = PyNumber_Float(args);
236    if (!pyfloat) {
237      PyErr_Format(PyExc_TypeError, "cannot convert an object of type '%s' to value of attribute '%s'", args->ob_type->tp_name, var->get_name().c_str());
238      return false;
239    }
240
241    value = TValue(float(PyFloat_AsDouble(pyfloat)));
242    Py_DECREF(pyfloat);
243    return true;
244  }
245
246  if (var)
247    PyErr_Format(PyExc_TypeError,  "cannot convert an object of type '%s' to value of attribute '%s'", args->ob_type->tp_name, var->get_name().c_str());
248  else
249    PyErr_Format(PyExc_TypeError,  "cannot convert an object of type '%s' to value of attribute", args->ob_type->tp_name);
250
251  return false;
252}
253
254
255/* Builds a TPyValue from arguments given in Python.
256   See Value_FromArguments for details. */
257
258bool convertFromPython(PyObject *args, TPyValue *&value)
259{
260  value = (TPyValue *)Value_FromArguments((PyTypeObject *)&PyOrValue_Type, args);
261  return value!=NULL;
262}
263
264
265
266/* The main constructor for TPyValue.
267   Gets a value and descriptor, allocates the memory and assigns fields. */
268
269PyObject *Value_FromVariableValueType(PyTypeObject *type, PVariable var, const TValue &val)
270{ 
271  TPyValue *value = PyObject_GC_New(TPyValue, type);
272  if (!value)
273    return PYNULL;
274
275  /* The below is needed since 'value' was allocated in C code, so it's
276     constructor has never been called and the below fields (wrapped pointers)
277     contain random data, which would lead to crash when trying to deallocate
278     them. */
279  value->value.svalV.init();
280  value->variable.init();
281
282  value->value = val;
283  value->variable = var;
284
285  PyObject_GC_Track(value);
286
287  return (PyObject *)value;
288}
289
290
291
292/* Constructs a value from arguments in Python. Arguments must be given as a tuple
293   with at least one element.
294   - If the single element is a variable, a DK() value for that attribute is returned
295   - Otherwise, it is converted using convertFromPython, without descriptor given
296
297   If there are two elements
298   - If one is variable, convertFromPython is used, passing the variable and the other
299   - Otherwise, both must be integers and are used for varType and valueType.
300*/
301
302PyObject *Value_FromArguments(PyTypeObject *type, PyObject *args)
303{   
304  PyTRY
305    PyObject *obj1;
306    PyObject *obj2 = NULL;
307
308    if (!PyArg_ParseTuple(args, "O|O:Value", &obj1, &obj2))
309      return PYNULL;
310
311    if (!obj2) {
312      if (PyOrVariable_Check(obj1))
313        return Value_FromVariableType(type, PyOrange_AsVariable(obj1));
314      else {
315        TValue val;
316        return convertFromPython(obj1, val) ? Value_FromValueType(type, val) : PYNULL;
317      }
318    }
319
320    TValue val;
321    if (PyOrVariable_Check(obj1)) {
322      const PVariable &var = PyOrange_AsVariable(obj1);
323      return convertFromPython(obj2, val, var) ? Value_FromVariableValueType(type, var, val) : PYNULL;
324    }
325    else if (PyOrVariable_Check(obj2)) {
326      const PVariable &var = PyOrange_AsVariable(obj2);
327      return convertFromPython(obj1, val, var) ? Value_FromVariableValueType(type, var, val) : PYNULL;
328    }
329    else if (PyInt_Check(obj1) && PyInt_Check(obj2)) {
330      int vartype = int(PyInt_AsLong(obj1));
331
332      if (vartype == STRINGVAR)
333        return Value_FromValueType(type, TValue(STRINGVAR, (signed char)PyInt_AsLong(obj2)));
334
335      if (vartype > TValue::FLOATVAR) {
336        PyErr_Format(PyExc_IndexError, "invalid value type (%i)", vartype);
337        return PYNULL;
338      }
339       
340      return Value_FromValueType(type, TValue((char)vartype, (signed char)PyInt_AsLong(obj2)));
341    }
342
343    PYERROR(PyExc_TypeError, "Value(): invalid arguments", PYNULL);
344  PyCATCH
345}
346
347
348
349
350PyObject *Value_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(ROOT, "([Variable], [int | float | Value | ...])")
351{ return Value_FromArguments(type, args); }
352
353
354void Value_dealloc(TPyValue *self)
355{ self->variable = PVariable();
356  self->value.~TValue();
357
358  if (PyObject_IsPointer(self)) {
359    PyObject_GC_UnTrack((PyObject *)self);
360    self->ob_type->tp_free((PyObject *)self); 
361  }
362}
363
364
365int Value_traverse(TPyValue *self, visitproc visit, void *arg)
366{ PVISIT(self->variable);
367  PVISIT(self->value.svalV);
368  return 0;
369}
370
371
372void Value_clear(TPyValue *self)
373{ self->variable=PVariable();
374  self->value.~TValue();
375}
376
377
378/* Returns a string representations for a value.
379   - If descriptor is given, its val2str should take care of everything
380   - If the value is special, we know that to do
381   - If value is
382     - FLOATVAR, convert a floatV
383     - INTVAR, print a intV in brackets
384     - else if svalV is given, it should take care of itself
385     - else, we return "###"
386*/
387
388char *pvs = NULL;
389const char *TPyValue2string(TPyValue *self)
390{ if (self->variable) {
391    string str;
392    self->variable->val2str(self->value, str);
393    pvs = (char *)realloc(pvs, str.size()+1);
394    strcpy(pvs, str.c_str());
395  }
396  else {
397    if (self->value.isDK())
398      return "?";
399    if (self->value.isDC())
400      return "~";
401    if (self->value.isSpecial())
402      return ".";
403
404    pvs = (char *)realloc(pvs, 16);
405    if (self->value.varType==TValue::FLOATVAR)
406      sprintf(pvs, "%f", self->value.floatV);
407    else if (self->value.varType==TValue::INTVAR)
408      sprintf(pvs, "<%i>", self->value.intV);
409    else if (self->value.svalV) {
410      string str;
411      self->value.svalV->val2str(str);
412      pvs = (char *)realloc(pvs, str.size()+1);
413      strcpy(pvs, str.c_str());
414    }
415    else
416      return "###";
417  }
418
419  return pvs;
420}
421
422
423
424/* Compares two values. The first is always TPyValue.
425   Comparisons of discrete are based on intV not on string representations
426   If both are TPyValue, the values must be of same type
427     - If both are special, they are equal/different if the valueType is
428       equal/different. Operators >, <, <= and >= are not defined.
429     - If only one is special, it's an error
430     - If they are discrete and descriptors are known but different,
431       each value's string representation is compared to the other's,
432       both comparisons are made and must give the same result.
433       If not, it's an error.
434     - Otherwise, intV's r floatV's are compared
435   If the other is an integer, it can be compared with discrete and
436     continuous attributes
437   If the other is a float, it can be compared with continuous attrs.
438   If the first value is special and the other is string "~" or "?",
439     they are compared as described above.
440   Otherwise, the descriptor for the first value must be known and is
441     used to convert the second value (if possible). The values are
442     then compared by the same rules as if both were PyValues
443     (except that both obviously have the same descriptor).
444*/
445
446#define errUndefinedIf(cond) if (cond) PYERROR(PyExc_TypeError, "Value.compare: cannot compare with undefined values", PYNULL);
447
448PyObject *richcmp_from_sign(const int &i, const int &op)
449{ int cmp;
450  switch (op) {
451        case Py_LT: cmp = (i<0); break;
452        case Py_LE: cmp = (i<=0); break;
453        case Py_EQ: cmp = (i==0); break;
454        case Py_NE: cmp = (i!=0); break;
455        case Py_GT: cmp = (i>0); break;
456        case Py_GE: cmp = (i>=0); break;
457    default:
458      Py_INCREF(Py_NotImplemented);
459      return Py_NotImplemented;
460  }
461 
462  PyObject *res;
463  if (cmp)
464    res = Py_True;
465  else
466    res = Py_False;
467  Py_INCREF(res);
468  return res;
469}
470
471
472PyObject *Value_richcmp(TPyValue *i, PyObject *j, int op)
473{ 
474  PyTRY
475
476    const TValue &val1 = i->value;
477
478    if (PyOrValue_Check(j)) {
479      const TValue &val2 = PyValue_AS_Value(j);
480
481      if (val1.varType != val2.varType)
482        PYERROR(PyExc_TypeError, "Value.compare: can't compare values of different types", PYNULL)
483
484      // Nominal values of different attributes are treated separately
485      PVariable &var1 = i->variable;
486      PVariable &var2 = PyValue_AS_Variable(j);
487      if ((val1.varType==TValue::INTVAR) && var1 && var2 && (var1 != var2)) {
488        TValue tempval;
489        string tempstr;
490
491        var2->val2str(val2, tempstr);
492        if (var1->str2val_try(tempstr, tempval)) {
493          int cmp1 = val1.compare(tempval);
494
495          var1->val2str(val1, tempstr);
496          if (var2->str2val_try(tempstr, tempval)) {
497            int cmp2 = tempval.compare(val2);
498            bool err = true;
499            switch (op) {
500              case Py_LE:
501              case Py_GE: err = ((cmp1*cmp2) == -1); break;
502              case Py_LT:
503              case Py_GT: err = (cmp1!=cmp2); break;
504              case Py_EQ:
505              case Py_NE: err = ((cmp1==0) != (cmp2==0)); break;
506            }
507
508            if (err)
509              PYERROR(PyExc_TypeError, "Value.compare: values are of different types and have different orders", PYNULL);
510          }
511
512          return richcmp_from_sign(cmp1, op);
513        }
514
515        var1->val2str(val1, tempstr);
516        if (var2->str2val_try(tempstr, tempval))
517          return richcmp_from_sign(tempval.compare(val2), op);
518
519        PYERROR(PyExc_TypeError, "Value.compare: values are of different types and cannot be compared", PYNULL);
520      }
521
522      // Not nominal OR both values or of the same attribute
523      return richcmp_from_sign(val1.compare(val2), op);
524    }
525
526
527    if (PyInt_Check(j)) {
528      errUndefinedIf(val1.isSpecial());
529
530      if (val1.varType==TValue::INTVAR)
531        return richcmp_from_sign(val1.intV - (int)PyInt_AsLong(j), op);
532      else if (val1.varType==TValue::FLOATVAR)
533        return richcmp_from_sign(sign(val1.floatV - (int)PyInt_AsLong(j)), op);
534    }
535
536    else if (PyFloat_Check(j)) {
537      errUndefinedIf(val1.isSpecial());
538      if (val1.varType==TValue::FLOATVAR)
539        return richcmp_from_sign(sign(val1.floatV - (float)PyFloat_AsDouble(j)), op);
540    }
541
542    else if (PyString_Check(j) && val1.isSpecial() && ((op==Py_EQ) || (op==Py_NE))) {
543      char *s = PyString_AsString(j);
544      PyObject *res = NULL;
545      if (!strcmp(s, "~"))
546        res = (val1.valueType==valueDC) == (op==Py_EQ) ? Py_True : Py_False;
547      else if (!strcmp(s, "?"))
548        res = (val1.valueType==valueDK) == (op==Py_EQ) ? Py_True : Py_False;
549      if (res) {
550        Py_INCREF(res);
551        return res;
552      }
553    }
554
555    if (i->variable) {
556      TValue val2;
557      if (!convertFromPython(j, val2, i->variable))
558        return PYNULL;
559
560      return richcmp_from_sign(val1.compare(val2), op);
561    }
562     
563    Py_INCREF(Py_NotImplemented);
564    return Py_NotImplemented;
565
566  PyCATCH
567}
568#undef errUndefinedIf
569
570
571
572PyObject *Value_str(TPyValue *self)
573{ PyTRY
574    return PyString_FromString(TPyValue2string(self)); 
575  PyCATCH
576}
577
578
579PyObject *Value_repr(TPyValue *self)
580{ PyTRY
581    if (self->variable)
582      return PyString_FromFormat("<orange.Value '%s'='%s'>", self->variable->get_name().c_str(), TPyValue2string(self));
583    else
584      return PyString_FromFormat("<orange.Value '%s'>", TPyValue2string(self)); 
585  PyCATCH
586}
587
588
589bool checkSpecial(TPyValue *self, char *casttype)
590{
591  if (self->value.isSpecial()) {
592    if (self->variable && self->variable->get_name().length())
593      PyErr_Format(PyExc_TypeError, "value of '%s' is unknown and cannot be %s", self->variable->get_name().c_str(), casttype);
594    else
595      PyErr_Format(PyExc_TypeError, "attribute value is unknown and cannot be %s", casttype);
596    return false;
597  }
598
599  return true;
600}
601
602PyObject *Value_int(TPyValue *self)
603{ PyTRY
604    if (!checkSpecial(self, "cast to an integer"))
605      return PYNULL;
606
607    return Py_BuildValue("i", (self->value.varType==TValue::INTVAR) ? self->value.intV : int(self->value.floatV)); 
608  PyCATCH
609}
610
611
612PyObject *Value_long(TPyValue *self)
613{ PyTRY
614    if (!checkSpecial(self, "cast to a long integer"))
615      return PYNULL;
616
617    return Py_BuildValue("l", (self->value.varType==TValue::INTVAR) ? long(self->value.intV) : long(self->value.floatV)); 
618  PyCATCH
619}
620
621
622PyObject *Value_float(TPyValue *self)
623{ PyTRY
624    if (!checkSpecial(self, "cast to a float"))
625      return PYNULL;
626
627    return Py_BuildValue("f", (self->value.varType==TValue::INTVAR) ? float(self->value.intV) : self->value.floatV); 
628  PyCATCH
629}
630
631
632inline bool checkForNumerical(const TValue &val1, const TValue &val2, const char *op)
633{
634  if (val1.isSpecial() || val2.isSpecial())
635    PYERROR(PyExc_TypeError, "cannot %s unknown values", false);
636  if ((val1.varType!=TValue::FLOATVAR) || (val2.varType!=TValue::FLOATVAR))
637    PYERROR(PyExc_TypeError, "cannot %s non-continuous values", false);
638  return true;
639}
640
641
642#define VALUEOP(opname,FUN,opverb) \
643PyObject *Value_##opname(TPyValue *self, PyObject *other) \
644{ PyTRY \
645    const TValue &val1 = self->value; \
646\
647    if (PyOrValue_Check(other)) { \
648      const TValue &val2 = PyValue_AS_Value(other); \
649      return checkForNumerical(val1, val2, opverb) ? PyFloat_FromDouble(val1.floatV FUN val2.floatV) : PYNULL; \
650    } \
651\
652    TValue val2; \
653    return convertFromPython(other, val2, self->variable) && checkForNumerical(val1, val2, opverb) ? PyFloat_FromDouble(val1.floatV FUN val2.floatV) : PYNULL; \
654  PyCATCH \
655}
656
657
658PyObject *Value_add(TPyValue *self, PyObject *other);
659PyObject *Value_sub(TPyValue *self, PyObject *other);
660PyObject *Value_mul(TPyValue *self, PyObject *other);
661PyObject *Value_div(TPyValue *self, PyObject *other);
662
663VALUEOP(add,+,"sum")
664VALUEOP(sub,-,"subtract")
665VALUEOP(mul,*,"multiply")
666VALUEOP(div,/,"divide")
667
668
669PyObject *Value_pow(TPyValue *self, PyObject *other, PyObject *)
670{ PyTRY
671    const TValue &val1 = self->value;
672   
673    if (!val1.isSpecial() && (val1.varType==TValue::FLOATVAR) && (val1.floatV<=0))
674      PYERROR(PyExc_TypeError, "negative base value", false);
675
676    if (PyOrValue_Check(other)) { 
677      const TValue &val2 = PyValue_AS_Value(other); 
678      return checkForNumerical(val1, val2, "add") ? PyFloat_FromDouble(exp(val2.floatV*log(val1.floatV))) : PYNULL;
679    }
680    else {
681      TValue val2; 
682      return    convertFromPython(other, val2, self->variable)
683             && checkForNumerical(val1, val2, "add")
684           ? PyFloat_FromDouble(exp(val2.floatV*log(val1.floatV)))
685           : PYNULL;
686    }
687  PyCATCH
688}
689
690
691PyObject *Value_neg(TPyValue *self)
692{ PyTRY
693    if (!checkSpecial(self, "negated"))
694      return PYNULL;
695
696    const TValue &val1 = self->value;
697    if (val1.varType!=TValue::FLOATVAR)
698      PYERROR(PyExc_TypeError, "cannot negate non-continuous value", false);
699    return PyFloat_FromDouble(-val1.floatV);
700  PyCATCH
701}
702
703
704PyObject *Value_abs(TPyValue *self)
705{ PyTRY
706    if (self->value.isSpecial())
707      if (self->variable && self->variable->get_name().length()) {
708        PyErr_Format(PyExc_TypeError, "cannot compute an absolute value of '%s' since its value is unknown", self->variable->get_name().c_str());
709        return PYNULL;
710      }
711      else
712        PYERROR(PyExc_TypeError, "cannot compute an absolute value of attribute since its value is unknown", PYNULL);
713
714    const TValue &val1 = self->value;
715    if (val1.varType!=TValue::FLOATVAR)
716      PYERROR(PyExc_TypeError, "cannot compute abs of non-continuous value", false);
717    return PyFloat_FromDouble(fabs(val1.floatV));
718  PyCATCH
719}
720
721
722int Value_nonzero(TPyValue *i)
723{ PyTRY
724    return !i->value.isSpecial();
725  PyCATCH_1
726}
727
728
729int Value_coerce(PyObject **i, PyObject **obj)
730{ PyTRY
731    if (PyString_Check(*obj)) {
732      *i = Value_str(*(TPyValue **)i);
733      if (!*i)
734        return -1;
735      Py_INCREF(*obj);
736      return 0;
737    }
738
739    if (PyInt_Check(*obj)) {
740      TPyValue *val = *(TPyValue **)i;
741      if (val->value.varType==TValue::INTVAR) {
742        *i = Value_int(val);
743        if (!*i)
744          return -1;
745        Py_INCREF(*obj);
746        return 0;
747      }
748      else if (val->value.varType==TValue::FLOATVAR) {
749        *i = Value_float(val);
750        if (!*i)
751          return -1;
752        double x = PyFloat_AsDouble(*obj);
753            *obj = PyFloat_FromDouble(x);
754        return 0;
755      }
756      else
757        return -1;
758    }
759
760    if (PyFloat_Check(*obj)) {
761      *i = Value_float(*(TPyValue **)i);
762      if (!*i)
763        return -1;
764      Py_INCREF(*obj);
765      return 0;
766    }
767
768    if (PyLong_Check(*obj)) {
769      *i = Value_long(*(TPyValue **)i);
770      if (!*i)
771        return -1;
772      Py_INCREF(*obj);
773      return 0;
774    }
775
776    return -1;
777  PyCATCH_1
778}
779
780
781
782PyObject *Value_get_svalue(TPyValue *self)
783{ PyTRY
784    if (self->value.varType == PYTHONVAR) {
785      PyObject *res = self->value.svalV ? ((TPythonValue &)(self->value.svalV.getReference())).value : Py_None;
786      Py_INCREF(res);
787      return res;
788    }
789
790    return WrapOrange(self->value.svalV);
791  PyCATCH
792}
793
794
795int Value_set_svalue(TPyValue *self, PyObject *arg)
796{ PyTRY
797
798    if (arg == Py_None) {
799      self->value.svalV = PSomeValue();
800      return 0;
801    }
802
803    if (PyOrSomeValue_Check(arg)) {
804      self->value.svalV = PyOrange_AsSomeValue(arg);
805      return 0;
806    }
807
808    self->value.svalV = mlnew TPythonValue(arg);
809    return 0;
810
811  PyCATCH_1
812}
813
814
815PyObject *Value_get_value(TPyValue *self)
816{ PyTRY
817    return convertToPythonNative(self);
818  PyCATCH
819}
820
821
822int Value_set_value(TPyValue *self, PyObject *arg)
823{ PyTRY
824    return convertFromPython(arg, self->value, self->variable) ? 0 : -1;
825  PyCATCH_1
826}
827
828
829PyObject *PyValue_Type_FromLong(long);
830
831PyObject *Value_get_valueType(TPyValue *self)
832{ return PyValue_Type_FromLong((long)self->value.valueType); }
833
834
835PyObject *Value_get_variable(TPyValue *self)
836{ return WrapOrange(self->variable); }
837
838
839int Value_set_variable(TPyValue *self, PyObject *arg)
840{ PyTRY
841    if (arg == Py_None) {
842      self->variable = PVariable();
843      return 0;
844    }
845    if (!PyOrVariable_Check(arg))
846      PYERROR(PyExc_TypeError, "invalid argument for attribute 'variable'", -1)
847    else {
848      self->variable = PyOrange_AsVariable(arg);
849      return 0;
850    }
851  PyCATCH_1
852}
853
854
855PyObject *PyVariable_Type_FromLong(long);
856
857PyObject *Value_get_varType(TPyValue *self)
858{ return PyVariable_Type_FromLong((long)self->value.varType); }
859
860
861
862
863char *value_underscores[][2] = {
864    {"firstvalue", "first_value"},
865    {"nextvalue", "next_value"},
866    {"randomvalue", "random_value"},
867    {"isDC", "is_DC"},
868    {"isDK", "is_DK"},
869    {"isSpecial", "is_special"},
870    {"varType", "var_type"},
871    {"valueType", "value_type"},   
872    {NULL, NULL}
873};
874
875PyObject *Value_getattr(PyObject *self, PyObject *name)
876{
877  char *orig = PyString_AsString(name);
878  for(char *(*ei)[2] = value_underscores; **ei; ei++) {
879      if (!strcmp(orig, **ei)) {
880          PyObject *trans = PyString_FromString((*ei)[1]);
881          PyObject *value = PyObject_GenericGetAttr((PyObject *)self, trans);
882          Py_DECREF(trans);
883          return value;
884      }
885  }
886
887  return PyObject_GenericGetAttr((PyObject *)self, name);
888
889}
890
891PyObject *Value_random_value(TPyValue *self) PYARGS(METH_NOARGS, "(); Sets the value to a random")
892{ PyTRY
893    CHECK_VARIABLE
894    self->value = self->variable->randomValue();
895    RETURN_NONE
896  PyCATCH
897}
898
899
900PyObject *Value_first_value(TPyValue *self)  PYARGS(METH_NOARGS, "() -> bool; Sets the value to the first value")
901{ PyTRY
902    CHECK_VARIABLE
903    return PyInt_FromLong(self->variable->firstValue(self->value) ? 1 : 0);
904  PyCATCH
905}
906
907
908PyObject *Value_next_value(TPyValue *self)  PYARGS(METH_NOARGS, "() -> bool; Increases the value (if possible)")
909{ PyTRY
910    CHECK_VARIABLE
911    return PyInt_FromLong(self->variable->nextValue(self->value) ? 1 : 0);
912  PyCATCH
913}
914
915
916PyObject *Value_isSpecial(TPyValue *self)  PYARGS(METH_NOARGS, "() -> bool; Returns true if value is DK, DC...")
917{ return PyInt_FromLong(self->value.isSpecial() ? 1 : 0); }
918
919
920PyObject *Value_isDK(TPyValue *self)  PYARGS(METH_NOARGS, "() -> bool; Returns true if value is DK")
921{ return PyInt_FromLong(self->value.isDK() ? 1 : 0); }
922
923
924PyObject *Value_isDC(TPyValue *self)  PYARGS(METH_NOARGS, "() -> bool; Returns true if value is DC")
925{ return PyInt_FromLong(self->value.isDC() ? 1 : 0); }
926
927
928PyObject *Value_native(TPyValue *self)   PYARGS(METH_NOARGS, "() -> bool; Converts the value into string or float")
929{ PyTRY
930    return convertToPythonNative(self);
931  PyCATCH
932}
933
934
935#include "slist.hpp"
936
937bool Value_pack(const TValue &value, TCharBuffer &buf, PyObject *&otherValues)
938{
939  const char svalFlag = value.svalV ? 1 << 5 : 0;
940  if (svalFlag) {
941    if (!otherValues)
942      otherValues = PyList_New(0);
943    PyObject *sv = WrapOrange(value.svalV);
944    PyList_Append(otherValues, sv);
945    Py_DECREF(sv);
946  }
947
948  if (value.valueType) {
949    buf.writeChar(svalFlag | (value.valueType & 0x1f));
950    return true;
951  }
952
953  if (value.varType == TValue::INTVAR) {
954    if (value.intV < (1 << (sizeof(char) << 3))) {
955      buf.writeChar((1 << 6) | svalFlag);
956      buf.writeChar(char(value.intV));
957    }
958
959    else if (value.intV < (1 << (sizeof(short) << 3))) {
960      buf.writeChar((2 << 6) | svalFlag);
961      buf.writeShort((unsigned short)(value.intV));
962    }
963
964    else {
965      buf.writeChar((3 << 6) | svalFlag);
966      buf.writeInt(value.intV);
967    }
968
969    return true;
970  }
971
972  else if (value.varType == TValue::FLOATVAR) {
973    buf.writeChar(svalFlag);
974    buf.writeFloat(value.floatV);
975  }
976
977  else
978    buf.writeChar(svalFlag);
979
980  return true;
981}
982
983
984bool Value_unpack(TValue &value, TCharBuffer &buf, PyObject *otherValues, int &otherValuesIndex)
985{
986  unsigned char flags = (unsigned char) buf.readChar();
987
988  if (flags & (1 << 5))
989    value.svalV = PyOrange_AsSomeValue(PyList_GetItem(otherValues, otherValuesIndex++));
990
991  value.valueType = flags & 0x1f;
992
993  if (value.valueType) {
994    value.floatV = numeric_limits<float>::quiet_NaN();
995    value.intV = numeric_limits<int>::max();
996    return true;
997  }
998
999  if (value.varType == TValue::INTVAR) {
1000    flags >>= 6;
1001    if (flags == 1)
1002      value.intV = (unsigned char) buf.readChar();
1003    else if (flags == 2)
1004      value.intV = buf.readShort();
1005    else if (flags == 3)
1006      value.intV = buf.readInt();
1007    value.floatV = numeric_limits<float>::quiet_NaN();
1008  }
1009
1010  else if (value.varType == TValue::FLOATVAR) {
1011    value.floatV = buf.readFloat();
1012    value.intV = numeric_limits<int>::max();
1013  }
1014   
1015  return true;
1016}
1017
1018PyObject *Value__reduce__(PyObject *self)
1019{
1020  PyTRY
1021    TCharBuffer buf(16);
1022    PyObject *otherValues = NULL;
1023    buf.writeChar(PyValue_AS_Value(self).varType);
1024    Value_pack(PyValue_AS_Value(self), buf, otherValues);
1025    if (!otherValues) {
1026      otherValues = Py_None;
1027      Py_INCREF(otherValues);
1028    }
1029   
1030    return Py_BuildValue("O(Ns#N)", getExportedFunction("__pickleLoaderValue"),
1031                                   WrapOrange(PyValue_AS_Variable(self)),
1032                                   buf.buf, buf.length(),
1033                                   otherValues);
1034  PyCATCH
1035}
1036
1037
1038PyObject *__pickleLoaderValue(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(variable, packed_values, other_values)")
1039{
1040  PyTRY
1041    PVariable var;
1042    char *pbuf;
1043    int bufSize;
1044    PyObject *otherValues;
1045    if (!PyArg_ParseTuple(args, "O&s#O:__pickleLoaderValue", ccn_Variable, &var, &pbuf, &bufSize, &otherValues))
1046      return PYNULL;
1047
1048    TCharBuffer buf(pbuf);
1049    int otherValuesIndex = 0;
1050    TValue val((const unsigned char &)(buf.readChar()));
1051    Value_unpack(val, buf, otherValues, otherValuesIndex);
1052    return Value_FromVariableValue(var, val);
1053  PyCATCH
1054}
1055
1056#undef CHECK_VARIABLE
1057#undef CHECK_SPECIAL_OTHER
1058
1059
1060// This is in a separate file to avoid scanning by pyxtract
1061#include "valuelisttemplate.hpp"
1062
1063// Modified new and related stuff, removed rich_cmp (might be added later, but needs to be programmed specifically)
1064PValueList PValueList_FromArguments(PyObject *arg, PVariable var = PVariable())
1065{ return TValueListMethods::P_FromArguments(arg, var); }
1066
1067
1068PyObject *ValueList_FromArguments(PyTypeObject *type, PyObject *arg, PVariable var = PVariable())
1069{ return TValueListMethods::_FromArguments(type, arg, var); }
1070
1071
1072PyObject *ValueList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of Value>)")  ALLOWS_EMPTY
1073{ return TValueListMethods::_new(type, arg, kwds); }
1074
1075
1076PyObject *ValueList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return TValueListMethods::_getitem(self, index); }
1077int       ValueList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return TValueListMethods::_setitem(self, index, item); }
1078PyObject *ValueList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return TValueListMethods::_getslice(self, start, stop); }
1079int       ValueList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return TValueListMethods::_setslice(self, start, stop, item); }
1080Py_ssize_t ValueList_len_sq(TPyOrange *self) { return TValueListMethods::_len(self); }
1081PyObject *ValueList_concat(TPyOrange *self, PyObject *obj) { return TValueListMethods::_concat(self, obj); }
1082PyObject *ValueList_repeat(TPyOrange *self, Py_ssize_t times) { return TValueListMethods::_repeat(self, times); }
1083PyObject *ValueList_str(TPyOrange *self) { return TValueListMethods::_str(self); }
1084PyObject *ValueList_repr(TPyOrange *self) { return TValueListMethods::_str(self); }
1085int       ValueList_contains(TPyOrange *self, PyObject *obj) { return TValueListMethods::_contains(self, obj); }
1086PyObject *ValueList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Value) -> None") { return TValueListMethods::_append(self, item); }
1087PyObject *ValueList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return TValueListMethods::_extend(self, obj); }
1088PyObject *ValueList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Value) -> int") { return TValueListMethods::_count(self, obj); }
1089PyObject *ValueList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ValueList") { return TValueListMethods::_filter(self, args); }
1090PyObject *ValueList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Value) -> int") { return TValueListMethods::_index(self, obj); }
1091PyObject *ValueList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return TValueListMethods::_insert(self, args); }
1092PyObject *ValueList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return TValueListMethods::_native(self); }
1093PyObject *ValueList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Value") { return TValueListMethods::_pop(self, args); }
1094PyObject *ValueList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Value) -> None") { return TValueListMethods::_remove(self, obj); }
1095PyObject *ValueList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return TValueListMethods::_reverse(self); }
1096PyObject *ValueList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return TValueListMethods::_sort(self, args); }
1097PyObject *ValueList__reduce__(TPyOrange *self, PyObject *) { return TValueListMethods::_reduce(self); }
1098
1099
1100
1101PyObject *VarTypes()
1102{ PyObject *vartypes=PyModule_New("Orange.data.Type");
1103  PyModule_AddObject(vartypes, "None", PyVariable_Type_FromLong((int)TValue::NONE));
1104  PyModule_AddObject(vartypes, "Discrete", PyVariable_Type_FromLong((int)TValue::INTVAR));
1105  PyModule_AddObject(vartypes, "Continuous", PyVariable_Type_FromLong((int)TValue::FLOATVAR));
1106  PyModule_AddObject(vartypes, "Other", PyVariable_Type_FromLong((int)TValue::FLOATVAR+1)); // for compatibility; don't use!
1107  PyModule_AddObject(vartypes, "String", PyVariable_Type_FromLong((int)STRINGVAR));
1108  return vartypes;
1109}
1110
1111/* Left here for compatibility */
1112
1113PYCONSTANTFUNC(VarTypes, VarTypes)
1114
1115/* This cannot be done in the header since Value is not derived from Orange */
1116
1117TNamedConstantsDef Value_Type_values[] = {{"Regular", 0}, {"DC", valueDC}, {"DK", valueDK}, {0, 0}};
1118
1119PYXTRACT_IGNORE static PyObject *Value_Type_repr(PyObject *self)
1120{
1121  return stringFromList(self, Value_Type_values);
1122}
1123
1124PYXTRACT_IGNORE PyObject *Value_Type__reduce__(PyObject *self);
1125PyMethodDef Value_Type_methods[] = { {"__reduce__", (binaryfunc)Value_Type__reduce__, METH_NOARGS, "reduce"}, {NULL, NULL}};
1126PyTypeObject PyValue_Type_Type = {PyObject_HEAD_INIT(&PyType_Type) 0, "Value.Type", sizeof(PyIntObject), 0, 0, 0, 0, 0, 0, (reprfunc)Value_Type_repr, 0, 0, 0, 0, 0, (reprfunc)Value_Type_repr, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, 0, 0, 0, 0, 0, 0, 0, Value_Type_methods, 0, 0, &PyInt_Type};
1127
1128PyObject *PyValue_Type_FromLong(long ok)
1129{ PyIntObject *r = PyObject_New(PyIntObject, &PyValue_Type_Type);
1130  r->ob_ival = ok;
1131  return (PyObject *)r;
1132}
1133
1134void *PTValue_Type(void *l)
1135{ return PyValue_Type_FromLong(*(long *)l); }
1136
1137
1138PYXTRACT_IGNORE PyObject *Value_Type__reduce__(PyObject *self)
1139{ return Py_BuildValue("O(i)", getExportedFunction("__pickleLoaderValueType"), ((PyIntObject *)(self))->ob_ival); }
1140
1141PyObject *__pickleLoaderValueType(PyObject *, PyObject *args) PYARGS(METH_O, "")
1142{ return PyValue_Type_FromLong(PyInt_AsLong(args)); }
1143
1144/* Left for backward compatibility; also used the opportunity to initialize the type */
1145
1146PyObject *ValueTypes()
1147{ PyType_Ready(&PyValue_Type_Type);
1148  PyValue_Type_Type.tp_print = 0;
1149  PyObject *valuetypes=PyModule_New("ValueTypes");
1150  PyModule_AddObject(valuetypes, "Regular", PyValue_Type_FromLong(valueRegular));
1151  PyModule_AddObject(valuetypes, "DC", PyValue_Type_FromLong(valueDC));
1152  PyModule_AddObject(valuetypes, "DK", PyValue_Type_FromLong(valueDK));
1153  return valuetypes;
1154}
1155
1156PYCONSTANTFUNC(ValueTypes, ValueTypes)
1157
1158PYCLASSCONSTANT(Value, Regular, PyValue_Type_FromLong(valueRegular))
1159PYCLASSCONSTANT(Value, DC, PyValue_Type_FromLong(valueDC))
1160PYCLASSCONSTANT(Value, DK, PyValue_Type_FromLong(valueDK))
1161
1162#include "cls_value.px"
Note: See TracBrowser for help on using the repository browser.