1 /**
2 * Copyright 2015, SRI International.
3 *
4 * This file is part of LibPoly.
5 *
6 * LibPoly is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * LibPoly is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with LibPoly. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "polypyValue.h"
21 #include "utils.h"
22 #include "polypyAlgebraicNumber.h"
23
24 #include <structmember.h>
25 #include <math.h>
26
27 static void
28 Value_dealloc(Value* self);
29
30 static PyObject*
31 Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
32
33 static int
34 Value_init(Value* self, PyObject* args);
35
36 static PyObject*
37 Value_to_double(PyObject* self);
38
39 static PyObject*
40 Value_richcompare(PyObject* self, PyObject* other, int op);
41
42 static PyObject*
43 Value_str(PyObject* self);
44
45 static long
46 Value_hash(PyObject* self);
47
48 static PyObject*
49 Value_get_value_between(PyObject* self, PyObject* args);
50
51 static PyObject*
52 Value_add(PyObject* self, PyObject* args);
53
54 static PyObject*
55 Value_neg(PyObject* self);
56
57 static PyObject*
58 Value_sub(PyObject* self, PyObject* args);
59
60 static PyObject*
61 Value_mul(PyObject* self, PyObject* args);
62
63 static PyObject*
64 Value_div(PyObject* self, PyObject* args);
65
66 static PyObject*
67 Value_pow(PyObject* self, PyObject* args);
68
69 static PyObject*
70 Value_long(PyObject* self);
71
72 static PyObject*
73 Value_float(PyObject* self);
74
75 PyMethodDef Value_methods[] = {
76 {"to_double", (PyCFunction)Value_to_double, METH_NOARGS, "Returns the approximation of the value"},
77 {"get_value_between", (PyCFunction)Value_get_value_between, METH_VARARGS, "Returns a value between this and given value"},
78 {NULL} /* Sentinel */
79 };
80
81 PyNumberMethods Value_NumberMethods = {
82 Value_add, // binaryfunc nb_add;
83 Value_sub, // binaryfunc nb_subtract;
84 Value_mul, // binaryfunc nb_multiply;
85 0, // binaryfunc nb_remainder;
86 0, // binaryfunc nb_divmod;
87 (ternaryfunc)Value_pow, // ternaryfunc nb_power;
88 Value_neg, // unaryfunc nb_negative;
89 0, // unaryfunc nb_positive;
90 0, // unaryfunc nb_absolute;
91 0, // inquiry nb_bool;
92 0, // unaryfunc nb_invert;
93 0, // binaryfunc nb_lshift;
94 0, // binaryfunc nb_rshift;
95 0, // binaryfunc nb_and;
96 0, // binaryfunc nb_xor;
97 0, // binaryfunc nb_or;
98 Value_long, // unaryfunc nb_int;
99 0, // void *nb_reserved;
100 Value_float, // unaryfunc nb_float;
101 0, // binaryfunc nb_inplace_add;
102 0, // binaryfunc nb_inplace_subtract;
103 0, // binaryfunc nb_inplace_multiply;
104 0, // binaryfunc nb_inplace_remainder;
105 0, // ternaryfunc nb_inplace_power;
106 0, // binaryfunc nb_inplace_lshift;
107 0, // binaryfunc nb_inplace_rshift;
108 0, // binaryfunc nb_inplace_and;
109 0, // binaryfunc nb_inplace_xor;
110 0, // binaryfunc nb_inplace_or;
111 0, // binaryfunc nb_floor_divide;
112 Value_div, // binaryfunc nb_true_divide;
113 0, // binaryfunc nb_inplace_floor_divide;
114 0, // binaryfunc nb_inplace_true_divide;
115 0, // unaryfunc nb_index;
116 0, // binaryfunc nb_matrix_multiply;
117 0, // binaryfunc nb_inplace_matrix_multiply;
118 };
119
120 PyTypeObject ValueType = {
121 {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD
122 "polypy.Value", // const char *tp_name;
123 sizeof(Value), // Py_ssize_t tp_basicsize;
124 0, // Py_ssize_t tp_itemsize;
125 (destructor)Value_dealloc, // destructor tp_dealloc;
126 0, // printfunc tp_print;
127 0, // getattrfunc tp_getattr;
128 0, // setattrfunc tp_setattr;
129 0, // PyAsyncMethods *tp_as_async;
130 Value_str, // reprfunc tp_repr;
131 &Value_NumberMethods, // PyNumberMethods *tp_as_number;
132 0, // PySequenceMethods *tp_as_sequence;
133 0, // PyMappingMethods *tp_as_mapping;
134 &Value_hash, // hashfunc tp_hash;
135 0, // ternaryfunc tp_call;
136 Value_str, // reprfunc tp_str;
137 0, // getattrofunc tp_getattro;
138 0, // setattrofunc tp_setattro;
139 0, // PyBufferProcs *tp_as_buffer;
140 Py_TPFLAGS_DEFAULT, // unsigned long tp_flags;
141 "Values of different kinds", // const char *tp_doc;
142 0, // traverseproc tp_traverse;
143 0, // inquiry tp_clear;
144 Value_richcompare, // richcmpfunc tp_richcompare;
145 0, // Py_ssize_t tp_weaklistoffset;
146 0, // getiterfunc tp_iter;
147 0, // iternextfunc tp_iternext;
148 Value_methods, // struct PyMethodDef *tp_methods;
149 0, // struct PyMemberDef *tp_members;
150 0, // struct PyGetSetDef *tp_getset;
151 0, // struct _typeobject *tp_base;
152 0, // PyObject *tp_dict;
153 0, // descrgetfunc tp_descr_get;
154 0, // descrsetfunc tp_descr_set;
155 0, // Py_ssize_t tp_dictoffset;
156 (initproc)Value_init, // initproc tp_init;
157 0, // allocfunc tp_alloc;
158 Value_new, // newfunc tp_new;
159 0, // freefunc tp_free;
160 0, // inquiry tp_is_gc;
161 0, // PyObject *tp_bases;
162 0, // PyObject *tp_mro;
163 0, // PyObject *tp_cache;
164 0, // PyObject *tp_subclasses;
165 0, // PyObject *tp_weaklist;
166 0, // destructor tp_del;
167 0, // unsigned int tp_version_tag;
168 0, // destructor tp_finalize;
169 };
170
171 static void
Value_dealloc(Value * self)172 Value_dealloc(Value* self)
173 {
174 lp_value_destruct(&self->v);
175 ((PyObject*)self)->ob_type->tp_free((PyObject*)self);
176 }
177
178 PyObject*
PyValue_create(const lp_value_t * v)179 PyValue_create(const lp_value_t* v) {
180 Value *self;
181 self = (Value*)ValueType.tp_alloc(&ValueType, 0);
182 if (self != NULL) {
183 if (v) {
184 lp_value_construct_copy(&self->v, v);
185 } else {
186 lp_value_construct_zero(&self->v);
187 }
188 }
189 return (PyObject *)self;
190 }
191
192 static PyObject*
Value_new(PyTypeObject * type,PyObject * args,PyObject * kwds)193 Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
194 return PyValue_create(0);
195 }
196
197 /** Construct a value from given number. */
198 static int
Value_init(Value * self,PyObject * args)199 Value_init(Value* self, PyObject* args)
200 {
201 if (PyTuple_Check(args)) {
202 if (PyTuple_Size(args) == 0) {
203 lp_value_construct_zero(&self->v);
204 } else if (PyTuple_Size(args) == 1) {
205 PyObject* v = PyTuple_GetItem(args, 0);
206 if (PyLong_Check(v)) {
207 long v_int = PyLong_AsLong(v);
208 lp_value_construct_int(&self->v, v_int);
209 } else if (PyAlgebraicNumber_CHECK(v)) {
210 AlgebraicNumber* v_alg = (AlgebraicNumber*) v;
211 lp_value_construct(&self->v, LP_VALUE_ALGEBRAIC, &v_alg->a);
212 } else {
213 return -1;
214 }
215 } else {
216 return -1;
217 }
218 } else {
219 return -1;
220 }
221
222 // All fine, initialized
223 return 0;
224 }
225
226 static PyObject*
Value_to_double(PyObject * self)227 Value_to_double(PyObject* self) {
228
229 Value* a = (Value*) self;
230
231 double value = 0;
232
233 switch (a->v.type) {
234 case LP_VALUE_NONE:
235 assert(0);
236 break;
237 case LP_VALUE_INTEGER:
238 value = lp_integer_to_int(&a->v.value.z);
239 break;
240 case LP_VALUE_DYADIC_RATIONAL:
241 value = lp_dyadic_rational_to_double(&a->v.value.dy_q);
242 break;
243 case LP_VALUE_RATIONAL:
244 value = lp_rational_to_double(&a->v.value.q);
245 break;
246 case LP_VALUE_ALGEBRAIC:
247 value = lp_algebraic_number_to_double(&a->v.value.a);
248 break;
249 case LP_VALUE_PLUS_INFINITY:
250 value = INFINITY;
251 break;
252 case LP_VALUE_MINUS_INFINITY:
253 value = -INFINITY;
254 break;
255 }
256
257 return PyFloat_FromDouble(value);
258 }
259
260 static PyObject*
Value_richcompare(PyObject * self,PyObject * other,int op)261 Value_richcompare(PyObject* self, PyObject* other, int op) {
262 PyObject *result = 0;
263
264 if (!PyValue_CHECK(other)) {
265 result = Py_NotImplemented;
266 } else {
267 lp_value_t* self_v = &((Value*) self)->v;
268 lp_value_t* other_v = &((Value*) other)->v;
269 int cmp = lp_value_cmp(self_v, other_v);
270
271 switch (op) {
272 case Py_LT:
273 result = cmp < 0 ? Py_True : Py_False;
274 break;
275 case Py_LE:
276 result = cmp <= 0 ? Py_True : Py_False;
277 break;
278 case Py_EQ:
279 result = cmp == 0 ? Py_True : Py_False;
280 break;
281 case Py_NE:
282 result = cmp != 0 ? Py_True : Py_False;
283 break;
284 case Py_GT:
285 result = cmp > 0 ? Py_True : Py_False;
286 break;
287 case Py_GE:
288 result = cmp >= 0 ? Py_True : Py_False;
289 break;
290 default:
291 assert(0);
292 }
293 }
294
295 Py_INCREF(result);
296 return result;
297 }
298
Value_str(PyObject * self)299 static PyObject* Value_str(PyObject* self) {
300 Value* v = (Value*) self;
301 char* cstr = lp_value_to_string(&v->v);
302 PyObject* pystr = PyUnicode_FromString(cstr);
303 free(cstr);
304 return pystr;
305 }
306
307 static long
Value_hash(PyObject * self)308 Value_hash(PyObject* self) {
309 Value* v = (Value*) self;
310 long hash = lp_value_hash(&v->v);
311 if (hash == -1) {
312 // value -1 should not be returned as a normal return value
313 hash = 0;
314 }
315 return hash;
316 }
317
318 static PyObject*
Value_get_value_between(PyObject * self,PyObject * args)319 Value_get_value_between(PyObject* self, PyObject* args) {
320 // self is always a polynomial
321 Value* v1 = (Value*) self;
322 if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
323 PyErr_SetString(PyExc_RuntimeError, "get_value_between(): need one argument.");
324 return NULL;
325 }
326 PyObject* other = PyTuple_GetItem(args, 0);
327
328 // other should be a value
329 if (!PyValue_CHECK(other)) {
330 PyErr_SetString(PyExc_RuntimeError, "get_value_between(): argument not a value.");
331 return NULL;
332 }
333 Value* v2 = (Value*) other;
334
335 // compare the values (they should be different)
336 if (v1->v.type == LP_VALUE_NONE || v2->v.type == LP_VALUE_NONE) {
337 PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should not be null.");
338 return NULL;
339 }
340 if (lp_value_cmp(&v1->v, &v2->v) == 0) {
341 PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should be different.");
342 return NULL;
343 }
344
345 lp_value_t m;
346 lp_value_construct_none(&m);
347 lp_value_get_value_between(&v1->v, 1, &v2->v, 1, &m);
348 PyObject* result = PyValue_create(&m);
349 lp_value_destruct(&m);
350
351 return result;
352 }
353
354 static PyObject*
Value_add(PyObject * self,PyObject * other)355 Value_add(PyObject* self, PyObject* other) {
356 if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) {
357 Py_INCREF(Py_NotImplemented);
358 return Py_NotImplemented;
359 }
360
361 Value* v1 = (Value*) self;
362 Value* v2 = (Value*) other;
363
364 lp_value_t add;
365 lp_value_construct_none(&add);
366 lp_value_add(&add, &v1->v, &v2->v);
367 PyObject* result = PyValue_create(&add);
368 lp_value_destruct(&add);
369
370 return result;
371 }
372
373 static PyObject*
Value_neg(PyObject * self)374 Value_neg(PyObject* self) {
375 if (!PyValue_CHECK(self)) {
376 Py_INCREF(Py_NotImplemented);
377 return Py_NotImplemented;
378 }
379
380 Value* v = (Value*) self;
381
382 lp_value_t neg;
383 lp_value_construct_none(&neg);
384 lp_value_neg(&neg, &v->v);
385 PyObject* result = PyValue_create(&neg);
386 lp_value_destruct(&neg);
387
388 return result;
389 }
390
391 static PyObject*
Value_sub(PyObject * self,PyObject * other)392 Value_sub(PyObject* self, PyObject* other) {
393 if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) {
394 Py_INCREF(Py_NotImplemented);
395 return Py_NotImplemented;
396 }
397
398 Value* v1 = (Value*) self;
399 Value* v2 = (Value*) other;
400
401 lp_value_t sub;
402 lp_value_construct_none(&sub);
403 lp_value_sub(&sub, &v1->v, &v2->v);
404 PyObject* result = PyValue_create(&sub);
405 lp_value_destruct(&sub);
406
407 return result;
408 }
409
410 static PyObject*
Value_mul(PyObject * self,PyObject * other)411 Value_mul(PyObject* self, PyObject* other) {
412 if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) {
413 Py_INCREF(Py_NotImplemented);
414 return Py_NotImplemented;
415 }
416
417 Value* v1 = (Value*) self;
418 Value* v2 = (Value*) other;
419
420 lp_value_t mul;
421 lp_value_construct_none(&mul);
422 lp_value_mul(&mul, &v1->v, &v2->v);
423 PyObject* result = PyValue_create(&mul);
424 lp_value_destruct(&mul);
425
426 return result;
427 }
428
429 static PyObject*
Value_div(PyObject * self,PyObject * other)430 Value_div(PyObject* self, PyObject* other) {
431 if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) {
432 Py_INCREF(Py_NotImplemented);
433 return Py_NotImplemented;
434 }
435
436 Value* v1 = (Value*) self;
437 Value* v2 = (Value*) other;
438
439 lp_value_t div;
440 lp_value_construct_none(&div);
441 lp_value_div(&div, &v1->v, &v2->v);
442 PyObject* result = PyValue_create(&div);
443 lp_value_destruct(&div);
444
445 return result;
446 }
447
448
449 static PyObject*
Value_pow(PyObject * self,PyObject * other)450 Value_pow(PyObject* self, PyObject* other) {
451 if (!PyValue_CHECK(self) || !PyLong_Check(other)) {
452 Py_INCREF(Py_NotImplemented);
453 return Py_NotImplemented;
454 }
455
456 Value* v = (Value*) self;
457 long n = PyLong_AsLong(other);
458
459 lp_value_t mul;
460 lp_value_construct_none(&mul);
461 lp_value_pow(&mul, &v->v, n);
462 PyObject* result = PyValue_create(&mul);
463 lp_value_destruct(&mul);
464
465 return result;
466 }
467
468 // Returns the o converted to a long integer object on success, or NULL on
469 // failure. This is the equivalent of the Python 3 expression int(o).
470 // Return value: New reference.
471 static PyObject*
Value_long(PyObject * self)472 Value_long(PyObject* self) {
473 Value* value_obj = (Value*) self;
474 lp_integer_t int_cast;
475 lp_integer_construct(&int_cast);
476 lp_value_floor(&value_obj->v, &int_cast);
477 PyObject* py_int_cast = integer_to_PyLong(&int_cast);
478 lp_integer_destruct(&int_cast);
479 return py_int_cast;
480 }
481
482 // Returns the o converted to a float object on success, or NULL on failure.
483 // This is the equivalent of the Python expression float(o).
484 // Return value: New reference.
485 static PyObject*
Value_float(PyObject * self)486 Value_float(PyObject* self) {
487 Value* value_obj = (Value*) self;
488 double value = lp_value_to_double(&value_obj->v);
489 return PyFloat_FromDouble(value);
490 }
491