diff --git a/CMakeLists.txt b/CMakeLists.txt index 33790c79..ec4b2af2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.12) # # Stop warning on cygwin @@ -67,16 +67,11 @@ add_subdirectory(src) add_subdirectory(include) if(LIBPOLY_BUILD_PYTHON_API) - - # Need the Python binary to run tests - find_package(PythonInterp) - + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) # Configure the Python bindings add_subdirectory(python) - # Configure the Python tests add_subdirectory(test/python) - endif() if (BUILD_TESTING) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index aa57fcd7..19facb62 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -13,18 +13,19 @@ set(polypy_SOURCES polypyFeasibilitySet.c ) -find_package(PythonLibs) - include_directories(${GMP_INCLUDE_DIR}) include_directories(${libpoly_SOURCE_DIR}/include) -include_directories(${PYTHON_INCLUDE_PATH}) add_library(polypy MODULE ${polypy_SOURCES}) +target_include_directories(polypy PRIVATE ${Python3_INCLUDE_DIRS}) +target_link_libraries(polypy PRIVATE poly ${Python3_LIBRARIES}) + set_target_properties(polypy PROPERTIES PREFIX "") +#set_target_properties(polypy PROPERTIES SUFFIX "${Python3_EXTENSION_SUFFIX}") + if (APPLE) set_target_properties(polypy PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") endif() -target_link_libraries(polypy poly) string (REPLACE ";" "', '" polypy_SOURCES_STR "${polypy_SOURCES}") configure_file(setup.py.in ${CMAKE_CURRENT_SOURCE_DIR}/setup.py) diff --git a/python/polypy.c b/python/polypy.c index 2bd880f9..89fd7ac6 100644 --- a/python/polypy.c +++ b/python/polypy.c @@ -17,11 +17,172 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include "Python.h" +#include "python.h" -#if PY_MAJOR_VERSION >= 3 -#include "polypy3.c" -#else -#include "polypy2.c" +#include "polypyInteger.h" +#include "polypyVariable.h" +#include "polypyVariableOrder.h" +#include "polypyUPolynomial.h" +#include "polypyAlgebraicNumber.h" +#include "polypyPolynomial.h" +#include "polypyAssignment.h" +#include "polypyValue.h" +#include "polypyInterval.h" +#include "polypyFeasibilitySet.h" + +static PyObject* +Trace_enable(PyObject* self, PyObject* args) { +#ifndef NDEBUG + const char *tag; + if (!PyArg_ParseTuple(args, "s", &tag)) { + return NULL; + } + lp_trace_enable(tag); +#endif + Py_RETURN_NONE; +} + +static PyObject* +Trace_disable(PyObject* self, PyObject* args) { +#ifndef NDEBUG + const char *tag; + if (!PyArg_ParseTuple(args, "s", &tag)) { + return NULL; + } + lp_trace_disable(tag); +#endif + Py_RETURN_NONE; +} + +static PyObject* +Stats_print(PyObject* self) { + lp_stats_print(stdout); + Py_RETURN_NONE; +} + +static PyMethodDef polypy_methods[] = { + {"trace_enable", (PyCFunction)Trace_enable, METH_VARARGS, "Enables tracing for the given tag"}, + {"trace_disable", (PyCFunction)Trace_disable, METH_VARARGS, "Disables tracing for the given tag"}, + {"stats_print", (PyCFunction)Stats_print, METH_NOARGS, "Prints the statistics"}, + {NULL} /* Sentinel */ +}; + + +static struct PyModuleDef polypymodule = { + PyModuleDef_HEAD_INIT, + "polypy", + NULL, + 0, // sizeof polypy struct + polypy_methods, + NULL, + NULL, + NULL +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void #endif +PyMODINIT_FUNC +PyInit_polypy(void) +{ + PyObject* m; + + if (PyType_Ready(&CoefficientRingType) < 0) + return NULL; + if (PyType_Ready(&VariableType) < 0) + return NULL; + if (PyType_Ready(&VariableOrderType) < 0) + return NULL; + if (PyType_Ready(&AssignmentType) < 0) + return NULL; + if (PyType_Ready(&PolynomialType) < 0) + return NULL; + if (PyType_Ready(&UPolynomialType) < 0) + return NULL; + if (PyType_Ready(&AlgebraicNumberType) < 0) + return NULL; + if (PyType_Ready(&ValueType) < 0) + return NULL; + if (PyType_Ready(&IntervalType) < 0) + return NULL; + if (PyType_Ready(&FeasibilitySetType) < 0) + return NULL; + + m = PyModule_Create(&polypymodule); + + // Initialize the library + lp_set_output_language(LP_OUTPUT_PYTHON); + + Py_INCREF(&CoefficientRingType); + PyModule_AddObject(m, "CoefficientRing", (PyObject*)&CoefficientRingType); + + PyObject* PyZ = PyCoefficientRing_create(lp_Z); + Py_INCREF(PyZ); + PyModule_AddObject(m, "Z", PyZ); + + Py_INCREF(&VariableType); + PyModule_AddObject(m, "Variable", (PyObject*)&VariableType); + + Py_INCREF(&VariableOrderType); + PyModule_AddObject(m, "VariableOrder", (PyObject*)&VariableOrderType); + + PyObject* variable_order = VariableOrder_create(VariableOrder_get_default_order()); + Py_INCREF(variable_order); + PyModule_AddObject(m, "variable_order", variable_order); + + Py_INCREF(&PolynomialType); + PyModule_AddObject(m, "Polynomial", (PyObject*)&PolynomialType); + + // Sign conditions + PyObject* Py_SGN_LT_0 = PyLong_FromLong(LP_SGN_LT_0); + PyObject* Py_SGN_LE_0 = PyLong_FromLong(LP_SGN_LE_0); + PyObject* Py_SGN_EQ_0 = PyLong_FromLong(LP_SGN_EQ_0); + PyObject* Py_SGN_NE_0 = PyLong_FromLong(LP_SGN_NE_0); + PyObject* Py_SGN_GT_0 = PyLong_FromLong(LP_SGN_GT_0); + PyObject* Py_SGN_GE_0 = PyLong_FromLong(LP_SGN_GE_0); + PyModule_AddObject(m, "SGN_LT_0", Py_SGN_LT_0); + PyModule_AddObject(m, "SGN_LE_0", Py_SGN_LE_0); + PyModule_AddObject(m, "SGN_EQ_0", Py_SGN_EQ_0); + PyModule_AddObject(m, "SGN_NE_0", Py_SGN_NE_0); + PyModule_AddObject(m, "SGN_GT_0", Py_SGN_GT_0); + PyModule_AddObject(m, "SGN_GE_0", Py_SGN_GE_0); + + Py_INCREF(&AssignmentType); + PyModule_AddObject(m, "Assignment", (PyObject*)&AssignmentType); + + Py_INCREF(&UPolynomialType); + PyModule_AddObject(m, "UPolynomial", (PyObject*)&UPolynomialType); + + int x_coeff[2] = { 0, 1 }; + lp_upolynomial_t* x_poly = lp_upolynomial_construct_from_int(lp_Z, 1, x_coeff); + PyObject* x = PyUPolynomial_create(x_poly); + Py_INCREF(x); + PyModule_AddObject(m, "x", x); + + Py_INCREF(&AlgebraicNumberType); + PyModule_AddObject(m, "AlgebraicNumber", (PyObject*)&AlgebraicNumberType); + + Py_INCREF(&ValueType); + PyModule_AddObject(m, "Value", (PyObject*)&ValueType); + + // Sign conditions + lp_value_t value_inf_pos, value_inf_neg; + lp_value_construct(&value_inf_pos, LP_VALUE_PLUS_INFINITY, NULL); + lp_value_construct(&value_inf_neg, LP_VALUE_MINUS_INFINITY, NULL); + PyObject* inf_pos = PyValue_create(&value_inf_pos); + PyObject* inf_neg = PyValue_create(&value_inf_neg); + PyModule_AddObject(m, "INFINITY_POS", inf_pos); + PyModule_AddObject(m, "INFINITY_NEG", inf_neg); + Py_INCREF(inf_pos); + Py_INCREF(inf_neg); + lp_value_destruct(&value_inf_pos); + lp_value_destruct(&value_inf_neg); + + Py_INCREF(&IntervalType); + PyModule_AddObject(m, "Interval", (PyObject*)&IntervalType); + + Py_INCREF(&FeasibilitySetType); + PyModule_AddObject(m, "FeasibilitySet", (PyObject*)&FeasibilitySetType); + + return m; +} diff --git a/python/polypy2.c b/python/polypy2.c deleted file mode 100644 index 6fabdce2..00000000 --- a/python/polypy2.c +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyInteger.h" -#include "polypyVariable.h" -#include "polypyVariableOrder.h" -#include "polypyUPolynomial.h" -#include "polypyAlgebraicNumber.h" -#include "polypyPolynomial.h" -#include "polypyAssignment.h" -#include "polypyValue.h" -#include "polypyInterval.h" -#include "polypyFeasibilitySet.h" - -static PyObject* -Trace_enable(PyObject* self, PyObject* args) { -#ifndef NDEBUG - const char *tag; - if (!PyArg_ParseTuple(args, "s", &tag)) { - return 0; - } - lp_trace_enable(tag); -#endif - Py_RETURN_NONE; -} - -static PyObject* -Trace_disable(PyObject* self, PyObject* args) { -#ifndef NDEBUG - const char *tag; - if (!PyArg_ParseTuple(args, "s", &tag)) { - return 0; - } - lp_trace_disable(tag); -#endif - Py_RETURN_NONE; -} - -static PyObject* -Stats_print(PyObject* self) { - lp_stats_print(stdout); - Py_RETURN_NONE; -} - -static PyMethodDef polypy_methods[] = { - {"trace_enable", (PyCFunction)Trace_enable, METH_VARARGS, "Enables tracing for the given tag"}, - {"trace_disable", (PyCFunction)Trace_disable, METH_VARARGS, "Disables tracing for the given tag"}, - {"stats_print", (PyCFunction)Stats_print, METH_NOARGS, "Prints the statistics"}, - {NULL} /* Sentinel */ -}; - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif -PyMODINIT_FUNC -initpolypy(void) -{ - PyObject* m; - - if (PyType_Ready(&CoefficientRingType) < 0) - return; - if (PyType_Ready(&VariableType) < 0) - return; - if (PyType_Ready(&VariableOrderType) < 0) - return; - if (PyType_Ready(&AssignmentType) < 0) - return; - if (PyType_Ready(&PolynomialType) < 0) - return; - if (PyType_Ready(&UPolynomialType) < 0) - return; - if (PyType_Ready(&AlgebraicNumberType) < 0) - return; - if (PyType_Ready(&ValueType) < 0) - return; - if (PyType_Ready(&IntervalType) < 0) - return; - if (PyType_Ready(&FeasibilitySetType) < 0) - return; - - m = Py_InitModule3("polypy", polypy_methods, "PolyPy Library."); - - // Initialize the library - lp_set_output_language(LP_OUTPUT_PYTHON); - - Py_INCREF(&CoefficientRingType); - PyModule_AddObject(m, "CoefficientRing", (PyObject*)&CoefficientRingType); - - PyObject* PyZ = PyCoefficientRing_create(lp_Z); - Py_INCREF(PyZ); - PyModule_AddObject(m, "Z", PyZ); - - Py_INCREF(&VariableType); - PyModule_AddObject(m, "Variable", (PyObject*)&VariableType); - - Py_INCREF(&VariableOrderType); - PyModule_AddObject(m, "VariableOrder", (PyObject*)&VariableOrderType); - - PyObject* variable_order = VariableOrder_create(VariableOrder_get_default_order()); - Py_INCREF(variable_order); - PyModule_AddObject(m, "variable_order", variable_order); - - Py_INCREF(&PolynomialType); - PyModule_AddObject(m, "Polynomial", (PyObject*)&PolynomialType); - - // Sign conditions - PyObject* Py_SGN_LT_0 = PyInt_FromLong(LP_SGN_LT_0); - PyObject* Py_SGN_LE_0 = PyInt_FromLong(LP_SGN_LE_0); - PyObject* Py_SGN_EQ_0 = PyInt_FromLong(LP_SGN_EQ_0); - PyObject* Py_SGN_NE_0 = PyInt_FromLong(LP_SGN_NE_0); - PyObject* Py_SGN_GT_0 = PyInt_FromLong(LP_SGN_GT_0); - PyObject* Py_SGN_GE_0 = PyInt_FromLong(LP_SGN_GE_0); - PyModule_AddObject(m, "SGN_LT_0", Py_SGN_LT_0); - PyModule_AddObject(m, "SGN_LE_0", Py_SGN_LE_0); - PyModule_AddObject(m, "SGN_EQ_0", Py_SGN_EQ_0); - PyModule_AddObject(m, "SGN_NE_0", Py_SGN_NE_0); - PyModule_AddObject(m, "SGN_GT_0", Py_SGN_GT_0); - PyModule_AddObject(m, "SGN_GE_0", Py_SGN_GE_0); - - Py_INCREF(&AssignmentType); - PyModule_AddObject(m, "Assignment", (PyObject*)&AssignmentType); - - Py_INCREF(&UPolynomialType); - PyModule_AddObject(m, "UPolynomial", (PyObject*)&UPolynomialType); - - int x_coeff[2] = { 0, 1 }; - lp_upolynomial_t* x_poly = lp_upolynomial_construct_from_int(lp_Z, 1, x_coeff); - PyObject* x = PyUPolynomial_create(x_poly); - Py_INCREF(x); - PyModule_AddObject(m, "x", x); - - Py_INCREF(&AlgebraicNumberType); - PyModule_AddObject(m, "AlgebraicNumber", (PyObject*)&AlgebraicNumberType); - - Py_INCREF(&ValueType); - PyModule_AddObject(m, "Value", (PyObject*)&ValueType); - - // Sign conditions - lp_value_t value_inf_pos, value_inf_neg; - lp_value_construct(&value_inf_pos, LP_VALUE_PLUS_INFINITY, NULL); - lp_value_construct(&value_inf_neg, LP_VALUE_MINUS_INFINITY, NULL); - PyObject* inf_pos = PyValue_create(&value_inf_pos); - PyObject* inf_neg = PyValue_create(&value_inf_neg); - PyModule_AddObject(m, "INFINITY_POS", inf_pos); - PyModule_AddObject(m, "INFINITY_NEG", inf_neg); - Py_INCREF(inf_pos); - Py_INCREF(inf_neg); - lp_value_destruct(&value_inf_pos); - lp_value_destruct(&value_inf_neg); - - Py_INCREF(&IntervalType); - PyModule_AddObject(m, "Interval", (PyObject*)&IntervalType); - - Py_INCREF(&FeasibilitySetType); - PyModule_AddObject(m, "FeasibilitySet", (PyObject*)&FeasibilitySetType); -} diff --git a/python/polypy3.c b/python/polypy3.c deleted file mode 100644 index 0bbcf75d..00000000 --- a/python/polypy3.c +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyInteger.h" -#include "polypyVariable.h" -#include "polypyVariableOrder.h" -#include "polypyUPolynomial.h" -#include "polypyAlgebraicNumber.h" -#include "polypyPolynomial.h" -#include "polypyAssignment.h" -#include "polypyValue.h" -#include "polypyInterval.h" -#include "polypyFeasibilitySet.h" - -static PyObject* -Trace_enable(PyObject* self, PyObject* args) { -#ifndef NDEBUG - const char *tag; - if (!PyArg_ParseTuple(args, "s", &tag)) { - return 0; - } - lp_trace_enable(tag); -#endif - Py_RETURN_NONE; -} - -static PyObject* -Trace_disable(PyObject* self, PyObject* args) { -#ifndef NDEBUG - const char *tag; - if (!PyArg_ParseTuple(args, "s", &tag)) { - return 0; - } - lp_trace_disable(tag); -#endif - Py_RETURN_NONE; -} - -static PyObject* -Stats_print(PyObject* self) { - lp_stats_print(stdout); - Py_RETURN_NONE; -} - -static PyMethodDef polypy_methods[] = { - {"trace_enable", (PyCFunction)Trace_enable, METH_VARARGS, "Enables tracing for the given tag"}, - {"trace_disable", (PyCFunction)Trace_disable, METH_VARARGS, "Disables tracing for the given tag"}, - {"stats_print", (PyCFunction)Stats_print, METH_NOARGS, "Prints the statistics"}, - {NULL} /* Sentinel */ -}; - - -static struct PyModuleDef polypymodule = { - PyModuleDef_HEAD_INIT, - "polypy", - NULL, - 0, // sizeof polypy struct - polypy_methods, - 0, - 0, - 0 -}; - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif -PyMODINIT_FUNC -PyInit_polypy(void) -{ - PyObject* m; - - if (PyType_Ready(&CoefficientRingType) < 0) - return NULL; - if (PyType_Ready(&VariableType) < 0) - return NULL; - if (PyType_Ready(&VariableOrderType) < 0) - return NULL; - if (PyType_Ready(&AssignmentType) < 0) - return NULL; - if (PyType_Ready(&PolynomialType) < 0) - return NULL; - if (PyType_Ready(&UPolynomialType) < 0) - return NULL; - if (PyType_Ready(&AlgebraicNumberType) < 0) - return NULL; - if (PyType_Ready(&ValueType) < 0) - return NULL; - if (PyType_Ready(&IntervalType) < 0) - return NULL; - if (PyType_Ready(&FeasibilitySetType) < 0) - return NULL; - - m = PyModule_Create(&polypymodule); - - // Initialize the library - lp_set_output_language(LP_OUTPUT_PYTHON); - - Py_INCREF(&CoefficientRingType); - PyModule_AddObject(m, "CoefficientRing", (PyObject*)&CoefficientRingType); - - PyObject* PyZ = PyCoefficientRing_create(lp_Z); - Py_INCREF(PyZ); - PyModule_AddObject(m, "Z", PyZ); - - Py_INCREF(&VariableType); - PyModule_AddObject(m, "Variable", (PyObject*)&VariableType); - - Py_INCREF(&VariableOrderType); - PyModule_AddObject(m, "VariableOrder", (PyObject*)&VariableOrderType); - - PyObject* variable_order = VariableOrder_create(VariableOrder_get_default_order()); - Py_INCREF(variable_order); - PyModule_AddObject(m, "variable_order", variable_order); - - Py_INCREF(&PolynomialType); - PyModule_AddObject(m, "Polynomial", (PyObject*)&PolynomialType); - - // Sign conditions - PyObject* Py_SGN_LT_0 = PyLong_FromLong(LP_SGN_LT_0); - PyObject* Py_SGN_LE_0 = PyLong_FromLong(LP_SGN_LE_0); - PyObject* Py_SGN_EQ_0 = PyLong_FromLong(LP_SGN_EQ_0); - PyObject* Py_SGN_NE_0 = PyLong_FromLong(LP_SGN_NE_0); - PyObject* Py_SGN_GT_0 = PyLong_FromLong(LP_SGN_GT_0); - PyObject* Py_SGN_GE_0 = PyLong_FromLong(LP_SGN_GE_0); - PyModule_AddObject(m, "SGN_LT_0", Py_SGN_LT_0); - PyModule_AddObject(m, "SGN_LE_0", Py_SGN_LE_0); - PyModule_AddObject(m, "SGN_EQ_0", Py_SGN_EQ_0); - PyModule_AddObject(m, "SGN_NE_0", Py_SGN_NE_0); - PyModule_AddObject(m, "SGN_GT_0", Py_SGN_GT_0); - PyModule_AddObject(m, "SGN_GE_0", Py_SGN_GE_0); - - Py_INCREF(&AssignmentType); - PyModule_AddObject(m, "Assignment", (PyObject*)&AssignmentType); - - Py_INCREF(&UPolynomialType); - PyModule_AddObject(m, "UPolynomial", (PyObject*)&UPolynomialType); - - int x_coeff[2] = { 0, 1 }; - lp_upolynomial_t* x_poly = lp_upolynomial_construct_from_int(lp_Z, 1, x_coeff); - PyObject* x = PyUPolynomial_create(x_poly); - Py_INCREF(x); - PyModule_AddObject(m, "x", x); - - Py_INCREF(&AlgebraicNumberType); - PyModule_AddObject(m, "AlgebraicNumber", (PyObject*)&AlgebraicNumberType); - - Py_INCREF(&ValueType); - PyModule_AddObject(m, "Value", (PyObject*)&ValueType); - - // Sign conditions - lp_value_t value_inf_pos, value_inf_neg; - lp_value_construct(&value_inf_pos, LP_VALUE_PLUS_INFINITY, NULL); - lp_value_construct(&value_inf_neg, LP_VALUE_MINUS_INFINITY, NULL); - PyObject* inf_pos = PyValue_create(&value_inf_pos); - PyObject* inf_neg = PyValue_create(&value_inf_neg); - PyModule_AddObject(m, "INFINITY_POS", inf_pos); - PyModule_AddObject(m, "INFINITY_NEG", inf_neg); - Py_INCREF(inf_pos); - Py_INCREF(inf_neg); - lp_value_destruct(&value_inf_pos); - lp_value_destruct(&value_inf_neg); - - Py_INCREF(&IntervalType); - PyModule_AddObject(m, "Interval", (PyObject*)&IntervalType); - - Py_INCREF(&FeasibilitySetType); - PyModule_AddObject(m, "FeasibilitySet", (PyObject*)&FeasibilitySetType); - - return m; -} diff --git a/python/polypyAlgebraicNumber.c b/python/polypyAlgebraicNumber.c index dbaf74db..6b1f1b85 100644 --- a/python/polypyAlgebraicNumber.c +++ b/python/polypyAlgebraicNumber.c @@ -17,13 +17,447 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include "Python.h" +#include "python.h" -#if PY_MAJOR_VERSION >= 3 - #include "polypyAlgebraicNumber3.c" -#else - #include "polypyAlgebraicNumber2.c" -#endif +#include "polypyAlgebraicNumber.h" +#include "polypyUPolynomial.h" +#include "polypyPolynomial.h" +#include +static void +AlgebraicNumber_dealloc(AlgebraicNumber* self); + +static PyObject* +AlgebraicNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +AlgebraicNumber_init(AlgebraicNumber* self, PyObject* args); + +static PyObject* +AlgebraicNumber_to_double(PyObject* self); + +static PyObject* +AlgebraicNumber_richcompare(PyObject* self, PyObject* other, int op); + +static PyObject* +AlgebraicNumber_str(PyObject* self); + +static PyObject* +AlgebraicNumber_refine(PyObject* self); + +static PyObject* +AlgebraicNumber_add(PyObject* self, PyObject* other); + +static PyObject* +AlgebraicNumber_neg(PyObject* self); + +static PyObject* +AlgebraicNumber_sub(PyObject* self, PyObject* other); + +static PyObject* +AlgebraicNumber_mul(PyObject* self, PyObject* other); + +static PyObject* +AlgebraicNumber_div(PyObject* self, PyObject* other); + +static PyObject* +AlgebraicNumber_pow(PyObject* self, PyObject* other); + +static PyObject* +AlgebraicNumber_positive_root(PyObject* self, PyObject* args); + +PyMethodDef AlgebraicNumber_methods[] = { + {"refine", (PyCFunction)AlgebraicNumber_refine, METH_NOARGS, "Refines the number to half the interval"}, + {"to_double", (PyCFunction)AlgebraicNumber_to_double, METH_NOARGS, "Returns the approximation of the algebraic number"}, + {"positive_root", (PyCFunction)AlgebraicNumber_positive_root, METH_VARARGS, "Returns the positive root of the number is positive"}, + {NULL} /* Sentinel */ +}; + +PyNumberMethods AlgebraicNumber_NumberMethods = { + AlgebraicNumber_add, // binaryfunc nb_add; + AlgebraicNumber_sub, // binaryfunc nb_subtract; + AlgebraicNumber_mul, // binaryfunc nb_multiply; + NULL, // binaryfunc nb_remainder; + NULL, // binaryfunc nb_divmod; + (ternaryfunc)AlgebraicNumber_pow, // ternaryfunc nb_power; + AlgebraicNumber_neg, // unaryfunc nb_negative; + NULL, // unaryfunc nb_positive; + NULL, // unaryfunc nb_absolute; + NULL, // inquiry nb_bool; + NULL, // unaryfunc nb_invert; + NULL, // binaryfunc nb_lshift; + NULL, // binaryfunc nb_rshift; + NULL, // binaryfunc nb_and; + NULL, // binaryfunc nb_xor; + NULL, // binaryfunc nb_or; + NULL, // unaryfunc nb_int; + NULL, // void *nb_reserved; + NULL, // unaryfunc nb_float; + NULL, // binaryfunc nb_inplace_add; + NULL, // binaryfunc nb_inplace_subtract; + NULL, // binaryfunc nb_inplace_multiply; + NULL, // binaryfunc nb_inplace_remainder; + NULL, // ternaryfunc nb_inplace_power; + NULL, // binaryfunc nb_inplace_lshift; + NULL, // binaryfunc nb_inplace_rshift; + NULL, // binaryfunc nb_inplace_and; + NULL, // binaryfunc nb_inplace_xor; + NULL, // binaryfunc nb_inplace_or; + NULL, // binaryfunc nb_floor_divide; + AlgebraicNumber_div, // binaryfunc nb_true_divide; + NULL, // binaryfunc nb_inplace_floor_divide; + NULL, // binaryfunc nb_inplace_true_divide; + NULL, // unaryfunc nb_index; + NULL, // binaryfunc nb_matrix_multiply; + NULL, // binaryfunc nb_inplace_matrix_multiply; +}; + +PyTypeObject AlgebraicNumberType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.AlgebraicNumber", // const char *tp_name; + sizeof(AlgebraicNumber), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)AlgebraicNumber_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async + AlgebraicNumber_str, // reprfunc tp_repr; + &AlgebraicNumber_NumberMethods, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + AlgebraicNumber_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Algebraic number objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + AlgebraicNumber_richcompare, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + AlgebraicNumber_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)AlgebraicNumber_init, // initproc tp_init; + NULL, // Pallocfunc tp_alloc; + AlgebraicNumber_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +AlgebraicNumber_dealloc(AlgebraicNumber* self) +{ + lp_algebraic_number_destruct(&self->a); + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +PyAlgebraicNumber_create(const lp_algebraic_number_t* a) { + AlgebraicNumber *self; + self = (AlgebraicNumber*)AlgebraicNumberType.tp_alloc(&AlgebraicNumberType, 0); + if (self != NULL) { + if (a) { + lp_algebraic_number_construct_copy(&self->a, a); + } else { + lp_dyadic_rational_t zero; + lp_dyadic_rational_construct(&zero); + lp_algebraic_number_construct_from_dyadic_rational(&self->a, &zero); + lp_dyadic_rational_destruct(&zero); + } + } + return (PyObject *)self; +} + +static PyObject* +AlgebraicNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyAlgebraicNumber_create(NULL); +} + +/** Construct an algebraic number from a polynomial and a root index */ +static int +AlgebraicNumber_init(AlgebraicNumber* self, PyObject* args) +{ + if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { + PyObject* f_obj = PyTuple_GetItem(args, 0); + PyObject* root_index_obj = PyTuple_GetItem(args, 1); + if (PyPolynomial_CHECK(f_obj) && PyLong_Check(root_index_obj)) { + // Get the polynomial + lp_polynomial_t* f = ((Polynomial*) f_obj)->p; + long root_index = PyLong_AsLong(root_index_obj); + // Get the univariate polynomial + lp_upolynomial_t* f_u = lp_polynomial_to_univariate(f); + if (f_u == NULL) { + // Not univariate + return -1; + } + // Check the roots + size_t roots_count = lp_upolynomial_roots_count(f_u, NULL); + if (root_index < 0 || root_index >= (long)roots_count) { + // Not enough roots + lp_upolynomial_delete(f_u); + return -1; + } + lp_algebraic_number_t* roots = malloc(roots_count * sizeof(lp_algebraic_number_t)); + lp_upolynomial_roots_isolate(f_u, roots, &roots_count); + lp_algebraic_number_destruct(&self->a); + lp_algebraic_number_construct_copy(&self->a, roots + root_index); + for (size_t i = 0; i < roots_count; ++ i) { + lp_algebraic_number_destruct(roots + i); + } + lp_upolynomial_delete(f_u); + free(roots); + } else if (PyUPolynomial_CHECK(f_obj) && PyLong_Check(root_index_obj)) { + lp_upolynomial_t* f = ((UPolynomialObject*) f_obj)->p; + long root_index = PyLong_AsLong(root_index_obj); + size_t roots_count = lp_upolynomial_roots_count(f, NULL); + if (root_index < 0 || root_index >= (long)roots_count) { + // Not enough roots + return -1; + } + lp_algebraic_number_t* roots = malloc(roots_count * sizeof(lp_algebraic_number_t)); + lp_upolynomial_roots_isolate(f, roots, &roots_count); + lp_algebraic_number_destruct(&self->a); + lp_algebraic_number_construct_copy(&self->a, roots + root_index); + for (size_t i = 0; i < roots_count; ++i) { + lp_algebraic_number_destruct(roots + i); + } + free(roots); + } else{ + return -1; + } + } else { + return -1; + } + + // All fine, initialized + return 0; +} + +static PyObject* +AlgebraicNumber_to_double(PyObject* self) { + AlgebraicNumber* a = (AlgebraicNumber*) self; + return algebraic_number_to_PyFloat(&a->a); +} + +static PyObject* +AlgebraicNumber_refine(PyObject* self) { + AlgebraicNumber* a = (AlgebraicNumber*) self; + lp_algebraic_number_refine(&a->a); + Py_RETURN_NONE; +} + +static PyObject* +AlgebraicNumber_richcompare(PyObject* self, PyObject* other, int op) { + PyObject *result = NULL; + + if (!PyAlgebraicNumber_CHECK(other)) { + result = Py_NotImplemented; + } else { + lp_algebraic_number_t* self_a = &((AlgebraicNumber*) self)->a; + lp_algebraic_number_t* other_a = &((AlgebraicNumber*) other)->a; + int cmp = lp_algebraic_number_cmp(self_a, other_a); + + switch (op) { + case Py_LT: + result = cmp < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = cmp <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = cmp == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = cmp != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = cmp > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = cmp >= 0 ? Py_True : Py_False; + break; + default: + assert(0); + } + } + + Py_INCREF(result); + return result; +} + +static PyObject* AlgebraicNumber_str(PyObject* self) { + AlgebraicNumber* a = (AlgebraicNumber*) self; + char* cstr = lp_algebraic_number_to_string(&a->a); + PyObject* pystr = PyUnicode_FromString(cstr); + free(cstr); + return pystr; +} + +static PyObject* +AlgebraicNumber_add(PyObject* self, PyObject* other) { + + if (PyLong_Check(self)) { + // To enable summation + long x = PyLong_AsLong(self); + if (x == 0) { + AlgebraicNumber* a = (AlgebraicNumber*) other; + return PyAlgebraicNumber_create(&a->a); + } + } + + if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + AlgebraicNumber* a2 = (AlgebraicNumber*) other; + + lp_algebraic_number_t sum; + lp_algebraic_number_construct_zero(&sum); + lp_algebraic_number_add(&sum, &a1->a, &a2->a); + PyObject* result = PyAlgebraicNumber_create(&sum); + lp_algebraic_number_destruct(&sum); + + return result; +} + +static PyObject* +AlgebraicNumber_neg(PyObject* self) { + if (!PyAlgebraicNumber_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + + lp_algebraic_number_t neg; + lp_algebraic_number_construct_zero(&neg); + lp_algebraic_number_neg(&neg, &a1->a); + PyObject* result = PyAlgebraicNumber_create(&neg); + lp_algebraic_number_destruct(&neg); + + return result; +} + +static PyObject* +AlgebraicNumber_sub(PyObject* self, PyObject* other) { + if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + AlgebraicNumber* a2 = (AlgebraicNumber*) other; + + lp_algebraic_number_t sub; + lp_algebraic_number_construct_zero(&sub); + lp_algebraic_number_sub(&sub, &a1->a, &a2->a); + PyObject* result = PyAlgebraicNumber_create(&sub); + lp_algebraic_number_destruct(&sub); + + return result; +} + +static PyObject* +AlgebraicNumber_mul(PyObject* self, PyObject* other) { + if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + AlgebraicNumber* a2 = (AlgebraicNumber*) other; + + lp_algebraic_number_t mul; + lp_algebraic_number_construct_zero(&mul); + lp_algebraic_number_mul(&mul, &a1->a, &a2->a); + PyObject* result = PyAlgebraicNumber_create(&mul); + lp_algebraic_number_destruct(&mul); + + return result; +} + +static PyObject* +AlgebraicNumber_div(PyObject* self, PyObject* other) { + if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + AlgebraicNumber* a2 = (AlgebraicNumber*) other; + + lp_algebraic_number_t mul; + lp_algebraic_number_construct_zero(&mul); + lp_algebraic_number_div(&mul, &a1->a, &a2->a); + PyObject* result = PyAlgebraicNumber_create(&mul); + lp_algebraic_number_destruct(&mul); + + return result; +} + +static PyObject* +AlgebraicNumber_pow(PyObject* self, PyObject* other) { + if (!PyAlgebraicNumber_CHECK(self) || !PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + long n = PyLong_AsLong(other); + + lp_algebraic_number_t pow; + lp_algebraic_number_construct_zero(&pow); + lp_algebraic_number_pow(&pow, &a1->a, n); + PyObject* result = PyAlgebraicNumber_create(&pow); + lp_algebraic_number_destruct(&pow); + + return result; +} + +static PyObject* +AlgebraicNumber_positive_root(PyObject* self, PyObject* args) { + UPolynomialObject* p = (UPolynomialObject*) self; + if (p) { + // Get the argument + if (PyTuple_Size(args) == 1) { + // Get n + PyObject* other = PyTuple_GetItem(args, 0); + AlgebraicNumber* a1 = (AlgebraicNumber*) self; + long n = PyLong_AsLong(other); + + lp_algebraic_number_t root; + lp_algebraic_number_construct_zero(&root); + lp_algebraic_number_positive_root(&root, &a1->a, n); + PyObject* result = PyAlgebraicNumber_create(&root); + lp_algebraic_number_destruct(&root); + + return result; + } else { + Py_RETURN_NONE; + } + } else { + Py_RETURN_NONE; + } +} diff --git a/python/polypyAlgebraicNumber.h b/python/polypyAlgebraicNumber.h index 20f950ed..84e8df22 100644 --- a/python/polypyAlgebraicNumber.h +++ b/python/polypyAlgebraicNumber.h @@ -19,7 +19,7 @@ #pragma once -#include +#include "python.h" #include "algebraic_number.h" diff --git a/python/polypyAlgebraicNumber2.c b/python/polypyAlgebraicNumber2.c deleted file mode 100644 index 293b5a93..00000000 --- a/python/polypyAlgebraicNumber2.c +++ /dev/null @@ -1,478 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyAlgebraicNumber.h" -#include "polypyUPolynomial.h" -#include "polypyPolynomial.h" - -#include - -static void -AlgebraicNumber_dealloc(AlgebraicNumber* self); - -static PyObject* -AlgebraicNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -AlgebraicNumber_init(AlgebraicNumber* self, PyObject* args); - -static PyObject* -AlgebraicNumber_to_double(PyObject* self); - - static int -AlgebraicNumber_cmp(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_richcompare(PyObject* self, PyObject* other, int op); - -static PyObject* -AlgebraicNumber_str(PyObject* self); - -static PyObject* -AlgebraicNumber_refine(PyObject* self); - -static PyObject* -AlgebraicNumber_add(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_neg(PyObject* self); - -static PyObject* -AlgebraicNumber_sub(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_mul(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_div(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_pow(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_positive_root(PyObject* self, PyObject* args); - -PyMethodDef AlgebraicNumber_methods[] = { - {"refine", (PyCFunction)AlgebraicNumber_refine, METH_NOARGS, "Refines the number to half the interval"}, - {"to_double", (PyCFunction)AlgebraicNumber_to_double, METH_NOARGS, "Returns the approximation of the algebraic number"}, - {"positive_root", (PyCFunction)AlgebraicNumber_positive_root, METH_VARARGS, "Returns the positive root of the number is positive"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods AlgebraicNumber_NumberMethods = { - AlgebraicNumber_add, // binaryfunc nb_add; - AlgebraicNumber_sub, // binaryfunc nb_subtract; - AlgebraicNumber_mul, // binaryfunc nb_multiply; - AlgebraicNumber_div, // binaryfunc nb_divide; - 0, // binaryfunc nb_remainder; - 0, // binaryfunc nb_divmod; - (ternaryfunc)AlgebraicNumber_pow, // ternaryfunc nb_power; - AlgebraicNumber_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - 0, // inquiry nb_nonzero; /* Used by PyObject_IsTrue */ - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // coercion nb_coerce; /* Used by the coerce() function */ - 0, // unaryfunc nb_int; - 0, // unaryfunc nb_long; - 0, // unaryfunc nb_float; - 0, // unaryfunc nb_oct; - 0, // unaryfunc nb_hex; - - /* Added in release 2.0 */ - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_divide; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - - /* Added in release 2.2 */ - 0, // binaryfunc nb_floor_divide; - 0, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - - /* Added in release 2.5 */ - 0 // unaryfunc nb_index; -}; - -PyTypeObject AlgebraicNumberType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.AlgebraicNumber", /*tp_name*/ - sizeof(AlgebraicNumber), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)AlgebraicNumber_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - AlgebraicNumber_cmp, /*tp_compare*/ - AlgebraicNumber_str, /*tp_repr*/ - &AlgebraicNumber_NumberMethods, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - AlgebraicNumber_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Algebraic number objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - AlgebraicNumber_richcompare,/* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - AlgebraicNumber_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)AlgebraicNumber_init,/* tp_init */ - 0, /* tp_alloc */ - AlgebraicNumber_new, /* tp_new */ -}; - -static void -AlgebraicNumber_dealloc(AlgebraicNumber* self) -{ - lp_algebraic_number_destruct(&self->a); - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyAlgebraicNumber_create(const lp_algebraic_number_t* a) { - AlgebraicNumber *self; - self = (AlgebraicNumber*)AlgebraicNumberType.tp_alloc(&AlgebraicNumberType, 0); - if (self != NULL) { - if (a) { - lp_algebraic_number_construct_copy(&self->a, a); - } else { - lp_dyadic_rational_t zero; - lp_dyadic_rational_construct(&zero); - lp_algebraic_number_construct_from_dyadic_rational(&self->a, &zero); - lp_dyadic_rational_destruct(&zero); - } - } - return (PyObject *)self; -} - -static PyObject* -AlgebraicNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyAlgebraicNumber_create(0); -} - -/** Construct an algebraic number from a polynomial and a root index */ -static int -AlgebraicNumber_init(AlgebraicNumber* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { - PyObject* f_obj = PyTuple_GetItem(args, 0); - PyObject* root_index_obj = PyTuple_GetItem(args, 1); - if (PyPolynomial_CHECK(f_obj) && PyInt_Check(root_index_obj)) { - // Get the polynomial - lp_polynomial_t* f = ((Polynomial*) f_obj)->p; - long root_index = PyInt_AsLong(root_index_obj); - // Get the univariate polynomial - lp_upolynomial_t* f_u = lp_polynomial_to_univariate(f); - if (f_u == 0) { - // Not univariate - return -1; - } - // Check the roots - size_t roots_count = lp_upolynomial_roots_count(f_u, 0); - if (root_index < 0 || root_index >= roots_count) { - // Not enough roots - lp_upolynomial_delete(f_u); - return -1; - } - lp_algebraic_number_t* roots = malloc(roots_count * sizeof(lp_algebraic_number_t)); - lp_upolynomial_roots_isolate(f_u, roots, &roots_count); - lp_algebraic_number_destruct(&self->a); - lp_algebraic_number_construct_copy(&self->a, roots + root_index); - int i; - for (i = 0; i < roots_count; ++ i) { - lp_algebraic_number_destruct(roots + i); - } - lp_upolynomial_delete(f_u); - free(roots); - } else if (PyUPolynomial_CHECK(f_obj) && PyInt_Check(root_index_obj)) { - lp_upolynomial_t* f = ((UPolynomialObject*) f_obj)->p; - long root_index = PyInt_AsLong(root_index_obj); - size_t roots_count = lp_upolynomial_roots_count(f, 0); - if (root_index < 0 || root_index >= roots_count) { - // Not enough roots - return -1; - } - lp_algebraic_number_t* roots = malloc(roots_count * sizeof(lp_algebraic_number_t)); - lp_upolynomial_roots_isolate(f, roots, &roots_count); - lp_algebraic_number_destruct(&self->a); - lp_algebraic_number_construct_copy(&self->a, roots + root_index); - int i; - for (i = 0; i < roots_count; ++i) { - lp_algebraic_number_destruct(roots + i); - } - free(roots); - } else{ - return -1; - } - } else { - return -1; - } - - // All fine, initialized - return 0; -} - -static PyObject* -AlgebraicNumber_to_double(PyObject* self) { - AlgebraicNumber* a = (AlgebraicNumber*) self; - return algebraic_number_to_PyFloat(&a->a); -} - -static PyObject* -AlgebraicNumber_refine(PyObject* self) { - AlgebraicNumber* a = (AlgebraicNumber*) self; - lp_algebraic_number_refine(&a->a); - Py_RETURN_NONE; -} - -static int -AlgebraicNumber_cmp(PyObject* self, PyObject* other) { - // Check arguments - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - // should return -1 and set an exception condition when an error occurred - return -1; - } - // Get arguments - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - // Compare - return lp_algebraic_number_cmp(&a1->a, &a2->a); -} - -static PyObject* -AlgebraicNumber_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - if (!PyAlgebraicNumber_CHECK(other)) { - result = Py_NotImplemented; - } else { - lp_algebraic_number_t* self_a = &((AlgebraicNumber*) self)->a; - lp_algebraic_number_t* other_a = &((AlgebraicNumber*) other)->a; - int cmp = lp_algebraic_number_cmp(self_a, other_a); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - } - - Py_INCREF(result); - return result; -} - -static PyObject* AlgebraicNumber_str(PyObject* self) { - AlgebraicNumber* a = (AlgebraicNumber*) self; - char* cstr = lp_algebraic_number_to_string(&a->a); - PyObject* pystr = PyString_FromString(cstr); - free(cstr); - return pystr; -} - -static PyObject* -AlgebraicNumber_add(PyObject* self, PyObject* other) { - - if (PyInt_Check(self)) { - // To enable summation - long x = PyInt_AsLong(self); - if (x == 0) { - AlgebraicNumber* a = (AlgebraicNumber*) other; - return PyAlgebraicNumber_create(&a->a); - } - } - - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t sum; - lp_algebraic_number_construct_zero(&sum); - lp_algebraic_number_add(&sum, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&sum); - lp_algebraic_number_destruct(&sum); - - return result; -} - -static PyObject* -AlgebraicNumber_neg(PyObject* self) { - if (!PyAlgebraicNumber_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - - lp_algebraic_number_t neg; - lp_algebraic_number_construct_zero(&neg); - lp_algebraic_number_neg(&neg, &a1->a); - PyObject* result = PyAlgebraicNumber_create(&neg); - lp_algebraic_number_destruct(&neg); - - return result; -} - -static PyObject* -AlgebraicNumber_sub(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t sub; - lp_algebraic_number_construct_zero(&sub); - lp_algebraic_number_sub(&sub, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&sub); - lp_algebraic_number_destruct(&sub); - - return result; -} - -static PyObject* -AlgebraicNumber_mul(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t mul; - lp_algebraic_number_construct_zero(&mul); - lp_algebraic_number_mul(&mul, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&mul); - lp_algebraic_number_destruct(&mul); - - return result; -} - -static PyObject* -AlgebraicNumber_div(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t mul; - lp_algebraic_number_construct_zero(&mul); - lp_algebraic_number_div(&mul, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&mul); - lp_algebraic_number_destruct(&mul); - - return result; -} - -static PyObject* -AlgebraicNumber_pow(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyInt_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - long n = PyInt_AsLong(other); - - lp_algebraic_number_t pow; - lp_algebraic_number_construct_zero(&pow); - lp_algebraic_number_pow(&pow, &a1->a, n); - PyObject* result = PyAlgebraicNumber_create(&pow); - lp_algebraic_number_destruct(&pow); - - return result; -} - -static PyObject* -AlgebraicNumber_positive_root(PyObject* self, PyObject* args) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - // Get the argument - if (PyTuple_Size(args) == 1) { - // Get n - PyObject* other = PyTuple_GetItem(args, 0); - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - long n = PyLong_AsLong(other); - - lp_algebraic_number_t root; - lp_algebraic_number_construct_zero(&root); - lp_algebraic_number_positive_root(&root, &a1->a, n); - PyObject* result = PyAlgebraicNumber_create(&root); - lp_algebraic_number_destruct(&root); - - return result; - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} diff --git a/python/polypyAlgebraicNumber3.c b/python/polypyAlgebraicNumber3.c deleted file mode 100644 index 452c3a49..00000000 --- a/python/polypyAlgebraicNumber3.c +++ /dev/null @@ -1,461 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyAlgebraicNumber.h" -#include "polypyUPolynomial.h" -#include "polypyPolynomial.h" - -#include - -static void -AlgebraicNumber_dealloc(AlgebraicNumber* self); - -static PyObject* -AlgebraicNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -AlgebraicNumber_init(AlgebraicNumber* self, PyObject* args); - -static PyObject* -AlgebraicNumber_to_double(PyObject* self); - -static PyObject* -AlgebraicNumber_richcompare(PyObject* self, PyObject* other, int op); - -static PyObject* -AlgebraicNumber_str(PyObject* self); - -static PyObject* -AlgebraicNumber_refine(PyObject* self); - -static PyObject* -AlgebraicNumber_add(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_neg(PyObject* self); - -static PyObject* -AlgebraicNumber_sub(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_mul(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_div(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_pow(PyObject* self, PyObject* args); - -static PyObject* -AlgebraicNumber_positive_root(PyObject* self, PyObject* args); - -PyMethodDef AlgebraicNumber_methods[] = { - {"refine", (PyCFunction)AlgebraicNumber_refine, METH_NOARGS, "Refines the number to half the interval"}, - {"to_double", (PyCFunction)AlgebraicNumber_to_double, METH_NOARGS, "Returns the approximation of the algebraic number"}, - {"positive_root", (PyCFunction)AlgebraicNumber_positive_root, METH_VARARGS, "Returns the positive root of the number is positive"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods AlgebraicNumber_NumberMethods = { - AlgebraicNumber_add, // binaryfunc nb_add; - AlgebraicNumber_sub, // binaryfunc nb_subtract; - AlgebraicNumber_mul, // binaryfunc nb_multiply; - 0, // binaryfunc nb_remainder; - 0, // binaryfunc nb_divmod; - (ternaryfunc)AlgebraicNumber_pow, // ternaryfunc nb_power; - AlgebraicNumber_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - 0, // inquiry nb_bool; - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // unaryfunc nb_int; - 0, // void *nb_reserved; - 0, // unaryfunc nb_float; - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - 0, // binaryfunc nb_floor_divide; - AlgebraicNumber_div, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - 0, // unaryfunc nb_index; - 0, // binaryfunc nb_matrix_multiply; - 0, // binaryfunc nb_inplace_matrix_multiply; -}; - -PyTypeObject AlgebraicNumberType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.AlgebraicNumber", // const char *tp_name; - sizeof(AlgebraicNumber), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)AlgebraicNumber_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async - AlgebraicNumber_str, // reprfunc tp_repr; - &AlgebraicNumber_NumberMethods, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - AlgebraicNumber_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Algebraic number objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - AlgebraicNumber_richcompare, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - AlgebraicNumber_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)AlgebraicNumber_init, // initproc tp_init; - 0, // Pallocfunc tp_alloc; - AlgebraicNumber_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -AlgebraicNumber_dealloc(AlgebraicNumber* self) -{ - lp_algebraic_number_destruct(&self->a); - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyAlgebraicNumber_create(const lp_algebraic_number_t* a) { - AlgebraicNumber *self; - self = (AlgebraicNumber*)AlgebraicNumberType.tp_alloc(&AlgebraicNumberType, 0); - if (self != NULL) { - if (a) { - lp_algebraic_number_construct_copy(&self->a, a); - } else { - lp_dyadic_rational_t zero; - lp_dyadic_rational_construct(&zero); - lp_algebraic_number_construct_from_dyadic_rational(&self->a, &zero); - lp_dyadic_rational_destruct(&zero); - } - } - return (PyObject *)self; -} - -static PyObject* -AlgebraicNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyAlgebraicNumber_create(0); -} - -/** Construct an algebraic number from a polynomial and a root index */ -static int -AlgebraicNumber_init(AlgebraicNumber* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { - PyObject* f_obj = PyTuple_GetItem(args, 0); - PyObject* root_index_obj = PyTuple_GetItem(args, 1); - if (PyPolynomial_CHECK(f_obj) && PyLong_Check(root_index_obj)) { - // Get the polynomial - lp_polynomial_t* f = ((Polynomial*) f_obj)->p; - long root_index = PyLong_AsLong(root_index_obj); - // Get the univariate polynomial - lp_upolynomial_t* f_u = lp_polynomial_to_univariate(f); - if (f_u == 0) { - // Not univariate - return -1; - } - // Check the roots - size_t roots_count = lp_upolynomial_roots_count(f_u, 0); - if (root_index < 0 || root_index >= (long)roots_count) { - // Not enough roots - lp_upolynomial_delete(f_u); - return -1; - } - lp_algebraic_number_t* roots = malloc(roots_count * sizeof(lp_algebraic_number_t)); - lp_upolynomial_roots_isolate(f_u, roots, &roots_count); - lp_algebraic_number_destruct(&self->a); - lp_algebraic_number_construct_copy(&self->a, roots + root_index); - size_t i; - for (i = 0; i < roots_count; ++ i) { - lp_algebraic_number_destruct(roots + i); - } - lp_upolynomial_delete(f_u); - free(roots); - } else if (PyUPolynomial_CHECK(f_obj) && PyLong_Check(root_index_obj)) { - lp_upolynomial_t* f = ((UPolynomialObject*) f_obj)->p; - long root_index = PyLong_AsLong(root_index_obj); - size_t roots_count = lp_upolynomial_roots_count(f, 0); - if (root_index < 0 || root_index >= (long)roots_count) { - // Not enough roots - return -1; - } - lp_algebraic_number_t* roots = malloc(roots_count * sizeof(lp_algebraic_number_t)); - lp_upolynomial_roots_isolate(f, roots, &roots_count); - lp_algebraic_number_destruct(&self->a); - lp_algebraic_number_construct_copy(&self->a, roots + root_index); - size_t i; - for (i = 0; i < roots_count; ++i) { - lp_algebraic_number_destruct(roots + i); - } - free(roots); - } else{ - return -1; - } - } else { - return -1; - } - - // All fine, initialized - return 0; -} - -static PyObject* -AlgebraicNumber_to_double(PyObject* self) { - AlgebraicNumber* a = (AlgebraicNumber*) self; - return algebraic_number_to_PyFloat(&a->a); -} - -static PyObject* -AlgebraicNumber_refine(PyObject* self) { - AlgebraicNumber* a = (AlgebraicNumber*) self; - lp_algebraic_number_refine(&a->a); - Py_RETURN_NONE; -} - -static PyObject* -AlgebraicNumber_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - if (!PyAlgebraicNumber_CHECK(other)) { - result = Py_NotImplemented; - } else { - lp_algebraic_number_t* self_a = &((AlgebraicNumber*) self)->a; - lp_algebraic_number_t* other_a = &((AlgebraicNumber*) other)->a; - int cmp = lp_algebraic_number_cmp(self_a, other_a); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - } - - Py_INCREF(result); - return result; -} - -static PyObject* AlgebraicNumber_str(PyObject* self) { - AlgebraicNumber* a = (AlgebraicNumber*) self; - char* cstr = lp_algebraic_number_to_string(&a->a); - PyObject* pystr = PyUnicode_FromString(cstr); - free(cstr); - return pystr; -} - -static PyObject* -AlgebraicNumber_add(PyObject* self, PyObject* other) { - - if (PyLong_Check(self)) { - // To enable summation - long x = PyLong_AsLong(self); - if (x == 0) { - AlgebraicNumber* a = (AlgebraicNumber*) other; - return PyAlgebraicNumber_create(&a->a); - } - } - - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t sum; - lp_algebraic_number_construct_zero(&sum); - lp_algebraic_number_add(&sum, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&sum); - lp_algebraic_number_destruct(&sum); - - return result; -} - -static PyObject* -AlgebraicNumber_neg(PyObject* self) { - if (!PyAlgebraicNumber_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - - lp_algebraic_number_t neg; - lp_algebraic_number_construct_zero(&neg); - lp_algebraic_number_neg(&neg, &a1->a); - PyObject* result = PyAlgebraicNumber_create(&neg); - lp_algebraic_number_destruct(&neg); - - return result; -} - -static PyObject* -AlgebraicNumber_sub(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t sub; - lp_algebraic_number_construct_zero(&sub); - lp_algebraic_number_sub(&sub, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&sub); - lp_algebraic_number_destruct(&sub); - - return result; -} - -static PyObject* -AlgebraicNumber_mul(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t mul; - lp_algebraic_number_construct_zero(&mul); - lp_algebraic_number_mul(&mul, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&mul); - lp_algebraic_number_destruct(&mul); - - return result; -} - -static PyObject* -AlgebraicNumber_div(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyAlgebraicNumber_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - AlgebraicNumber* a2 = (AlgebraicNumber*) other; - - lp_algebraic_number_t mul; - lp_algebraic_number_construct_zero(&mul); - lp_algebraic_number_div(&mul, &a1->a, &a2->a); - PyObject* result = PyAlgebraicNumber_create(&mul); - lp_algebraic_number_destruct(&mul); - - return result; -} - -static PyObject* -AlgebraicNumber_pow(PyObject* self, PyObject* other) { - if (!PyAlgebraicNumber_CHECK(self) || !PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - long n = PyLong_AsLong(other); - - lp_algebraic_number_t pow; - lp_algebraic_number_construct_zero(&pow); - lp_algebraic_number_pow(&pow, &a1->a, n); - PyObject* result = PyAlgebraicNumber_create(&pow); - lp_algebraic_number_destruct(&pow); - - return result; -} - -static PyObject* -AlgebraicNumber_positive_root(PyObject* self, PyObject* args) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - // Get the argument - if (PyTuple_Size(args) == 1) { - // Get n - PyObject* other = PyTuple_GetItem(args, 0); - AlgebraicNumber* a1 = (AlgebraicNumber*) self; - long n = PyLong_AsLong(other); - - lp_algebraic_number_t root; - lp_algebraic_number_construct_zero(&root); - lp_algebraic_number_positive_root(&root, &a1->a, n); - PyObject* result = PyAlgebraicNumber_create(&root); - lp_algebraic_number_destruct(&root); - - return result; - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} diff --git a/python/polypyAssignment.c b/python/polypyAssignment.c index fdecb04c..216854b7 100644 --- a/python/polypyAssignment.c +++ b/python/polypyAssignment.c @@ -17,11 +17,268 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include "Python.h" - -#if PY_MAJOR_VERSION >= 3 -#include "polypyAssignment3.c" -#else -#include "polypyAssignment2.c" -#endif +#include "python.h" + +#include "polypyAssignment.h" +#include "polypyVariable.h" +#include "utils.h" +#include "polypyAlgebraicNumber.h" +#include "polypyValue.h" + +/** Default variable database */ +static lp_assignment_t* default_assignment = NULL; + +lp_assignment_t* Assignment_get_default_assignment(void) { + if (!default_assignment) { + default_assignment = lp_assignment_new(Variable_get_default_db()); + } + return default_assignment; +} + +static PyObject* +Assignment_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +Assignment_init(Assignment* self, PyObject* args); + +static void +Assignment_dealloc(Assignment* self); + +static PyObject* +Assignment_str(PyObject* self); + +static PyObject* +Assignment_get_value(PyObject* self, PyObject* args); + +static PyObject* +Assignment_set_value(PyObject* self, PyObject* args); + +static PyObject* +Assignment_unset_value(PyObject* self, PyObject* args); + +PyMethodDef Assignment_methods[] = { + {"get_value", (PyCFunction)Assignment_get_value, METH_VARARGS, "Returns the value of the variable"}, + {"set_value", (PyCFunction)Assignment_set_value, METH_VARARGS, "Sets the value of the variable"}, + {"unset_value", (PyCFunction)Assignment_unset_value, METH_VARARGS, "Marks the variable as unassigned"}, + {NULL} /* Sentinel */ +}; + + +PyTypeObject AssignmentType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.Assignment", // const char *tp_name; + sizeof(Variable), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)Assignment_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + NULL, // reprfunc tp_repr; + NULL, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + Assignment_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Variable objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + NULL, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + Assignment_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)Assignment_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + Assignment_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +PyObject* +PyAssignment_create(lp_assignment_t* assignment) { + Assignment *self = (Assignment*)AssignmentType.tp_alloc(&AssignmentType, 0); + if (self != NULL) { + self->assignment = assignment; + } + return (PyObject *)self; +} + +static PyObject* +Assignment_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyAssignment_create(NULL); +} + +static int +Assignment_init(Assignment* self, PyObject* args) +{ + if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { + self->assignment = lp_assignment_new(Variable_get_default_db()); + } else { + return -1; + } + return 0; +} + +static void +Assignment_dealloc(Assignment* self) +{ + if (self->assignment) { + lp_assignment_delete(self->assignment); + } + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +static PyObject* Assignment_str(PyObject* self) { + Assignment* a = (Assignment*) self; + char* a_str = lp_assignment_to_string(a->assignment); + PyObject* str = PyUnicode_FromString(a_str); + free(a_str); + return str; +} + +static PyObject* +Assignment_get_value(PyObject* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* var_obj = PyTuple_GetItem(args, 0); + if (PyVariable_CHECK(var_obj)) { + Variable* var = (Variable*) var_obj; + Assignment* a = (Assignment*) self; + const lp_value_t* value = lp_assignment_get_value(a->assignment, var->x); + switch (value->type) { + case LP_VALUE_DYADIC_RATIONAL: + return dyadic_rational_to_PyFloat(&value->value.dy_q); + case LP_VALUE_NONE: + Py_RETURN_NONE; + case LP_VALUE_RATIONAL: + case LP_VALUE_ALGEBRAIC: + default: + return NULL; + } + } + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject* +Assignment_set_value(PyObject* self, PyObject* args) { + if (PyTuple_Check(args)) { + if (PyTuple_Size(args) == 2) { + PyObject* var_obj = PyTuple_GetItem(args, 0); + PyObject* value_obj = PyTuple_GetItem(args, 1); + if (PyVariable_CHECK(var_obj)) { + Assignment* a = (Assignment*) self; + Variable* var = (Variable*) var_obj; + if (PyFloat_Check(value_obj)) { + lp_dyadic_rational_t value_dyrat; + PyFloat_to_dyadic_rational(value_obj, &value_dyrat); + lp_value_t value; + lp_value_construct(&value, LP_VALUE_DYADIC_RATIONAL, &value_dyrat); + lp_assignment_set_value(a->assignment, var->x, &value); + lp_value_destruct(&value); + lp_dyadic_rational_destruct(&value_dyrat); + Py_RETURN_NONE; + } else if (PyLong_or_Int_Check(value_obj)) { + lp_integer_t value_int; + PyLong_or_Int_to_integer(value_obj, lp_Z, &value_int); + lp_dyadic_rational_t value_dyrat; + lp_dyadic_rational_construct_from_integer(&value_dyrat, &value_int); + lp_value_t value; + lp_value_construct(&value, LP_VALUE_DYADIC_RATIONAL, &value_dyrat); + lp_assignment_set_value(a->assignment, var->x, &value); + lp_value_destruct(&value); + lp_dyadic_rational_destruct(&value_dyrat); + lp_integer_destruct(&value_int); + Py_RETURN_NONE; + } else if (PyAlgebraicNumber_CHECK(value_obj)) { + lp_value_t value; + lp_value_construct(&value, LP_VALUE_ALGEBRAIC, &((AlgebraicNumber*) value_obj)->a); + lp_assignment_set_value(a->assignment, var->x, &value); + lp_value_destruct(&value); + Py_RETURN_NONE; + } else if (PyValue_CHECK(value_obj)) { + Value* value = (Value*) value_obj; + lp_assignment_set_value(a->assignment, var->x, &value->v); + Py_RETURN_NONE; + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): not a value."); + return NULL; + } + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): not a variable."); + return NULL; + } + } else if (PyTuple_Size(args) == 3) { + // Three arguments, rational + PyObject* var_obj = PyTuple_GetItem(args, 0); + PyObject* p_obj = PyTuple_GetItem(args, 1); + PyObject* q_obj = PyTuple_GetItem(args, 2); + if (PyLong_or_Int_Check(p_obj) && PyLong_or_Int_Check(q_obj)) { + Assignment* a = (Assignment*) self; + Variable* var = (Variable*) var_obj; + lp_integer_t p_int, q_int; + PyLong_or_Int_to_integer(p_obj, lp_Z, &p_int); + PyLong_or_Int_to_integer(q_obj, lp_Z, &q_int); + lp_rational_t value_rat; + lp_rational_construct_from_div(&value_rat, &p_int, &q_int); + lp_value_t value; + lp_value_construct(&value, LP_VALUE_RATIONAL, &value_rat); + lp_assignment_set_value(a->assignment, var->x, &value); + lp_value_destruct(&value); + lp_rational_destruct(&value_rat); + lp_integer_destruct(&p_int); + lp_integer_destruct(&q_int); + Py_RETURN_NONE; + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): for rationals, both numerator and denominator must be integer."); + return NULL; + } + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): need two or three arguments."); + return NULL; + } + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): need two or three arguments."); + return NULL; + } +} + +static PyObject* +Assignment_unset_value(PyObject* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* var_obj = PyTuple_GetItem(args, 0); + if (PyVariable_CHECK(var_obj)) { + Variable* var = (Variable*) var_obj; + Assignment* a = (Assignment*) self; + lp_assignment_set_value(a->assignment, var->x, NULL); + Py_RETURN_NONE; + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): not a variable."); + return NULL; + } + } else { + PyErr_SetString(PyExc_RuntimeError, "set_value(): need one argument."); + return NULL; + } +} diff --git a/python/polypyAssignment.h b/python/polypyAssignment.h index acb86d6d..3d3a33a1 100644 --- a/python/polypyAssignment.h +++ b/python/polypyAssignment.h @@ -19,9 +19,7 @@ #pragma once - -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "assignment.h" diff --git a/python/polypyAssignment2.c b/python/polypyAssignment2.c deleted file mode 100644 index b37b3720..00000000 --- a/python/polypyAssignment2.c +++ /dev/null @@ -1,285 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyAssignment.h" -#include "polypyVariable.h" -#include "utils.h" -#include "polypyAlgebraicNumber.h" -#include "polypyValue.h" - -#include - -/** Default variable database */ -static lp_assignment_t* default_assignment = 0; - -lp_assignment_t* Assignment_get_default_assignment(void) { - if (!default_assignment) { - default_assignment = lp_assignment_new(Variable_get_default_db()); - } - return default_assignment; -} - -static PyObject* -Assignment_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Assignment_init(Assignment* self, PyObject* args); - -static void -Assignment_dealloc(Assignment* self); - -static PyObject* -Assignment_str(PyObject* self); - -static PyObject* -Assignment_get_value(PyObject* self, PyObject* args); - -static PyObject* -Assignment_set_value(PyObject* self, PyObject* args); - -static PyObject* -Assignment_unset_value(PyObject* self, PyObject* args); - -PyMethodDef Assignment_methods[] = { - {"get_value", (PyCFunction)Assignment_get_value, METH_VARARGS, "Returns the value of the variable"}, - {"set_value", (PyCFunction)Assignment_set_value, METH_VARARGS, "Sets the value of the variable"}, - {"unset_value", (PyCFunction)Assignment_unset_value, METH_VARARGS, "Marks the variable as unassigned"}, - {NULL} /* Sentinel */ -}; - -PyTypeObject AssignmentType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.Assignment", /*tp_name*/ - sizeof(Variable), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Assignment_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - Assignment_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Variable objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Assignment_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Assignment_init, /* tp_init */ - 0, /* tp_alloc */ - Assignment_new, /* tp_new */ -}; - -PyObject* -PyAssignment_create(lp_assignment_t* assignment) { - Assignment *self; - self = (Assignment*)AssignmentType.tp_alloc(&AssignmentType, 0); - if (self != NULL) { - self->assignment = assignment; - } - return (PyObject *)self; -} - -static PyObject* -Assignment_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyAssignment_create(0); -} - -static int -Assignment_init(Assignment* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { - self->assignment = lp_assignment_new(Variable_get_default_db()); - } else { - return -1; - } - return 0; -} - -static void -Assignment_dealloc(Assignment* self) -{ - if (self->assignment) { - lp_assignment_delete(self->assignment); - } - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject* Assignment_str(PyObject* self) { - Assignment* a = (Assignment*) self; - char* a_str = lp_assignment_to_string(a->assignment); - PyObject* str = PyString_FromString(a_str); - free(a_str); - return str; -} - -static PyObject* -Assignment_get_value(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* var_obj = PyTuple_GetItem(args, 0); - if (PyVariable_CHECK(var_obj)) { - Variable* var = (Variable*) var_obj; - Assignment* a = (Assignment*) self; - const lp_value_t* value = lp_assignment_get_value(a->assignment, var->x); - switch (value->type) { - case LP_VALUE_ALGEBRAIC: - return 0; - break; - case LP_VALUE_DYADIC_RATIONAL: - return dyadic_rational_to_PyFloat(&value->value.dy_q); - break; - case LP_VALUE_NONE: - Py_RETURN_NONE; - break; - case LP_VALUE_RATIONAL: - return 0; - break; - default: - return 0; - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Assignment_set_value(PyObject* self, PyObject* args) { - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 2) { - PyObject* var_obj = PyTuple_GetItem(args, 0); - PyObject* value_obj = PyTuple_GetItem(args, 1); - if (PyVariable_CHECK(var_obj)) { - Assignment* a = (Assignment*) self; - Variable* var = (Variable*) var_obj; - if (PyFloat_Check(value_obj)) { - lp_dyadic_rational_t value_dyrat; - PyFloat_to_dyadic_rational(value_obj, &value_dyrat); - lp_value_t value; - lp_value_construct(&value, LP_VALUE_DYADIC_RATIONAL, &value_dyrat); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - lp_dyadic_rational_destruct(&value_dyrat); - Py_RETURN_NONE; - } else if (PyLong_or_Int_Check(value_obj)) { - lp_integer_t value_int; - PyLong_or_Int_to_integer(value_obj, lp_Z, &value_int); - lp_dyadic_rational_t value_dyrat; - lp_dyadic_rational_construct_from_integer(&value_dyrat, &value_int); - lp_value_t value; - lp_value_construct(&value, LP_VALUE_DYADIC_RATIONAL, &value_dyrat); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - lp_dyadic_rational_destruct(&value_dyrat); - lp_integer_destruct(&value_int); - Py_RETURN_NONE; - } else if (PyAlgebraicNumber_CHECK(value_obj)) { - lp_value_t value; - lp_value_construct(&value, LP_VALUE_ALGEBRAIC, &((AlgebraicNumber*) value_obj)->a); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - Py_RETURN_NONE; - } else if (PyValue_CHECK(value_obj)) { - Value* value = (Value*) value_obj; - lp_assignment_set_value(a->assignment, var->x, &value->v); - Py_RETURN_NONE; - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): not a value."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): not a variable."); - return NULL; - } - } else if (PyTuple_Size(args) == 3) { - // Three arguments, rational - PyObject* var_obj = PyTuple_GetItem(args, 0); - PyObject* p_obj = PyTuple_GetItem(args, 1); - PyObject* q_obj = PyTuple_GetItem(args, 2); - if (PyLong_or_Int_Check(p_obj) && PyLong_or_Int_Check(q_obj)) { - Assignment* a = (Assignment*) self; - Variable* var = (Variable*) var_obj; - lp_integer_t p_int, q_int; - PyLong_or_Int_to_integer(p_obj, lp_Z, &p_int); - PyLong_or_Int_to_integer(q_obj, lp_Z, &q_int); - lp_rational_t value_rat; - lp_rational_construct_from_div(&value_rat, &p_int, &q_int); - lp_value_t value; - lp_value_construct(&value, LP_VALUE_RATIONAL, &value_rat); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - lp_rational_destruct(&value_rat); - lp_integer_destruct(&p_int); - lp_integer_destruct(&q_int); - Py_RETURN_NONE; - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): for rationals, both numerator and denominator must be integer."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): need two or three arguments."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): need two or three arguments."); - return NULL; - } -} - -static PyObject* -Assignment_unset_value(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* var_obj = PyTuple_GetItem(args, 0); - if (PyVariable_CHECK(var_obj)) { - Variable* var = (Variable*) var_obj; - Assignment* a = (Assignment*) self; - lp_assignment_set_value(a->assignment, var->x, 0); - Py_RETURN_NONE; - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): not a variable."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): need one argument."); - return NULL; - } -} diff --git a/python/polypyAssignment3.c b/python/polypyAssignment3.c deleted file mode 100644 index db5b147c..00000000 --- a/python/polypyAssignment3.c +++ /dev/null @@ -1,295 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyAssignment.h" -#include "polypyVariable.h" -#include "utils.h" -#include "polypyAlgebraicNumber.h" -#include "polypyValue.h" - -#include - -/** Default variable database */ -static lp_assignment_t* default_assignment = 0; - -lp_assignment_t* Assignment_get_default_assignment(void) { - if (!default_assignment) { - default_assignment = lp_assignment_new(Variable_get_default_db()); - } - return default_assignment; -} - -static PyObject* -Assignment_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Assignment_init(Assignment* self, PyObject* args); - -static void -Assignment_dealloc(Assignment* self); - -static PyObject* -Assignment_str(PyObject* self); - -static PyObject* -Assignment_get_value(PyObject* self, PyObject* args); - -static PyObject* -Assignment_set_value(PyObject* self, PyObject* args); - -static PyObject* -Assignment_unset_value(PyObject* self, PyObject* args); - -PyMethodDef Assignment_methods[] = { - {"get_value", (PyCFunction)Assignment_get_value, METH_VARARGS, "Returns the value of the variable"}, - {"set_value", (PyCFunction)Assignment_set_value, METH_VARARGS, "Sets the value of the variable"}, - {"unset_value", (PyCFunction)Assignment_unset_value, METH_VARARGS, "Marks the variable as unassigned"}, - {NULL} /* Sentinel */ -}; - - -PyTypeObject AssignmentType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.Assignment", // const char *tp_name; - sizeof(Variable), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)Assignment_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - 0, // reprfunc tp_repr; - 0, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - Assignment_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Variable objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - 0, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - Assignment_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)Assignment_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - Assignment_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -PyObject* -PyAssignment_create(lp_assignment_t* assignment) { - Assignment *self; - self = (Assignment*)AssignmentType.tp_alloc(&AssignmentType, 0); - if (self != NULL) { - self->assignment = assignment; - } - return (PyObject *)self; -} - -static PyObject* -Assignment_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyAssignment_create(0); -} - -static int -Assignment_init(Assignment* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { - self->assignment = lp_assignment_new(Variable_get_default_db()); - } else { - return -1; - } - return 0; -} - -static void -Assignment_dealloc(Assignment* self) -{ - if (self->assignment) { - lp_assignment_delete(self->assignment); - } - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -static PyObject* Assignment_str(PyObject* self) { - Assignment* a = (Assignment*) self; - char* a_str = lp_assignment_to_string(a->assignment); - PyObject* str = PyUnicode_FromString(a_str); - free(a_str); - return str; -} - -static PyObject* -Assignment_get_value(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* var_obj = PyTuple_GetItem(args, 0); - if (PyVariable_CHECK(var_obj)) { - Variable* var = (Variable*) var_obj; - Assignment* a = (Assignment*) self; - const lp_value_t* value = lp_assignment_get_value(a->assignment, var->x); - switch (value->type) { - case LP_VALUE_ALGEBRAIC: - return 0; - break; - case LP_VALUE_DYADIC_RATIONAL: - return dyadic_rational_to_PyFloat(&value->value.dy_q); - break; - case LP_VALUE_NONE: - Py_RETURN_NONE; - break; - case LP_VALUE_RATIONAL: - return 0; - break; - default: - return 0; - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Assignment_set_value(PyObject* self, PyObject* args) { - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 2) { - PyObject* var_obj = PyTuple_GetItem(args, 0); - PyObject* value_obj = PyTuple_GetItem(args, 1); - if (PyVariable_CHECK(var_obj)) { - Assignment* a = (Assignment*) self; - Variable* var = (Variable*) var_obj; - if (PyFloat_Check(value_obj)) { - lp_dyadic_rational_t value_dyrat; - PyFloat_to_dyadic_rational(value_obj, &value_dyrat); - lp_value_t value; - lp_value_construct(&value, LP_VALUE_DYADIC_RATIONAL, &value_dyrat); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - lp_dyadic_rational_destruct(&value_dyrat); - Py_RETURN_NONE; - } else if (PyLong_or_Int_Check(value_obj)) { - lp_integer_t value_int; - PyLong_or_Int_to_integer(value_obj, lp_Z, &value_int); - lp_dyadic_rational_t value_dyrat; - lp_dyadic_rational_construct_from_integer(&value_dyrat, &value_int); - lp_value_t value; - lp_value_construct(&value, LP_VALUE_DYADIC_RATIONAL, &value_dyrat); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - lp_dyadic_rational_destruct(&value_dyrat); - lp_integer_destruct(&value_int); - Py_RETURN_NONE; - } else if (PyAlgebraicNumber_CHECK(value_obj)) { - lp_value_t value; - lp_value_construct(&value, LP_VALUE_ALGEBRAIC, &((AlgebraicNumber*) value_obj)->a); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - Py_RETURN_NONE; - } else if (PyValue_CHECK(value_obj)) { - Value* value = (Value*) value_obj; - lp_assignment_set_value(a->assignment, var->x, &value->v); - Py_RETURN_NONE; - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): not a value."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): not a variable."); - return NULL; - } - } else if (PyTuple_Size(args) == 3) { - // Three arguments, rational - PyObject* var_obj = PyTuple_GetItem(args, 0); - PyObject* p_obj = PyTuple_GetItem(args, 1); - PyObject* q_obj = PyTuple_GetItem(args, 2); - if (PyLong_or_Int_Check(p_obj) && PyLong_or_Int_Check(q_obj)) { - Assignment* a = (Assignment*) self; - Variable* var = (Variable*) var_obj; - lp_integer_t p_int, q_int; - PyLong_or_Int_to_integer(p_obj, lp_Z, &p_int); - PyLong_or_Int_to_integer(q_obj, lp_Z, &q_int); - lp_rational_t value_rat; - lp_rational_construct_from_div(&value_rat, &p_int, &q_int); - lp_value_t value; - lp_value_construct(&value, LP_VALUE_RATIONAL, &value_rat); - lp_assignment_set_value(a->assignment, var->x, &value); - lp_value_destruct(&value); - lp_rational_destruct(&value_rat); - lp_integer_destruct(&p_int); - lp_integer_destruct(&q_int); - Py_RETURN_NONE; - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): for rationals, both numerator and denominator must be integer."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): need two or three arguments."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): need two or three arguments."); - return NULL; - } -} - -static PyObject* -Assignment_unset_value(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* var_obj = PyTuple_GetItem(args, 0); - if (PyVariable_CHECK(var_obj)) { - Variable* var = (Variable*) var_obj; - Assignment* a = (Assignment*) self; - lp_assignment_set_value(a->assignment, var->x, 0); - Py_RETURN_NONE; - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): not a variable."); - return NULL; - } - } else { - PyErr_SetString(PyExc_RuntimeError, "set_value(): need one argument."); - return NULL; - } -} diff --git a/python/polypyFeasibilitySet.c b/python/polypyFeasibilitySet.c index 11d23b92..8b90b201 100644 --- a/python/polypyFeasibilitySet.c +++ b/python/polypyFeasibilitySet.c @@ -17,11 +17,199 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include "Python.h" - -#if PY_MAJOR_VERSION >= 3 -#include "polypyFeasibilitySet3.c" -#else -#include "polypyFeasibilitySet2.c" -#endif +#include "python.h" + +#include "polypyFeasibilitySet.h" +#include "polypyValue.h" + +static void +FeasibilitySet_dealloc(FeasibilitySet* self); + +static PyObject* +FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +FeasibilitySet_init(FeasibilitySet* self, PyObject* args); + +static PyObject* +FeasibilitySet_str(PyObject* self); + +static PyObject* +FeasibilitySet_pick_value(PyObject* self); + +static PyObject* +FeasibilitySet_intersect(PyObject* self, PyObject* args); + +static PyObject* +FeasibilitySet_contains_value(PyObject* self, PyObject* args); + +static PyObject* +FeasibilitySet_contains_int(PyObject* self); + +PyMethodDef FeasibilitySet_methods[] = { + {"pick_value", (PyCFunction)FeasibilitySet_pick_value, METH_NOARGS, "Returns a value from the interval."}, + {"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the set with another one."}, + {"contains", (PyCFunction)FeasibilitySet_contains_value, METH_VARARGS, "Returns true if the value is in the feasibility set."}, + {"contains_int", (PyCFunction)FeasibilitySet_contains_int, METH_NOARGS, "Returns true if the set contains an integer value."}, + {NULL} /* Sentinel */ +}; + +PyTypeObject FeasibilitySetType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.FeasibilitySet", // const char *tp_name; + sizeof(FeasibilitySet), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)FeasibilitySet_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + FeasibilitySet_str, // reprfunc tp_repr; + NULL, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + FeasibilitySet_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "FeasibilitySet objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + NULL, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + FeasibilitySet_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)FeasibilitySet_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + FeasibilitySet_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +FeasibilitySet_dealloc(FeasibilitySet* self) { + lp_feasibility_set_delete(self->S); + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +PyFeasibilitySet_create(lp_feasibility_set_t* S) { + FeasibilitySet *self; + self = (FeasibilitySet*)FeasibilitySetType.tp_alloc(&FeasibilitySetType, 0); + if (self != NULL) { + self->S = S; + } + return (PyObject *)self; +} + +static PyObject* +FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyFeasibilitySet_create(NULL); +} + +static int +FeasibilitySet_init(FeasibilitySet* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { + // Defaults to (-inf, +inf) + self->S = lp_feasibility_set_new_full(); + } else { + return -1; + } + return 0; +} + +static PyObject* FeasibilitySet_str(PyObject* self) { + FeasibilitySet* S = (FeasibilitySet*) self; + char* I_str = lp_feasibility_set_to_string(S->S); + PyObject* str = PyUnicode_FromString(I_str); + free(I_str); + return str; +} + +static PyObject* +FeasibilitySet_pick_value(PyObject* self) { + FeasibilitySet* S = (FeasibilitySet*) self; + lp_value_t v; + lp_value_construct_none(&v); + lp_feasibility_set_pick_value(S->S, &v); + PyObject* result = PyValue_create(&v); + lp_value_destruct(&v); + return result; +} + +static PyObject* +FeasibilitySet_intersect(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* feasibility_set_obj = PyTuple_GetItem(args, 0); + if (!PyFeasibilitySet_CHECK(feasibility_set_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Get the arguments + lp_feasibility_set_t* S1 = ((FeasibilitySet*) self)->S; + lp_feasibility_set_t* S2 = ((FeasibilitySet*) feasibility_set_obj)->S; + + // The intersection + lp_feasibility_set_t* P = lp_feasibility_set_intersect(S1, S2); + PyObject* P_obj = PyFeasibilitySet_create(P); + + return P_obj; +} + +static PyObject* +FeasibilitySet_contains_value(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* value_obj = PyTuple_GetItem(args, 0); + + if (!PyValue_CHECK(value_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S; + lp_value_t* v = &((Value*) value_obj)->v; + + int result = lp_feasibility_set_contains(S, v); + + PyObject* result_object = result ? Py_True : Py_False; + Py_INCREF(result_object); + return result_object; +} + +static PyObject* +FeasibilitySet_contains_int(PyObject* self) { + lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S; + PyObject* result_object = lp_feasibility_set_contains_int(S) ? Py_True : Py_False; + Py_INCREF(result_object); + return result_object; +} diff --git a/python/polypyFeasibilitySet.h b/python/polypyFeasibilitySet.h index 94b7d51d..b937237b 100644 --- a/python/polypyFeasibilitySet.h +++ b/python/polypyFeasibilitySet.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "feasibility_set.h" diff --git a/python/polypyFeasibilitySet2.c b/python/polypyFeasibilitySet2.c deleted file mode 100644 index 3705d8c1..00000000 --- a/python/polypyFeasibilitySet2.c +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyFeasibilitySet.h" -#include "polypyValue.h" - -#include - -static void -FeasibilitySet_dealloc(FeasibilitySet* self); - -static PyObject* -FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -FeasibilitySet_init(FeasibilitySet* self, PyObject* args); - -static PyObject* -FeasibilitySet_str(PyObject* self); - -static PyObject* -FeasibilitySet_pick_value(PyObject* self); - -static PyObject* -FeasibilitySet_intersect(PyObject* self, PyObject* args); - -static PyObject* -FeasibilitySet_contains_value(PyObject* self, PyObject* args); - -static PyObject* -FeasibilitySet_contains_int(PyObject* self); - -PyMethodDef FeasibilitySet_methods[] = { - {"pick_value", (PyCFunction)FeasibilitySet_pick_value, METH_NOARGS, "Returns a value from the interval."}, - {"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the set with another one."}, - {"contains", (PyCFunction)FeasibilitySet_contains_value, METH_VARARGS, "Returns true if the value is in the feasibility set."}, - {"contains_int", (PyCFunction)FeasibilitySet_contains_int, METH_NOARGS, "Returns true if the set contains an integer value."}, - {NULL} /* Sentinel */ -}; - -PyTypeObject FeasibilitySetType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.FeasibilitySet", /*tp_name*/ - sizeof(FeasibilitySet), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)FeasibilitySet_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0 , /*tp_compare*/ - FeasibilitySet_str, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - FeasibilitySet_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "FeasibilitySet objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - FeasibilitySet_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)FeasibilitySet_init,/* tp_init */ - 0, /* tp_alloc */ - FeasibilitySet_new, /* tp_new */ -}; - -static void -FeasibilitySet_dealloc(FeasibilitySet* self) -{ - lp_feasibility_set_delete(self->S); - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyFeasibilitySet_create(lp_feasibility_set_t* S) { - FeasibilitySet *self; - self = (FeasibilitySet*)FeasibilitySetType.tp_alloc(&FeasibilitySetType, 0); - if (self != NULL) { - self->S = S; - } - return (PyObject *)self; -} - -static PyObject* -FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyFeasibilitySet_create(0); -} - -static int -FeasibilitySet_init(FeasibilitySet* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { - // Defaults to (-inf, +inf) - self->S = lp_feasibility_set_new_full(); - } else { - return -1; - } - return 0; -} - -static PyObject* FeasibilitySet_str(PyObject* self) { - FeasibilitySet* S = (FeasibilitySet*) self; - char* I_str = lp_feasibility_set_to_string(S->S); - PyObject* str = PyString_FromString(I_str); - free(I_str); - return str; -} - -static PyObject* -FeasibilitySet_pick_value(PyObject* self) { - FeasibilitySet* S = (FeasibilitySet*) self; - lp_value_t v; - lp_value_construct_none(&v); - lp_feasibility_set_pick_value(S->S, &v); - PyObject* result = PyValue_create(&v); - lp_value_destruct(&v); - return result; -} - -static PyObject* -FeasibilitySet_intersect(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* feasibility_set_obj = PyTuple_GetItem(args, 0); - if (!PyFeasibilitySet_CHECK(feasibility_set_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Get the arguments - lp_feasibility_set_t* S1 = ((FeasibilitySet*) self)->S; - lp_feasibility_set_t* S2 = ((FeasibilitySet*) feasibility_set_obj)->S; - - // The intersection - lp_feasibility_set_t* P = lp_feasibility_set_intersect(S1, S2); - PyObject* P_obj = PyFeasibilitySet_create(P); - - return P_obj; -} - -static PyObject* -FeasibilitySet_contains_value(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* value_obj = PyTuple_GetItem(args, 0); - - if (!PyValue_CHECK(value_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S; - lp_value_t* v = &((Value*) value_obj)->v; - - int result = lp_feasibility_set_contains(S, v); - - PyObject* result_object = result ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} - -static PyObject* -FeasibilitySet_contains_int(PyObject* self) { - lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S; - PyObject* result_object = lp_feasibility_set_contains_int(S) ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} diff --git a/python/polypyFeasibilitySet3.c b/python/polypyFeasibilitySet3.c deleted file mode 100644 index 979d4f11..00000000 --- a/python/polypyFeasibilitySet3.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyFeasibilitySet.h" -#include "polypyValue.h" - -#include - -static void -FeasibilitySet_dealloc(FeasibilitySet* self); - -static PyObject* -FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -FeasibilitySet_init(FeasibilitySet* self, PyObject* args); - -static PyObject* -FeasibilitySet_str(PyObject* self); - -static PyObject* -FeasibilitySet_pick_value(PyObject* self); - -static PyObject* -FeasibilitySet_intersect(PyObject* self, PyObject* args); - -static PyObject* -FeasibilitySet_contains_value(PyObject* self, PyObject* args); - -static PyObject* -FeasibilitySet_contains_int(PyObject* self); - -PyMethodDef FeasibilitySet_methods[] = { - {"pick_value", (PyCFunction)FeasibilitySet_pick_value, METH_NOARGS, "Returns a value from the interval."}, - {"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the set with another one."}, - {"contains", (PyCFunction)FeasibilitySet_contains_value, METH_VARARGS, "Returns true if the value is in the feasibility set."}, - {"contains_int", (PyCFunction)FeasibilitySet_contains_int, METH_NOARGS, "Returns true if the set contains an integer value."}, - {NULL} /* Sentinel */ -}; - -PyTypeObject FeasibilitySetType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.FeasibilitySet", // const char *tp_name; - sizeof(FeasibilitySet), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)FeasibilitySet_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - FeasibilitySet_str, // reprfunc tp_repr; - 0, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - FeasibilitySet_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "FeasibilitySet objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - 0, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - FeasibilitySet_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)FeasibilitySet_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - FeasibilitySet_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -FeasibilitySet_dealloc(FeasibilitySet* self) { - lp_feasibility_set_delete(self->S); - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyFeasibilitySet_create(lp_feasibility_set_t* S) { - FeasibilitySet *self; - self = (FeasibilitySet*)FeasibilitySetType.tp_alloc(&FeasibilitySetType, 0); - if (self != NULL) { - self->S = S; - } - return (PyObject *)self; -} - -static PyObject* -FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyFeasibilitySet_create(0); -} - -static int -FeasibilitySet_init(FeasibilitySet* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { - // Defaults to (-inf, +inf) - self->S = lp_feasibility_set_new_full(); - } else { - return -1; - } - return 0; -} - -static PyObject* FeasibilitySet_str(PyObject* self) { - FeasibilitySet* S = (FeasibilitySet*) self; - char* I_str = lp_feasibility_set_to_string(S->S); - PyObject* str = PyUnicode_FromString(I_str); - free(I_str); - return str; -} - -static PyObject* -FeasibilitySet_pick_value(PyObject* self) { - FeasibilitySet* S = (FeasibilitySet*) self; - lp_value_t v; - lp_value_construct_none(&v); - lp_feasibility_set_pick_value(S->S, &v); - PyObject* result = PyValue_create(&v); - lp_value_destruct(&v); - return result; -} - -static PyObject* -FeasibilitySet_intersect(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* feasibility_set_obj = PyTuple_GetItem(args, 0); - if (!PyFeasibilitySet_CHECK(feasibility_set_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Get the arguments - lp_feasibility_set_t* S1 = ((FeasibilitySet*) self)->S; - lp_feasibility_set_t* S2 = ((FeasibilitySet*) feasibility_set_obj)->S; - - // The intersection - lp_feasibility_set_t* P = lp_feasibility_set_intersect(S1, S2); - PyObject* P_obj = PyFeasibilitySet_create(P); - - return P_obj; -} - -static PyObject* -FeasibilitySet_contains_value(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* value_obj = PyTuple_GetItem(args, 0); - - if (!PyValue_CHECK(value_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S; - lp_value_t* v = &((Value*) value_obj)->v; - - int result = lp_feasibility_set_contains(S, v); - - PyObject* result_object = result ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} - -static PyObject* -FeasibilitySet_contains_int(PyObject* self) { - lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S; - PyObject* result_object = lp_feasibility_set_contains_int(S) ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} diff --git a/python/polypyInteger.c b/python/polypyInteger.c index f782b964..1c9aa4b8 100644 --- a/python/polypyInteger.c +++ b/python/polypyInteger.c @@ -17,11 +17,248 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include - -#if PY_MAJOR_VERSION >= 3 -#include "polypyInteger3.c" -#else -#include "polypyInteger2.c" -#endif +#include "python.h" + +#include "polypyInteger.h" +#include "utils.h" + +static void +CoefficientRing_dealloc(CoefficientRing* self); + +static PyObject* +CoefficientRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +CoefficientRing_init(CoefficientRing* self, PyObject* args); + +static PyObject* +CoefficientRing_modulus(PyObject* self); + +static PyObject* +CoefficientRing_str(PyObject* self); + +static PyObject * +CoefficientRing_richcompare(PyObject *self, PyObject *other, int op); + +PyMethodDef CoefficientRing_methods[] = { + {"modulus", (PyCFunction)CoefficientRing_modulus, METH_NOARGS, "Returns the degree of the polynomial"}, + {NULL} /* Sentinel */ +}; + +PyTypeObject CoefficientRingType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.CoefficientRing", // const char *tp_name; + sizeof(CoefficientRing), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)CoefficientRing_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + NULL, // reprfunc tp_repr; + NULL, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + CoefficientRing_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Coefficient ring objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + CoefficientRing_richcompare, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + CoefficientRing_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)CoefficientRing_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + CoefficientRing_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +CoefficientRing_dealloc(CoefficientRing* self) +{ + if (self->K) lp_int_ring_detach(self->K); + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +PyCoefficientRing_create(lp_int_ring_t* K) { + CoefficientRing *self; + self = (CoefficientRing*)CoefficientRingType.tp_alloc(&CoefficientRingType, 0); + if (self != NULL) { + self->K = (lp_int_ring_t*)K; + } + return (PyObject *)self; +} + +static PyObject* +CoefficientRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyCoefficientRing_create(NULL); +} + + +static int +CoefficientRing_init(CoefficientRing* self, PyObject* args) +{ + if (PyTuple_Check(args)) { + if (PyTuple_Size(args) == 0) { + // Defaults to Z + self->K = lp_Z; + } else if (PyTuple_Size(args) == 1) { + // Get the list of coefficients + PyObject* modulus = PyTuple_GetItem(args, 0); + if (!PyLong_Check(modulus)) { + if (!PyLong_Check(modulus)) { + return -1; + } else { + long M_int = PyLong_AsLong(modulus); + lp_integer_t M; + lp_integer_construct_from_int(lp_Z, &M, M_int); + int is_prime = lp_integer_is_prime(&M); + self->K = lp_int_ring_create(&M, is_prime); + lp_integer_destruct(&M); + } + } else { + int overflow = 0; + long M_int = PyLong_AsLongAndOverflow(modulus, &overflow); + if (overflow) { + const char* M_cstr = pythonObject2CharStar(modulus); + lp_integer_t M; + lp_integer_construct_from_string(lp_Z, &M, M_cstr, 10); + int is_prime = lp_integer_is_prime(&M); + self->K = lp_int_ring_create(&M, is_prime); + } else if (M_int > 0) { + lp_integer_t M; + lp_integer_construct_from_int(lp_Z, &M, M_int); + int is_prime = lp_integer_is_prime(&M); + self->K = lp_int_ring_create(&M, is_prime); + } else { + return -1; + } + } + } else { + return -1; + } + } else { + return -1; + } + + return 0; +} + +static PyObject* +CoefficientRing_modulus(PyObject* self) { + CoefficientRing* K = (CoefficientRing*) self; + if (K && K->K) { + char* K_str = lp_integer_to_string(&K->K->M); + char* p = NULL; + PyObject* M = PyLong_FromString(K_str, &p, 10); + free(K_str); + return M; + } else { + Py_RETURN_NONE; + } +} + +static PyObject* CoefficientRing_str(PyObject* self) { + CoefficientRing* K = (CoefficientRing*) self; + if (K) { + if (K->K) { + char* K_str = lp_int_ring_to_string(K->K); + PyObject* str = PyUnicode_FromString(K_str); + free(K_str); + return str; + } else { + return PyUnicode_FromString("Z"); + } + } else { + Py_RETURN_NONE; + } +} + +static PyObject * +CoefficientRing_richcompare(PyObject *self, PyObject *other, int op){ + PyObject *result = Py_NotImplemented; + + if(!PyCoefficientRing_CHECK(other)){ + //IAM: Unless I am violating some sacrosanct python contract, this seems like a no-brainer. + if(op == Py_EQ){ return Py_False; } + if(op == Py_NE){ return Py_True; } + } else { + // Get arguments + CoefficientRing* K1 = (CoefficientRing*) self; + CoefficientRing* K2 = (CoefficientRing*) other; + + //Are they equal? + if (K1->K == K2->K) { + if( op == Py_LE || op == Py_EQ || op == Py_GE){ + return Py_True; + } + return Py_False; + } + + // Is one of them Z + if (K1->K == lp_Z) { + // self > other + if( op == Py_LT || op == Py_LE || op == Py_EQ){ + return Py_False; + } + return Py_True; + } + if (K2->K == lp_Z) { + //self < other + if( op == Py_LT || op == Py_LE){ + return Py_True; + } + return Py_False; + } + + int cmp = lp_integer_cmp(lp_Z, &K1->K->M, &K2->K->M); + + switch (op) { + case Py_LT: + result = cmp < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = cmp <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = cmp == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = cmp != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = cmp > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = cmp >= 0 ? Py_True : Py_False; + break; + default: + assert(0); + } + } + return result; +} diff --git a/python/polypyInteger.h b/python/polypyInteger.h index e4485145..bb872119 100644 --- a/python/polypyInteger.h +++ b/python/polypyInteger.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "integer.h" diff --git a/python/polypyInteger2.c b/python/polypyInteger2.c deleted file mode 100644 index 06c369f3..00000000 --- a/python/polypyInteger2.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyInteger.h" - -#include - -static void -CoefficientRing_dealloc(CoefficientRing* self); - -static PyObject* -CoefficientRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -CoefficientRing_init(CoefficientRing* self, PyObject* args); - -static int -CoefficientRing_cmp(PyObject* self, PyObject* args); - -static PyObject* -CoefficientRing_modulus(PyObject* self); - -static PyObject* -CoefficientRing_str(PyObject* self); - -PyMethodDef CoefficientRing_methods[] = { - {"modulus", (PyCFunction)CoefficientRing_modulus, METH_NOARGS, "Returns the degree of the polynomial"}, - {NULL} /* Sentinel */ -}; - -PyTypeObject CoefficientRingType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.CoefficientRing", /*tp_name*/ - sizeof(CoefficientRing), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)CoefficientRing_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - CoefficientRing_cmp, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - CoefficientRing_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Coefficient ring objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - CoefficientRing_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)CoefficientRing_init,/* tp_init */ - 0, /* tp_alloc */ - CoefficientRing_new, /* tp_new */ -}; - -static void -CoefficientRing_dealloc(CoefficientRing* self) -{ - if (self->K) lp_int_ring_detach(self->K); - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyCoefficientRing_create(lp_int_ring_t* K) { - CoefficientRing *self; - self = (CoefficientRing*)CoefficientRingType.tp_alloc(&CoefficientRingType, 0); - if (self != NULL) { - self->K = K; - } - return (PyObject *)self; -} - -static PyObject* -CoefficientRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyCoefficientRing_create(0); -} - -static int -CoefficientRing_init(CoefficientRing* self, PyObject* args) -{ - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 0) { - // Defaults to Z - self->K = lp_Z; - } else if (PyTuple_Size(args) == 1) { - // Get the list of coefficients - PyObject* modulus = PyTuple_GetItem(args, 0); - if (!PyLong_Check(modulus)) { - if (!PyInt_Check(modulus)) { - return -1; - } else { - long M_int = PyInt_AsLong(modulus); - lp_integer_t M; - lp_integer_construct_from_int(lp_Z, &M, M_int); - int is_prime = lp_integer_is_prime(&M); - self->K = lp_int_ring_create(&M, is_prime); - lp_integer_destruct(&M); - } - } else { - int overflow = 0; - long M_int = PyLong_AsLongAndOverflow(modulus, &overflow); - if (overflow) { - PyObject* M_str = PyObject_Str(modulus); - char* M_cstr = PyString_AsString(M_str); - lp_integer_t M; - lp_integer_construct_from_string(lp_Z, &M, M_cstr, 10); - int is_prime = lp_integer_is_prime(&M); - self->K = lp_int_ring_create(&M, is_prime); - Py_DECREF(M_str); - } else if (M_int > 0) { - lp_integer_t M; - lp_integer_construct_from_int(lp_Z, &M, M_int); - int is_prime = lp_integer_is_prime(&M); - self->K = lp_int_ring_create(&M, is_prime); - } else { - return -1; - } - } - } else { - return -1; - } - } else { - return -1; - } - - return 0; -} - -static int -CoefficientRing_cmp(PyObject* self, PyObject* other) { - // Check arguments - if (!PyCoefficientRing_CHECK(self) || !PyCoefficientRing_CHECK(other)) { - // should return -1 and set an exception condition when an error occurred - return -1; - } - // Get arguments - CoefficientRing* K1 = (CoefficientRing*) self; - CoefficientRing* K2 = (CoefficientRing*) other; - // Are they equal - if (K1->K == K2->K) { - return 0; - } - // Is one of them Z - if (K1->K == lp_Z) { - return 1; - } - if (K2->K == lp_Z) { - return -1; - } - // Compare - return lp_integer_cmp(lp_Z, &K1->K->M, &K2->K->M); -} - -static PyObject* -CoefficientRing_modulus(PyObject* self) { - CoefficientRing* K = (CoefficientRing*) self; - if (K && K->K) { - char* K_str = lp_integer_to_string(&K->K->M); - char* p = 0; - PyObject* M = PyLong_FromString(K_str, &p, 10); - free(K_str); - return M; - } else { - Py_RETURN_NONE; - } -} - -static PyObject* CoefficientRing_str(PyObject* self) { - CoefficientRing* K = (CoefficientRing*) self; - if (K) { - if (K->K) { - char* K_str = lp_int_ring_to_string(K->K); - PyObject* str = PyString_FromString(K_str); - free(K_str); - return str; - } else { - return PyString_FromString("Z"); - } - } else { - Py_RETURN_NONE; - } -} diff --git a/python/polypyInteger3.c b/python/polypyInteger3.c deleted file mode 100644 index 12d5ace0..00000000 --- a/python/polypyInteger3.c +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyInteger.h" -#include "utils.h" - -#include - -static void -CoefficientRing_dealloc(CoefficientRing* self); - -static PyObject* -CoefficientRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -CoefficientRing_init(CoefficientRing* self, PyObject* args); - -static PyObject* -CoefficientRing_modulus(PyObject* self); - -static PyObject* -CoefficientRing_str(PyObject* self); - -static PyObject * -CoefficientRing_richcompare(PyObject *self, PyObject *other, int op); - -PyMethodDef CoefficientRing_methods[] = { - {"modulus", (PyCFunction)CoefficientRing_modulus, METH_NOARGS, "Returns the degree of the polynomial"}, - {NULL} /* Sentinel */ -}; - -PyTypeObject CoefficientRingType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.CoefficientRing", // const char *tp_name; - sizeof(CoefficientRing), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)CoefficientRing_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - 0, // reprfunc tp_repr; - 0, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - CoefficientRing_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Coefficient ring objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - CoefficientRing_richcompare, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - CoefficientRing_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)CoefficientRing_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - CoefficientRing_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -CoefficientRing_dealloc(CoefficientRing* self) -{ - if (self->K) lp_int_ring_detach(self->K); - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyCoefficientRing_create(lp_int_ring_t* K) { - CoefficientRing *self; - self = (CoefficientRing*)CoefficientRingType.tp_alloc(&CoefficientRingType, 0); - if (self != NULL) { - self->K = (lp_int_ring_t*)K; - } - return (PyObject *)self; -} - -static PyObject* -CoefficientRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyCoefficientRing_create(0); -} - - -static int -CoefficientRing_init(CoefficientRing* self, PyObject* args) -{ - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 0) { - // Defaults to Z - self->K = lp_Z; - } else if (PyTuple_Size(args) == 1) { - // Get the list of coefficients - PyObject* modulus = PyTuple_GetItem(args, 0); - if (!PyLong_Check(modulus)) { - if (!PyLong_Check(modulus)) { - return -1; - } else { - long M_int = PyLong_AsLong(modulus); - lp_integer_t M; - lp_integer_construct_from_int(lp_Z, &M, M_int); - int is_prime = lp_integer_is_prime(&M); - self->K = lp_int_ring_create(&M, is_prime); - lp_integer_destruct(&M); - } - } else { - int overflow = 0; - long M_int = PyLong_AsLongAndOverflow(modulus, &overflow); - if (overflow) { - const char* M_cstr = pythonObject2CharStar(modulus); - lp_integer_t M; - lp_integer_construct_from_string(lp_Z, &M, M_cstr, 10); - int is_prime = lp_integer_is_prime(&M); - self->K = lp_int_ring_create(&M, is_prime); - } else if (M_int > 0) { - lp_integer_t M; - lp_integer_construct_from_int(lp_Z, &M, M_int); - int is_prime = lp_integer_is_prime(&M); - self->K = lp_int_ring_create(&M, is_prime); - } else { - return -1; - } - } - } else { - return -1; - } - } else { - return -1; - } - - return 0; -} - -static PyObject* -CoefficientRing_modulus(PyObject* self) { - CoefficientRing* K = (CoefficientRing*) self; - if (K && K->K) { - char* K_str = lp_integer_to_string(&K->K->M); - char* p = 0; - PyObject* M = PyLong_FromString(K_str, &p, 10); - free(K_str); - return M; - } else { - Py_RETURN_NONE; - } -} - -static PyObject* CoefficientRing_str(PyObject* self) { - CoefficientRing* K = (CoefficientRing*) self; - if (K) { - if (K->K) { - char* K_str = lp_int_ring_to_string(K->K); - PyObject* str = PyUnicode_FromString(K_str); - free(K_str); - return str; - } else { - return PyUnicode_FromString("Z"); - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject * -CoefficientRing_richcompare(PyObject *self, PyObject *other, int op){ - PyObject *result = Py_NotImplemented; - - if(!PyCoefficientRing_CHECK(other)){ - //IAM: Unless I am violating some sacrosanct python contract, this seems like a no-brainer. - if(op == Py_EQ){ return Py_False; } - if(op == Py_NE){ return Py_True; } - } else { - // Get arguments - CoefficientRing* K1 = (CoefficientRing*) self; - CoefficientRing* K2 = (CoefficientRing*) other; - - //Are they equal? - if (K1->K == K2->K) { - if( op == Py_LE || op == Py_EQ || op == Py_GE){ - return Py_True; - } - return Py_False; - } - - // Is one of them Z - if (K1->K == lp_Z) { - // self > other - if( op == Py_LT || op == Py_LE || op == Py_EQ){ - return Py_False; - } - return Py_True; - } - if (K2->K == lp_Z) { - //self < other - if( op == Py_LT || op == Py_LE){ - return Py_True; - } - return Py_False; - } - - int cmp = lp_integer_cmp(lp_Z, &K1->K->M, &K2->K->M); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - } - return result; -} diff --git a/python/polypyInterval.c b/python/polypyInterval.c index 87673d84..5150817b 100644 --- a/python/polypyInterval.c +++ b/python/polypyInterval.c @@ -17,11 +17,169 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include - -#if PY_MAJOR_VERSION >= 3 -#include "polypyInterval3.c" -#else -#include "polypyInterval2.c" -#endif +#include "python.h" + +#include "polypyInterval.h" +#include "polypyValue.h" + +static void +Interval_dealloc(Interval* self); + +static PyObject* +Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +Interval_init(Interval* self, PyObject* args); + +static PyObject* +Interval_str(PyObject* self); + +static PyObject* +Interval_pick_value(PyObject* self); + +static PyObject* +Interval_contains_value(PyObject* self, PyObject* args); + +static PyObject* +Interval_contains_int(PyObject* self); + +PyMethodDef Interval_methods[] = { + {"pick_value", (PyCFunction)Interval_pick_value, METH_NOARGS, "Returns a value from the interval."}, + {"contains", (PyCFunction)Interval_contains_value, METH_VARARGS, "Returns true if the value is in the interval."}, + {"contains_int", (PyCFunction)Interval_contains_int, METH_NOARGS, "Returns true if the interval contains an integer value."}, + {NULL} /* Sentinel */ +}; + +PyTypeObject IntervalType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.Interval", // const char *tp_name; + sizeof(Interval), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)Interval_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + Interval_str, // reprfunc tp_repr; + NULL, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + Interval_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Interval objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + NULL, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + Interval_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)Interval_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + Interval_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +Interval_dealloc(Interval* self) { + lp_interval_destruct(&self->I); + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +PyInterval_create(const lp_interval_t* I) { + Interval *self = (Interval*)IntervalType.tp_alloc(&IntervalType, 0); + if (self != NULL && I) { + lp_interval_construct_copy(&self->I, I); + } + return (PyObject *)self; +} + +static PyObject* +Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyInterval_create(NULL); +} + +static int +Interval_init(Interval* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { + // Defaults to (-inf, +inf) + lp_interval_construct_full(&self->I); + } else { + return -1; + } + return 0; +} + +static PyObject* Interval_str(PyObject* self) { + Interval* I = (Interval*) self; + char* I_str = lp_interval_to_string(&I->I); + PyObject* str = PyUnicode_FromString(I_str); + free(I_str); + return str; +} + +static PyObject* +Interval_pick_value(PyObject* self) { + Interval* I = (Interval*) self; + lp_value_t v; + lp_value_construct_none(&v); + lp_interval_pick_value(&I->I, &v); + PyObject* result = PyValue_create(&v); + lp_value_destruct(&v); + return result; +} + +static PyObject* +Interval_contains_value(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* value_obj = PyTuple_GetItem(args, 0); + + if (!PyValue_CHECK(value_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + lp_interval_t* I = &((Interval*) self)->I; + lp_value_t* v = &((Value*) value_obj)->v; + + int result = lp_interval_contains(I, v); + + PyObject* result_object = result ? Py_True : Py_False; + Py_INCREF(result_object); + return result_object; +} + +static PyObject* +Interval_contains_int(PyObject* self) { + Interval* I = (Interval*) self; + PyObject* result_object = lp_interval_contains_int(&I->I) ? Py_True : Py_False; + Py_INCREF(result_object); + return result_object; +} diff --git a/python/polypyInterval.h b/python/polypyInterval.h index 4431fabb..bda15a3f 100644 --- a/python/polypyInterval.h +++ b/python/polypyInterval.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "interval.h" diff --git a/python/polypyInterval2.c b/python/polypyInterval2.c deleted file mode 100644 index 8dbdca0b..00000000 --- a/python/polypyInterval2.c +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyInterval.h" -#include "polypyValue.h" - -#include - -static void -Interval_dealloc(Interval* self); - -static PyObject* -Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Interval_init(Interval* self, PyObject* args); - -static PyObject* -Interval_str(PyObject* self); - -static PyObject* -Interval_pick_value(PyObject* self); - -static PyObject* -Interval_contains_value(PyObject* self, PyObject* args); - -static PyObject* -Interval_contains_int(PyObject* self); - -PyMethodDef Interval_methods[] = { - {"pick_value", (PyCFunction)Interval_pick_value, METH_NOARGS, "Returns a value from the interval."}, - {"contains", (PyCFunction)Interval_contains_value, METH_VARARGS, "Returns true if the value is in the interval."}, - {"contains_int", (PyCFunction)Interval_contains_int, METH_NOARGS, "Returns true if the interval contains an integer value."}, - {NULL} /* Sentinel */ -}; - -PyTypeObject IntervalType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.Interval", /*tp_name*/ - sizeof(Interval), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Interval_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0 , /*tp_compare*/ - Interval_str, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - Interval_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Interval objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Interval_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Interval_init,/* tp_init */ - 0, /* tp_alloc */ - Interval_new, /* tp_new */ -}; - -static void -Interval_dealloc(Interval* self) { - lp_interval_destruct(&self->I); - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyInterval_create(const lp_interval_t* I) { - Interval *self; - self = (Interval*)IntervalType.tp_alloc(&IntervalType, 0); - if (self != NULL && I) { - lp_interval_construct_copy(&self->I, I); - } - return (PyObject *)self; -} - -static PyObject* -Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyInterval_create(0); -} - -static int -Interval_init(Interval* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { - // Defaults to (-inf, +inf) - lp_interval_construct_full(&self->I); - } else { - return -1; - } - return 0; -} - -static PyObject* Interval_str(PyObject* self) { - Interval* I = (Interval*) self; - char* I_str = lp_interval_to_string(&I->I); - PyObject* str = PyString_FromString(I_str); - free(I_str); - return str; -} - -static PyObject* -Interval_pick_value(PyObject* self) { - Interval* I = (Interval*) self; - lp_value_t v; - lp_value_construct_none(&v); - lp_interval_pick_value(&I->I, &v); - PyObject* result = PyValue_create(&v); - lp_value_destruct(&v); - return result; -} - -static PyObject* -Interval_contains_value(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* value_obj = PyTuple_GetItem(args, 0); - - if (!PyValue_CHECK(value_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_interval_t* I = &((Interval*) self)->I; - lp_value_t* v = &((Value*) value_obj)->v; - - int result = lp_interval_contains(I, v); - - PyObject* result_object = result ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} - -static PyObject* -Interval_contains_int(PyObject* self) { - Interval* I = (Interval*) self; - PyObject* result_object = lp_interval_contains_int(&I->I) ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} diff --git a/python/polypyInterval3.c b/python/polypyInterval3.c deleted file mode 100644 index adf34c11..00000000 --- a/python/polypyInterval3.c +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyInterval.h" -#include "polypyValue.h" - -#include - -static void -Interval_dealloc(Interval* self); - -static PyObject* -Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Interval_init(Interval* self, PyObject* args); - -static PyObject* -Interval_str(PyObject* self); - -static PyObject* -Interval_pick_value(PyObject* self); - -static PyObject* -Interval_contains_value(PyObject* self, PyObject* args); - -static PyObject* -Interval_contains_int(PyObject* self); - -PyMethodDef Interval_methods[] = { - {"pick_value", (PyCFunction)Interval_pick_value, METH_NOARGS, "Returns a value from the interval."}, - {"contains", (PyCFunction)Interval_contains_value, METH_VARARGS, "Returns true if the value is in the interval."}, - {"contains_int", (PyCFunction)Interval_contains_int, METH_NOARGS, "Returns true if the interval contains an integer value."}, - {NULL} /* Sentinel */ -}; - -PyTypeObject IntervalType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.Interval", // const char *tp_name; - sizeof(Interval), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)Interval_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - Interval_str, // reprfunc tp_repr; - 0, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - Interval_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Interval objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - 0, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - Interval_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)Interval_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - Interval_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -Interval_dealloc(Interval* self) { - lp_interval_destruct(&self->I); - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyInterval_create(const lp_interval_t* I) { - Interval *self; - self = (Interval*)IntervalType.tp_alloc(&IntervalType, 0); - if (self != NULL && I) { - lp_interval_construct_copy(&self->I, I); - } - return (PyObject *)self; -} - -static PyObject* -Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyInterval_create(0); -} - -static int -Interval_init(Interval* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 0) { - // Defaults to (-inf, +inf) - lp_interval_construct_full(&self->I); - } else { - return -1; - } - return 0; -} - -static PyObject* Interval_str(PyObject* self) { - Interval* I = (Interval*) self; - char* I_str = lp_interval_to_string(&I->I); - PyObject* str = PyUnicode_FromString(I_str); - free(I_str); - return str; -} - -static PyObject* -Interval_pick_value(PyObject* self) { - Interval* I = (Interval*) self; - lp_value_t v; - lp_value_construct_none(&v); - lp_interval_pick_value(&I->I, &v); - PyObject* result = PyValue_create(&v); - lp_value_destruct(&v); - return result; -} - -static PyObject* -Interval_contains_value(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* value_obj = PyTuple_GetItem(args, 0); - - if (!PyValue_CHECK(value_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_interval_t* I = &((Interval*) self)->I; - lp_value_t* v = &((Value*) value_obj)->v; - - int result = lp_interval_contains(I, v); - - PyObject* result_object = result ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} - -static PyObject* -Interval_contains_int(PyObject* self) { - Interval* I = (Interval*) self; - PyObject* result_object = lp_interval_contains_int(&I->I) ? Py_True : Py_False; - Py_INCREF(result_object); - return result_object; -} diff --git a/python/polypyPolynomial.c b/python/polypyPolynomial.c index 96f0e1a2..1fc71a80 100644 --- a/python/polypyPolynomial.c +++ b/python/polypyPolynomial.c @@ -17,12 +17,1668 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" -#if PY_MAJOR_VERSION >= 3 -#include "polypyPolynomial3.c" -#else -#include "polypyPolynomial2.c" -#endif +#include "polypyPolynomial.h" +#include "polypyInteger.h" +#include "polypyVariable.h" +#include "polypyVariableOrder.h" +#include "polypyAssignment.h" +#include "polypyValue.h" +#include "polypyInterval.h" +#include "polypyFeasibilitySet.h" + +#include "utils.h" +#include "variable_list.h" +#include "sign_condition.h" +#include "feasibility_set.h" +#include "value.h" +#include "polynomial_vector.h" + +#include + +static lp_polynomial_context_t* default_ctx = NULL; + +const lp_polynomial_context_t* Polynomial_get_default_context(void) { + if (!default_ctx) { + default_ctx = lp_polynomial_context_new(NULL, Variable_get_default_db(), (lp_variable_order_t*) VariableOrder_get_default_order()); + } + return default_ctx; +} + +static void +Polynomial_dealloc(Polynomial* self); + +static PyObject* +Polynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject* +Polynomial_richcompare(PyObject* self, PyObject* other, int op); + +static Py_hash_t +Polynomial_hash(PyObject* self); + +static PyObject* +Polynomial_degree(PyObject* self); + +static PyObject* +Polynomial_coefficients(PyObject* self); + +static PyObject* +Polynomial_reductum(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_sgn(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_sgn_check(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_rem(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_prem(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_sprem(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_pdivrem(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_spdivrem(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_gcd(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_lcm(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_derivative(PyObject* self); + +static PyObject* +Polynomial_extended_gcd(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_factor(PyObject* self); + +static PyObject* +Polynomial_factor_square_free(PyObject* self); + +static PyObject* +Polynomial_roots_count(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_roots_isolate(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_sturm_sequence(PyObject* self); + +static PyObject* +Polynomial_str(PyObject* self); + +static int +Polynomial_nonzero(PyObject* self); + +static PyObject* +Polynomial_add(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_neg(PyObject* self); + +static PyObject* +Polynomial_sub(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_mul(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_div(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_rem_operator(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_divmod(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_pow(PyObject* self, PyObject* other); + +static PyObject* +Polynomial_resultant(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_psc(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_subres(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_mgcd(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_evaluate(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_vars(PyObject* self); + +static PyObject* +Polynomial_var(PyObject* self); + +static PyObject* +Polynomial_pp(PyObject* self); + +static PyObject* +Polynomial_cont(PyObject* self); + +static PyObject* +Polynomial_pp_cont(PyObject* self); + +static PyObject* +Polynomial_feasible_intervals(PyObject* self, PyObject* args); + +static PyObject* +Polynomial_feasible_set(PyObject* self, PyObject* args); + +PyMethodDef Polynomial_methods[] = { + {"degree", (PyCFunction)Polynomial_degree, METH_NOARGS, "Returns the degree of the polynomial in its top variable"}, + {"coefficients", (PyCFunction)Polynomial_coefficients, METH_NOARGS, "Returns a dictionary from degrees to coefficients"}, + {"reductum", (PyCFunction)Polynomial_reductum, METH_VARARGS, "Returns the reductum of the polynomial"}, + {"sgn", (PyCFunction)Polynomial_sgn, METH_VARARGS, "Returns the sign of the polynomials in the given model"}, + {"sgn_check", (PyCFunction)Polynomial_sgn_check, METH_VARARGS, "Returns true if the sign of the polynomial respects the sign condition."}, + {"rem", (PyCFunction)Polynomial_rem, METH_VARARGS, "Returns the remainder of current and given polynomial"}, + {"prem", (PyCFunction)Polynomial_prem, METH_VARARGS, "Returns the pseudo remainder of current and given polynomial"}, + {"sprem", (PyCFunction)Polynomial_sprem, METH_VARARGS, "Returns the sparse pseudo remainder of current and given polynomial"}, + {"pdivrem", (PyCFunction)Polynomial_pdivrem, METH_VARARGS, "Returns the pseudo quotient and pseudo remainder of current and given polynomial"}, + {"spdivprem", (PyCFunction)Polynomial_spdivrem, METH_VARARGS, "Returns the sparse pseudo quotient and sparse pseudo remainder of current and given polynomial"}, + {"gcd", (PyCFunction)Polynomial_gcd, METH_VARARGS, "Returns the gcd of current and given polynomial"}, + {"lcm", (PyCFunction)Polynomial_lcm, METH_VARARGS, "Returns the lcm of current and given polynomial"}, + {"extended_gcd", (PyCFunction)Polynomial_extended_gcd, METH_VARARGS, "Returns the extended gcd, i.e. (gcd, u, v), of current and given polynomial"}, + {"factor", (PyCFunction)Polynomial_factor, METH_NOARGS, "Returns the factorization of the polynomial"}, + {"factor_square_free", (PyCFunction)Polynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, + {"roots_count", (PyCFunction)Polynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"}, + {"roots_isolate", (PyCFunction)Polynomial_roots_isolate, METH_VARARGS, "Returns the list of real roots (has to be univariate modulo the assignment)"}, + {"sturm_sequence", (PyCFunction)Polynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"}, + {"derivative", (PyCFunction)Polynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"}, + {"resultant", (PyCFunction)Polynomial_resultant, METH_VARARGS, "Returns the resultant of the current and given polynomial"}, + {"psc", (PyCFunction)Polynomial_psc, METH_VARARGS, "Returns the principal subresultant coefficients of the current and given polynomial"}, + {"subres", (PyCFunction) Polynomial_subres, METH_VARARGS, "Returns the subresultant chain of the current and given polynomial"}, + {"mgcd", (PyCFunction)Polynomial_mgcd, METH_VARARGS, "Returns assumptions that the GCD of two polynomials is of same degree"}, + {"factor_square_free", (PyCFunction)Polynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, + {"evaluate", (PyCFunction)Polynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial in the given assignment (or null if it doesn't fully evaluate"}, + {"vars", (PyCFunction)Polynomial_vars, METH_NOARGS, "Returns the list of variables in the polynomial"}, + {"var", (PyCFunction)Polynomial_var, METH_NOARGS, "Returns the top variable of the polynomial"}, + {"pp", (PyCFunction)Polynomial_pp, METH_NOARGS, "Returns the primitive part of the polynomial"}, + {"cont", (PyCFunction)Polynomial_cont, METH_NOARGS, "Returns the content of the polynomial"}, + {"pp_cont", (PyCFunction)Polynomial_pp_cont, METH_NOARGS, "Returns the tuple (pp, cont) of the polynomial"}, + {"feasible_intervals", (PyCFunction)Polynomial_feasible_intervals, METH_VARARGS, "Returns feasible intervals (list) of the polynomial (has to be univariate modulo the assignment)"}, + {"feasible_set", (PyCFunction)Polynomial_feasible_set, METH_VARARGS, "Returns feasible set of the polynomial (has to be univariate modulo the assignment)"}, + {NULL} /* Sentinel */ +}; + +PyNumberMethods Polynomial_NumberMethods = { + Polynomial_add, // binaryfunc nb_add; + Polynomial_sub, // binaryfunc nb_subtract; + Polynomial_mul, // binaryfunc nb_multiply; + Polynomial_rem_operator, // binaryfunc nb_remainder; + Polynomial_divmod, // binaryfunc nb_divmod; + (ternaryfunc)Polynomial_pow, // ternaryfunc nb_power; + Polynomial_neg, // unaryfunc nb_negative; + NULL, // unaryfunc nb_positive; + NULL, // unaryfunc nb_absolute; + Polynomial_nonzero, // inquiry nb_bool; + NULL, // unaryfunc nb_invert; + NULL, // binaryfunc nb_lshift; + NULL, // binaryfunc nb_rshift; + NULL, // binaryfunc nb_and; + NULL, // binaryfunc nb_xor; + NULL, // binaryfunc nb_or; + NULL, // unaryfunc nb_int; + NULL, // void *nb_reserved; + NULL, // unaryfunc nb_float; + NULL, // binaryfunc nb_inplace_add; + NULL, // binaryfunc nb_inplace_subtract; + NULL, // binaryfunc nb_inplace_multiply; + NULL, // binaryfunc nb_inplace_remainder; + NULL, // ternaryfunc nb_inplace_power; + NULL, // binaryfunc nb_inplace_lshift; + NULL, // binaryfunc nb_inplace_rshift; + NULL, // binaryfunc nb_inplace_and; + NULL, // binaryfunc nb_inplace_xor; + NULL, // binaryfunc nb_inplace_or; + NULL, // binaryfunc nb_floor_divide; + Polynomial_div, // binaryfunc nb_true_divide; + NULL, // binaryfunc nb_inplace_floor_divide; + NULL, // binaryfunc nb_inplace_true_divide; + NULL, // unaryfunc nb_index; + NULL, // binaryfunc nb_matrix_multiply; + NULL, // binaryfunc nb_inplace_matrix_multiply; +}; + +PyTypeObject PolynomialType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.Polynomial", // const char *tp_name; + sizeof(Polynomial), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)Polynomial_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + Polynomial_str, // reprfunc tp_repr; + &Polynomial_NumberMethods, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + Polynomial_hash, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + Polynomial_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Polynomial objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + Polynomial_richcompare, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + Polynomial_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + NULL, // initproc tp_init; + NULL, // allocfunc tp_alloc; + Polynomial_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +Polynomial_dealloc(Polynomial* self) +{ + if (self->p) { + lp_polynomial_destruct(self->p); + free(self->p); + } + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +Polynomial_create(lp_polynomial_t* p) { + Polynomial *self = (Polynomial*)PolynomialType.tp_alloc(&PolynomialType, 0); + lp_polynomial_set_external(p); + self->p = p; + return (PyObject*) self; +} + +static PyObject* +Polynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return Polynomial_create(NULL); +} + +static PyObject* +Polynomial_richcompare(PyObject* self, PyObject* other, int op) { + PyObject *result = NULL; + + const lp_polynomial_context_t* ctx = NULL; + + // One of them is a polynomial + if (PyPolynomial_CHECK(self)) { + ctx = lp_polynomial_get_context(((Polynomial*) self)->p); + } else { + ctx = lp_polynomial_get_context(((Polynomial*) other)->p); + } + + int dec_other = 0; + int dec_self = 0; + + // Check arguments + if (!PyPolynomial_CHECK(self)) { + if (PyVariable_CHECK(self)) { + self = PyPolynomial_FromVariable(self, ctx); + dec_self = 1; + } else if (PyLong_or_Int_Check(self)) { + self = PyPolynomial_FromLong_or_Int(self, ctx); + dec_self = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // Check arguments + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + lp_polynomial_t* self_p = ((Polynomial*) self)->p; + lp_polynomial_t* other_p = ((Polynomial*) other)->p; + + int cmp = lp_polynomial_cmp(self_p, other_p); + + switch (op) { + case Py_LT: + result = cmp < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = cmp <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = cmp == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = cmp != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = cmp > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = cmp >= 0 ? Py_True : Py_False; + break; + default: + assert(0); + } + + if (dec_self) { + Py_DECREF(self); + } + if (dec_other) { + Py_DECREF(other); + } + + Py_INCREF(result); + return result; +} + +static Py_hash_t +Polynomial_hash(PyObject* self) { + Polynomial* p = (Polynomial*) self; + Py_hash_t hash = lp_polynomial_hash(p->p); + if (hash == -1) { + // value -1 should not be returned as a normal return value + hash = 0; + } + return hash; +} + +static PyObject* Polynomial_str(PyObject* self) { + Polynomial* p = (Polynomial*) self; + if (p) { + char* p_str = lp_polynomial_to_string(p->p); + PyObject* str = PyUnicode_FromString(p_str); + free(p_str); + return str; + } else { + Py_RETURN_NONE; + } +} + +PyObject* +PyPolynomial_FromVariable(PyObject* variable, const lp_polynomial_context_t* ctx) { + // The variable + lp_variable_t x = ((Variable*) variable)->x; + + // The constant + lp_integer_t one; + lp_integer_construct_from_int(ctx->K, &one, 1); + + // The x polynomial + lp_polynomial_t* p_x = lp_polynomial_alloc(); + lp_polynomial_construct_simple(p_x, ctx, &one, x, 1); + + // Remove temps + lp_integer_destruct(&one); + + // Return the polynomial + PyObject* result = Polynomial_create(p_x); + Py_INCREF(result); + return result; +} + +PyObject* +PyPolynomial_FromLong_or_Int(PyObject* number, const lp_polynomial_context_t* ctx) { + // The constants + lp_integer_t c; + PyLong_or_Int_to_integer(number, NULL, &c); + + // The c polynomial + lp_polynomial_t* p_c = lp_polynomial_alloc(); + lp_polynomial_construct_simple(p_c, ctx, &c, 0, 0); + + // Remove temps + lp_integer_destruct(&c); + + // Return the polynomial + PyObject* result = Polynomial_create(p_c); + Py_INCREF(result); + return result; +} + +static PyObject* +Polynomial_add(PyObject* self, PyObject* other) { + + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + return Polynomial_add(other, self); + } + + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + // Check argument + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // Get arguments + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (p1_ctx != p2_ctx) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Add the polynomials + lp_polynomial_t* sum = lp_polynomial_new(p1_ctx); + lp_polynomial_add(sum, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(sum); +} + +static PyObject* +Polynomial_neg(PyObject* self) { + Polynomial* p = (Polynomial*) self; + const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p->p); + lp_polynomial_t* neg = lp_polynomial_new(p_ctx); + lp_polynomial_neg(neg, p->p); + return Polynomial_create(neg); +} + +static PyObject* +Polynomial_sub(PyObject* self, PyObject* other) { + + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + Polynomial* sub = (Polynomial*) Polynomial_sub(other, self); + lp_polynomial_neg(sub->p, sub->p); + return (PyObject*) sub; + } + + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + // Check argument + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // Get arguments + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (p1_ctx != p2_ctx) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Subtract the polynomials + lp_polynomial_t* sub = lp_polynomial_new(p1_ctx); + lp_polynomial_sub(sub, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(sub); +} + +static PyObject* +Polynomial_mul(PyObject* self, PyObject* other) { + + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + return Polynomial_mul(other, self); + } + + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + // Check argument + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // Get arguments + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Multiply the polynomials + lp_polynomial_t* mul = lp_polynomial_new(p1_ctx); + lp_polynomial_mul(mul, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(mul); +} + + +static PyObject* +Polynomial_pow(PyObject* self, PyObject* other) { + // Check arguments + if (!PyPolynomial_CHECK(self) || !PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + Polynomial* p = (Polynomial*) self; + long n = PyLong_AsLong(other); + if (n < 0) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p->p); + // Compute + lp_polynomial_t* pow = lp_polynomial_new(p_ctx); + lp_polynomial_pow(pow, p->p, n); + // Return the result + return Polynomial_create(pow); +} + +static PyObject* +Polynomial_div(PyObject* self, PyObject* other) { + + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // other can be a variable or a number + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Multiply the polynomials + lp_polynomial_t* div = lp_polynomial_new(p1_ctx); + lp_polynomial_div(div, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(div); +} + +static PyObject* +Polynomial_rem_operator(PyObject* self, PyObject* other) { + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // other can be a variable or a number + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Multiply the polynomials + lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); + lp_polynomial_rem(rem, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(rem); +} + +enum rem_type { + REM_EXACT, + REM_PSEUDO, + REM_SPARSE_PSEUDO +}; + +static PyObject* +Polynomial_divmod_general(PyObject* self, PyObject* args, enum rem_type type) { + + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // self is always a polynomial + Polynomial *p1 = (Polynomial *) self; + const lp_polynomial_context_t *p1_ctx = lp_polynomial_get_context(p1->p); + + // check that there is only one other + PyObject *other; + if (PyTuple_Check(args)) { + if (PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + other = PyTuple_GetItem(args, 0); + } else { + other = args; + } + // make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // other can be a variable or a number + Polynomial *p2 = (Polynomial *) other; + const lp_polynomial_context_t *p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Divide the polynomials + lp_polynomial_t *rem = lp_polynomial_new(p1_ctx); + lp_polynomial_t *div = lp_polynomial_new(p1_ctx); + switch (type) { + case REM_EXACT: + lp_polynomial_divrem(div, rem, p1->p, p2->p); + break; + case REM_PSEUDO: + lp_polynomial_pdivrem(div, rem, p1->p, p2->p); + break; + case REM_SPARSE_PSEUDO: + lp_polynomial_spdivrem(div, rem, p1->p, p2->p); + break; + } + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + PyObject *pair = PyTuple_New(2); + PyObject *divObj = Polynomial_create(div); + PyObject *remObj = Polynomial_create(rem); + Py_INCREF(divObj); + Py_INCREF(remObj); + PyTuple_SetItem(pair, 0, divObj); + PyTuple_SetItem(pair, 1, remObj); + return pair; +} + +static PyObject* +Polynomial_divmod(PyObject* self, PyObject* other) { + return Polynomial_divmod_general(self, other, REM_EXACT); +} + +static PyObject* +Polynomial_pdivrem(PyObject* self, PyObject* other) { + return Polynomial_divmod_general(self, other, REM_PSEUDO); +} + +static PyObject* +Polynomial_spdivrem(PyObject* self, PyObject* other) { + return Polynomial_divmod_general(self, other, REM_SPARSE_PSEUDO); +} + +static int +Polynomial_nonzero(PyObject* self) { + // Get arguments + Polynomial* p = (Polynomial*) self; + // Return the result + return !lp_polynomial_is_zero(p->p); +} + +static PyObject* +Polynomial_rem_general(PyObject* self, PyObject* args, enum rem_type type) { + int dec_other = 0; + + if (!PyPolynomial_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* other = PyTuple_GetItem(args, 0); + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // other can be a variable or a number + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Multiply the polynomials + lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); + switch (type) { + case REM_EXACT: + lp_polynomial_rem(rem, p1->p, p2->p); + break; + case REM_PSEUDO: + lp_polynomial_prem(rem, p1->p, p2->p); + break; + case REM_SPARSE_PSEUDO: + lp_polynomial_sprem(rem, p1->p, p2->p); + break; + } + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(rem); +} + +static PyObject* +Polynomial_rem(PyObject* self, PyObject* other) { + return Polynomial_rem_general(self, other, REM_EXACT); +} + +static PyObject* +Polynomial_prem(PyObject* self, PyObject* other) { + return Polynomial_rem_general(self, other, REM_PSEUDO); +} + +static PyObject* +Polynomial_sprem(PyObject* self, PyObject* other) { + return Polynomial_rem_general(self, other, REM_SPARSE_PSEUDO); +} + +static PyObject* +Polynomial_gcd(PyObject* self, PyObject* args) { + + int dec_other = 0; + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* other = PyTuple_GetItem(args, 0); + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // other can be a variable or a number + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Multiply the polynomials + lp_polynomial_t* gcd = lp_polynomial_new(p1_ctx); + lp_polynomial_gcd(gcd, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(gcd); +} + +static PyObject* +Polynomial_lcm(PyObject* self, PyObject* args) { + + int dec_other = 0; + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* other = PyTuple_GetItem(args, 0); + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // other can be a variable or a number + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Multiply the polynomials + lp_polynomial_t* lcm = lp_polynomial_new(p1_ctx); + lp_polynomial_lcm(lcm, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(lcm); +} + +enum subres_type { + SUBRES, + SUBRES_PSC +}; + +static PyObject* +Polynomial_subres_impl(PyObject* self, PyObject* args, enum subres_type type) { + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* other = PyTuple_GetItem(args, 0); + + int dec_other = 0; + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // Other polynomial + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Check the arguments (must be same top variable) + if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Allocate the polynomials for the sequence + size_t p1_deg = lp_polynomial_degree(p1->p); + size_t p2_deg = lp_polynomial_degree(p2->p); + size_t size = p1_deg > p2_deg ? p2_deg + 1 : p1_deg + 1; + + lp_polynomial_t** S = malloc(sizeof(lp_polynomial_t*)*size); + for (size_t i = 0; i < size; ++ i) { + S[i] = lp_polynomial_new(p1_ctx); + } + + switch (type) { + case SUBRES: + // Compute the full subres + lp_polynomial_subres(S, p1->p, p2->p); + break; + case SUBRES_PSC: + // Compute the psc + lp_polynomial_psc(S, p1->p, p2->p); + break; + } + + // Copy the polynomials into a list + PyObject* list = PyList_New(size); + for (size_t i = 0; i < size; ++i) { + PyObject* p = Polynomial_create(S[i]); + PyList_SetItem(list, i, p); + } + free(S); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return list; +} + +static PyObject* +Polynomial_psc(PyObject* self, PyObject* args) { + return Polynomial_subres_impl(self, args, SUBRES_PSC); +} + +static PyObject* +Polynomial_subres(PyObject* self, PyObject* args) { + return Polynomial_subres_impl(self, args, SUBRES); +} + +static PyObject* +Polynomial_mgcd(PyObject* self, PyObject* args) { + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { + PyErr_SetString(PyExc_RuntimeError, "mgcd(): Need two arguments."); + return NULL; + } + + // Assignment + PyObject* py_assignment = PyTuple_GetItem(args, 1); + if (!PyAssignment_CHECK(py_assignment)) { + PyErr_SetString(PyExc_RuntimeError, "mgcd(): Second argument should be an assignment."); + return NULL; + } + const lp_assignment_t* assignment = ((Assignment*) py_assignment)->assignment; + + // Other polynomial + PyObject* other = PyTuple_GetItem(args, 0); + + int dec_other = 0; + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else { + PyErr_SetString(PyExc_RuntimeError, "mgcd(): First argument should be a polynomial."); + return NULL; + } + } + + // Othe polynomial + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same context."); + return NULL; + } + + // Check the arguments (must be same top variable) + if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { + PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same top variables."); + return NULL; + } + + if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { + PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same top variables."); + return NULL; + } + + // Compute the gcd + lp_polynomial_vector_t* mgcd = lp_polynomial_mgcd(p1->p, p2->p, assignment); + + // Copy the polynomials into a list + size_t size = lp_polynomial_vector_size(mgcd); + PyObject* list = PyList_New(size); + for (size_t i = 0; i < size; ++i) { + lp_polynomial_t* mgcd_i = lp_polynomial_vector_at(mgcd, i); + PyObject* p = Polynomial_create(mgcd_i); + PyList_SetItem(list, i, p); + } + lp_polynomial_vector_delete(mgcd); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return list; +} + +static PyObject* +Polynomial_resultant(PyObject* self, PyObject* args) { + + // self is always a polynomial + Polynomial* p1 = (Polynomial*) self; + const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* other = PyTuple_GetItem(args, 0); + + int dec_other = 0; + + // Make sure other is a polynomial + if (!PyPolynomial_CHECK(other)) { + if (PyVariable_CHECK(other)) { + other = PyPolynomial_FromVariable(other, p1_ctx); + dec_other = 1; + } else if (PyLong_or_Int_Check(other)) { + other = PyPolynomial_FromLong_or_Int(other, p1_ctx); + dec_other = 1; + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + + // Other polynomial + Polynomial* p2 = (Polynomial*) other; + const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); + if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Check the arguments (must be same top variable) + if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Allocate the resultant + lp_polynomial_t* resultant = lp_polynomial_new(p1_ctx); + + // Compute the psc + lp_polynomial_resultant(resultant, p1->p, p2->p); + + if (dec_other) { + Py_DECREF(other); + } + + // Return the result + return Polynomial_create(resultant); +} + +static PyObject* +Polynomial_extended_gcd(PyObject* self, PyObject* args) { + return NULL; +} + +static PyObject* +Polynomial_factor(PyObject* self) { + return NULL; +} + +// Creates a python list from the factors, taking over the polynomials +PyObject* factors_to_PyList(lp_polynomial_t** factors, size_t* multiplicities, size_t size) { + // Construct the result + PyObject* factors_list = PyList_New(size); + + // Copy the constant + // Copy over the factors + for (size_t i = 0; i < size; ++ i) { + PyObject* p_i = Polynomial_create(factors[i]); + Py_INCREF(p_i); + PyObject* d = PyLong_FromSize_t(multiplicities[i]); + PyObject* pair = PyTuple_New(2); + PyTuple_SetItem(pair, 0, p_i); + PyTuple_SetItem(pair, 1, d); + PyList_SetItem(factors_list, i, pair); + } + + // Return the list + return factors_list; +} + +static PyObject* +Polynomial_factor_square_free(PyObject* self) { + // Get arguments + Polynomial* p = (Polynomial*) self; + // Factor + lp_polynomial_t** factors = NULL; + size_t* multiplicities = NULL; + size_t factors_size = 0; + lp_polynomial_factor_square_free(p->p, &factors, &multiplicities, &factors_size); + // Create the list + PyObject* factors_list = factors_to_PyList(factors, multiplicities, factors_size); + // Get rid of the factors (not the polynomials) + free(factors); + free(multiplicities); + // Return the list + return factors_list; +} + +static PyObject* +Polynomial_roots_count(PyObject* self, PyObject* args) { + return NULL; +} + +static PyObject* +Polynomial_roots_isolate(PyObject* self, PyObject* args) { + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + + if (!PyAssignment_CHECK(assignment_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; + + // Check that the top variable is the only unassigned + if (!lp_polynomial_is_univariate_m(p, assignment)) { + PyErr_SetString(PyExc_RuntimeError, "roots_count(): Polynomial must be univariate modulo the assignment."); + return NULL; + } + + // Get the degree of the polynomial and allocate the values + lp_value_t* roots = malloc(sizeof(lp_value_t)*lp_polynomial_degree(p)); + size_t roots_size = 0; + + // Get the roots + lp_polynomial_roots_isolate(p, assignment, roots, &roots_size); + + // Generate a list of roots + PyObject* list = PyList_New(roots_size); + + for (size_t i = 0; i < roots_size; ++ i) { + PyObject* c = PyValue_create(roots + i); + PyList_SetItem(list, i, c); + } + + // Get rid of the temporaries + for (size_t i = 0; i < roots_size; ++ i) { + lp_value_destruct(roots + i); + } + free(roots); + + // Return the list + return list; +} + +static PyObject* +Polynomial_derivative(PyObject* self) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_polynomial_t* p_derivative = lp_polynomial_new(lp_polynomial_get_context(p)); + lp_polynomial_derivative(p_derivative, p); + return Polynomial_create(p_derivative); +} + +static PyObject* +Polynomial_sturm_sequence(PyObject* self) { + return NULL; +} + +static PyObject* +Polynomial_degree(PyObject* self) { + Polynomial* p = (Polynomial*) self; + return PyLong_FromUnsignedLong(lp_polynomial_degree(p->p)); +} + +static PyObject* +Polynomial_coefficients(PyObject* self) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + size_t size = lp_polynomial_degree(p) + 1; + + // Get the coefficients + const lp_polynomial_context_t* ctx = lp_polynomial_get_context(p); + + // Copy the polynomials into a list + PyObject* list = PyList_New(size); + for (size_t i = 0; i < size; ++i) { + lp_polynomial_t* c_p = lp_polynomial_new(ctx); + lp_polynomial_get_coefficient(c_p, p, i); + PyObject* c = Polynomial_create(c_p); + PyList_SetItem(list, i, c); + } + + return list; +} + +static PyObject* +Polynomial_vars(PyObject* self) { + + lp_polynomial_t* p = ((Polynomial*) self)->p; + + lp_variable_list_t p_vars; + lp_variable_list_construct(&p_vars); + + // Get the variables + lp_polynomial_get_variables(p, &p_vars); + + // Copy the polynomials into a list + PyObject* list = PyList_New(p_vars.list_size); + for (size_t i = 0; i < p_vars.list_size; ++i) { + PyObject* c = PyVariable_create(p_vars.list[i]); + PyList_SetItem(list, i, c); + } + + lp_variable_list_destruct(&p_vars); + + return list; +} + +static PyObject* +Polynomial_var(PyObject* self) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + return PyVariable_create(lp_polynomial_top_variable(p)); +} + + +static PyObject* +Polynomial_reductum(PyObject* self, PyObject* args) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + const lp_polynomial_context_t* ctx = lp_polynomial_get_context(p); + + if (!PyTuple_Check(args) || PyTuple_Size(args) > 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + lp_assignment_t* assignment = NULL; + + if (PyTuple_Size(args) == 1) { + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + if (!PyAssignment_CHECK(assignment_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } else { + assignment = ((Assignment*) assignment_obj)->assignment; + } + } + + lp_polynomial_t* result = lp_polynomial_new(ctx); + if (assignment) { + lp_polynomial_reductum_m(result, p, assignment); + } else { + lp_polynomial_reductum(result, p); + } + + return Polynomial_create(result); +} + +static PyObject* +Polynomial_sgn(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + + if (!PyAssignment_CHECK(assignment_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; + + int sgn = lp_polynomial_sgn(p, assignment); + + return PyLong_FromLong(sgn); +} + + +static PyObject* +Polynomial_evaluate(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + + if (!PyAssignment_CHECK(assignment_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; + + lp_value_t* value = lp_polynomial_evaluate(p, assignment); + PyObject* value_obj = PyValue_create(value); + lp_value_delete(value); + + return value_obj; +} + +static PyObject* +Polynomial_feasible_intervals(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { + PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Needs two arguments, an assignment and a sign condition."); + return NULL; + } + + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + if (!PyAssignment_CHECK(assignment_obj)) { + PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): First argument must be an assignment."); + return NULL; + } + + PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); + if (!PyLong_Check(sgn_condition_obj)) { + PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Second argument must be a sign-condition."); + return NULL; + } + + // Get the arguments + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; + lp_sign_condition_t sgn_condition = PyLong_AsLong(sgn_condition_obj); + + // Check if all but the top variable are unassigned + if (!lp_polynomial_is_univariate_m(p, assignment)) { + PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Polynomial must be univariate modulo the assignment."); + return NULL; + } + + // Get the feasible intervals + lp_feasibility_set_t* feasible = lp_polynomial_constraint_get_feasible_set(p, sgn_condition, 0, assignment); + + // The list where we return the arguments + PyObject* list = PyList_New(feasible->size); + // Copy over to the list + for (size_t i = 0; i < feasible->size; ++i) { + PyObject* pp = PyInterval_create(feasible->intervals + i); + PyList_SetItem(list, i, pp); + } + // Remove temp + lp_feasibility_set_delete(feasible); + + // Return the list + return list; +} + +static PyObject* +Polynomial_feasible_set(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + if (!PyAssignment_CHECK(assignment_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); + if (!PyLong_Check(sgn_condition_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Get the arguments + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; + lp_sign_condition_t sgn_condition = PyLong_AsLong(sgn_condition_obj); + + // Check if all but the top variable are unassigned + if (!lp_polynomial_is_univariate_m(p, assignment)) { + PyErr_SetString(PyExc_RuntimeError, "feasible_set(): Polynomial must be univariate modulo the assignment."); + return NULL; + } + + // Get the feasible intervals + lp_feasibility_set_t* feasible = lp_polynomial_constraint_get_feasible_set(p, sgn_condition, 0, assignment); + + // Return the list + return PyFeasibilitySet_create(feasible); +} + +static PyObject* +Polynomial_sgn_check(PyObject* self, PyObject* args) { + + if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* assignment_obj = PyTuple_GetItem(args, 0); + if (!PyAssignment_CHECK(assignment_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); + if (!PyLong_Check(sgn_condition_obj)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + // Get the arguments + lp_polynomial_t* p = ((Polynomial*) self)->p; + lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; + lp_sign_condition_t sgn_condition = PyLong_AsLong(sgn_condition_obj); + + // Check if all but the top variable are unassigned + if (!lp_polynomial_is_assigned(p, assignment)) { + PyErr_SetString(PyExc_RuntimeError, "sgn_check(): All polynomial variables should be assigned by the given assignment."); + return NULL; + } + + // Check the sign + int sgn = lp_polynomial_sgn(p, assignment); + if (lp_sign_condition_consistent(sgn_condition, sgn)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +static PyObject* +Polynomial_pp(PyObject* self) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); + lp_polynomial_t* pp = lp_polynomial_new(p_ctx); + lp_polynomial_pp(pp, p); + PyObject* pp_py = Polynomial_create(pp); + return pp_py; +} + +static PyObject* +Polynomial_cont(PyObject* self) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); + lp_polynomial_t* cont = lp_polynomial_new(p_ctx); + lp_polynomial_cont(cont, p); + PyObject* cont_py = Polynomial_create(cont); + return cont_py; +} + +static PyObject* +Polynomial_pp_cont(PyObject* self) { + lp_polynomial_t* p = ((Polynomial*) self)->p; + const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); + lp_polynomial_t* pp = lp_polynomial_new(p_ctx); + lp_polynomial_t* cont = lp_polynomial_new(p_ctx); + lp_polynomial_pp_cont(pp, cont, p); + PyObject* pp_py = Polynomial_create(pp); + PyObject* cont_py = Polynomial_create(cont); + PyObject* tuple = PyTuple_New(2); + PyTuple_SetItem(tuple, 0, pp_py); + PyTuple_SetItem(tuple, 1, cont_py); + return tuple; +} diff --git a/python/polypyPolynomial.h b/python/polypyPolynomial.h index 2ac1213c..e0fbd9d2 100644 --- a/python/polypyPolynomial.h +++ b/python/polypyPolynomial.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "utils.h" #include "polynomial.h" diff --git a/python/polypyPolynomial2.c b/python/polypyPolynomial2.c deleted file mode 100644 index da42fa68..00000000 --- a/python/polypyPolynomial2.c +++ /dev/null @@ -1,1678 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyPolynomial.h" - -#include "polypyInteger.h" -#include "polypyVariable.h" -#include "polypyVariableOrder.h" -#include "polypyAssignment.h" -#include "polypyValue.h" -#include "polypyInterval.h" -#include "polypyFeasibilitySet.h" - -#include "utils.h" -#include "variable_list.h" -#include "sign_condition.h" -#include "feasibility_set.h" -#include "value.h" -#include "polynomial_vector.h" - -#include - -static lp_polynomial_context_t* default_ctx = 0; - -const lp_polynomial_context_t* Polynomial_get_default_context(void) { - if (!default_ctx) { - default_ctx = lp_polynomial_context_new(0, Variable_get_default_db(), (lp_variable_order_t*) VariableOrder_get_default_order()); - } - return default_ctx; -} - -static void -Polynomial_dealloc(Polynomial* self); - -static PyObject* -Polynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Polynomial_cmp(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_richcompare(PyObject* self, PyObject* args, int op); - -static long -Polynomial_hash(PyObject* self); - -static PyObject* -Polynomial_degree(PyObject* self); - -static PyObject* -Polynomial_coefficients(PyObject* self); - -static PyObject* -Polynomial_reductum(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_sgn(PyObject* self, PyObject* arguments); - -static PyObject* -Polynomial_sgn_check(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_rem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_prem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_sprem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_pdivrem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_spdivrem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_gcd(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_lcm(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_derivative(PyObject* self); - -static PyObject* -Polynomial_extended_gcd(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_factor(PyObject* self); - -static PyObject* -Polynomial_factor_square_free(PyObject* self); - -static PyObject* -Polynomial_roots_count(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_roots_isolate(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_sturm_sequence(PyObject* self); - -static PyObject* -Polynomial_str(PyObject* self); - -static int -Polynomial_nonzero(PyObject* self); - -static PyObject* -Polynomial_add(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_neg(PyObject* self); - -static PyObject* -Polynomial_sub(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_mul(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_div(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_rem_operator(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_divmod(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_pow(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_resultant(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_psc(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_mgcd(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_evaluate(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_vars(PyObject* self); - -static PyObject* -Polynomial_var(PyObject* self); - -static PyObject* -Polynomial_pp(PyObject* self); - -static PyObject* -Polynomial_cont(PyObject* self); - -static PyObject* -Polynomial_pp_cont(PyObject* self); - -static PyObject* -Polynomial_feasible_intervals(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_feasible_set(PyObject* self, PyObject* args); - -PyMethodDef Polynomial_methods[] = { - {"degree", (PyCFunction)Polynomial_degree, METH_NOARGS, "Returns the degree of the polynomial in its top variable"}, - {"coefficients", (PyCFunction)Polynomial_coefficients, METH_NOARGS, "Returns a dictionary from degrees to coefficients"}, - {"reductum", (PyCFunction)Polynomial_reductum, METH_VARARGS, "Returns the reductum of the polynomial"}, - {"sgn", (PyCFunction)Polynomial_sgn, METH_VARARGS, "Returns the sign of the polynomials in the given model"}, - {"sgn_check", (PyCFunction)Polynomial_sgn_check, METH_VARARGS, "Returns true if the sign of the polynomail respects the sign condition."}, - {"rem", (PyCFunction)Polynomial_rem, METH_VARARGS, "Returns the remainder of current and given polynomial"}, - {"prem", (PyCFunction)Polynomial_prem, METH_VARARGS, "Returns the pseudo remainder of current and given polynomial"}, - {"sprem", (PyCFunction)Polynomial_sprem, METH_VARARGS, "Returns the sparse pseudo remainder of current and given polynomial"}, - {"pdivrem", (PyCFunction)Polynomial_pdivrem, METH_VARARGS, "Returns the pseudo quotient and pseudo remainder of current and given polynomial"}, - {"spdivprem", (PyCFunction)Polynomial_spdivrem, METH_VARARGS, "Returns the sparse pseudo quotient and sparse pseudo remainder of current and given polynomial"}, - {"gcd", (PyCFunction)Polynomial_gcd, METH_VARARGS, "Returns the gcd of current and given polynomial"}, - {"lcm", (PyCFunction)Polynomial_lcm, METH_VARARGS, "Returns the lcm of current and given polynomial"}, - {"extended_gcd", (PyCFunction)Polynomial_extended_gcd, METH_VARARGS, "Returns the extended gcd, i.e. (gcd, u, v), of current and given polynomial"}, - {"factor", (PyCFunction)Polynomial_factor, METH_NOARGS, "Returns the factorization of the polynomial"}, - {"factor_square_free", (PyCFunction)Polynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, - {"roots_count", (PyCFunction)Polynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"}, - {"roots_isolate", (PyCFunction)Polynomial_roots_isolate, METH_VARARGS, "Returns the list of real roots (has to be univariate modulo the assignment)"}, - {"sturm_sequence", (PyCFunction)Polynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"}, - {"derivative", (PyCFunction)Polynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"}, - {"resultant", (PyCFunction)Polynomial_resultant, METH_VARARGS, "Returns the resultant of the current and given polynomial"}, - {"psc", (PyCFunction)Polynomial_psc, METH_VARARGS, "Returns the principal subresultant coefficients of the current and given polynomial"}, - {"mgcd", (PyCFunction)Polynomial_mgcd, METH_VARARGS, "Returns assumptions that the GCD of two polynomials is of same degree"}, - {"factor_square_free", (PyCFunction)Polynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, - {"evaluate", (PyCFunction)Polynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial in the given assignment (or null if it doesn't fully evaluate"}, - {"vars", (PyCFunction)Polynomial_vars, METH_NOARGS, "Returns the list of variables in the polynomial"}, - {"var", (PyCFunction)Polynomial_var, METH_NOARGS, "Returns the top variable of the polynomial"}, - {"pp", (PyCFunction)Polynomial_pp, METH_NOARGS, "Returns the primitive part of the polynomial"}, - {"cont", (PyCFunction)Polynomial_cont, METH_NOARGS, "Returns the content of the polynomial"}, - {"pp_cont", (PyCFunction)Polynomial_pp_cont, METH_NOARGS, "Returns the tuple (pp, cont) of the polynomial"}, - {"feasible_intervals", (PyCFunction)Polynomial_feasible_intervals, METH_VARARGS, "Returns feasible intervals (list) of the polynomial (has to be univariate modulo the assignment)"}, - {"feasible_set", (PyCFunction)Polynomial_feasible_set, METH_VARARGS, "Returns feasible set of the polynomial (has to be univariate modulo the assignment)"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods Polynomial_NumberMethods = { - Polynomial_add, // binaryfunc nb_add; - Polynomial_sub, // binaryfunc nb_subtract; - Polynomial_mul, // binaryfunc nb_multiply; - Polynomial_div, // binaryfunc nb_divide; - Polynomial_rem_operator, // binaryfunc nb_remainder; - Polynomial_divmod, // binaryfunc nb_divmod; - (ternaryfunc)Polynomial_pow, // ternaryfunc nb_power; - Polynomial_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - Polynomial_nonzero, // inquiry nb_nonzero; /* Used by PyObject_IsTrue */ - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // coercion nb_coerce; /* Used by the coerce() function */ - 0, // unaryfunc nb_int; - 0, // unaryfunc nb_long; - 0, // unaryfunc nb_float; - 0, // unaryfunc nb_oct; - 0, // unaryfunc nb_hex; - - /* Added in release 2.0 */ - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_divide; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - - /* Added in release 2.2 */ - 0, // binaryfunc nb_floor_divide; - 0, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - - /* Added in release 2.5 */ - 0 // unaryfunc nb_index; -}; - -PyTypeObject PolynomialType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.Polynomial", /*tp_name*/ - sizeof(Polynomial), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Polynomial_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - Polynomial_cmp, /*tp_compare*/ - Polynomial_str, /*tp_repr*/ - &Polynomial_NumberMethods, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - Polynomial_hash, /*tp_hash */ - 0, /*tp_call*/ - Polynomial_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Polynomial objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - Polynomial_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Polynomial_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Polynomial_new, /* tp_new */ -}; - -static void -Polynomial_dealloc(Polynomial* self) -{ - if (self->p) { - lp_polynomial_destruct(self->p); - free(self->p); - } - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -Polynomial_create(lp_polynomial_t* p) { - Polynomial *self; - self = (Polynomial*)PolynomialType.tp_alloc(&PolynomialType, 0); - lp_polynomial_set_external(p); - self->p = p; - return (PyObject*) self; -} - -static PyObject* -Polynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return Polynomial_create(0); -} - -static PyObject* -Polynomial_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - const lp_polynomial_context_t* ctx = 0; - - // One of them is a polynomial - if (PyPolynomial_CHECK(self)) { - ctx = lp_polynomial_get_context(((Polynomial*) self)->p); - } else { - ctx = lp_polynomial_get_context(((Polynomial*) other)->p); - } - - int dec_other = 0; - int dec_self = 0; - - // Check arguments - if (!PyPolynomial_CHECK(self)) { - if (PyVariable_CHECK(self)) { - self = PyPolynomial_FromVariable(self, ctx); - dec_self = 1; - } else if (PyLong_or_Int_Check(self)) { - self = PyPolynomial_FromLong_or_Int(self, ctx); - dec_self = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Check arguments - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - lp_polynomial_t* self_p = ((Polynomial*) self)->p; - lp_polynomial_t* other_p = ((Polynomial*) other)->p; - - int cmp = lp_polynomial_cmp(self_p, other_p); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - - if (dec_self) { - Py_DECREF(self); - } - if (dec_other) { - Py_DECREF(other); - } - - Py_INCREF(result); - return result; -} - -static int -Polynomial_cmp(PyObject* self, PyObject* other) { - - // Check arguments - if (!PyPolynomial_CHECK(self) || !PyPolynomial_CHECK(other)) { - // should return -1 and set an exception condition when an error occurred - return -1; - } - // Get arguments - Polynomial* p1 = (Polynomial*) self; - Polynomial* p2 = (Polynomial*) other; - // Compare - int cmp = lp_polynomial_cmp(p1->p, p2->p); - return cmp > 0 ? 1 : cmp < 0 ? -1 : 0; -} - -static long -Polynomial_hash(PyObject* self) { - Polynomial* p = (Polynomial*) self; - long hash = lp_polynomial_hash(p->p); - if (hash == -1) { - // value -1 should not be returned as a normal return value - hash = 0; - } - return hash; -} - -static PyObject* Polynomial_str(PyObject* self) { - Polynomial* p = (Polynomial*) self; - if (p) { - char* p_str = lp_polynomial_to_string(p->p); - PyObject* str = PyString_FromString(p_str); - free(p_str); - return str; - } else { - Py_RETURN_NONE; - } -} - -PyObject* -PyPolynomial_FromVariable(PyObject* variable, const lp_polynomial_context_t* ctx) { - // The variable - lp_variable_t x = ((Variable*) variable)->x; - - // The constant - lp_integer_t one; - lp_integer_construct_from_int(ctx->K, &one, 1); - - // The x polynomial - lp_polynomial_t* p_x = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_x, ctx, &one, x, 1); - - // Remove temps - lp_integer_destruct(&one); - - // Return the polynomial - PyObject* result = Polynomial_create(p_x); - Py_INCREF(result); - return result; -} - -PyObject* -PyPolynomial_FromLong_or_Int(PyObject* number, const lp_polynomial_context_t* ctx) { - // The constants - lp_integer_t c; - PyLong_or_Int_to_integer(number, 0, &c); - - // The c polynomial - lp_polynomial_t* p_c = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_c, ctx, &c, 0, 0); - - // Remove temps - lp_integer_destruct(&c); - - // Return the polynomial - PyObject* result = Polynomial_create(p_c); - Py_INCREF(result); - return result; -} - -static PyObject* -Polynomial_add(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - return Polynomial_add(other, self); - } - - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Check argument - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Get arguments - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (p1_ctx != p2_ctx) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Add the polynomials - lp_polynomial_t* sum = lp_polynomial_new(p1_ctx); - lp_polynomial_add(sum, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(sum); -} - -static PyObject* -Polynomial_neg(PyObject* self) { - Polynomial* p = (Polynomial*) self; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p->p); - lp_polynomial_t* neg = lp_polynomial_new(p_ctx); - lp_polynomial_neg(neg, p->p); - return Polynomial_create(neg); -} - -static PyObject* -Polynomial_sub(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Polynomial* sub = (Polynomial*) Polynomial_sub(other, self); - lp_polynomial_neg(sub->p, sub->p); - return (PyObject*) sub; - } - - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Check argument - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Get arguments - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (p1_ctx != p2_ctx) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Subtract the polynomials - lp_polynomial_t* sub = lp_polynomial_new(p1_ctx); - lp_polynomial_sub(sub, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(sub); -} - -static PyObject* -Polynomial_mul(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - return Polynomial_mul(other, self); - } - - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Check argument - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Get arguments - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* mul = lp_polynomial_new(p1_ctx); - lp_polynomial_mul(mul, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(mul); -} - - -static PyObject* -Polynomial_pow(PyObject* self, PyObject* other) { - // Check arguments - if (!PyPolynomial_CHECK(self) || !PyInt_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - Polynomial* p = (Polynomial*) self; - long n = PyInt_AsLong(other); - if (n < 0) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p->p); - // Compute - lp_polynomial_t* pow = lp_polynomial_new(p_ctx); - lp_polynomial_pow(pow, p->p, n); - // Return the result - return Polynomial_create(pow); -} - -static PyObject* -Polynomial_div(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* div = lp_polynomial_new(p1_ctx); - lp_polynomial_div(div, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(div); -} - -static PyObject* -Polynomial_rem_operator(PyObject* self, PyObject* other) { - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); - lp_polynomial_rem(rem, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(rem); -} - -enum rem_type { - REM_EXACT, - REM_PSEUDO, - REM_SPARSE_PSEUDO -}; - -static PyObject* -Polynomial_divmod_general(PyObject* self, PyObject* args, enum rem_type type) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // check that there is only one other - PyObject *other; - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - other = PyTuple_GetItem(args, 0); - } else { - other = args; - } - // make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Divide the polynomials - lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); - lp_polynomial_t* div = lp_polynomial_new(p1_ctx); - switch (type) { - case REM_EXACT: - lp_polynomial_divrem(div, rem, p1->p, p2->p); - break; - case REM_PSEUDO: - lp_polynomial_pdivrem(div, rem, p1->p, p2->p); - break; - case REM_SPARSE_PSEUDO: - lp_polynomial_spdivrem(div, rem, p1->p, p2->p); - break; - } - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - PyObject* pair = PyTuple_New(2); - PyObject* divObj = Polynomial_create(div); - PyObject* remObj = Polynomial_create(rem); - Py_INCREF(divObj); - Py_INCREF(remObj); - PyTuple_SetItem(pair, 0, divObj); - PyTuple_SetItem(pair, 1, remObj); - return pair; -} - -static PyObject* -Polynomial_divmod(PyObject* self, PyObject* other) { - return Polynomial_divmod_general(self, other, REM_EXACT); -} - -static PyObject* -Polynomial_pdivrem(PyObject* self, PyObject* other) { - return Polynomial_divmod_general(self, other, REM_PSEUDO); -} - -static PyObject* -Polynomial_spdivrem(PyObject* self, PyObject* other) { - return Polynomial_divmod_general(self, other, REM_SPARSE_PSEUDO); -} - -static int -Polynomial_nonzero(PyObject* self) { - // Get arguments - Polynomial* p = (Polynomial*) self; - // Return the result - return !lp_polynomial_is_zero(p->p); -} - -static PyObject* -Polynomial_rem_general(PyObject* self, PyObject* args, enum rem_type type) { - int dec_other = 0; - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); - switch (type) { - case REM_EXACT: - lp_polynomial_rem(rem, p1->p, p2->p); - break; - case REM_PSEUDO: - lp_polynomial_prem(rem, p1->p, p2->p); - break; - case REM_SPARSE_PSEUDO: - lp_polynomial_sprem(rem, p1->p, p2->p); - break; - } - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(rem); -} - -static PyObject* -Polynomial_rem(PyObject* self, PyObject* other) { - return Polynomial_rem_general(self, other, REM_EXACT); -} - -static PyObject* -Polynomial_prem(PyObject* self, PyObject* other) { - return Polynomial_rem_general(self, other, REM_PSEUDO); -} - -static PyObject* -Polynomial_sprem(PyObject* self, PyObject* other) { - return Polynomial_rem_general(self, other, REM_SPARSE_PSEUDO); -} - -static PyObject* -Polynomial_gcd(PyObject* self, PyObject* args) { - - int dec_other = 0; - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* gcd = lp_polynomial_new(p1_ctx); - lp_polynomial_gcd(gcd, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(gcd); -} - -static PyObject* -Polynomial_lcm(PyObject* self, PyObject* args) { - - int dec_other = 0; - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* lcm = lp_polynomial_new(p1_ctx); - lp_polynomial_lcm(lcm, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(lcm); -} - -static PyObject* -Polynomial_psc(PyObject* self, PyObject* args) { - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - int dec_other = 0; - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Othe polynomial - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Check the arguments (must be same top variable) - if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Allocate the polynomials for the sequence - size_t p1_deg = lp_polynomial_degree(p1->p); - size_t p2_deg = lp_polynomial_degree(p2->p); - int size = p1_deg > p2_deg ? p2_deg + 1 : p1_deg + 1; - - lp_polynomial_t** psc = malloc(sizeof(lp_polynomial_t*)*size); - int i; - for (i = 0; i < size; ++ i) { - psc[i] = lp_polynomial_new(p1_ctx); - } - - // Compute the psc - lp_polynomial_psc(psc, p1->p, p2->p); - - // Copy the polynomials into a list - PyObject* list = PyList_New(size); - for (i = 0; i < size; ++i) { - PyObject* p = Polynomial_create(psc[i]); - PyList_SetItem(list, i, p); - } - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return list; -} - -static PyObject* -Polynomial_mgcd(PyObject* self, PyObject* args) { - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Need two arguments."); - return NULL; - } - - // Assignment - PyObject* py_assignment = PyTuple_GetItem(args, 1); - if (!PyAssignment_CHECK(py_assignment)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Second argument should be an assignment."); - return NULL; - } - const lp_assignment_t* assignment = ((Assignment*) py_assignment)->assignment; - - // Other polynomial - PyObject* other = PyTuple_GetItem(args, 0); - - int dec_other = 0; - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): First argument should be a polynomial."); - return NULL; - } - } - - // Othe polynomial - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same context."); - return NULL; - } - - // Check the arguments (must be same top variable) - if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same top variables."); - return NULL; - } - - if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same top variables."); - return NULL; - } - - // Compute the gcd - lp_polynomial_vector_t* mgcd = lp_polynomial_mgcd(p1->p, p2->p, assignment); - - // Copy the polynomials into a list - size_t size = lp_polynomial_vector_size(mgcd); - PyObject* list = PyList_New(size); - size_t i; - for (i = 0; i < size; ++i) { - lp_polynomial_t* mgcd_i = lp_polynomial_vector_at(mgcd, i); - PyObject* p = Polynomial_create(mgcd_i); - PyList_SetItem(list, i, p); - } - lp_polynomial_vector_delete(mgcd); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return list; -} - -static PyObject* -Polynomial_resultant(PyObject* self, PyObject* args) { - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - int dec_other = 0; - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Othe polynomial - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Check the arguments (must be same top variable) - if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Allocate the resultant - lp_polynomial_t* resultant = lp_polynomial_new(p1_ctx); - - // Compute the psc - lp_polynomial_resultant(resultant, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(resultant); -} - - -static PyObject* -Polynomial_extended_gcd(PyObject* self, PyObject* args) { - return 0; -} - -static PyObject* -Polynomial_factor(PyObject* self) { - return 0; -} - -// Creates a python list from the factors, taking over the polynomials -PyObject* factors_to_PyList(lp_polynomial_t** factors, size_t* multiplicities, size_t size) { - // Construct the result - PyObject* factors_list = PyList_New(size); - - // Copy the constant - // Copy over the factors - int i; - for (i = 0; i < size; ++ i) { - PyObject* p_i = Polynomial_create(factors[i]); - Py_INCREF(p_i); - PyObject* d = PyInt_FromSize_t(multiplicities[i]); - PyObject* pair = PyTuple_New(2); - PyTuple_SetItem(pair, 0, p_i); - PyTuple_SetItem(pair, 1, d); - PyList_SetItem(factors_list, i, pair); - } - - // Return the list - return factors_list; -} - -static PyObject* -Polynomial_factor_square_free(PyObject* self) { - // Get arguments - Polynomial* p = (Polynomial*) self; - // Factor - lp_polynomial_t** factors = 0; - size_t* multiplicities = 0; - size_t factors_size = 0; - lp_polynomial_factor_square_free(p->p, &factors, &multiplicities, &factors_size); - // Create the list - PyObject* factors_list = factors_to_PyList(factors, multiplicities, factors_size); - // Get rid of the factors (not the polynomials) - free(factors); - free(multiplicities); - // Return the list - return factors_list; -} - -static PyObject* -Polynomial_roots_count(PyObject* self, PyObject* args) { - return 0; -} - -static PyObject* -Polynomial_roots_isolate(PyObject* self, PyObject* args) { - - int i; - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - - // Check that the top variable is the only unassigned - if (!lp_polynomial_is_univariate_m(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "roots_count(): Polynomial must be univariate modulo the assignment."); - return NULL; - } - - // Get the degree of the polynomial and allocate the values - lp_value_t* roots = malloc(sizeof(lp_value_t)*lp_polynomial_degree(p)); - size_t roots_size = 0; - - // Get the roots - lp_polynomial_roots_isolate(p, assignment, roots, &roots_size); - - // Generate a list of roots - PyObject* list = PyList_New(roots_size); - - for (i = 0; i < roots_size; ++ i) { - PyObject* c = PyValue_create(roots + i); - PyList_SetItem(list, i, c); - } - - // Get rid of the temporaries - for (i = 0; i < roots_size; ++ i) { - lp_value_destruct(roots + i); - } - free(roots); - - // Return the list - return list; -} - -static PyObject* -Polynomial_derivative(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_polynomial_t* p_derivative = lp_polynomial_new(lp_polynomial_get_context(p)); - lp_polynomial_derivative(p_derivative, p); - return Polynomial_create(p_derivative); -} - -static PyObject* -Polynomial_sturm_sequence(PyObject* self) { - return 0; -} - -static PyObject* -Polynomial_degree(PyObject* self) { - Polynomial* p = (Polynomial*) self; - return PyInt_FromLong(lp_polynomial_degree(p->p)); -} - -static PyObject* -Polynomial_coefficients(PyObject* self) { - int i; - - lp_polynomial_t* p = ((Polynomial*) self)->p; - size_t size = lp_polynomial_degree(p) + 1; - - // Get the coefficients - const lp_polynomial_context_t* ctx = lp_polynomial_get_context(p); - - // Copy the polynomials into a list - PyObject* list = PyList_New(size); - for (i = 0; i < size; ++i) { - lp_polynomial_t* c_p = lp_polynomial_new(ctx); - lp_polynomial_get_coefficient(c_p, p, i); - PyObject* c = Polynomial_create(c_p); - PyList_SetItem(list, i, c); - } - - return list; -} - -static PyObject* -Polynomial_vars(PyObject* self) { - - lp_polynomial_t* p = ((Polynomial*) self)->p; - - lp_variable_list_t p_vars; - lp_variable_list_construct(&p_vars); - - // Get the variables - lp_polynomial_get_variables(p, &p_vars); - - // Copy the polynomials into a list - PyObject* list = PyList_New(p_vars.list_size); - size_t i; - for (i = 0; i < p_vars.list_size; ++i) { - PyObject* c = PyVariable_create(p_vars.list[i]); - PyList_SetItem(list, i, c); - } - - lp_variable_list_destruct(&p_vars); - - return list; -} - -static PyObject* -Polynomial_var(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - return PyVariable_create(lp_polynomial_top_variable(p)); -} - - -static PyObject* -Polynomial_reductum(PyObject* self, PyObject* args) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* ctx = lp_polynomial_get_context(p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) > 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_assignment_t* assignment = 0; - - if (PyTuple_Size(args) == 1) { - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } else { - assignment = ((Assignment*) assignment_obj)->assignment; - } - } - - lp_polynomial_t* result = lp_polynomial_new(ctx); - if (assignment) { - lp_polynomial_reductum_m(result, p, assignment); - } else { - lp_polynomial_reductum(result, p); - } - - return Polynomial_create(result); -} - -static PyObject* -Polynomial_sgn(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - - int sgn = lp_polynomial_sgn(p, assignment); - - return PyInt_FromLong(sgn); -} - - -static PyObject* -Polynomial_evaluate(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - - lp_value_t* value = lp_polynomial_evaluate(p, assignment); - PyObject* value_obj = PyValue_create(value); - lp_value_delete(value); - - return value_obj; -} - -static PyObject* -Polynomial_feasible_intervals(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Needs two arguments, an assignment and a sign condition."); - return NULL; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): First argument must be an assignment."); - return NULL; - } - - PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); - if (!PyInt_Check(sgn_condition_obj)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Second argument must be a sign-condition."); - return NULL; - } - - // Get the arguments - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - lp_sign_condition_t sgn_condition = PyInt_AsLong(sgn_condition_obj); - - // Check if all but the top variable are unassigned - if (!lp_polynomial_is_univariate_m(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Polynomial must be univariate modulo the assignment."); - return NULL; - } - - // Get the feasible intervals - lp_feasibility_set_t* feasible = lp_polynomial_constraint_get_feasible_set(p, sgn_condition, 0, assignment); - - // The list where we return the arguments - PyObject* list = PyList_New(feasible->size); - // Copy over to the list - size_t i; - for (i = 0; i < feasible->size; ++i) { - PyObject* p = PyInterval_create(feasible->intervals + i); - PyList_SetItem(list, i, p); - } - // Remove temp - lp_feasibility_set_delete(feasible); - - // Return the list - return list; -} - -static PyObject* -Polynomial_feasible_set(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); - if (!PyInt_Check(sgn_condition_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Get the arguments - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - lp_sign_condition_t sgn_condition = PyInt_AsLong(sgn_condition_obj); - - // Check if all but the top variable are unassigned - if (!lp_polynomial_is_univariate_m(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_set(): Polynomial must be univariate modulo the assignment."); - return NULL; - } - - // Get the feasible intervals - lp_feasibility_set_t* feasible = lp_polynomial_constraint_get_feasible_set(p, sgn_condition, 0, assignment); - - // Return the list - return PyFeasibilitySet_create(feasible); -} - -static PyObject* -Polynomial_sgn_check(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); - if (!PyInt_Check(sgn_condition_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Get the arguments - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - lp_sign_condition_t sgn_condition = PyInt_AsLong(sgn_condition_obj); - - // Check if all but the top variable are unassigned - if (!lp_polynomial_is_assigned(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "sgn_check(): All polynomial variables should be assigned by the given assignment."); - return NULL; - } - - // Check the sign - int sgn = lp_polynomial_sgn(p, assignment); - if (lp_sign_condition_consistent(sgn_condition, sgn)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -static PyObject* -Polynomial_pp(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); - lp_polynomial_t* pp = lp_polynomial_new(p_ctx); - lp_polynomial_pp(pp, p); - PyObject* pp_py = Polynomial_create(pp); - return pp_py; -} - -static PyObject* -Polynomial_cont(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); - lp_polynomial_t* cont = lp_polynomial_new(p_ctx); - lp_polynomial_cont(cont, p); - PyObject* cont_py = Polynomial_create(cont); - return cont_py; -} - -static PyObject* -Polynomial_pp_cont(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); - lp_polynomial_t* pp = lp_polynomial_new(p_ctx); - lp_polynomial_t* cont = lp_polynomial_new(p_ctx); - lp_polynomial_pp_cont(pp, cont, p); - PyObject* pp_py = Polynomial_create(pp); - PyObject* cont_py = Polynomial_create(cont); - PyObject* tuple = PyTuple_New(2); - PyTuple_SetItem(tuple, 0, pp_py); - PyTuple_SetItem(tuple, 1, cont_py); - return tuple; -} diff --git a/python/polypyPolynomial3.c b/python/polypyPolynomial3.c deleted file mode 100644 index f76bd98e..00000000 --- a/python/polypyPolynomial3.c +++ /dev/null @@ -1,1691 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyPolynomial.h" - -#include "polypyInteger.h" -#include "polypyVariable.h" -#include "polypyVariableOrder.h" -#include "polypyAssignment.h" -#include "polypyValue.h" -#include "polypyInterval.h" -#include "polypyFeasibilitySet.h" - -#include "utils.h" -#include "variable_list.h" -#include "sign_condition.h" -#include "feasibility_set.h" -#include "value.h" -#include "polynomial_vector.h" - -#include - -static lp_polynomial_context_t* default_ctx = 0; - -const lp_polynomial_context_t* Polynomial_get_default_context(void) { - if (!default_ctx) { - default_ctx = lp_polynomial_context_new(0, Variable_get_default_db(), (lp_variable_order_t*) VariableOrder_get_default_order()); - } - return default_ctx; -} - -static void -Polynomial_dealloc(Polynomial* self); - -static PyObject* -Polynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject* -Polynomial_richcompare(PyObject* self, PyObject* args, int op); - -static Py_hash_t -Polynomial_hash(PyObject* self); - -static PyObject* -Polynomial_degree(PyObject* self); - -static PyObject* -Polynomial_coefficients(PyObject* self); - -static PyObject* -Polynomial_reductum(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_sgn(PyObject* self, PyObject* arguments); - -static PyObject* -Polynomial_sgn_check(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_rem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_prem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_sprem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_pdivrem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_spdivrem(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_gcd(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_lcm(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_derivative(PyObject* self); - -static PyObject* -Polynomial_extended_gcd(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_factor(PyObject* self); - -static PyObject* -Polynomial_factor_square_free(PyObject* self); - -static PyObject* -Polynomial_roots_count(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_roots_isolate(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_sturm_sequence(PyObject* self); - -static PyObject* -Polynomial_str(PyObject* self); - -static int -Polynomial_nonzero(PyObject* self); - -static PyObject* -Polynomial_add(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_neg(PyObject* self); - -static PyObject* -Polynomial_sub(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_mul(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_div(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_rem_operator(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_divmod(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_pow(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_resultant(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_psc(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_subres(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_mgcd(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_evaluate(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_vars(PyObject* self); - -static PyObject* -Polynomial_var(PyObject* self); - -static PyObject* -Polynomial_pp(PyObject* self); - -static PyObject* -Polynomial_cont(PyObject* self); - -static PyObject* -Polynomial_pp_cont(PyObject* self); - -static PyObject* -Polynomial_feasible_intervals(PyObject* self, PyObject* args); - -static PyObject* -Polynomial_feasible_set(PyObject* self, PyObject* args); - -PyMethodDef Polynomial_methods[] = { - {"degree", (PyCFunction)Polynomial_degree, METH_NOARGS, "Returns the degree of the polynomial in its top variable"}, - {"coefficients", (PyCFunction)Polynomial_coefficients, METH_NOARGS, "Returns a dictionary from degrees to coefficients"}, - {"reductum", (PyCFunction)Polynomial_reductum, METH_VARARGS, "Returns the reductum of the polynomial"}, - {"sgn", (PyCFunction)Polynomial_sgn, METH_VARARGS, "Returns the sign of the polynomials in the given model"}, - {"sgn_check", (PyCFunction)Polynomial_sgn_check, METH_VARARGS, "Returns true if the sign of the polynomial respects the sign condition."}, - {"rem", (PyCFunction)Polynomial_rem, METH_VARARGS, "Returns the remainder of current and given polynomial"}, - {"prem", (PyCFunction)Polynomial_prem, METH_VARARGS, "Returns the pseudo remainder of current and given polynomial"}, - {"sprem", (PyCFunction)Polynomial_sprem, METH_VARARGS, "Returns the sparse pseudo remainder of current and given polynomial"}, - {"pdivrem", (PyCFunction)Polynomial_pdivrem, METH_VARARGS, "Returns the pseudo quotient and pseudo remainder of current and given polynomial"}, - {"spdivprem", (PyCFunction)Polynomial_spdivrem, METH_VARARGS, "Returns the sparse pseudo quotient and sparse pseudo remainder of current and given polynomial"}, - {"gcd", (PyCFunction)Polynomial_gcd, METH_VARARGS, "Returns the gcd of current and given polynomial"}, - {"lcm", (PyCFunction)Polynomial_lcm, METH_VARARGS, "Returns the lcm of current and given polynomial"}, - {"extended_gcd", (PyCFunction)Polynomial_extended_gcd, METH_VARARGS, "Returns the extended gcd, i.e. (gcd, u, v), of current and given polynomial"}, - {"factor", (PyCFunction)Polynomial_factor, METH_NOARGS, "Returns the factorization of the polynomial"}, - {"factor_square_free", (PyCFunction)Polynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, - {"roots_count", (PyCFunction)Polynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"}, - {"roots_isolate", (PyCFunction)Polynomial_roots_isolate, METH_VARARGS, "Returns the list of real roots (has to be univariate modulo the assignment)"}, - {"sturm_sequence", (PyCFunction)Polynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"}, - {"derivative", (PyCFunction)Polynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"}, - {"resultant", (PyCFunction)Polynomial_resultant, METH_VARARGS, "Returns the resultant of the current and given polynomial"}, - {"psc", (PyCFunction)Polynomial_psc, METH_VARARGS, "Returns the principal subresultant coefficients of the current and given polynomial"}, - {"subres", (PyCFunction) Polynomial_subres, METH_VARARGS, "Returns the subresultant chain of the current and given polynomial"}, - {"mgcd", (PyCFunction)Polynomial_mgcd, METH_VARARGS, "Returns assumptions that the GCD of two polynomials is of same degree"}, - {"factor_square_free", (PyCFunction)Polynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, - {"evaluate", (PyCFunction)Polynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial in the given assignment (or null if it doesn't fully evaluate"}, - {"vars", (PyCFunction)Polynomial_vars, METH_NOARGS, "Returns the list of variables in the polynomial"}, - {"var", (PyCFunction)Polynomial_var, METH_NOARGS, "Returns the top variable of the polynomial"}, - {"pp", (PyCFunction)Polynomial_pp, METH_NOARGS, "Returns the primitive part of the polynomial"}, - {"cont", (PyCFunction)Polynomial_cont, METH_NOARGS, "Returns the content of the polynomial"}, - {"pp_cont", (PyCFunction)Polynomial_pp_cont, METH_NOARGS, "Returns the tuple (pp, cont) of the polynomial"}, - {"feasible_intervals", (PyCFunction)Polynomial_feasible_intervals, METH_VARARGS, "Returns feasible intervals (list) of the polynomial (has to be univariate modulo the assignment)"}, - {"feasible_set", (PyCFunction)Polynomial_feasible_set, METH_VARARGS, "Returns feasible set of the polynomial (has to be univariate modulo the assignment)"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods Polynomial_NumberMethods = { - Polynomial_add, // binaryfunc nb_add; - Polynomial_sub, // binaryfunc nb_subtract; - Polynomial_mul, // binaryfunc nb_multiply; - Polynomial_rem_operator, // binaryfunc nb_remainder; - Polynomial_divmod, // binaryfunc nb_divmod; - (ternaryfunc)Polynomial_pow, // ternaryfunc nb_power; - Polynomial_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - Polynomial_nonzero, // inquiry nb_bool; - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // unaryfunc nb_int; - 0, // void *nb_reserved; - 0, // unaryfunc nb_float; - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - 0, // binaryfunc nb_floor_divide; - Polynomial_div, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - 0, // unaryfunc nb_index; - 0, // binaryfunc nb_matrix_multiply; - 0, // binaryfunc nb_inplace_matrix_multiply; -}; - -PyTypeObject PolynomialType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.Polynomial", // const char *tp_name; - sizeof(Polynomial), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)Polynomial_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - Polynomial_str, // reprfunc tp_repr; - &Polynomial_NumberMethods, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - Polynomial_hash, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - Polynomial_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Polynomial objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - Polynomial_richcompare, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - Polynomial_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - 0, // initproc tp_init; - 0, // allocfunc tp_alloc; - Polynomial_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -Polynomial_dealloc(Polynomial* self) -{ - if (self->p) { - lp_polynomial_destruct(self->p); - free(self->p); - } - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -Polynomial_create(lp_polynomial_t* p) { - Polynomial *self; - self = (Polynomial*)PolynomialType.tp_alloc(&PolynomialType, 0); - lp_polynomial_set_external(p); - self->p = p; - return (PyObject*) self; -} - -static PyObject* -Polynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return Polynomial_create(0); -} - -static PyObject* -Polynomial_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - const lp_polynomial_context_t* ctx = 0; - - // One of them is a polynomial - if (PyPolynomial_CHECK(self)) { - ctx = lp_polynomial_get_context(((Polynomial*) self)->p); - } else { - ctx = lp_polynomial_get_context(((Polynomial*) other)->p); - } - - int dec_other = 0; - int dec_self = 0; - - // Check arguments - if (!PyPolynomial_CHECK(self)) { - if (PyVariable_CHECK(self)) { - self = PyPolynomial_FromVariable(self, ctx); - dec_self = 1; - } else if (PyLong_or_Int_Check(self)) { - self = PyPolynomial_FromLong_or_Int(self, ctx); - dec_self = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Check arguments - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - lp_polynomial_t* self_p = ((Polynomial*) self)->p; - lp_polynomial_t* other_p = ((Polynomial*) other)->p; - - int cmp = lp_polynomial_cmp(self_p, other_p); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - - if (dec_self) { - Py_DECREF(self); - } - if (dec_other) { - Py_DECREF(other); - } - - Py_INCREF(result); - return result; -} - -static Py_hash_t -Polynomial_hash(PyObject* self) { - Polynomial* p = (Polynomial*) self; - Py_hash_t hash = lp_polynomial_hash(p->p); - if (hash == -1) { - // value -1 should not be returned as a normal return value - hash = 0; - } - return hash; -} - -static PyObject* Polynomial_str(PyObject* self) { - Polynomial* p = (Polynomial*) self; - if (p) { - char* p_str = lp_polynomial_to_string(p->p); - PyObject* str = PyUnicode_FromString(p_str); - free(p_str); - return str; - } else { - Py_RETURN_NONE; - } -} - -PyObject* -PyPolynomial_FromVariable(PyObject* variable, const lp_polynomial_context_t* ctx) { - // The variable - lp_variable_t x = ((Variable*) variable)->x; - - // The constant - lp_integer_t one; - lp_integer_construct_from_int(ctx->K, &one, 1); - - // The x polynomial - lp_polynomial_t* p_x = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_x, ctx, &one, x, 1); - - // Remove temps - lp_integer_destruct(&one); - - // Return the polynomial - PyObject* result = Polynomial_create(p_x); - Py_INCREF(result); - return result; -} - -PyObject* -PyPolynomial_FromLong_or_Int(PyObject* number, const lp_polynomial_context_t* ctx) { - // The constants - lp_integer_t c; - PyLong_or_Int_to_integer(number, 0, &c); - - // The c polynomial - lp_polynomial_t* p_c = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_c, ctx, &c, 0, 0); - - // Remove temps - lp_integer_destruct(&c); - - // Return the polynomial - PyObject* result = Polynomial_create(p_c); - Py_INCREF(result); - return result; -} - -static PyObject* -Polynomial_add(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - return Polynomial_add(other, self); - } - - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Check argument - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Get arguments - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (p1_ctx != p2_ctx) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Add the polynomials - lp_polynomial_t* sum = lp_polynomial_new(p1_ctx); - lp_polynomial_add(sum, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(sum); -} - -static PyObject* -Polynomial_neg(PyObject* self) { - Polynomial* p = (Polynomial*) self; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p->p); - lp_polynomial_t* neg = lp_polynomial_new(p_ctx); - lp_polynomial_neg(neg, p->p); - return Polynomial_create(neg); -} - -static PyObject* -Polynomial_sub(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Polynomial* sub = (Polynomial*) Polynomial_sub(other, self); - lp_polynomial_neg(sub->p, sub->p); - return (PyObject*) sub; - } - - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Check argument - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Get arguments - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (p1_ctx != p2_ctx) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Subtract the polynomials - lp_polynomial_t* sub = lp_polynomial_new(p1_ctx); - lp_polynomial_sub(sub, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(sub); -} - -static PyObject* -Polynomial_mul(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - return Polynomial_mul(other, self); - } - - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Check argument - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Get arguments - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* mul = lp_polynomial_new(p1_ctx); - lp_polynomial_mul(mul, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(mul); -} - - -static PyObject* -Polynomial_pow(PyObject* self, PyObject* other) { - // Check arguments - if (!PyPolynomial_CHECK(self) || !PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - Polynomial* p = (Polynomial*) self; - long n = PyLong_AsLong(other); - if (n < 0) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p->p); - // Compute - lp_polynomial_t* pow = lp_polynomial_new(p_ctx); - lp_polynomial_pow(pow, p->p, n); - // Return the result - return Polynomial_create(pow); -} - -static PyObject* -Polynomial_div(PyObject* self, PyObject* other) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* div = lp_polynomial_new(p1_ctx); - lp_polynomial_div(div, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(div); -} - -static PyObject* -Polynomial_rem_operator(PyObject* self, PyObject* other) { - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); - lp_polynomial_rem(rem, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(rem); -} - -enum rem_type { - REM_EXACT, - REM_PSEUDO, - REM_SPARSE_PSEUDO -}; - -static PyObject* -Polynomial_divmod_general(PyObject* self, PyObject* args, enum rem_type type) { - - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial *p1 = (Polynomial *) self; - const lp_polynomial_context_t *p1_ctx = lp_polynomial_get_context(p1->p); - - // check that there is only one other - PyObject *other; - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - other = PyTuple_GetItem(args, 0); - } else { - other = args; - } - // make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial *p2 = (Polynomial *) other; - const lp_polynomial_context_t *p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Divide the polynomials - lp_polynomial_t *rem = lp_polynomial_new(p1_ctx); - lp_polynomial_t *div = lp_polynomial_new(p1_ctx); - switch (type) { - case REM_EXACT: - lp_polynomial_divrem(div, rem, p1->p, p2->p); - break; - case REM_PSEUDO: - lp_polynomial_pdivrem(div, rem, p1->p, p2->p); - break; - case REM_SPARSE_PSEUDO: - lp_polynomial_spdivrem(div, rem, p1->p, p2->p); - break; - } - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - PyObject *pair = PyTuple_New(2); - PyObject *divObj = Polynomial_create(div); - PyObject *remObj = Polynomial_create(rem); - Py_INCREF(divObj); - Py_INCREF(remObj); - PyTuple_SetItem(pair, 0, divObj); - PyTuple_SetItem(pair, 1, remObj); - return pair; -} - -static PyObject* -Polynomial_divmod(PyObject* self, PyObject* other) { - return Polynomial_divmod_general(self, other, REM_EXACT); -} - -static PyObject* -Polynomial_pdivrem(PyObject* self, PyObject* other) { - return Polynomial_divmod_general(self, other, REM_PSEUDO); -} - -static PyObject* -Polynomial_spdivrem(PyObject* self, PyObject* other) { - return Polynomial_divmod_general(self, other, REM_SPARSE_PSEUDO); -} - -static int -Polynomial_nonzero(PyObject* self) { - // Get arguments - Polynomial* p = (Polynomial*) self; - // Return the result - return !lp_polynomial_is_zero(p->p); -} - -static PyObject* -Polynomial_rem_general(PyObject* self, PyObject* args, enum rem_type type) { - int dec_other = 0; - - if (!PyPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* rem = lp_polynomial_new(p1_ctx); - switch (type) { - case REM_EXACT: - lp_polynomial_rem(rem, p1->p, p2->p); - break; - case REM_PSEUDO: - lp_polynomial_prem(rem, p1->p, p2->p); - break; - case REM_SPARSE_PSEUDO: - lp_polynomial_sprem(rem, p1->p, p2->p); - break; - } - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(rem); -} - -static PyObject* -Polynomial_rem(PyObject* self, PyObject* other) { - return Polynomial_rem_general(self, other, REM_EXACT); -} - -static PyObject* -Polynomial_prem(PyObject* self, PyObject* other) { - return Polynomial_rem_general(self, other, REM_PSEUDO); -} - -static PyObject* -Polynomial_sprem(PyObject* self, PyObject* other) { - return Polynomial_rem_general(self, other, REM_SPARSE_PSEUDO); -} - -static PyObject* -Polynomial_gcd(PyObject* self, PyObject* args) { - - int dec_other = 0; - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* gcd = lp_polynomial_new(p1_ctx); - lp_polynomial_gcd(gcd, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(gcd); -} - -static PyObject* -Polynomial_lcm(PyObject* self, PyObject* args) { - - int dec_other = 0; - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // other can be a variable or a number - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Multiply the polynomials - lp_polynomial_t* lcm = lp_polynomial_new(p1_ctx); - lp_polynomial_lcm(lcm, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(lcm); -} - -enum subres_type { - SUBRES, - SUBRES_PSC -}; - -static PyObject* -Polynomial_subres_impl(PyObject* self, PyObject* args, enum subres_type type) { - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - int dec_other = 0; - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Other polynomial - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Check the arguments (must be same top variable) - if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Allocate the polynomials for the sequence - size_t p1_deg = lp_polynomial_degree(p1->p); - size_t p2_deg = lp_polynomial_degree(p2->p); - int size = p1_deg > p2_deg ? p2_deg + 1 : p1_deg + 1; - - lp_polynomial_t** S = malloc(sizeof(lp_polynomial_t*)*size); - int i; - for (i = 0; i < size; ++ i) { - S[i] = lp_polynomial_new(p1_ctx); - } - - switch (type) { - case SUBRES: - // Compute the full subres - lp_polynomial_subres(S, p1->p, p2->p); - break; - case SUBRES_PSC: - // Compute the psc - lp_polynomial_psc(S, p1->p, p2->p); - break; - } - - // Copy the polynomials into a list - PyObject* list = PyList_New(size); - for (i = 0; i < size; ++i) { - PyObject* p = Polynomial_create(S[i]); - PyList_SetItem(list, i, p); - } - free(S); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return list; -} - -static PyObject* -Polynomial_psc(PyObject* self, PyObject* args) { - return Polynomial_subres_impl(self, args, SUBRES_PSC); -} - -static PyObject* -Polynomial_subres(PyObject* self, PyObject* args) { - return Polynomial_subres_impl(self, args, SUBRES); -} - -static PyObject* -Polynomial_mgcd(PyObject* self, PyObject* args) { - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Need two arguments."); - return NULL; - } - - // Assignment - PyObject* py_assignment = PyTuple_GetItem(args, 1); - if (!PyAssignment_CHECK(py_assignment)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Second argument should be an assignment."); - return NULL; - } - const lp_assignment_t* assignment = ((Assignment*) py_assignment)->assignment; - - // Other polynomial - PyObject* other = PyTuple_GetItem(args, 0); - - int dec_other = 0; - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): First argument should be a polynomial."); - return NULL; - } - } - - // Othe polynomial - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same context."); - return NULL; - } - - // Check the arguments (must be same top variable) - if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same top variables."); - return NULL; - } - - if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { - PyErr_SetString(PyExc_RuntimeError, "mgcd(): Polynomials should be over the same top variables."); - return NULL; - } - - // Compute the gcd - lp_polynomial_vector_t* mgcd = lp_polynomial_mgcd(p1->p, p2->p, assignment); - - // Copy the polynomials into a list - size_t size = lp_polynomial_vector_size(mgcd); - PyObject* list = PyList_New(size); - size_t i; - for (i = 0; i < size; ++i) { - lp_polynomial_t* mgcd_i = lp_polynomial_vector_at(mgcd, i); - PyObject* p = Polynomial_create(mgcd_i); - PyList_SetItem(list, i, p); - } - lp_polynomial_vector_delete(mgcd); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return list; -} - -static PyObject* -Polynomial_resultant(PyObject* self, PyObject* args) { - - // self is always a polynomial - Polynomial* p1 = (Polynomial*) self; - const lp_polynomial_context_t* p1_ctx = lp_polynomial_get_context(p1->p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* other = PyTuple_GetItem(args, 0); - - int dec_other = 0; - - // Make sure other is a polynomial - if (!PyPolynomial_CHECK(other)) { - if (PyVariable_CHECK(other)) { - other = PyPolynomial_FromVariable(other, p1_ctx); - dec_other = 1; - } else if (PyLong_or_Int_Check(other)) { - other = PyPolynomial_FromLong_or_Int(other, p1_ctx); - dec_other = 1; - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - - // Other polynomial - Polynomial* p2 = (Polynomial*) other; - const lp_polynomial_context_t* p2_ctx = lp_polynomial_get_context(p2->p); - if (!lp_polynomial_context_equal(p1_ctx, p2_ctx)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Check the arguments (must be same top variable) - if (lp_polynomial_is_constant(p1->p) || lp_polynomial_is_constant(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (lp_polynomial_top_variable(p1->p) != lp_polynomial_top_variable(p2->p)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Allocate the resultant - lp_polynomial_t* resultant = lp_polynomial_new(p1_ctx); - - // Compute the psc - lp_polynomial_resultant(resultant, p1->p, p2->p); - - if (dec_other) { - Py_DECREF(other); - } - - // Return the result - return Polynomial_create(resultant); -} - -static PyObject* -Polynomial_extended_gcd(PyObject* self, PyObject* args) { - return 0; -} - -static PyObject* -Polynomial_factor(PyObject* self) { - return 0; -} - -// Creates a python list from the factors, taking over the polynomials -PyObject* factors_to_PyList(lp_polynomial_t** factors, size_t* multiplicities, size_t size) { - // Construct the result - PyObject* factors_list = PyList_New(size); - - // Copy the constant - // Copy over the factors - size_t i; - for (i = 0; i < size; ++ i) { - PyObject* p_i = Polynomial_create(factors[i]); - Py_INCREF(p_i); - PyObject* d = PyLong_FromSize_t(multiplicities[i]); - PyObject* pair = PyTuple_New(2); - PyTuple_SetItem(pair, 0, p_i); - PyTuple_SetItem(pair, 1, d); - PyList_SetItem(factors_list, i, pair); - } - - // Return the list - return factors_list; -} - -static PyObject* -Polynomial_factor_square_free(PyObject* self) { - // Get arguments - Polynomial* p = (Polynomial*) self; - // Factor - lp_polynomial_t** factors = 0; - size_t* multiplicities = 0; - size_t factors_size = 0; - lp_polynomial_factor_square_free(p->p, &factors, &multiplicities, &factors_size); - // Create the list - PyObject* factors_list = factors_to_PyList(factors, multiplicities, factors_size); - // Get rid of the factors (not the polynomials) - free(factors); - free(multiplicities); - // Return the list - return factors_list; -} - -static PyObject* -Polynomial_roots_count(PyObject* self, PyObject* args) { - return 0; -} - -static PyObject* -Polynomial_roots_isolate(PyObject* self, PyObject* args) { - - size_t i; - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - - // Check that the top variable is the only unassigned - if (!lp_polynomial_is_univariate_m(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "roots_count(): Polynomial must be univariate modulo the assignment."); - return NULL; - } - - // Get the degree of the polynomial and allocate the values - lp_value_t* roots = malloc(sizeof(lp_value_t)*lp_polynomial_degree(p)); - size_t roots_size = 0; - - // Get the roots - lp_polynomial_roots_isolate(p, assignment, roots, &roots_size); - - // Generate a list of roots - PyObject* list = PyList_New(roots_size); - - for (i = 0; i < roots_size; ++ i) { - PyObject* c = PyValue_create(roots + i); - PyList_SetItem(list, i, c); - } - - // Get rid of the temporaries - for (i = 0; i < roots_size; ++ i) { - lp_value_destruct(roots + i); - } - free(roots); - - // Return the list - return list; -} - -static PyObject* -Polynomial_derivative(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_polynomial_t* p_derivative = lp_polynomial_new(lp_polynomial_get_context(p)); - lp_polynomial_derivative(p_derivative, p); - return Polynomial_create(p_derivative); -} - -static PyObject* -Polynomial_sturm_sequence(PyObject* self) { - return 0; -} - -static PyObject* -Polynomial_degree(PyObject* self) { - Polynomial* p = (Polynomial*) self; - return PyLong_FromLong(lp_polynomial_degree(p->p)); -} - -static PyObject* -Polynomial_coefficients(PyObject* self) { - size_t i; - - lp_polynomial_t* p = ((Polynomial*) self)->p; - size_t size = lp_polynomial_degree(p) + 1; - - // Get the coefficients - const lp_polynomial_context_t* ctx = lp_polynomial_get_context(p); - - // Copy the polynomials into a list - PyObject* list = PyList_New(size); - for (i = 0; i < size; ++i) { - lp_polynomial_t* c_p = lp_polynomial_new(ctx); - lp_polynomial_get_coefficient(c_p, p, i); - PyObject* c = Polynomial_create(c_p); - PyList_SetItem(list, i, c); - } - - return list; -} - -static PyObject* -Polynomial_vars(PyObject* self) { - - lp_polynomial_t* p = ((Polynomial*) self)->p; - - lp_variable_list_t p_vars; - lp_variable_list_construct(&p_vars); - - // Get the variables - lp_polynomial_get_variables(p, &p_vars); - - // Copy the polynomials into a list - PyObject* list = PyList_New(p_vars.list_size); - size_t i; - for (i = 0; i < p_vars.list_size; ++i) { - PyObject* c = PyVariable_create(p_vars.list[i]); - PyList_SetItem(list, i, c); - } - - lp_variable_list_destruct(&p_vars); - - return list; -} - -static PyObject* -Polynomial_var(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - return PyVariable_create(lp_polynomial_top_variable(p)); -} - - -static PyObject* -Polynomial_reductum(PyObject* self, PyObject* args) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* ctx = lp_polynomial_get_context(p); - - if (!PyTuple_Check(args) || PyTuple_Size(args) > 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_assignment_t* assignment = 0; - - if (PyTuple_Size(args) == 1) { - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } else { - assignment = ((Assignment*) assignment_obj)->assignment; - } - } - - lp_polynomial_t* result = lp_polynomial_new(ctx); - if (assignment) { - lp_polynomial_reductum_m(result, p, assignment); - } else { - lp_polynomial_reductum(result, p); - } - - return Polynomial_create(result); -} - -static PyObject* -Polynomial_sgn(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - - int sgn = lp_polynomial_sgn(p, assignment); - - return PyLong_FromLong(sgn); -} - - -static PyObject* -Polynomial_evaluate(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - - lp_value_t* value = lp_polynomial_evaluate(p, assignment); - PyObject* value_obj = PyValue_create(value); - lp_value_delete(value); - - return value_obj; -} - -static PyObject* -Polynomial_feasible_intervals(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Needs two arguments, an assignment and a sign condition."); - return NULL; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): First argument must be an assignment."); - return NULL; - } - - PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); - if (!PyLong_Check(sgn_condition_obj)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Second argument must be a sign-condition."); - return NULL; - } - - // Get the arguments - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - lp_sign_condition_t sgn_condition = PyLong_AsLong(sgn_condition_obj); - - // Check if all but the top variable are unassigned - if (!lp_polynomial_is_univariate_m(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_intervals(): Polynomial must be univariate modulo the assignment."); - return NULL; - } - - // Get the feasible intervals - lp_feasibility_set_t* feasible = lp_polynomial_constraint_get_feasible_set(p, sgn_condition, 0, assignment); - - // The list where we return the arguments - PyObject* list = PyList_New(feasible->size); - // Copy over to the list - size_t i; - for (i = 0; i < feasible->size; ++i) { - PyObject* p = PyInterval_create(feasible->intervals + i); - PyList_SetItem(list, i, p); - } - // Remove temp - lp_feasibility_set_delete(feasible); - - // Return the list - return list; -} - -static PyObject* -Polynomial_feasible_set(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); - if (!PyLong_Check(sgn_condition_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Get the arguments - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - lp_sign_condition_t sgn_condition = PyLong_AsLong(sgn_condition_obj); - - // Check if all but the top variable are unassigned - if (!lp_polynomial_is_univariate_m(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "feasible_set(): Polynomial must be univariate modulo the assignment."); - return NULL; - } - - // Get the feasible intervals - lp_feasibility_set_t* feasible = lp_polynomial_constraint_get_feasible_set(p, sgn_condition, 0, assignment); - - // Return the list - return PyFeasibilitySet_create(feasible); -} - -static PyObject* -Polynomial_sgn_check(PyObject* self, PyObject* args) { - - if (!PyTuple_Check(args) || PyTuple_Size(args) != 2) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* assignment_obj = PyTuple_GetItem(args, 0); - if (!PyAssignment_CHECK(assignment_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - PyObject* sgn_condition_obj = PyTuple_GetItem(args, 1); - if (!PyLong_Check(sgn_condition_obj)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - // Get the arguments - lp_polynomial_t* p = ((Polynomial*) self)->p; - lp_assignment_t* assignment = ((Assignment*) assignment_obj)->assignment; - lp_sign_condition_t sgn_condition = PyLong_AsLong(sgn_condition_obj); - - // Check if all but the top variable are unassigned - if (!lp_polynomial_is_assigned(p, assignment)) { - PyErr_SetString(PyExc_RuntimeError, "sgn_check(): All polynomial variables should be assigned by the given assignment."); - return NULL; - } - - // Check the sign - int sgn = lp_polynomial_sgn(p, assignment); - if (lp_sign_condition_consistent(sgn_condition, sgn)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -static PyObject* -Polynomial_pp(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); - lp_polynomial_t* pp = lp_polynomial_new(p_ctx); - lp_polynomial_pp(pp, p); - PyObject* pp_py = Polynomial_create(pp); - return pp_py; -} - -static PyObject* -Polynomial_cont(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); - lp_polynomial_t* cont = lp_polynomial_new(p_ctx); - lp_polynomial_cont(cont, p); - PyObject* cont_py = Polynomial_create(cont); - return cont_py; -} - -static PyObject* -Polynomial_pp_cont(PyObject* self) { - lp_polynomial_t* p = ((Polynomial*) self)->p; - const lp_polynomial_context_t* p_ctx = lp_polynomial_get_context(p); - lp_polynomial_t* pp = lp_polynomial_new(p_ctx); - lp_polynomial_t* cont = lp_polynomial_new(p_ctx); - lp_polynomial_pp_cont(pp, cont, p); - PyObject* pp_py = Polynomial_create(pp); - PyObject* cont_py = Polynomial_create(cont); - PyObject* tuple = PyTuple_New(2); - PyTuple_SetItem(tuple, 0, pp_py); - PyTuple_SetItem(tuple, 1, cont_py); - return tuple; -} diff --git a/python/polypyUPolynomial.c b/python/polypyUPolynomial.c index 8ca57cb2..bb3831e9 100644 --- a/python/polypyUPolynomial.c +++ b/python/polypyUPolynomial.c @@ -17,12 +17,910 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" -#if PY_MAJOR_VERSION >= 3 -#include "polypyUPolynomial3.c" -#else -#include "polypyUPolynomial2.c" -#endif +#include "polypyUPolynomial.h" +#include "polypyInteger.h" +#include "polypyAlgebraicNumber.h" +#include "utils.h" + +#include "rational_interval.h" + +#include + +static void +UPolynomial_dealloc(UPolynomialObject* self); + +static PyObject* +UPolynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +UPolynomial_init(UPolynomialObject* self, PyObject* args); + +static PyObject* +UPolynomial_richcompare(PyObject* self, PyObject* other, int op); + +static PyObject* +UPolynomial_degree(PyObject* self); + +static PyObject* +UPolynomial_coefficients(PyObject* self); + +static PyObject* +UPolynomial_ring(PyObject* self); + +static PyObject* +UPolynomial_gcd(PyObject* self, PyObject* args); + +static PyObject* +UPolynomial_derivative(PyObject* self); + +static PyObject* +UPolynomial_extended_gcd(PyObject* self, PyObject* args); + +static PyObject* +UPolynomial_factor(PyObject* self); + +static PyObject* +UPolynomial_factor_square_free(PyObject* self); + +static PyObject* +UPolynomial_roots_count(PyObject* self, PyObject* args); + +static PyObject* +UPolynomial_roots_isolate(PyObject* self); + +static PyObject* +UPolynomial_sturm_sequence(PyObject* self); + +static PyObject* +UPolynomial_roots_find_Zp(PyObject* self); + +static PyObject* +UPolynomial_evaluate(PyObject* self, PyObject* args); + +static PyObject* +UPolynomial_to_ring(PyObject* self, PyObject* args); + +static PyObject* +UPolynomial_str(PyObject* self); + +static int +UPolynomialObject_nonzero(PyObject* self); + +static PyObject* +UPolynomialObject_add(PyObject* self, PyObject* other); + +static PyObject* +UPolynomialObject_sub(PyObject* self, PyObject* other); + +static PyObject* +UPolynomialObject_mul(PyObject* self, PyObject* other); + +static PyObject* +UPolynomialObject_div(PyObject* self, PyObject* args); + +static PyObject* +UPolynomialObject_rem(PyObject* self, PyObject* args); + +static PyObject* +UPolynomialObject_divmod(PyObject* self, PyObject* args); + +static PyObject* +UPolynomialObject_pow(PyObject* self, PyObject* other); + +static PyObject* +UPolynomialObject_neg(PyObject* self); + +PyMethodDef UPolynomial_methods[] = { + {"degree", (PyCFunction)UPolynomial_degree, METH_NOARGS, "Returns the degree of the polynomial"}, + {"coefficients", (PyCFunction)UPolynomial_coefficients, METH_NOARGS, "Returns a dictionary from degrees to coefficients"}, + {"ring", (PyCFunction)UPolynomial_ring, METH_NOARGS, "Returns the ring of the polynomial"}, + {"to_ring", (PyCFunction)UPolynomial_to_ring, METH_VARARGS, "Returns the polynomial in the given ring"}, + {"gcd", (PyCFunction)UPolynomial_gcd, METH_VARARGS, "Returns the gcd of current and given polynomial in the given ring"}, + {"extended_gcd", (PyCFunction)UPolynomial_extended_gcd, METH_VARARGS, "Returns the extended gcd, i.e. (gcd, u, v), of current and given polynomial in the given ring"}, + {"factor", (PyCFunction)UPolynomial_factor, METH_NOARGS, "Returns the factorization of the polynomial"}, + {"factor_square_free", (PyCFunction)UPolynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, + {"roots_count", (PyCFunction)UPolynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"}, + {"roots_isolate", (PyCFunction)UPolynomial_roots_isolate, METH_NOARGS, "Returns the list of real roots"}, + {"sturm_sequence", (PyCFunction)UPolynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"}, + {"roots_find_Zp", (PyCFunction)UPolynomial_roots_find_Zp, METH_NOARGS, "Returns the roots of the polynomial in Zp"}, + {"derivative", (PyCFunction)UPolynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"}, + {"evaluate", (PyCFunction)UPolynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial at the given point"}, + {NULL} /* Sentinel */ +}; + +PyNumberMethods UPolynomial_NumberMethods = { + UPolynomialObject_add, // binaryfunc nb_add; + UPolynomialObject_sub, // binaryfunc nb_subtract; + UPolynomialObject_mul, // binaryfunc nb_multiply; + UPolynomialObject_rem, // binaryfunc nb_remainder; + UPolynomialObject_divmod, // binaryfunc nb_divmod; + (ternaryfunc)UPolynomialObject_pow, // ternaryfunc nb_power; + UPolynomialObject_neg, // unaryfunc nb_negative; + NULL, // unaryfunc nb_positive; + NULL, // unaryfunc nb_absolute; + UPolynomialObject_nonzero, // inquiry nb_bool; + NULL, // unaryfunc nb_invert; + NULL, // binaryfunc nb_lshift; + NULL, // binaryfunc nb_rshift; + NULL, // binaryfunc nb_and; + NULL, // binaryfunc nb_xor; + NULL, // binaryfunc nb_or; + NULL, // unaryfunc nb_int; + NULL, // void *nb_reserved; + NULL, // unaryfunc nb_float; + NULL, // binaryfunc nb_inplace_add; + NULL, // binaryfunc nb_inplace_subtract; + NULL, // binaryfunc nb_inplace_multiply; + NULL, // binaryfunc nb_inplace_remainder; + NULL, // ternaryfunc nb_inplace_power; + NULL, // binaryfunc nb_inplace_lshift; + NULL, // binaryfunc nb_inplace_rshift; + NULL, // binaryfunc nb_inplace_and; + NULL, // binaryfunc nb_inplace_xor; + NULL, // binaryfunc nb_inplace_or; + NULL, // binaryfunc nb_floor_divide; + UPolynomialObject_div, // binaryfunc nb_true_divide; + NULL, // binaryfunc nb_inplace_floor_divide; + NULL, // binaryfunc nb_inplace_true_divide; + NULL, // unaryfunc nb_index; + NULL, // binaryfunc nb_matrix_multiply; + NULL, // binaryfunc nb_inplace_matrix_multiply; +}; + +PyTypeObject UPolynomialType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.UPolynomial", // const char *tp_name; + sizeof(UPolynomialObject), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)UPolynomial_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + UPolynomial_str, // reprfunc tp_repr; + &UPolynomial_NumberMethods, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + UPolynomial_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Univariate polynomial objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + UPolynomial_richcompare, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + UPolynomial_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)UPolynomial_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + UPolynomial_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +UPolynomial_dealloc(UPolynomialObject* self) +{ + if (self->p) lp_upolynomial_delete(self->p); + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +PyUPolynomial_create(lp_upolynomial_t* p) { + UPolynomialObject *self; + self = (UPolynomialObject*)UPolynomialType.tp_alloc(&UPolynomialType, 0); + if (self != NULL) { + self->p = p; + } + return (PyObject *)self; +} + +static PyObject* +UPolynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyUPolynomial_create(NULL); +} + +static int +UPolynomial_init(UPolynomialObject* self, PyObject* args) +{ + if (PyTuple_Check(args)) { + if (PyTuple_Size(args) == 0) { + // Just a zero polynomial + int coeff[] = { 0 }; + self->p = lp_upolynomial_construct_from_int(lp_Z, 0, coeff); + } else if (PyTuple_Size(args) <= 2) { + lp_int_ring_t* K = lp_Z; + + // Get the list of coefficients + PyObject* coefficients = PyTuple_GetItem(args, 0); + + // The first item might be the ring + if (PyCoefficientRing_CHECK(coefficients)) { + K = ((CoefficientRing*) coefficients)->K; + coefficients = PyTuple_GetItem(args, 1); + } else { + if (PyTuple_Size(args) == 2) { + return -1; + } + } + + if (PyList_Check(coefficients)) { + Py_ssize_t size = PyList_Size(coefficients); + if (size > 0) { + long c_ints[size]; + for (Py_ssize_t i = 0; i < size; ++ i) { + PyObject* c_i = PyList_GetItem(coefficients, i); + if (!PyLong_Check(c_i)) { + return -1; + } else { + c_ints[i] = PyLong_AsLong(c_i); + } + } + self->p = lp_upolynomial_construct_from_long(K, size-1, c_ints); + } else { + return -1; + } + } else { + return -1; + } + } else { + return -1; + } + } else { + return -1; + } + + return 0; +} + +static PyObject* +UPolynomial_richcompare(PyObject* self, PyObject* other, int op) { + PyObject *result = NULL; + + if (!PyUPolynomial_CHECK(other) && !PyLong_Check(other)) { + //IAM: Surely we can be braver here? + // if op == Py_EQ we could return Py_False + // if op == Py_NE we could return Py_True + // I am sure this holds for other versions of: + // _cmp AND _richcompare in this codebase. + result = Py_NotImplemented; + } else { + lp_upolynomial_t* self_p = ((UPolynomialObject*) self)->p; + lp_upolynomial_t* other_p = NULL; + if (PyUPolynomial_CHECK(other)) { + other_p = ((UPolynomialObject*) other)->p; + } else { + long c = PyLong_AsLong(other); + const lp_int_ring_t* K = lp_upolynomial_ring(self_p); + other_p = lp_upolynomial_construct_from_long(K, 0, &c); + } + + int cmp = lp_upolynomial_cmp(self_p, other_p); + + switch (op) { + case Py_LT: + result = cmp < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = cmp <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = cmp == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = cmp != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = cmp > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = cmp >= 0 ? Py_True : Py_False; + break; + default: + assert(0); + } + + if (PyLong_Check(other)) { + lp_upolynomial_delete(other_p); + } + } + + Py_INCREF(result); + return result; +} + +static PyObject* +UPolynomial_degree(PyObject* self) { + UPolynomialObject* p = (UPolynomialObject*) self; + if (p) { + return PyLong_FromUnsignedLong(lp_upolynomial_degree(p->p)); + } else { + Py_RETURN_NONE; + } +} + +static PyObject* +UPolynomial_coefficients(PyObject* self) { + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + size_t size = lp_upolynomial_degree(p) + 1; + + lp_integer_t coefficients[size]; + for (size_t i = 0; i < size; ++ i) { + lp_integer_construct_from_int(lp_Z, coefficients + i, 0); + } + + lp_upolynomial_unpack(p, coefficients); + + PyObject* list = PyList_New(size); + + for (size_t i = 0; i < size; ++ i) { + PyObject* c = integer_to_PyLong(coefficients + i); + PyList_SetItem(list, i, c); + lp_integer_destruct(coefficients + i); + } + + return list; +} + +static PyObject* +UPolynomial_ring(PyObject* self) { + UPolynomialObject* p = (UPolynomialObject*) self; + if (p) { + lp_int_ring_t* K = (lp_int_ring_t*) lp_upolynomial_ring(p->p); + lp_int_ring_attach(K); + return PyCoefficientRing_create(K); + } else { + Py_RETURN_NONE; + } +} + +static PyObject* +UPolynomial_to_ring(PyObject* self, PyObject* args) { + UPolynomialObject* p = (UPolynomialObject*) self; + if (p) { + // Get the ring argument + if (PyTuple_Size(args) == 1) { + // Get the ring + PyObject* arg = PyTuple_GetItem(args, 0); + if (PyCoefficientRing_CHECK(arg)) { + CoefficientRing* K = (CoefficientRing*)arg; + lp_upolynomial_t* p_K = lp_upolynomial_construct_copy_K(K->K, p->p); + return PyUPolynomial_create(p_K); + } else { + Py_RETURN_NONE; + } + } else { + Py_RETURN_NONE; + } + } else { + Py_RETURN_NONE; + } +} + +static PyObject* UPolynomial_str(PyObject* self) { + UPolynomialObject* p = (UPolynomialObject*) self; + if (p) { + char* p_str = lp_upolynomial_to_string(p->p); + PyObject* str = PyUnicode_FromString(p_str); + free(p_str); + return str; + } else { + Py_RETURN_NONE; + } +} + +// Add other integer +static PyObject* +UPolynomialObject_add_number(PyObject* self, PyObject* other) { + UPolynomialObject* p1 = (UPolynomialObject*) self; + lp_integer_t c; + const lp_int_ring_t* K = lp_upolynomial_ring(p1->p); + PyLong_or_Int_to_integer(other, K, &c); + lp_upolynomial_t* c_p = lp_upolynomial_construct(K, 0, &c); + lp_upolynomial_t* sum = lp_upolynomial_add(p1->p, c_p); + lp_upolynomial_delete(c_p); + lp_integer_destruct(&c); + return PyUPolynomial_create(sum); +} + +static PyObject* +UPolynomialObject_add(PyObject* self, PyObject* other) { + // Integer addition + if (PyLong_or_Int_Check(other)) { + return UPolynomialObject_add_number(self, other); + } + if (PyLong_or_Int_Check(self)) { + return UPolynomialObject_add_number(other, self); + } + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p1 = (UPolynomialObject*) self; + UPolynomialObject* p2 = (UPolynomialObject*) other; + // Add the polynomials + lp_upolynomial_t* sum = lp_upolynomial_add(p1->p, p2->p); + // Return the result + return PyUPolynomial_create(sum); +} + +static PyObject* +UPolynomialObject_sub_int(PyObject* self, PyObject* other, int negate) { + UPolynomialObject* p1 = (UPolynomialObject*) self; + lp_integer_t c; + const lp_int_ring_t* K = lp_upolynomial_ring(p1->p); + PyLong_or_Int_to_integer(other, K, &c); + lp_upolynomial_t* c_p = lp_upolynomial_construct(K, 0, &c); + lp_upolynomial_t* sub = + negate ? lp_upolynomial_sub(c_p, p1->p) : lp_upolynomial_sub(p1->p, c_p); + lp_upolynomial_delete(c_p); + lp_integer_destruct(&c); + return PyUPolynomial_create(sub); +} + +static PyObject* +UPolynomialObject_sub(PyObject* self, PyObject* other) { + // Integer addition + if (PyLong_or_Int_Check(other)) { + return UPolynomialObject_sub_int(self, other, 0); + } + if (PyLong_or_Int_Check(self)) { + return UPolynomialObject_sub_int(other, self, 1); + } + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p1 = (UPolynomialObject*) self; + UPolynomialObject* p2 = (UPolynomialObject*) other; + // Add the polynomials + lp_upolynomial_t* sum = lp_upolynomial_sub(p1->p, p2->p); + // Return the result + return PyUPolynomial_create(sum); +} + +// Multiply other integer +static PyObject* +UPolynomialObject_mul_int(PyObject* self, PyObject* other) { + UPolynomialObject* p1 = (UPolynomialObject*) self; + lp_integer_t c; + PyLong_or_Int_to_integer(other, lp_upolynomial_ring(p1->p), &c); + lp_upolynomial_t* sum = lp_upolynomial_mul_c(p1->p, &c); + lp_integer_destruct(&c); + return PyUPolynomial_create(sum); +} + +static PyObject* +UPolynomialObject_mul(PyObject* self, PyObject* other) { + // Integer multiplication + if (PyLong_or_Int_Check(other)) { + return UPolynomialObject_mul_int(self, other); + } + if (PyLong_or_Int_Check(self)) { + return UPolynomialObject_mul_int(other, self); + } + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p1 = (UPolynomialObject*) self; + UPolynomialObject* p2 = (UPolynomialObject*) other; + // Add the polynomials + lp_upolynomial_t* sum = lp_upolynomial_mul(p1->p, p2->p); + // Return the result + return PyUPolynomial_create(sum); +} + +static PyObject* +UPolynomialObject_div(PyObject* self, PyObject* args) { + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p1 = (UPolynomialObject*) self; + UPolynomialObject* p2 = (UPolynomialObject*) args; + // Divide the polynomials + lp_upolynomial_t* div = lp_upolynomial_div_exact(p1->p, p2->p); + // Return the result + return PyUPolynomial_create(div); +} + +static PyObject* +UPolynomialObject_rem(PyObject* self, PyObject* args) { + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p1 = (UPolynomialObject*) self; + UPolynomialObject* p2 = (UPolynomialObject*) args; + // Divide the polynomials + lp_upolynomial_t* rem = lp_upolynomial_rem_exact(p1->p, p2->p); + // Return the result + return PyUPolynomial_create(rem); +} + +static PyObject* +UPolynomialObject_divmod(PyObject* self, PyObject* args) { + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p1 = (UPolynomialObject*) self; + UPolynomialObject* p2 = (UPolynomialObject*) args; + // To store div, rem + lp_upolynomial_t* div = NULL; + lp_upolynomial_t* rem = NULL; + // Divide the polynomials + lp_upolynomial_div_rem_exact(p1->p, p2->p, &div, &rem); + // Return the result + PyObject* pair = PyTuple_New(2); + PyObject* divObj = PyUPolynomial_create(div); + PyObject* remObj = PyUPolynomial_create(rem); + Py_INCREF(divObj); + Py_INCREF(remObj); + PyTuple_SetItem(pair, 0, divObj); + PyTuple_SetItem(pair, 1, remObj); + return pair; +} + +// object.__neg__(self) +static PyObject* +UPolynomialObject_neg(PyObject* self) { + // Check arguments + if (!PyUPolynomial_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p = (UPolynomialObject*) self; + // Add the polynomials + lp_integer_t c; + lp_integer_construct_from_int(lp_upolynomial_ring(p->p), &c, -1); + lp_upolynomial_t* neg = lp_upolynomial_mul_c(p->p, &c); + lp_integer_destruct(&c); + // Return the result + return PyUPolynomial_create(neg); +} + +static PyObject* +UPolynomialObject_pow(PyObject* self, PyObject* other) { + // Check arguments + if (!PyUPolynomial_CHECK(self) || !PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + // Get arguments + UPolynomialObject* p = (UPolynomialObject*) self; + long pow = PyLong_AsLong(other); + // Power the polynomial + lp_upolynomial_t* p_pow = lp_upolynomial_pow(p->p, pow); + // Return the result + return PyUPolynomial_create(p_pow); +} + +static int +UPolynomialObject_nonzero(PyObject* self) { + // Get arguments + UPolynomialObject* p = (UPolynomialObject*) self; + // Return the result + return !lp_upolynomial_is_zero(p->p); +} + +static PyObject* +UPolynomial_gcd(PyObject* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* arg = PyTuple_GetItem(args, 0); + if (PyUPolynomial_CHECK(arg)) { + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + lp_upolynomial_t* q = ((UPolynomialObject*) arg)->p; + lp_upolynomial_t* gcd = lp_upolynomial_gcd(p, q); + return PyUPolynomial_create(gcd); + } else { + Py_RETURN_NONE; + } + } else { + Py_RETURN_NONE; + } +} + +static PyObject* +UPolynomial_extended_gcd(PyObject* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* arg = PyTuple_GetItem(args, 0); + if (PyUPolynomial_CHECK(arg)) { + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + lp_upolynomial_t* q = ((UPolynomialObject*) arg)->p; + lp_upolynomial_t* u = NULL; + lp_upolynomial_t* v = NULL; + lp_upolynomial_t* gcd = lp_upolynomial_extended_gcd(p, q, &u, &v); + + PyObject* t = PyTuple_New(3); + PyObject* t0 = PyUPolynomial_create(gcd); + PyObject* t1 = PyUPolynomial_create(u); + PyObject* t2 = PyUPolynomial_create(v); + Py_INCREF(t0); + Py_INCREF(t1); + Py_INCREF(t2); + PyTuple_SetItem(t, 0, t0); + PyTuple_SetItem(t, 1, t1); + PyTuple_SetItem(t, 2, t2); + return t; + } else { + Py_RETURN_NONE; + } + } else { + Py_RETURN_NONE; + } +} + +static PyObject* factors_to_PyList(lp_upolynomial_factors_t* factors) { + // Construct the result + size_t size = lp_upolynomial_factors_size(factors); + PyObject* factors_list = PyList_New(size + 1); + + // Copy the constant + PyObject* constant = integer_to_PyLong(lp_upolynomial_factors_get_constant(factors)); + PyList_SetItem(factors_list, 0, constant); // Steals the reference + + // Copy over the factors + for (size_t i = 0; i < size; ++ i) { + size_t degree; + PyObject* p_i = PyUPolynomial_create(lp_upolynomial_factors_get_factor(factors, i, °ree)); + Py_INCREF(p_i); + PyObject* d = PyLong_FromSize_t(degree); + PyObject* pair = PyTuple_New(2); + PyTuple_SetItem(pair, 0, p_i); + PyTuple_SetItem(pair, 1, d); + PyList_SetItem(factors_list, i + 1, pair); + } + + // Return the list + return factors_list; +} + +static PyObject* +UPolynomial_factor(PyObject* self) { + // Get arguments + UPolynomialObject* p = (UPolynomialObject*) self; + // Factor + lp_upolynomial_factors_t* factors = lp_upolynomial_factor(p->p); + // Create the list + PyObject* factors_list = factors_to_PyList(factors); + // Get rid of the factors (not the polynomials) + lp_upolynomial_factors_destruct(factors, 0); + // Return the list + return factors_list; +} + +static PyObject* +UPolynomial_factor_square_free(PyObject* self) { + // Get arguments + UPolynomialObject* p = (UPolynomialObject*) self; + // Factor + lp_upolynomial_factors_t* factors = lp_upolynomial_factor_square_free(p->p); + // Create the list + PyObject* factors_list = factors_to_PyList(factors); + // Get rid of the factors (not the polynomials) + lp_upolynomial_factors_destruct(factors, 0); + // Return the list + return factors_list; +} + +static PyObject* +UPolynomial_roots_count(PyObject* self, PyObject* args) { + // Get arguments + UPolynomialObject* p = (UPolynomialObject*) self; + + int roots = 0; + + if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { + PyObject* a = PyTuple_GetItem(args, 0); + PyObject* b = PyTuple_GetItem(args, 1); + + // Ends of the interval + lp_dyadic_rational_t a_rat, b_rat; + + if (PyLong_or_Int_Check(a)) { + lp_integer_t a_int; + PyLong_or_Int_to_integer(a, lp_Z, &a_int); + lp_dyadic_rational_construct_from_integer(&a_rat, &a_int); + lp_integer_destruct(&a_int); + } else if (PyFloat_Check(a)) { + PyFloat_to_dyadic_rational(a, &a_rat); + } else { + Py_RETURN_NONE; + } + + if (PyLong_or_Int_Check(b)) { + lp_integer_t b_int; + PyLong_or_Int_to_integer(b, lp_Z, &b_int); + lp_dyadic_rational_construct_from_integer(&b_rat, &b_int); + lp_integer_destruct(&b_int); + } else if (PyFloat_Check(b)) { + PyFloat_to_dyadic_rational(b, &b_rat); + } else { + lp_dyadic_rational_destruct(&a_rat); + Py_RETURN_NONE; + } + + // The interval + lp_rational_interval_t ab; + lp_rational_interval_construct_from_dyadic(&ab, &a_rat, 1, &b_rat, 1); + + // Count + roots = lp_upolynomial_roots_count(p->p, &ab); + + // Remove the temporaries + lp_rational_interval_destruct(&ab); + lp_dyadic_rational_destruct(&a_rat); + lp_dyadic_rational_destruct(&b_rat); + + } else if (PyTuple_Size(args) == 0) { + // count in (-inf, inf) + roots = lp_upolynomial_roots_count(p->p, NULL); + } else { + Py_RETURN_NONE; + } + + return PyLong_FromLong(roots); +} + +static PyObject* +UPolynomial_roots_isolate(PyObject* self) { + + // Get the polynomial + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + + // The isolating intervals + size_t roots_size = lp_upolynomial_degree(p)+1; + lp_algebraic_number_t* roots = malloc(sizeof(lp_algebraic_number_t)*roots_size); + + // Isolate the intervals (up to 2^precision) + lp_upolynomial_roots_isolate(p, roots, &roots_size); + + // Generate a list of floats + PyObject* list = PyList_New(roots_size); + + for (size_t i = 0; i < roots_size; ++ i) { + PyObject* c = PyAlgebraicNumber_create(&roots[i]); + PyList_SetItem(list, i, c); + } + + // Get rid of the temporaries + for (size_t i = 0; i < roots_size; ++ i) { + lp_algebraic_number_destruct(roots + i); + } + free(roots); + + // This is the list + return list; +} + +static PyObject* +UPolynomial_derivative(PyObject* self) { + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + lp_upolynomial_t* p_derivative = lp_upolynomial_derivative(p); + return PyUPolynomial_create(p_derivative); +} + +static PyObject* upolynomials_to_PyList(lp_upolynomial_t** list, size_t size) { + // Construct the result + PyObject* pylist = PyList_New(size); + + // Copy over the polynomials + for (size_t i = 0; i < size; ++ i) { + PyObject* pylist_i = PyUPolynomial_create(list[i]); + Py_INCREF(pylist_i); + PyList_SetItem(pylist, i, pylist_i); + } + + // Return the list + return pylist; +} + + +static PyObject* +UPolynomial_sturm_sequence(PyObject* self) { + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + lp_upolynomial_t** S; + size_t S_size; + lp_upolynomial_sturm_sequence(p, &S, &S_size); + PyObject* result = upolynomials_to_PyList(S, S_size); + free(S); + return result; +} + +static PyObject* integer_list_to_PyList(const lp_integer_t *list, size_t size) { + // Construct the result + PyObject* pylist = PyList_New(size); + + // Copy over the integers + for (size_t i = 0; i < size; ++ i) { + PyObject* pylist_i = integer_to_PyLong(&list[i]); + Py_INCREF(pylist_i); + PyList_SetItem(pylist, i, pylist_i); + } + + // Return the list + return pylist; +} + +static PyObject* +UPolynomial_roots_find_Zp(PyObject* self) { + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + lp_integer_t* roots; + size_t roots_size; + lp_upolynomial_roots_find_Zp(p, &roots, &roots_size); + PyObject* result = integer_list_to_PyList(roots, roots_size); + for (size_t i = 0; i < roots_size; ++i) { + lp_integer_destruct(&roots[i]); + } + free(roots); + return result; +} + +static PyObject* +UPolynomial_evaluate(PyObject* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* x = PyTuple_GetItem(args, 0); + // Ends of the interval + lp_dyadic_rational_t x_rat; + if (PyLong_or_Int_Check(x)) { + lp_integer_t x_int; + PyLong_or_Int_to_integer(x, lp_Z, &x_int); + lp_dyadic_rational_construct_from_integer(&x_rat, &x_int); + lp_integer_destruct(&x_int); + } else if (PyFloat_Check(x)) { + PyFloat_to_dyadic_rational(x, &x_rat); + } else { + Py_RETURN_NONE; + } + + lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; + lp_dyadic_rational_t value; + lp_dyadic_rational_construct(&value); + lp_upolynomial_evaluate_at_dyadic_rational(p, &x_rat, &value); + PyObject* result = dyadic_rational_to_PyFloat(&value); + lp_dyadic_rational_destruct(&x_rat); + lp_dyadic_rational_destruct(&value); + return result; + } else { + Py_RETURN_NONE; + } + +} diff --git a/python/polypyUPolynomial.h b/python/polypyUPolynomial.h index 371750fd..ec15800b 100644 --- a/python/polypyUPolynomial.h +++ b/python/polypyUPolynomial.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "utils.h" #include "upolynomial.h" diff --git a/python/polypyUPolynomial2.c b/python/polypyUPolynomial2.c deleted file mode 100644 index 14a6d6a1..00000000 --- a/python/polypyUPolynomial2.c +++ /dev/null @@ -1,909 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyUPolynomial.h" -#include "polypyInteger.h" -#include "polypyAlgebraicNumber.h" - -#include "utils.h" - -#include "rational_interval.h" - -#include - -static void -UPolynomial_dealloc(UPolynomialObject* self); - -static PyObject* -UPolynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -UPolynomial_init(UPolynomialObject* self, PyObject* args); - -static int -UPolynomial_cmp(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_richcompare(PyObject* self, PyObject* args, int op); - -static PyObject* -UPolynomial_degree(PyObject* self); - -static PyObject* -UPolynomial_coefficients(PyObject* self); - -static PyObject* -UPolynomial_ring(PyObject* self); - -static PyObject* -UPolynomial_gcd(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_derivative(PyObject* self); - -static PyObject* -UPolynomial_extended_gcd(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_factor(PyObject* self); - -static PyObject* -UPolynomial_factor_square_free(PyObject* self); - -static PyObject* -UPolynomial_roots_count(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_roots_isolate(PyObject* self); - -static PyObject* -UPolynomial_sturm_sequence(PyObject* self); - -static PyObject* -UPolynomial_evaluate(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_to_ring(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_str(PyObject* self); - -static int -UPolynomialObject_nonzero(PyObject* self); - -static PyObject* -UPolynomialObject_add(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_sub(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_mul(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_div(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_rem(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_divmod(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_pow(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_neg(PyObject* self); - -PyMethodDef UPolynomial_methods[] = { - {"degree", (PyCFunction)UPolynomial_degree, METH_NOARGS, "Returns the degree of the polynomial"}, - {"coefficients", (PyCFunction)UPolynomial_coefficients, METH_NOARGS, "Returns a dictionary from degrees to coefficients"}, - {"ring", (PyCFunction)UPolynomial_ring, METH_NOARGS, "Returns the ring of the polynomial"}, - {"to_ring", (PyCFunction)UPolynomial_to_ring, METH_VARARGS, "Returns the polynomial in the given ring"}, - {"gcd", (PyCFunction)UPolynomial_gcd, METH_VARARGS, "Returns the gcd of current and given polynomial in the given ring"}, - {"extended_gcd", (PyCFunction)UPolynomial_extended_gcd, METH_VARARGS, "Returns the extended gcd, i.e. (gcd, u, v), of current and given polynomial in the given ring"}, - {"factor", (PyCFunction)UPolynomial_factor, METH_NOARGS, "Returns the factorization of the polynomial"}, - {"factor_square_free", (PyCFunction)UPolynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, - {"roots_count", (PyCFunction)UPolynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"}, - {"roots_isolate", (PyCFunction)UPolynomial_roots_isolate, METH_NOARGS, "Returns the list of real roots"}, - {"sturm_sequence", (PyCFunction)UPolynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"}, - {"derivative", (PyCFunction)UPolynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"}, - {"evaluate", (PyCFunction)UPolynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial at the given point"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods UPolynomial_NumberMethods = { - UPolynomialObject_add, // binaryfunc nb_add; - UPolynomialObject_sub, // binaryfunc nb_subtract; - UPolynomialObject_mul, // binaryfunc nb_multiply; - UPolynomialObject_div, // binaryfunc nb_divide; - UPolynomialObject_rem, // binaryfunc nb_remainder; - UPolynomialObject_divmod, // binaryfunc nb_divmod; - (ternaryfunc)UPolynomialObject_pow, // ternaryfunc nb_power; - UPolynomialObject_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - UPolynomialObject_nonzero, // inquiry nb_nonzero; /* Used by PyObject_IsTrue */ - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // coercion nb_coerce; /* Used by the coerce() function */ - 0, // unaryfunc nb_int; - 0, // unaryfunc nb_long; - 0, // unaryfunc nb_float; - 0, // unaryfunc nb_oct; - 0, // unaryfunc nb_hex; - - /* Added in release 2.0 */ - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_divide; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - - /* Added in release 2.2 */ - 0, // binaryfunc nb_floor_divide; - 0, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - - /* Added in release 2.5 */ - 0 // unaryfunc nb_index; -}; - -PyTypeObject UPolynomialType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.UPolynomial", /*tp_name*/ - sizeof(UPolynomialObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)UPolynomial_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - UPolynomial_cmp, /*tp_compare*/ - UPolynomial_str, /*tp_repr*/ - &UPolynomial_NumberMethods, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - UPolynomial_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Univariate polynomial objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - UPolynomial_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - UPolynomial_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)UPolynomial_init,/* tp_init */ - 0, /* tp_alloc */ - UPolynomial_new, /* tp_new */ -}; - -static void -UPolynomial_dealloc(UPolynomialObject* self) -{ - if (self->p) lp_upolynomial_delete(self->p); - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyUPolynomial_create(lp_upolynomial_t* p) { - UPolynomialObject *self; - self = (UPolynomialObject*)UPolynomialType.tp_alloc(&UPolynomialType, 0); - if (self != NULL) { - self->p = p; - } - return (PyObject *)self; -} - -static PyObject* -UPolynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyUPolynomial_create(0); -} - -static int -UPolynomial_init(UPolynomialObject* self, PyObject* args) -{ - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 0) { - // Just a zero polynomial - int coeff[] = { 0 }; - self->p = lp_upolynomial_construct_from_int(lp_Z, 0, coeff); - } else if (PyTuple_Size(args) <= 2) { - const lp_int_ring_t* K = lp_Z; - - // Get the list of coefficients - PyObject* coefficients = PyTuple_GetItem(args, 0); - - // The first item might be the ring - if (PyCoefficientRing_CHECK(coefficients)) { - K = ((CoefficientRing*) coefficients)->K; - coefficients = PyTuple_GetItem(args, 1); - } else { - if (PyTuple_Size(args) == 2) { - return -1; - } - } - - if (PyList_Check(coefficients)) { - Py_ssize_t size = PyList_Size(coefficients); - if (size > 0) { - long c_ints[size]; - Py_ssize_t i; - for (i = 0; i < size; ++ i) { - PyObject* c_i = PyList_GetItem(coefficients, i); - if (!PyInt_Check(c_i)) { - return -1; - } else { - c_ints[i] = PyInt_AsLong(c_i); - } - } - self->p = lp_upolynomial_construct_from_long(K, size-1, c_ints); - } else { - return -1; - } - } else { - return -1; - } - } else { - return -1; - } - } else { - return -1; - } - - return 0; -} - -static PyObject* -UPolynomial_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - if (!PyUPolynomial_CHECK(other) && !PyInt_Check(other)) { - result = Py_NotImplemented; - } else { - lp_upolynomial_t* self_p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* other_p = 0; - if (PyUPolynomial_CHECK(other)) { - other_p = ((UPolynomialObject*) other)->p; - } else { - long c = PyInt_AsLong(other); - const lp_int_ring_t* K = lp_upolynomial_ring(self_p); - other_p = lp_upolynomial_construct_from_long(K, 0, &c); - } - - int cmp = lp_upolynomial_cmp(self_p, other_p); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - - if (PyInt_Check(other)) { - lp_upolynomial_delete(other_p); - } - } - - Py_INCREF(result); - return result; -} - -static int -UPolynomial_cmp(PyObject* self, PyObject* other) { - - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - // should return -1 and set an exception condition when an error occurred - return -1; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Compare - int cmp = lp_upolynomial_cmp(p1->p, p2->p); - return cmp > 0 ? 1 : cmp < 0 ? -1 : 0; -} - -static PyObject* -UPolynomial_degree(PyObject* self) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - return PyInt_FromLong(lp_upolynomial_degree(p->p)); - } else { - Py_RETURN_NONE; - } -} - -static PyObject* -UPolynomial_coefficients(PyObject* self) { - int i; - - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - size_t size = lp_upolynomial_degree(p) + 1; - - lp_integer_t coefficients[size]; - for (i = 0; i < size; ++ i) { - lp_integer_construct_from_int(lp_Z, coefficients + i, 0); - } - - lp_upolynomial_unpack(p, coefficients); - - PyObject* list = PyList_New(size); - - for (i = 0; i < size; ++ i) { - PyObject* c = integer_to_PyInt(coefficients + i); - PyList_SetItem(list, i, c); - lp_integer_destruct(coefficients + i); - } - - return list; -} - -static PyObject* -UPolynomial_ring(PyObject* self) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - lp_int_ring_t* K = (lp_int_ring_t*) lp_upolynomial_ring(p->p); - lp_int_ring_attach(K); - return PyCoefficientRing_create(K); - } else { - Py_RETURN_NONE; - } -} - -static PyObject* -UPolynomial_to_ring(PyObject* self, PyObject* args) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - // Get the ring argument - if (PyTuple_Size(args) == 1) { - // Get the ring - PyObject* arg = PyTuple_GetItem(args, 0); - if (PyCoefficientRing_CHECK(arg)) { - CoefficientRing* K = (CoefficientRing*)arg; - lp_upolynomial_t* p_K = lp_upolynomial_construct_copy_K(K->K, p->p); - return PyUPolynomial_create(p_K); - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject* UPolynomial_str(PyObject* self) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - char* p_str = lp_upolynomial_to_string(p->p); - PyObject* str = PyString_FromString(p_str); - free(p_str); - return str; - } else { - Py_RETURN_NONE; - } -} - -// Add other integer -static PyObject* -UPolynomialObject_add_number(PyObject* self, PyObject* other) { - UPolynomialObject* p1 = (UPolynomialObject*) self; - lp_integer_t c; - const lp_int_ring_t* K = lp_upolynomial_ring(p1->p); - PyLong_or_Int_to_integer(other, K, &c); - lp_upolynomial_t* c_p = lp_upolynomial_construct(K, 0, &c); - lp_upolynomial_t* sum = lp_upolynomial_add(p1->p, c_p); - lp_upolynomial_delete(c_p); - lp_integer_destruct(&c); - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_add(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return UPolynomialObject_add_number(self, other); - } - if (PyLong_or_Int_Check(self)) { - return UPolynomialObject_add_number(other, self); - } - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Add the polynomials - lp_upolynomial_t* sum = lp_upolynomial_add(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_sub_int(PyObject* self, PyObject* other, int negate) { - UPolynomialObject* p1 = (UPolynomialObject*) self; - lp_integer_t c; - const lp_int_ring_t* K = lp_upolynomial_ring(p1->p); - PyLong_or_Int_to_integer(other, K, &c); - lp_upolynomial_t* c_p = lp_upolynomial_construct(K, 0, &c); - lp_upolynomial_t* sub = - negate ? lp_upolynomial_sub(c_p, p1->p) : lp_upolynomial_sub(p1->p, c_p); - lp_upolynomial_delete(c_p); - lp_integer_destruct(&c); - return PyUPolynomial_create(sub); -} - -static PyObject* -UPolynomialObject_sub(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return UPolynomialObject_sub_int(self, other, 0); - } - if (PyLong_or_Int_Check(self)) { - return UPolynomialObject_sub_int(other, self, 1); - } - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Add the polynomials - lp_upolynomial_t* sum = lp_upolynomial_sub(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(sum); -} - -// Multiply other integer -static PyObject* -UPolynomialObject_mul_int(PyObject* self, PyObject* other) { - UPolynomialObject* p1 = (UPolynomialObject*) self; - lp_integer_t c; - PyLong_or_Int_to_integer(other, lp_upolynomial_ring(p1->p), &c); - lp_upolynomial_t* sum = lp_upolynomial_mul_c(p1->p, &c); - lp_integer_destruct(&c); - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_mul(PyObject* self, PyObject* other) { - // Integer multiplication - if (PyLong_or_Int_Check(other)) { - return UPolynomialObject_mul_int(self, other); - } - if (PyLong_or_Int_Check(self)) { - return UPolynomialObject_mul_int(other, self); - } - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Add the polynomials - lp_upolynomial_t* sum = lp_upolynomial_mul(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_div(PyObject* self, PyObject* args) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) args; - // Divide the polynomials - lp_upolynomial_t* div = lp_upolynomial_div_exact(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(div); -} - -static PyObject* -UPolynomialObject_rem(PyObject* self, PyObject* args) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) args; - // Divide the polynomials - lp_upolynomial_t* rem = lp_upolynomial_rem_exact(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(rem); -} - -static PyObject* -UPolynomialObject_divmod(PyObject* self, PyObject* args) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) args; - // To store div, rem - lp_upolynomial_t* div = 0; - lp_upolynomial_t* rem = 0; - // Divide the polynomials - lp_upolynomial_div_rem_exact(p1->p, p2->p, &div, &rem); - // Return the result - PyObject* pair = PyTuple_New(2); - PyObject* divObj = PyUPolynomial_create(div); - PyObject* remObj = PyUPolynomial_create(rem); - Py_INCREF(divObj); - Py_INCREF(remObj); - PyTuple_SetItem(pair, 0, divObj); - PyTuple_SetItem(pair, 1, remObj); - return pair; -} - -// object.__neg__(self) -static PyObject* -UPolynomialObject_neg(PyObject* self) { - // Check arguments - if (!PyUPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Add the polynomials - lp_integer_t c; - lp_integer_construct_from_int(lp_upolynomial_ring(p->p), &c, -1); - lp_upolynomial_t* neg = lp_upolynomial_mul_c(p->p, &c); - lp_integer_destruct(&c); - // Return the result - return PyUPolynomial_create(neg); -} - -static PyObject* -UPolynomialObject_pow(PyObject* self, PyObject* other) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyInt_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - long pow = PyInt_AsLong(other); - // Power the polynomial - lp_upolynomial_t* p_pow = lp_upolynomial_pow(p->p, pow); - // Return the result - return PyUPolynomial_create(p_pow); -} - -static int -UPolynomialObject_nonzero(PyObject* self) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Return the result - return !lp_upolynomial_is_zero(p->p); -} - -static PyObject* -UPolynomial_gcd(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* arg = PyTuple_GetItem(args, 0); - if (PyUPolynomial_CHECK(arg)) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* q = ((UPolynomialObject*) arg)->p; - lp_upolynomial_t* gcd = lp_upolynomial_gcd(p, q); - return PyUPolynomial_create(gcd); - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject* -UPolynomial_extended_gcd(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* arg = PyTuple_GetItem(args, 0); - if (PyUPolynomial_CHECK(arg)) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* q = ((UPolynomialObject*) arg)->p; - lp_upolynomial_t* u = 0; - lp_upolynomial_t* v = 0; - lp_upolynomial_t* gcd = lp_upolynomial_extended_gcd(p, q, &u, &v); - - PyObject* t = PyTuple_New(3); - PyObject* t0 = PyUPolynomial_create(gcd); - PyObject* t1 = PyUPolynomial_create(u); - PyObject* t2 = PyUPolynomial_create(v); - Py_INCREF(t0); - Py_INCREF(t1); - Py_INCREF(t2); - PyTuple_SetItem(t, 0, t0); - PyTuple_SetItem(t, 1, t1); - PyTuple_SetItem(t, 2, t2); - return t; - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject* factors_to_PyList(lp_upolynomial_factors_t* factors) { - // Construct the result - size_t size = lp_upolynomial_factors_size(factors); - PyObject* factors_list = PyList_New(size + 1); - - // Copy the constant - PyObject* constant = integer_to_PyInt(lp_upolynomial_factors_get_constant(factors)); - PyList_SetItem(factors_list, 0, constant); // Steals the reference - - // Copy over the factors - int i; - for (i = 0; i < size; ++ i) { - size_t degree; - PyObject* p_i = PyUPolynomial_create(lp_upolynomial_factors_get_factor(factors, i, °ree)); - Py_INCREF(p_i); - PyObject* d = PyInt_FromSize_t(degree); - PyObject* pair = PyTuple_New(2); - PyTuple_SetItem(pair, 0, p_i); - PyTuple_SetItem(pair, 1, d); - PyList_SetItem(factors_list, i + 1, pair); - } - - // Return the list - return factors_list; -} - -static PyObject* -UPolynomial_factor(PyObject* self) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Factor - lp_upolynomial_factors_t* factors = lp_upolynomial_factor(p->p); - // Create the list - PyObject* factors_list = factors_to_PyList(factors); - // Get rid of the factors (not the polynomials) - lp_upolynomial_factors_destruct(factors, 0); - // Return the list - return factors_list; -} - -static PyObject* -UPolynomial_factor_square_free(PyObject* self) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Factor - lp_upolynomial_factors_t* factors = lp_upolynomial_factor_square_free(p->p); - // Create the list - PyObject* factors_list = factors_to_PyList(factors); - // Get rid of the factors (not the polynomials) - lp_upolynomial_factors_destruct(factors, 0); - // Return the list - return factors_list; -} - -static PyObject* -UPolynomial_roots_count(PyObject* self, PyObject* args) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - - int roots = 0; - - if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { - PyObject* a = PyTuple_GetItem(args, 0); - PyObject* b = PyTuple_GetItem(args, 1); - - // Ends of the interval - lp_dyadic_rational_t a_rat, b_rat; - - if (PyLong_or_Int_Check(a)) { - lp_integer_t a_int; - PyLong_or_Int_to_integer(a, lp_Z, &a_int); - lp_dyadic_rational_construct_from_integer(&a_rat, &a_int); - lp_integer_destruct(&a_int); - } else if (PyFloat_Check(a)) { - PyFloat_to_dyadic_rational(a, &a_rat); - } else { - Py_RETURN_NONE; - } - - if (PyLong_or_Int_Check(b)) { - lp_integer_t b_int; - PyLong_or_Int_to_integer(b, lp_Z, &b_int); - lp_dyadic_rational_construct_from_integer(&b_rat, &b_int); - lp_integer_destruct(&b_int); - } else if (PyFloat_Check(b)) { - PyFloat_to_dyadic_rational(b, &b_rat); - } else { - lp_dyadic_rational_destruct(&a_rat); - Py_RETURN_NONE; - } - - // The interval - lp_rational_interval_t ab; - lp_rational_interval_construct_from_dyadic(&ab, &a_rat, 1, &b_rat, 1); - - // Count - roots = lp_upolynomial_roots_count(p->p, &ab); - - // Remove the temporaries - lp_rational_interval_destruct(&ab); - lp_dyadic_rational_destruct(&a_rat); - lp_dyadic_rational_destruct(&b_rat); - - } else if (PyTuple_Size(args) == 0) { - // count in (-inf, inf) - roots = lp_upolynomial_roots_count(p->p, 0); - } else { - Py_RETURN_NONE; - } - - return PyInt_FromLong(roots); -} - -static PyObject* -UPolynomial_roots_isolate(PyObject* self) { - - // Get the polynomial - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - - // The isolating intervals - size_t roots_size = lp_upolynomial_degree(p)+1; - lp_algebraic_number_t* roots = malloc(sizeof(lp_algebraic_number_t)*roots_size); - - // Isolate the intervals (up to 2^precision) - lp_upolynomial_roots_isolate(p, roots, &roots_size); - - // Generate a list of floats - PyObject* list = PyList_New(roots_size); - - int i; - for (i = 0; i < roots_size; ++ i) { - PyObject* c = PyAlgebraicNumber_create(&roots[i]); - PyList_SetItem(list, i, c); - } - - // Get rid of the temporaries - for (i = 0; i < roots_size; ++ i) { - lp_algebraic_number_destruct(roots + i); - } - free(roots); - - // This is the list - return list; -} - -static PyObject* -UPolynomial_derivative(PyObject* self) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* p_derivative = lp_upolynomial_derivative(p); - return PyUPolynomial_create(p_derivative); -} - -static PyObject* upolynomials_to_PyList(lp_upolynomial_t** list, size_t size) { - // Construct the result - PyObject* pylist = PyList_New(size); - - // Copy over the polynomials - size_t i; - for (i = 0; i < size; ++ i) { - PyObject* pylist_i = PyUPolynomial_create(list[i]); - Py_INCREF(pylist_i); - PyList_SetItem(pylist, i, pylist_i); - } - - // Return the list - return pylist; -} - - -static PyObject* -UPolynomial_sturm_sequence(PyObject* self) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t** S; - size_t S_size; - lp_upolynomial_sturm_sequence(p, &S, &S_size); - PyObject* result = upolynomials_to_PyList(S, S_size); - free(S); - return result; -} - -static PyObject* -UPolynomial_evaluate(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* x = PyTuple_GetItem(args, 0); - // Ends of the interval - lp_dyadic_rational_t x_rat; - if (PyLong_or_Int_Check(x)) { - lp_integer_t x_int; - PyLong_or_Int_to_integer(x, lp_Z, &x_int); - lp_dyadic_rational_construct_from_integer(&x_rat, &x_int); - lp_integer_destruct(&x_int); - } else if (PyFloat_Check(x)) { - PyFloat_to_dyadic_rational(x, &x_rat); - } else { - Py_RETURN_NONE; - } - - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_dyadic_rational_t value; - lp_dyadic_rational_construct(&value); - lp_upolynomial_evaluate_at_dyadic_rational(p, &x_rat, &value); - PyObject* result = dyadic_rational_to_PyFloat(&value); - lp_dyadic_rational_destruct(&x_rat); - lp_dyadic_rational_destruct(&value); - return result; - } else { - Py_RETURN_NONE; - } - -} diff --git a/python/polypyUPolynomial3.c b/python/polypyUPolynomial3.c deleted file mode 100644 index e3b65056..00000000 --- a/python/polypyUPolynomial3.c +++ /dev/null @@ -1,929 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyUPolynomial.h" -#include "polypyInteger.h" -#include "polypyAlgebraicNumber.h" - -#include "utils.h" - -#include "rational_interval.h" - -#include - -static void -UPolynomial_dealloc(UPolynomialObject* self); - -static PyObject* -UPolynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -UPolynomial_init(UPolynomialObject* self, PyObject* args); - -static PyObject* -UPolynomial_richcompare(PyObject* self, PyObject* args, int op); - -static PyObject* -UPolynomial_degree(PyObject* self); - -static PyObject* -UPolynomial_coefficients(PyObject* self); - -static PyObject* -UPolynomial_ring(PyObject* self); - -static PyObject* -UPolynomial_gcd(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_derivative(PyObject* self); - -static PyObject* -UPolynomial_extended_gcd(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_factor(PyObject* self); - -static PyObject* -UPolynomial_factor_square_free(PyObject* self); - -static PyObject* -UPolynomial_roots_count(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_roots_isolate(PyObject* self); - -static PyObject* -UPolynomial_sturm_sequence(PyObject* self); - -static PyObject* -UPolynomial_roots_find_Zp(PyObject* self); - -static PyObject* -UPolynomial_evaluate(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_to_ring(PyObject* self, PyObject* args); - -static PyObject* -UPolynomial_str(PyObject* self); - -static int -UPolynomialObject_nonzero(PyObject* self); - -static PyObject* -UPolynomialObject_add(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_sub(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_mul(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_div(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_rem(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_divmod(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_pow(PyObject* self, PyObject* args); - -static PyObject* -UPolynomialObject_neg(PyObject* self); - -PyMethodDef UPolynomial_methods[] = { - {"degree", (PyCFunction)UPolynomial_degree, METH_NOARGS, "Returns the degree of the polynomial"}, - {"coefficients", (PyCFunction)UPolynomial_coefficients, METH_NOARGS, "Returns a dictionary from degrees to coefficients"}, - {"ring", (PyCFunction)UPolynomial_ring, METH_NOARGS, "Returns the ring of the polynomial"}, - {"to_ring", (PyCFunction)UPolynomial_to_ring, METH_VARARGS, "Returns the polynomial in the given ring"}, - {"gcd", (PyCFunction)UPolynomial_gcd, METH_VARARGS, "Returns the gcd of current and given polynomial in the given ring"}, - {"extended_gcd", (PyCFunction)UPolynomial_extended_gcd, METH_VARARGS, "Returns the extended gcd, i.e. (gcd, u, v), of current and given polynomial in the given ring"}, - {"factor", (PyCFunction)UPolynomial_factor, METH_NOARGS, "Returns the factorization of the polynomial"}, - {"factor_square_free", (PyCFunction)UPolynomial_factor_square_free, METH_NOARGS, "Returns the square-free factorization of the polynomial"}, - {"roots_count", (PyCFunction)UPolynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"}, - {"roots_isolate", (PyCFunction)UPolynomial_roots_isolate, METH_NOARGS, "Returns the list of real roots"}, - {"sturm_sequence", (PyCFunction)UPolynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"}, - {"roots_find_Zp", (PyCFunction)UPolynomial_roots_find_Zp, METH_NOARGS, "Returns the roots of the polynomial in Zp"}, - {"derivative", (PyCFunction)UPolynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"}, - {"evaluate", (PyCFunction)UPolynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial at the given point"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods UPolynomial_NumberMethods = { - UPolynomialObject_add, // binaryfunc nb_add; - UPolynomialObject_sub, // binaryfunc nb_subtract; - UPolynomialObject_mul, // binaryfunc nb_multiply; - UPolynomialObject_rem, // binaryfunc nb_remainder; - UPolynomialObject_divmod, // binaryfunc nb_divmod; - (ternaryfunc)UPolynomialObject_pow, // ternaryfunc nb_power; - UPolynomialObject_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - UPolynomialObject_nonzero, // inquiry nb_bool; - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // unaryfunc nb_int; - 0, // void *nb_reserved; - 0, // unaryfunc nb_float; - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - 0, // binaryfunc nb_floor_divide; - UPolynomialObject_div, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - 0, // unaryfunc nb_index; - 0, // binaryfunc nb_matrix_multiply; - 0, // binaryfunc nb_inplace_matrix_multiply; -}; - -PyTypeObject UPolynomialType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.UPolynomial", // const char *tp_name; - sizeof(UPolynomialObject), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)UPolynomial_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - UPolynomial_str, // reprfunc tp_repr; - &UPolynomial_NumberMethods, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - UPolynomial_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Univariate polynomial objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - UPolynomial_richcompare, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - UPolynomial_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)UPolynomial_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - UPolynomial_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -UPolynomial_dealloc(UPolynomialObject* self) -{ - if (self->p) lp_upolynomial_delete(self->p); - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyUPolynomial_create(lp_upolynomial_t* p) { - UPolynomialObject *self; - self = (UPolynomialObject*)UPolynomialType.tp_alloc(&UPolynomialType, 0); - if (self != NULL) { - self->p = p; - } - return (PyObject *)self; -} - -static PyObject* -UPolynomial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyUPolynomial_create(0); -} - -static int -UPolynomial_init(UPolynomialObject* self, PyObject* args) -{ - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 0) { - // Just a zero polynomial - int coeff[] = { 0 }; - self->p = lp_upolynomial_construct_from_int(lp_Z, 0, coeff); - } else if (PyTuple_Size(args) <= 2) { - lp_int_ring_t* K = lp_Z; - - // Get the list of coefficients - PyObject* coefficients = PyTuple_GetItem(args, 0); - - // The first item might be the ring - if (PyCoefficientRing_CHECK(coefficients)) { - K = ((CoefficientRing*) coefficients)->K; - coefficients = PyTuple_GetItem(args, 1); - } else { - if (PyTuple_Size(args) == 2) { - return -1; - } - } - - if (PyList_Check(coefficients)) { - Py_ssize_t size = PyList_Size(coefficients); - if (size > 0) { - long c_ints[size]; - Py_ssize_t i; - for (i = 0; i < size; ++ i) { - PyObject* c_i = PyList_GetItem(coefficients, i); - if (!PyLong_Check(c_i)) { - return -1; - } else { - c_ints[i] = PyLong_AsLong(c_i); - } - } - self->p = lp_upolynomial_construct_from_long(K, size-1, c_ints); - } else { - return -1; - } - } else { - return -1; - } - } else { - return -1; - } - } else { - return -1; - } - - return 0; -} - -static PyObject* -UPolynomial_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - if (!PyUPolynomial_CHECK(other) && !PyLong_Check(other)) { - //IAM: Surely we can be braver here? - // if op == Py_EQ we could return Py_False - // if op == Py_NE we could return Py_True - // I am sure this holds for other versions of: - // _cmp AND _richcompare in this codebase. - result = Py_NotImplemented; - } else { - lp_upolynomial_t* self_p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* other_p = 0; - if (PyUPolynomial_CHECK(other)) { - other_p = ((UPolynomialObject*) other)->p; - } else { - long c = PyLong_AsLong(other); - const lp_int_ring_t* K = lp_upolynomial_ring(self_p); - other_p = lp_upolynomial_construct_from_long(K, 0, &c); - } - - int cmp = lp_upolynomial_cmp(self_p, other_p); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - } - - if (PyLong_Check(other)) { - lp_upolynomial_delete(other_p); - } - } - - Py_INCREF(result); - return result; -} - -static PyObject* -UPolynomial_degree(PyObject* self) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - return PyLong_FromLong(lp_upolynomial_degree(p->p)); - } else { - Py_RETURN_NONE; - } -} - -static PyObject* -UPolynomial_coefficients(PyObject* self) { - size_t i; - - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - size_t size = lp_upolynomial_degree(p) + 1; - - lp_integer_t coefficients[size]; - for (i = 0; i < size; ++ i) { - lp_integer_construct_from_int(lp_Z, coefficients + i, 0); - } - - lp_upolynomial_unpack(p, coefficients); - - PyObject* list = PyList_New(size); - - for (i = 0; i < size; ++ i) { - PyObject* c = integer_to_PyLong(coefficients + i); - PyList_SetItem(list, i, c); - lp_integer_destruct(coefficients + i); - } - - return list; -} - -static PyObject* -UPolynomial_ring(PyObject* self) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - lp_int_ring_t* K = (lp_int_ring_t*) lp_upolynomial_ring(p->p); - lp_int_ring_attach(K); - return PyCoefficientRing_create(K); - } else { - Py_RETURN_NONE; - } -} - -static PyObject* -UPolynomial_to_ring(PyObject* self, PyObject* args) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - // Get the ring argument - if (PyTuple_Size(args) == 1) { - // Get the ring - PyObject* arg = PyTuple_GetItem(args, 0); - if (PyCoefficientRing_CHECK(arg)) { - CoefficientRing* K = (CoefficientRing*)arg; - lp_upolynomial_t* p_K = lp_upolynomial_construct_copy_K(K->K, p->p); - return PyUPolynomial_create(p_K); - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject* UPolynomial_str(PyObject* self) { - UPolynomialObject* p = (UPolynomialObject*) self; - if (p) { - char* p_str = lp_upolynomial_to_string(p->p); - PyObject* str = PyUnicode_FromString(p_str); - free(p_str); - return str; - } else { - Py_RETURN_NONE; - } -} - -// Add other integer -static PyObject* -UPolynomialObject_add_number(PyObject* self, PyObject* other) { - UPolynomialObject* p1 = (UPolynomialObject*) self; - lp_integer_t c; - const lp_int_ring_t* K = lp_upolynomial_ring(p1->p); - PyLong_or_Int_to_integer(other, K, &c); - lp_upolynomial_t* c_p = lp_upolynomial_construct(K, 0, &c); - lp_upolynomial_t* sum = lp_upolynomial_add(p1->p, c_p); - lp_upolynomial_delete(c_p); - lp_integer_destruct(&c); - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_add(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return UPolynomialObject_add_number(self, other); - } - if (PyLong_or_Int_Check(self)) { - return UPolynomialObject_add_number(other, self); - } - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Add the polynomials - lp_upolynomial_t* sum = lp_upolynomial_add(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_sub_int(PyObject* self, PyObject* other, int negate) { - UPolynomialObject* p1 = (UPolynomialObject*) self; - lp_integer_t c; - const lp_int_ring_t* K = lp_upolynomial_ring(p1->p); - PyLong_or_Int_to_integer(other, K, &c); - lp_upolynomial_t* c_p = lp_upolynomial_construct(K, 0, &c); - lp_upolynomial_t* sub = - negate ? lp_upolynomial_sub(c_p, p1->p) : lp_upolynomial_sub(p1->p, c_p); - lp_upolynomial_delete(c_p); - lp_integer_destruct(&c); - return PyUPolynomial_create(sub); -} - -static PyObject* -UPolynomialObject_sub(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return UPolynomialObject_sub_int(self, other, 0); - } - if (PyLong_or_Int_Check(self)) { - return UPolynomialObject_sub_int(other, self, 1); - } - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Add the polynomials - lp_upolynomial_t* sum = lp_upolynomial_sub(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(sum); -} - -// Multiply other integer -static PyObject* -UPolynomialObject_mul_int(PyObject* self, PyObject* other) { - UPolynomialObject* p1 = (UPolynomialObject*) self; - lp_integer_t c; - PyLong_or_Int_to_integer(other, lp_upolynomial_ring(p1->p), &c); - lp_upolynomial_t* sum = lp_upolynomial_mul_c(p1->p, &c); - lp_integer_destruct(&c); - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_mul(PyObject* self, PyObject* other) { - // Integer multiplication - if (PyLong_or_Int_Check(other)) { - return UPolynomialObject_mul_int(self, other); - } - if (PyLong_or_Int_Check(self)) { - return UPolynomialObject_mul_int(other, self); - } - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) other; - // Add the polynomials - lp_upolynomial_t* sum = lp_upolynomial_mul(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(sum); -} - -static PyObject* -UPolynomialObject_div(PyObject* self, PyObject* args) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) args; - // Divide the polynomials - lp_upolynomial_t* div = lp_upolynomial_div_exact(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(div); -} - -static PyObject* -UPolynomialObject_rem(PyObject* self, PyObject* args) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) args; - // Divide the polynomials - lp_upolynomial_t* rem = lp_upolynomial_rem_exact(p1->p, p2->p); - // Return the result - return PyUPolynomial_create(rem); -} - -static PyObject* -UPolynomialObject_divmod(PyObject* self, PyObject* args) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyUPolynomial_CHECK(args)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p1 = (UPolynomialObject*) self; - UPolynomialObject* p2 = (UPolynomialObject*) args; - // To store div, rem - lp_upolynomial_t* div = 0; - lp_upolynomial_t* rem = 0; - // Divide the polynomials - lp_upolynomial_div_rem_exact(p1->p, p2->p, &div, &rem); - // Return the result - PyObject* pair = PyTuple_New(2); - PyObject* divObj = PyUPolynomial_create(div); - PyObject* remObj = PyUPolynomial_create(rem); - Py_INCREF(divObj); - Py_INCREF(remObj); - PyTuple_SetItem(pair, 0, divObj); - PyTuple_SetItem(pair, 1, remObj); - return pair; -} - -// object.__neg__(self) -static PyObject* -UPolynomialObject_neg(PyObject* self) { - // Check arguments - if (!PyUPolynomial_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Add the polynomials - lp_integer_t c; - lp_integer_construct_from_int(lp_upolynomial_ring(p->p), &c, -1); - lp_upolynomial_t* neg = lp_upolynomial_mul_c(p->p, &c); - lp_integer_destruct(&c); - // Return the result - return PyUPolynomial_create(neg); -} - -static PyObject* -UPolynomialObject_pow(PyObject* self, PyObject* other) { - // Check arguments - if (!PyUPolynomial_CHECK(self) || !PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - long pow = PyLong_AsLong(other); - // Power the polynomial - lp_upolynomial_t* p_pow = lp_upolynomial_pow(p->p, pow); - // Return the result - return PyUPolynomial_create(p_pow); -} - -static int -UPolynomialObject_nonzero(PyObject* self) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Return the result - return !lp_upolynomial_is_zero(p->p); -} - -static PyObject* -UPolynomial_gcd(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* arg = PyTuple_GetItem(args, 0); - if (PyUPolynomial_CHECK(arg)) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* q = ((UPolynomialObject*) arg)->p; - lp_upolynomial_t* gcd = lp_upolynomial_gcd(p, q); - return PyUPolynomial_create(gcd); - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject* -UPolynomial_extended_gcd(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* arg = PyTuple_GetItem(args, 0); - if (PyUPolynomial_CHECK(arg)) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* q = ((UPolynomialObject*) arg)->p; - lp_upolynomial_t* u = 0; - lp_upolynomial_t* v = 0; - lp_upolynomial_t* gcd = lp_upolynomial_extended_gcd(p, q, &u, &v); - - PyObject* t = PyTuple_New(3); - PyObject* t0 = PyUPolynomial_create(gcd); - PyObject* t1 = PyUPolynomial_create(u); - PyObject* t2 = PyUPolynomial_create(v); - Py_INCREF(t0); - Py_INCREF(t1); - Py_INCREF(t2); - PyTuple_SetItem(t, 0, t0); - PyTuple_SetItem(t, 1, t1); - PyTuple_SetItem(t, 2, t2); - return t; - } else { - Py_RETURN_NONE; - } - } else { - Py_RETURN_NONE; - } -} - -static PyObject* factors_to_PyList(lp_upolynomial_factors_t* factors) { - // Construct the result - size_t size = lp_upolynomial_factors_size(factors); - PyObject* factors_list = PyList_New(size + 1); - - // Copy the constant - PyObject* constant = integer_to_PyLong(lp_upolynomial_factors_get_constant(factors)); - PyList_SetItem(factors_list, 0, constant); // Steals the reference - - // Copy over the factors - size_t i; - for (i = 0; i < size; ++ i) { - size_t degree; - PyObject* p_i = PyUPolynomial_create(lp_upolynomial_factors_get_factor(factors, i, °ree)); - Py_INCREF(p_i); - PyObject* d = PyLong_FromSize_t(degree); - PyObject* pair = PyTuple_New(2); - PyTuple_SetItem(pair, 0, p_i); - PyTuple_SetItem(pair, 1, d); - PyList_SetItem(factors_list, i + 1, pair); - } - - // Return the list - return factors_list; -} - -static PyObject* -UPolynomial_factor(PyObject* self) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Factor - lp_upolynomial_factors_t* factors = lp_upolynomial_factor(p->p); - // Create the list - PyObject* factors_list = factors_to_PyList(factors); - // Get rid of the factors (not the polynomials) - lp_upolynomial_factors_destruct(factors, 0); - // Return the list - return factors_list; -} - -static PyObject* -UPolynomial_factor_square_free(PyObject* self) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - // Factor - lp_upolynomial_factors_t* factors = lp_upolynomial_factor_square_free(p->p); - // Create the list - PyObject* factors_list = factors_to_PyList(factors); - // Get rid of the factors (not the polynomials) - lp_upolynomial_factors_destruct(factors, 0); - // Return the list - return factors_list; -} - -static PyObject* -UPolynomial_roots_count(PyObject* self, PyObject* args) { - // Get arguments - UPolynomialObject* p = (UPolynomialObject*) self; - - int roots = 0; - - if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { - PyObject* a = PyTuple_GetItem(args, 0); - PyObject* b = PyTuple_GetItem(args, 1); - - // Ends of the interval - lp_dyadic_rational_t a_rat, b_rat; - - if (PyLong_or_Int_Check(a)) { - lp_integer_t a_int; - PyLong_or_Int_to_integer(a, lp_Z, &a_int); - lp_dyadic_rational_construct_from_integer(&a_rat, &a_int); - lp_integer_destruct(&a_int); - } else if (PyFloat_Check(a)) { - PyFloat_to_dyadic_rational(a, &a_rat); - } else { - Py_RETURN_NONE; - } - - if (PyLong_or_Int_Check(b)) { - lp_integer_t b_int; - PyLong_or_Int_to_integer(b, lp_Z, &b_int); - lp_dyadic_rational_construct_from_integer(&b_rat, &b_int); - lp_integer_destruct(&b_int); - } else if (PyFloat_Check(b)) { - PyFloat_to_dyadic_rational(b, &b_rat); - } else { - lp_dyadic_rational_destruct(&a_rat); - Py_RETURN_NONE; - } - - // The interval - lp_rational_interval_t ab; - lp_rational_interval_construct_from_dyadic(&ab, &a_rat, 1, &b_rat, 1); - - // Count - roots = lp_upolynomial_roots_count(p->p, &ab); - - // Remove the temporaries - lp_rational_interval_destruct(&ab); - lp_dyadic_rational_destruct(&a_rat); - lp_dyadic_rational_destruct(&b_rat); - - } else if (PyTuple_Size(args) == 0) { - // count in (-inf, inf) - roots = lp_upolynomial_roots_count(p->p, 0); - } else { - Py_RETURN_NONE; - } - - return PyLong_FromLong(roots); -} - -static PyObject* -UPolynomial_roots_isolate(PyObject* self) { - - // Get the polynomial - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - - // The isolating intervals - size_t roots_size = lp_upolynomial_degree(p)+1; - lp_algebraic_number_t* roots = malloc(sizeof(lp_algebraic_number_t)*roots_size); - - // Isolate the intervals (up to 2^precision) - lp_upolynomial_roots_isolate(p, roots, &roots_size); - - // Generate a list of floats - PyObject* list = PyList_New(roots_size); - - size_t i; - for (i = 0; i < roots_size; ++ i) { - PyObject* c = PyAlgebraicNumber_create(&roots[i]); - PyList_SetItem(list, i, c); - } - - // Get rid of the temporaries - for (i = 0; i < roots_size; ++ i) { - lp_algebraic_number_destruct(roots + i); - } - free(roots); - - // This is the list - return list; -} - -static PyObject* -UPolynomial_derivative(PyObject* self) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t* p_derivative = lp_upolynomial_derivative(p); - return PyUPolynomial_create(p_derivative); -} - -static PyObject* upolynomials_to_PyList(lp_upolynomial_t** list, size_t size) { - // Construct the result - PyObject* pylist = PyList_New(size); - - // Copy over the polynomials - size_t i; - for (i = 0; i < size; ++ i) { - PyObject* pylist_i = PyUPolynomial_create(list[i]); - Py_INCREF(pylist_i); - PyList_SetItem(pylist, i, pylist_i); - } - - // Return the list - return pylist; -} - - -static PyObject* -UPolynomial_sturm_sequence(PyObject* self) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_upolynomial_t** S; - size_t S_size; - lp_upolynomial_sturm_sequence(p, &S, &S_size); - PyObject* result = upolynomials_to_PyList(S, S_size); - free(S); - return result; -} - -static PyObject* integer_list_to_PyList(lp_integer_t *list, size_t size) { - // Construct the result - PyObject* pylist = PyList_New(size); - - // Copy over the integers - size_t i; - for (i = 0; i < size; ++ i) { - PyObject* pylist_i = integer_to_PyLong(&list[i]); - Py_INCREF(pylist_i); - PyList_SetItem(pylist, i, pylist_i); - } - - // Return the list - return pylist; -} - -static PyObject* -UPolynomial_roots_find_Zp(PyObject* self) { - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_integer_t* roots; - size_t roots_size; - lp_upolynomial_roots_find_Zp(p, &roots, &roots_size); - PyObject* result = integer_list_to_PyList(roots, roots_size); - for (size_t i = 0; i < roots_size; ++i) { - lp_integer_destruct(&roots[i]); - } - free(roots); - return result; -} - -static PyObject* -UPolynomial_evaluate(PyObject* self, PyObject* args) { - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* x = PyTuple_GetItem(args, 0); - // Ends of the interval - lp_dyadic_rational_t x_rat; - if (PyLong_or_Int_Check(x)) { - lp_integer_t x_int; - PyLong_or_Int_to_integer(x, lp_Z, &x_int); - lp_dyadic_rational_construct_from_integer(&x_rat, &x_int); - lp_integer_destruct(&x_int); - } else if (PyFloat_Check(x)) { - PyFloat_to_dyadic_rational(x, &x_rat); - } else { - Py_RETURN_NONE; - } - - lp_upolynomial_t* p = ((UPolynomialObject*) self)->p; - lp_dyadic_rational_t value; - lp_dyadic_rational_construct(&value); - lp_upolynomial_evaluate_at_dyadic_rational(p, &x_rat, &value); - PyObject* result = dyadic_rational_to_PyFloat(&value); - lp_dyadic_rational_destruct(&x_rat); - lp_dyadic_rational_destruct(&value); - return result; - } else { - Py_RETURN_NONE; - } - -} diff --git a/python/polypyValue.c b/python/polypyValue.c index e67d7892..d13bba20 100644 --- a/python/polypyValue.c +++ b/python/polypyValue.c @@ -17,12 +17,475 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" -#if PY_MAJOR_VERSION >= 3 -#include "polypyValue3.c" -#else -#include "polypyValue2.c" -#endif +#include "polypyValue.h" +#include "utils.h" +#include "polypyAlgebraicNumber.h" +#include +#include + +static void +Value_dealloc(Value* self); + +static PyObject* +Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +Value_init(Value* self, PyObject* args); + +static PyObject* +Value_to_double(PyObject* self); + +static PyObject* +Value_richcompare(PyObject* self, PyObject* other, int op); + +static PyObject* +Value_str(PyObject* self); + +static Py_hash_t +Value_hash(PyObject* self); + +static PyObject* +Value_get_value_between(PyObject* self, PyObject* args); + +static PyObject* +Value_add(PyObject* self, PyObject* other); + +static PyObject* +Value_neg(PyObject* self); + +static PyObject* +Value_sub(PyObject* self, PyObject* other); + +static PyObject* +Value_mul(PyObject* self, PyObject* other); + +static PyObject* +Value_div(PyObject* self, PyObject* other); + +static PyObject* +Value_pow(PyObject* self, PyObject* other); + +static PyObject* +Value_long(PyObject* self); + +static PyObject* +Value_float(PyObject* self); + +PyMethodDef Value_methods[] = { + {"to_double", (PyCFunction)Value_to_double, METH_NOARGS, "Returns the approximation of the value"}, + {"get_value_between", (PyCFunction)Value_get_value_between, METH_VARARGS, "Returns a value between this and given value"}, + {NULL} /* Sentinel */ +}; + +PyNumberMethods Value_NumberMethods = { + Value_add, // binaryfunc nb_add; + Value_sub, // binaryfunc nb_subtract; + Value_mul, // binaryfunc nb_multiply; + NULL, // binaryfunc nb_remainder; + NULL, // binaryfunc nb_divmod; + (ternaryfunc)Value_pow, // ternaryfunc nb_power; + Value_neg, // unaryfunc nb_negative; + NULL, // unaryfunc nb_positive; + NULL, // unaryfunc nb_absolute; + NULL, // inquiry nb_bool; + NULL, // unaryfunc nb_invert; + NULL, // binaryfunc nb_lshift; + NULL, // binaryfunc nb_rshift; + NULL, // binaryfunc nb_and; + NULL, // binaryfunc nb_xor; + NULL, // binaryfunc nb_or; + Value_long, // unaryfunc nb_int; + NULL, // void *nb_reserved; + Value_float, // unaryfunc nb_float; + NULL, // binaryfunc nb_inplace_add; + NULL, // binaryfunc nb_inplace_subtract; + NULL, // binaryfunc nb_inplace_multiply; + NULL, // binaryfunc nb_inplace_remainder; + NULL, // ternaryfunc nb_inplace_power; + NULL, // binaryfunc nb_inplace_lshift; + NULL, // binaryfunc nb_inplace_rshift; + NULL, // binaryfunc nb_inplace_and; + NULL, // binaryfunc nb_inplace_xor; + NULL, // binaryfunc nb_inplace_or; + NULL, // binaryfunc nb_floor_divide; + Value_div, // binaryfunc nb_true_divide; + NULL, // binaryfunc nb_inplace_floor_divide; + NULL, // binaryfunc nb_inplace_true_divide; + NULL, // unaryfunc nb_index; + NULL, // binaryfunc nb_matrix_multiply; + NULL, // binaryfunc nb_inplace_matrix_multiply; +}; + +PyTypeObject ValueType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.Value", // const char *tp_name; + sizeof(Value), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)Value_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + Value_str, // reprfunc tp_repr; + &Value_NumberMethods, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + &Value_hash, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + Value_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Values of different kinds", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + Value_richcompare, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + Value_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)Value_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + Value_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +static void +Value_dealloc(Value* self) +{ + lp_value_destruct(&self->v); + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +PyObject* +PyValue_create(const lp_value_t* v) { + Value *self = (Value*)ValueType.tp_alloc(&ValueType, 0); + if (self != NULL) { + if (v) { + lp_value_construct_copy(&self->v, v); + } else { + lp_value_construct_zero(&self->v); + } + } + return (PyObject *)self; +} + +static PyObject* +Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyValue_create(NULL); +} + +/** Construct a value from given number. */ +static int +Value_init(Value* self, PyObject* args) +{ + if (PyTuple_Check(args)) { + if (PyTuple_Size(args) == 0) { + lp_value_construct_zero(&self->v); + } else if (PyTuple_Size(args) == 1) { + PyObject* v = PyTuple_GetItem(args, 0); + if (PyLong_Check(v)) { + long v_int = PyLong_AsLong(v); + lp_value_construct_int(&self->v, v_int); + } else if (PyAlgebraicNumber_CHECK(v)) { + AlgebraicNumber* v_alg = (AlgebraicNumber*) v; + lp_value_construct(&self->v, LP_VALUE_ALGEBRAIC, &v_alg->a); + } else { + return -1; + } + } else { + return -1; + } + } else { + return -1; + } + + // All fine, initialized + return 0; +} + +static PyObject* +Value_to_double(PyObject* self) { + + Value* a = (Value*) self; + + double value = 0; + + switch (a->v.type) { + case LP_VALUE_NONE: + assert(0); + break; + case LP_VALUE_INTEGER: + value = lp_integer_to_int(&a->v.value.z); + break; + case LP_VALUE_DYADIC_RATIONAL: + value = lp_dyadic_rational_to_double(&a->v.value.dy_q); + break; + case LP_VALUE_RATIONAL: + value = lp_rational_to_double(&a->v.value.q); + break; + case LP_VALUE_ALGEBRAIC: + value = lp_algebraic_number_to_double(&a->v.value.a); + break; + case LP_VALUE_PLUS_INFINITY: + value = INFINITY; + break; + case LP_VALUE_MINUS_INFINITY: + value = -INFINITY; + break; + } + + return PyFloat_FromDouble(value); +} + +static PyObject* +Value_richcompare(PyObject* self, PyObject* other, int op) { + PyObject *result = NULL; + + if (!PyValue_CHECK(other)) { + result = Py_NotImplemented; + } else { + lp_value_t* self_v = &((Value*) self)->v; + lp_value_t* other_v = &((Value*) other)->v; + int cmp = lp_value_cmp(self_v, other_v); + + switch (op) { + case Py_LT: + result = cmp < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = cmp <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = cmp == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = cmp != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = cmp > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = cmp >= 0 ? Py_True : Py_False; + break; + default: + assert(0); + } + } + + Py_INCREF(result); + return result; +} + +static PyObject* Value_str(PyObject* self) { + Value* v = (Value*) self; + char* cstr = lp_value_to_string(&v->v); + PyObject* pystr = PyUnicode_FromString(cstr); + free(cstr); + return pystr; +} + +static Py_hash_t +Value_hash(PyObject* self) { + Value* v = (Value*) self; + Py_hash_t hash = lp_value_hash(&v->v); + if (hash == -1) { + // value -1 should not be returned as a normal return value + hash = 0; + } + return hash; +} + +static PyObject* +Value_get_value_between(PyObject* self, PyObject* args) { + // self is always a polynomial + Value* v1 = (Value*) self; + if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { + PyErr_SetString(PyExc_RuntimeError, "get_value_between(): need one argument."); + return NULL; + } + PyObject* other = PyTuple_GetItem(args, 0); + + // other should be a value + if (!PyValue_CHECK(other)) { + PyErr_SetString(PyExc_RuntimeError, "get_value_between(): argument not a value."); + return NULL; + } + Value* v2 = (Value*) other; + + // compare the values (they should be different) + if (v1->v.type == LP_VALUE_NONE || v2->v.type == LP_VALUE_NONE) { + PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should not be null."); + return NULL; + } + if (lp_value_cmp(&v1->v, &v2->v) == 0) { + PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should be different."); + return NULL; + } + + lp_value_t m; + lp_value_construct_none(&m); + lp_value_get_value_between(&v1->v, 1, &v2->v, 1, &m); + PyObject* result = PyValue_create(&m); + lp_value_destruct(&m); + + return result; +} + +static PyObject* +Value_add(PyObject* self, PyObject* other) { + if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Value* v1 = (Value*) self; + Value* v2 = (Value*) other; + + lp_value_t add; + lp_value_construct_none(&add); + lp_value_add(&add, &v1->v, &v2->v); + PyObject* result = PyValue_create(&add); + lp_value_destruct(&add); + + return result; +} + +static PyObject* +Value_neg(PyObject* self) { + if (!PyValue_CHECK(self)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Value* v = (Value*) self; + + lp_value_t neg; + lp_value_construct_none(&neg); + lp_value_neg(&neg, &v->v); + PyObject* result = PyValue_create(&neg); + lp_value_destruct(&neg); + + return result; +} + +static PyObject* +Value_sub(PyObject* self, PyObject* other) { + if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Value* v1 = (Value*) self; + Value* v2 = (Value*) other; + + lp_value_t sub; + lp_value_construct_none(&sub); + lp_value_sub(&sub, &v1->v, &v2->v); + PyObject* result = PyValue_create(&sub); + lp_value_destruct(&sub); + + return result; +} + +static PyObject* +Value_mul(PyObject* self, PyObject* other) { + if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Value* v1 = (Value*) self; + Value* v2 = (Value*) other; + + lp_value_t mul; + lp_value_construct_none(&mul); + lp_value_mul(&mul, &v1->v, &v2->v); + PyObject* result = PyValue_create(&mul); + lp_value_destruct(&mul); + + return result; +} + +static PyObject* +Value_div(PyObject* self, PyObject* other) { + if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Value* v1 = (Value*) self; + Value* v2 = (Value*) other; + + lp_value_t div; + lp_value_construct_none(&div); + lp_value_div(&div, &v1->v, &v2->v); + PyObject* result = PyValue_create(&div); + lp_value_destruct(&div); + + return result; +} + + +static PyObject* +Value_pow(PyObject* self, PyObject* other) { + if (!PyValue_CHECK(self) || !PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Value* v = (Value*) self; + long n = PyLong_AsLong(other); + + lp_value_t mul; + lp_value_construct_none(&mul); + lp_value_pow(&mul, &v->v, n); + PyObject* result = PyValue_create(&mul); + lp_value_destruct(&mul); + + return result; +} + +// Returns the o converted to a long integer object on success, or NULL on +// failure. This is the equivalent of the Python 3 expression int(o). +// Return value: New reference. +static PyObject* +Value_long(PyObject* self) { + Value* value_obj = (Value*) self; + lp_integer_t int_cast; + lp_integer_construct(&int_cast); + lp_value_floor(&value_obj->v, &int_cast); + PyObject* py_int_cast = integer_to_PyLong(&int_cast); + lp_integer_destruct(&int_cast); + return py_int_cast; +} + +// Returns the o converted to a float object on success, or NULL on failure. +// This is the equivalent of the Python expression float(o). +// Return value: New reference. +static PyObject* +Value_float(PyObject* self) { + Value* value_obj = (Value*) self; + double value = lp_value_to_double(&value_obj->v); + return PyFloat_FromDouble(value); +} diff --git a/python/polypyValue.h b/python/polypyValue.h index fca471f8..d3ddd6f4 100644 --- a/python/polypyValue.h +++ b/python/polypyValue.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "value.h" diff --git a/python/polypyValue2.c b/python/polypyValue2.c deleted file mode 100644 index 7f82a456..00000000 --- a/python/polypyValue2.c +++ /dev/null @@ -1,525 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyValue.h" -#include "utils.h" -#include "polypyAlgebraicNumber.h" - -#include -#include - -static void -Value_dealloc(Value* self); - -static PyObject* -Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Value_init(Value* self, PyObject* args); - -static PyObject* -Value_to_double(PyObject* self); - -static int -Value_cmp(PyObject* self, PyObject* args); - -static PyObject* -Value_richcompare(PyObject* self, PyObject* other, int op); - -static PyObject* -Value_str(PyObject* self); - -static long -Value_hash(PyObject* self); - -static PyObject* -Value_get_value_between(PyObject* self, PyObject* args); - -static PyObject* -Value_add(PyObject* self, PyObject* args); - -static PyObject* -Value_neg(PyObject* self); - -static PyObject* -Value_sub(PyObject* self, PyObject* args); - -static PyObject* -Value_mul(PyObject* self, PyObject* args); - -static PyObject* -Value_div(PyObject* self, PyObject* args); - -static PyObject* -Value_pow(PyObject* self, PyObject* args); - -static PyObject* -Value_int(PyObject* self); - -static PyObject* -Value_long(PyObject* self); - -static PyObject* -Value_float(PyObject* self); - -PyMethodDef Value_methods[] = { - {"to_double", (PyCFunction)Value_to_double, METH_NOARGS, "Returns the approximation of the value"}, - {"get_value_between", (PyCFunction)Value_get_value_between, METH_VARARGS, "Returns a value between this and given value"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods Value_NumberMethods = { - Value_add, // binaryfunc nb_add; - Value_sub, // binaryfunc nb_subtract; - Value_mul, // binaryfunc nb_multiply; - Value_div, // binaryfunc nb_divide; - 0, // binaryfunc nb_remainder; - 0, // binaryfunc nb_divmod; - (ternaryfunc)Value_pow, // ternaryfunc nb_power; - Value_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - 0, // inquiry nb_nonzero; /* Used by PyObject_IsTrue */ - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // coercion nb_coerce; /* Used by the coerce() function */ - Value_int, // unaryfunc nb_int; - Value_long, // unaryfunc nb_long; - Value_float, // unaryfunc nb_float; - 0, // unaryfunc nb_oct; - 0, // unaryfunc nb_hex; - - /* Added in release 2.0 */ - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_divide; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - - /* Added in release 2.2 */ - 0, // binaryfunc nb_floor_divide; - 0, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - - /* Added in release 2.5 */ - 0 // unaryfunc nb_index; -}; - -PyTypeObject ValueType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.Value", /*tp_name*/ - sizeof(Value), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Value_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - Value_cmp, /*tp_compare*/ - Value_str, /*tp_repr*/ - &Value_NumberMethods, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - &Value_hash, /*tp_hash */ - 0, /*tp_call*/ - Value_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Values of different kinds", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - Value_richcompare,/* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Value_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Value_init,/* tp_init */ - 0, /* tp_alloc */ - Value_new, /* tp_new */ -}; - -static void -Value_dealloc(Value* self) -{ - lp_value_destruct(&self->v); - self->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyValue_create(const lp_value_t* v) { - Value *self; - self = (Value*)ValueType.tp_alloc(&ValueType, 0); - if (self != NULL) { - if (v) { - lp_value_construct_copy(&self->v, v); - } else { - lp_value_construct_zero(&self->v); - } - } - return (PyObject *)self; -} - -static PyObject* -Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyValue_create(0); -} - -/** Construct a value from given number (integer, long or algebraic. */ -static int -Value_init(Value* self, PyObject* args) -{ - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 0) { - lp_value_construct_zero(&self->v); - } else if (PyTuple_Size(args) == 1) { - PyObject* v = PyTuple_GetItem(args, 0); - if (PyInt_Check(v)) { - long v_int = PyInt_AsLong(v); - lp_value_construct_int(&self->v, v_int); - } else if (PyAlgebraicNumber_CHECK(v)) { - AlgebraicNumber* v_alg = (AlgebraicNumber*) v; - lp_value_construct(&self->v, LP_VALUE_ALGEBRAIC, &v_alg->a); - } else { - return -1; - } - } else { - return -1; - } - } else { - return -1; - } - - // All fine, initialized - return 0; -} - -static PyObject* -Value_to_double(PyObject* self) { - - Value* a = (Value*) self; - - double value = 0; - - switch (a->v.type) { - case LP_VALUE_NONE: - assert(0); - break; - case LP_VALUE_INTEGER: - value = lp_integer_to_int(&a->v.value.z); - break; - case LP_VALUE_DYADIC_RATIONAL: - value = lp_dyadic_rational_to_double(&a->v.value.dy_q); - break; - case LP_VALUE_RATIONAL: - value = lp_rational_to_double(&a->v.value.q); - break; - case LP_VALUE_ALGEBRAIC: - value = lp_algebraic_number_to_double(&a->v.value.a); - break; - case LP_VALUE_PLUS_INFINITY: - value = INFINITY; - break; - case LP_VALUE_MINUS_INFINITY: - value = -INFINITY; - break; - } - - return PyFloat_FromDouble(value); -} - -static int -Value_cmp(PyObject* self, PyObject* other) { - // Check arguments - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - // should return -1 and set an exception condition when an error occurred - return -1; - } - // Get arguments - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - // Compare - return lp_value_cmp(&v1->v, &v2->v); -} - -static PyObject* -Value_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - if (!PyValue_CHECK(other)) { - result = Py_NotImplemented; - } else { - lp_value_t* self_v = &((Value*) self)->v; - lp_value_t* other_v = &((Value*) other)->v; - int cmp = lp_value_cmp(self_v, other_v); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - default: - assert(0); - } - } - - Py_INCREF(result); - return result; -} - -static PyObject* Value_str(PyObject* self) { - Value* v = (Value*) self; - char* cstr = lp_value_to_string(&v->v); - PyObject* pystr = PyString_FromString(cstr); - free(cstr); - return pystr; -} - -static long -Value_hash(PyObject* self) { - Value* v = (Value*) self; - long hash = lp_value_hash(&v->v); - if (hash == -1) { - // value -1 should not be returned as a normal return value - hash = 0; - } - return hash; -} - -static PyObject* -Value_get_value_between(PyObject* self, PyObject* args) { - // self is always a polynomial - Value* v1 = (Value*) self; - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): need one argument."); - return NULL; - } - PyObject* other = PyTuple_GetItem(args, 0); - - // other should be a value - if (!PyValue_CHECK(other)) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): argument not a value."); - return NULL; - } - Value* v2 = (Value*) other; - - // compare the values (they should be different) - if (v1->v.type == LP_VALUE_NONE || v2->v.type == LP_VALUE_NONE) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should not be null."); - return NULL; - } - if (lp_value_cmp(&v1->v, &v2->v) == 0) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should be different."); - return NULL; - } - - lp_value_t m; - lp_value_construct_none(&m); - lp_value_get_value_between(&v1->v, 1, &v2->v, 1, &m); - PyObject* result = PyValue_create(&m); - lp_value_destruct(&m); - - return result; -} - -static PyObject* -Value_add(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t add; - lp_value_construct_none(&add); - lp_value_add(&add, &v1->v, &v2->v); - PyObject* result = PyValue_create(&add); - lp_value_destruct(&add); - - return result; -} - -static PyObject* -Value_neg(PyObject* self) { - if (!PyValue_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v = (Value*) self; - - lp_value_t neg; - lp_value_construct_none(&neg); - lp_value_neg(&neg, &v->v); - PyObject* result = PyValue_create(&neg); - lp_value_destruct(&neg); - - return result; -} - -static PyObject* -Value_sub(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t sub; - lp_value_construct_none(&sub); - lp_value_sub(&sub, &v1->v, &v2->v); - PyObject* result = PyValue_create(&sub); - lp_value_destruct(&sub); - - return result; -} - -static PyObject* -Value_mul(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t mul; - lp_value_construct_none(&mul); - lp_value_mul(&mul, &v1->v, &v2->v); - PyObject* result = PyValue_create(&mul); - lp_value_destruct(&mul); - - return result; -} - -static PyObject* -Value_div(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t div; - lp_value_construct_none(&div); - lp_value_div(&div, &v1->v, &v2->v); - PyObject* result = PyValue_create(&div); - lp_value_destruct(&div); - - return result; -} - - -static PyObject* -Value_pow(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyInt_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v = (Value*) self; - long n = PyInt_AsLong(other); - - lp_value_t mul; - lp_value_construct_none(&mul); - lp_value_pow(&mul, &v->v, n); - PyObject* result = PyValue_create(&mul); - lp_value_destruct(&mul); - - return result; -} - -// Returns the o converted to an integer object on success, or NULL on failure. -// If the argument is outside the integer range a long object will be returned -// instead. This is the equivalent of the Python expression int(o). -// Return value: New reference. -static PyObject* -Value_int(PyObject* self) { - Value* value_obj = (Value*) self; - lp_integer_t int_cast; - lp_integer_construct(&int_cast); - lp_value_floor(&value_obj->v, &int_cast); - PyObject* py_int_cast = integer_to_PyInt(&int_cast); - lp_integer_destruct(&int_cast); - return py_int_cast; -} - -// Returns the o converted to a long integer object on success, or NULL on -// failure. This is the equivalent of the Python expression long(o). -// Return value: New reference. -static PyObject* -Value_long(PyObject* self) { - Value* value_obj = (Value*) self; - lp_integer_t int_cast; - lp_integer_construct(&int_cast); - lp_value_floor(&value_obj->v, &int_cast); - PyObject* py_int_cast = integer_to_PyLong(&int_cast); - lp_integer_destruct(&int_cast); - return py_int_cast; -} - -// Returns the o converted to a float object on success, or NULL on failure. -// This is the equivalent of the Python expression float(o). -// Return value: New reference. -static PyObject* -Value_float(PyObject* self) { - Value* value_obj = (Value*) self; - double value = lp_value_to_double(&value_obj->v); - return PyFloat_FromDouble(value); -} diff --git a/python/polypyValue3.c b/python/polypyValue3.c deleted file mode 100644 index 6fccbe71..00000000 --- a/python/polypyValue3.c +++ /dev/null @@ -1,490 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyValue.h" -#include "utils.h" -#include "polypyAlgebraicNumber.h" - -#include -#include - -static void -Value_dealloc(Value* self); - -static PyObject* -Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Value_init(Value* self, PyObject* args); - -static PyObject* -Value_to_double(PyObject* self); - -static PyObject* -Value_richcompare(PyObject* self, PyObject* other, int op); - -static PyObject* -Value_str(PyObject* self); - -static Py_hash_t -Value_hash(PyObject* self); - -static PyObject* -Value_get_value_between(PyObject* self, PyObject* args); - -static PyObject* -Value_add(PyObject* self, PyObject* args); - -static PyObject* -Value_neg(PyObject* self); - -static PyObject* -Value_sub(PyObject* self, PyObject* args); - -static PyObject* -Value_mul(PyObject* self, PyObject* args); - -static PyObject* -Value_div(PyObject* self, PyObject* args); - -static PyObject* -Value_pow(PyObject* self, PyObject* args); - -static PyObject* -Value_long(PyObject* self); - -static PyObject* -Value_float(PyObject* self); - -PyMethodDef Value_methods[] = { - {"to_double", (PyCFunction)Value_to_double, METH_NOARGS, "Returns the approximation of the value"}, - {"get_value_between", (PyCFunction)Value_get_value_between, METH_VARARGS, "Returns a value between this and given value"}, - {NULL} /* Sentinel */ -}; - -PyNumberMethods Value_NumberMethods = { - Value_add, // binaryfunc nb_add; - Value_sub, // binaryfunc nb_subtract; - Value_mul, // binaryfunc nb_multiply; - 0, // binaryfunc nb_remainder; - 0, // binaryfunc nb_divmod; - (ternaryfunc)Value_pow, // ternaryfunc nb_power; - Value_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - 0, // inquiry nb_bool; - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - Value_long, // unaryfunc nb_int; - 0, // void *nb_reserved; - Value_float, // unaryfunc nb_float; - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - 0, // binaryfunc nb_floor_divide; - Value_div, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - 0, // unaryfunc nb_index; - 0, // binaryfunc nb_matrix_multiply; - 0, // binaryfunc nb_inplace_matrix_multiply; -}; - -PyTypeObject ValueType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.Value", // const char *tp_name; - sizeof(Value), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)Value_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - Value_str, // reprfunc tp_repr; - &Value_NumberMethods, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - &Value_hash, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - Value_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Values of different kinds", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - Value_richcompare, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - Value_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)Value_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - Value_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -static void -Value_dealloc(Value* self) -{ - lp_value_destruct(&self->v); - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -PyObject* -PyValue_create(const lp_value_t* v) { - Value *self; - self = (Value*)ValueType.tp_alloc(&ValueType, 0); - if (self != NULL) { - if (v) { - lp_value_construct_copy(&self->v, v); - } else { - lp_value_construct_zero(&self->v); - } - } - return (PyObject *)self; -} - -static PyObject* -Value_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyValue_create(0); -} - -/** Construct a value from given number. */ -static int -Value_init(Value* self, PyObject* args) -{ - if (PyTuple_Check(args)) { - if (PyTuple_Size(args) == 0) { - lp_value_construct_zero(&self->v); - } else if (PyTuple_Size(args) == 1) { - PyObject* v = PyTuple_GetItem(args, 0); - if (PyLong_Check(v)) { - long v_int = PyLong_AsLong(v); - lp_value_construct_int(&self->v, v_int); - } else if (PyAlgebraicNumber_CHECK(v)) { - AlgebraicNumber* v_alg = (AlgebraicNumber*) v; - lp_value_construct(&self->v, LP_VALUE_ALGEBRAIC, &v_alg->a); - } else { - return -1; - } - } else { - return -1; - } - } else { - return -1; - } - - // All fine, initialized - return 0; -} - -static PyObject* -Value_to_double(PyObject* self) { - - Value* a = (Value*) self; - - double value = 0; - - switch (a->v.type) { - case LP_VALUE_NONE: - assert(0); - break; - case LP_VALUE_INTEGER: - value = lp_integer_to_int(&a->v.value.z); - break; - case LP_VALUE_DYADIC_RATIONAL: - value = lp_dyadic_rational_to_double(&a->v.value.dy_q); - break; - case LP_VALUE_RATIONAL: - value = lp_rational_to_double(&a->v.value.q); - break; - case LP_VALUE_ALGEBRAIC: - value = lp_algebraic_number_to_double(&a->v.value.a); - break; - case LP_VALUE_PLUS_INFINITY: - value = INFINITY; - break; - case LP_VALUE_MINUS_INFINITY: - value = -INFINITY; - break; - } - - return PyFloat_FromDouble(value); -} - -static PyObject* -Value_richcompare(PyObject* self, PyObject* other, int op) { - PyObject *result = 0; - - if (!PyValue_CHECK(other)) { - result = Py_NotImplemented; - } else { - lp_value_t* self_v = &((Value*) self)->v; - lp_value_t* other_v = &((Value*) other)->v; - int cmp = lp_value_cmp(self_v, other_v); - - switch (op) { - case Py_LT: - result = cmp < 0 ? Py_True : Py_False; - break; - case Py_LE: - result = cmp <= 0 ? Py_True : Py_False; - break; - case Py_EQ: - result = cmp == 0 ? Py_True : Py_False; - break; - case Py_NE: - result = cmp != 0 ? Py_True : Py_False; - break; - case Py_GT: - result = cmp > 0 ? Py_True : Py_False; - break; - case Py_GE: - result = cmp >= 0 ? Py_True : Py_False; - break; - default: - assert(0); - } - } - - Py_INCREF(result); - return result; -} - -static PyObject* Value_str(PyObject* self) { - Value* v = (Value*) self; - char* cstr = lp_value_to_string(&v->v); - PyObject* pystr = PyUnicode_FromString(cstr); - free(cstr); - return pystr; -} - -static Py_hash_t -Value_hash(PyObject* self) { - Value* v = (Value*) self; - Py_hash_t hash = lp_value_hash(&v->v); - if (hash == -1) { - // value -1 should not be returned as a normal return value - hash = 0; - } - return hash; -} - -static PyObject* -Value_get_value_between(PyObject* self, PyObject* args) { - // self is always a polynomial - Value* v1 = (Value*) self; - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): need one argument."); - return NULL; - } - PyObject* other = PyTuple_GetItem(args, 0); - - // other should be a value - if (!PyValue_CHECK(other)) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): argument not a value."); - return NULL; - } - Value* v2 = (Value*) other; - - // compare the values (they should be different) - if (v1->v.type == LP_VALUE_NONE || v2->v.type == LP_VALUE_NONE) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should not be null."); - return NULL; - } - if (lp_value_cmp(&v1->v, &v2->v) == 0) { - PyErr_SetString(PyExc_RuntimeError, "get_value_between(): values should be different."); - return NULL; - } - - lp_value_t m; - lp_value_construct_none(&m); - lp_value_get_value_between(&v1->v, 1, &v2->v, 1, &m); - PyObject* result = PyValue_create(&m); - lp_value_destruct(&m); - - return result; -} - -static PyObject* -Value_add(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t add; - lp_value_construct_none(&add); - lp_value_add(&add, &v1->v, &v2->v); - PyObject* result = PyValue_create(&add); - lp_value_destruct(&add); - - return result; -} - -static PyObject* -Value_neg(PyObject* self) { - if (!PyValue_CHECK(self)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v = (Value*) self; - - lp_value_t neg; - lp_value_construct_none(&neg); - lp_value_neg(&neg, &v->v); - PyObject* result = PyValue_create(&neg); - lp_value_destruct(&neg); - - return result; -} - -static PyObject* -Value_sub(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t sub; - lp_value_construct_none(&sub); - lp_value_sub(&sub, &v1->v, &v2->v); - PyObject* result = PyValue_create(&sub); - lp_value_destruct(&sub); - - return result; -} - -static PyObject* -Value_mul(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t mul; - lp_value_construct_none(&mul); - lp_value_mul(&mul, &v1->v, &v2->v); - PyObject* result = PyValue_create(&mul); - lp_value_destruct(&mul); - - return result; -} - -static PyObject* -Value_div(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyValue_CHECK(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v1 = (Value*) self; - Value* v2 = (Value*) other; - - lp_value_t div; - lp_value_construct_none(&div); - lp_value_div(&div, &v1->v, &v2->v); - PyObject* result = PyValue_create(&div); - lp_value_destruct(&div); - - return result; -} - - -static PyObject* -Value_pow(PyObject* self, PyObject* other) { - if (!PyValue_CHECK(self) || !PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Value* v = (Value*) self; - long n = PyLong_AsLong(other); - - lp_value_t mul; - lp_value_construct_none(&mul); - lp_value_pow(&mul, &v->v, n); - PyObject* result = PyValue_create(&mul); - lp_value_destruct(&mul); - - return result; -} - -// Returns the o converted to a long integer object on success, or NULL on -// failure. This is the equivalent of the Python 3 expression int(o). -// Return value: New reference. -static PyObject* -Value_long(PyObject* self) { - Value* value_obj = (Value*) self; - lp_integer_t int_cast; - lp_integer_construct(&int_cast); - lp_value_floor(&value_obj->v, &int_cast); - PyObject* py_int_cast = integer_to_PyLong(&int_cast); - lp_integer_destruct(&int_cast); - return py_int_cast; -} - -// Returns the o converted to a float object on success, or NULL on failure. -// This is the equivalent of the Python expression float(o). -// Return value: New reference. -static PyObject* -Value_float(PyObject* self) { - Value* value_obj = (Value*) self; - double value = lp_value_to_double(&value_obj->v); - return PyFloat_FromDouble(value); -} diff --git a/python/polypyVariable.c b/python/polypyVariable.c index 026e904f..e5c93bc0 100644 --- a/python/polypyVariable.c +++ b/python/polypyVariable.c @@ -17,12 +17,507 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include - -#if PY_MAJOR_VERSION >= 3 -#include "polypyVariable3.c" -#else -#include "polypyVariable2.c" -#endif +#include "python.h" + +#include "polypyVariable.h" +#include "polypyInteger.h" +#include "polypyPolynomial.h" +#include "utils.h" + +#include + +/** Default variable database */ +static lp_variable_db_t* default_var_db = NULL; + +void Variable_init_default_db(void) { + if (default_var_db) { + lp_variable_db_detach(default_var_db); + } + default_var_db = lp_variable_db_new(); +} + +lp_variable_db_t* Variable_get_default_db(void) { + if (!default_var_db) { + Variable_init_default_db(); + } + return default_var_db; +} + +static PyObject* +Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +Variable_init(Variable* self, PyObject* args); + +static void +Variable_dealloc(Variable* self); + +static PyObject* +Variable_str(PyObject* self); + +static PyObject* +Variable_repr(PyObject* self); + +static Py_hash_t +Variable_hash(PyObject* self); + +static PyObject * +Variable_richcompare(PyObject *self, PyObject *other, int op); + +PyMethodDef Variable_methods[] = { + {NULL} /* Sentinel */ +}; + +static PyObject* +Variable_add(PyObject* self, PyObject* other); + +static PyObject* +Variable_neg(PyObject* self); + +static PyObject* +Variable_sub(PyObject* self, PyObject* other); + +static PyObject* +Variable_mul(PyObject* self, PyObject* other); + +static PyObject* +Variable_pow(PyObject* self, PyObject* other); + +PyNumberMethods Variable_NumberMethods = { + Variable_add, // binaryfunc nb_add; + Variable_sub, // binaryfunc nb_subtract; + Variable_mul, // binaryfunc nb_multiply; + NULL, // binaryfunc nb_remainder; + NULL, // binaryfunc nb_divmod; + (ternaryfunc)Variable_pow, // ternaryfunc nb_power; + Variable_neg, // unaryfunc nb_negative; + NULL, // unaryfunc nb_positive; + NULL, // unaryfunc nb_absolute; + NULL, // inquiry nb_bool; + NULL, // unaryfunc nb_invert; + NULL, // binaryfunc nb_lshift; + NULL, // binaryfunc nb_rshift; + NULL, // binaryfunc nb_and; + NULL, // binaryfunc nb_xor; + NULL, // binaryfunc nb_or; + NULL, // unaryfunc nb_int; + NULL, // void *nb_reserved; + NULL, // unaryfunc nb_float; + NULL, // binaryfunc nb_inplace_add; + NULL, // binaryfunc nb_inplace_subtract; + NULL, // binaryfunc nb_inplace_multiply; + NULL, // binaryfunc nb_inplace_remainder; + NULL, // ternaryfunc nb_inplace_power; + NULL, // binaryfunc nb_inplace_lshift; + NULL, // binaryfunc nb_inplace_rshift; + NULL, // binaryfunc nb_inplace_and; + NULL, // binaryfunc nb_inplace_xor; + NULL, // binaryfunc nb_inplace_or; + NULL, // binaryfunc nb_floor_divide; + NULL, // binaryfunc nb_true_divide; + NULL, // binaryfunc nb_inplace_floor_divide; + NULL, // binaryfunc nb_inplace_true_divide; + NULL, // unaryfunc nb_index; + NULL, // binaryfunc nb_matrix_multiply; + NULL, // binaryfunc nb_inplace_matrix_multiply; +}; + +PyTypeObject VariableType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.Variable", // const char *tp_name; + sizeof(Variable), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)Variable_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + Variable_repr, // reprfunc tp_repr; + &Variable_NumberMethods, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + Variable_hash, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + Variable_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "Variable objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + Variable_richcompare, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + Variable_methods, // struct PyMethodDef *tp_methods; + NULL, // istruct PyMemberDef *tp_members; + NULL, // istruct PyGetSetDef *tp_getset; + NULL, // istruct _typeobject *tp_base; + NULL, // iPyObject *tp_dict; + NULL, // idescrgetfunc tp_descr_get; + NULL, // idescrsetfunc tp_descr_set; + 0, // iPy_ssize_t tp_dictoffset; + (initproc)Variable_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + Variable_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +PyObject* +PyVariable_create(lp_variable_t x) { + Variable *self = (Variable*)VariableType.tp_alloc(&VariableType, 0); + if (self != NULL) { + self->x = x; + } + return (PyObject *)self; +} + +static PyObject* +Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return PyVariable_create(0); +} + +static int +Variable_init(Variable* self, PyObject* args) +{ + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* obj = PyTuple_GetItem(args, 0); + if (PyUnicode_Check(obj) || PyBytes_Check(obj)) { + const char* c_str = pythonObject2CharStar(obj); + lp_variable_t x = lp_variable_db_new_variable(Variable_get_default_db(), c_str); + self->x = x; + } else { + return -1; + } + } else { + return -1; + } + return 0; +} + +static void +Variable_dealloc(Variable* self) +{ + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +static PyObject* Variable_str(PyObject* self) { + Variable* x = (Variable*) self; + const char* x_str = lp_variable_db_get_name(Variable_get_default_db(), x->x); + PyObject* str = PyUnicode_FromString(x_str); + return str; +} + +static PyObject* Variable_repr(PyObject* self) { + Variable* x = (Variable*) self; + const char* x_str = lp_variable_db_get_name(Variable_get_default_db(), x->x); + char* x_repr = malloc(strlen(x_str) + strlen(VariableType.tp_name) + 5); + sprintf(x_repr, "%s('%s')", VariableType.tp_name, x_str); + PyObject* str = PyUnicode_FromString(x_repr); + free(x_repr); + return str; +} + +static Py_hash_t Variable_hash(PyObject* self) { + Variable* x = (Variable*) self; + return x->x; +} + +static +lp_polynomial_t* PyLong_Or_Int_to_polynomial(PyObject* number) { + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + lp_integer_t c; + PyLong_or_Int_to_integer(number, NULL, &c); + lp_polynomial_t* p_c = lp_polynomial_alloc(); + lp_polynomial_construct_simple(p_c, ctx, &c, 0, 0); + lp_integer_destruct(&c); + return p_c; +} + +static +lp_polynomial_t* Variable_to_polynomial(PyObject* var) { + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + Variable* x = (Variable*) var; + lp_integer_t one; + lp_integer_construct_from_int(lp_Z, &one, 1); + lp_polynomial_t* p_x = lp_polynomial_alloc(); + lp_polynomial_construct_simple(p_x, ctx, &one, x->x, 1); + lp_integer_destruct(&one); + return p_x; +} + +static PyObject* +Variable_add_number(PyObject* self, PyObject* other) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + // The c polynomial + lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); + + // x + c polynomial + lp_polynomial_t* p_sum = lp_polynomial_new(ctx); + lp_polynomial_add(p_sum, p_x, p_c); + + // Remove temporaries + lp_polynomial_destruct(p_x); + lp_polynomial_destruct(p_c); + free(p_x); + free(p_c); + + return Polynomial_create(p_sum); +} + +static PyObject* +Variable_add_Variable(PyObject* self, PyObject* other) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + // The c polynomial + lp_polynomial_t* p_y = Variable_to_polynomial(other); + + // x + c polynomial + lp_polynomial_t* p_sum = lp_polynomial_new(ctx); + lp_polynomial_add(p_sum, p_x, p_y); + + // Remove temporaries + lp_polynomial_destruct(p_x); + lp_polynomial_destruct(p_y); + free(p_x); + free(p_y); + + return Polynomial_create(p_sum); +} + +static PyObject* +Variable_add(PyObject* self, PyObject* other) { + // Integer addition + if (PyLong_or_Int_Check(other)) { + return Variable_add_number(self, other); + } else if (PyLong_or_Int_Check(self)) { + return Variable_add_number(other, self); + } else if (PyVariable_CHECK(other)) { + return Variable_add_Variable(self, other); + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static PyObject* +Variable_neg(PyObject* self) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + + // -x polynomial + lp_polynomial_t* p_neg = lp_polynomial_new(ctx); + lp_polynomial_neg(p_neg, p_x); + + // Remove temporaries + lp_polynomial_destruct(p_x); + free(p_x); + + return Polynomial_create(p_neg); +} + +static PyObject* +Variable_sub_number(PyObject* self, PyObject* other) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + // The c polynomial + lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); + + // x + c polynomial + lp_polynomial_t* p_sub = lp_polynomial_new(ctx); + lp_polynomial_sub(p_sub, p_x, p_c); + + // Remove temporaries + lp_polynomial_destruct(p_x); + lp_polynomial_destruct(p_c); + free(p_x); + free(p_c); + + return Polynomial_create(p_sub); +} + +static PyObject* +Variable_sub_Variable(PyObject* self, PyObject* other) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + // The c polynomial + lp_polynomial_t* p_y = Variable_to_polynomial(other); + + // x - y polynomial + lp_polynomial_t* p_sub = lp_polynomial_new(ctx); + lp_polynomial_sub(p_sub, p_x, p_y); + + // Remove temporaries + lp_polynomial_destruct(p_x); + lp_polynomial_destruct(p_y); + free(p_x); + free(p_y); + + return Polynomial_create(p_sub); +} + +static PyObject* +Variable_sub(PyObject* self, PyObject* other) { + // Integer addition + if (PyLong_or_Int_Check(other)) { + return Variable_sub_number(self, other); + } else if (PyLong_or_Int_Check(self)) { + Polynomial* result = (Polynomial*) Variable_sub_number(other, self); + lp_polynomial_neg(result->p, result->p); + return (PyObject*) result; + } else if (PyVariable_CHECK(other)) { + return Variable_sub_Variable(self, other); + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static PyObject* +Variable_mul_number(PyObject* self, PyObject* other) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + // The c polynomial + lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); + + // x + c polynomial + lp_polynomial_t* p_mul = lp_polynomial_new(ctx); + lp_polynomial_mul(p_mul, p_x, p_c); + + // Remove temporaries + lp_polynomial_destruct(p_x); + lp_polynomial_destruct(p_c); + free(p_x); + free(p_c); + + return Polynomial_create(p_mul); +} + +static PyObject* +Variable_mul_Variable(PyObject* self, PyObject* other) { + + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + + // The x polynomial + lp_polynomial_t* p_x = Variable_to_polynomial(self); + // The c polynomial + lp_polynomial_t* p_y = Variable_to_polynomial(other); + + // x + c polynomial + lp_polynomial_t* p_mul = lp_polynomial_new(ctx); + lp_polynomial_mul(p_mul, p_x, p_y); + + // Remove temporaries + lp_polynomial_destruct(p_x); + lp_polynomial_destruct(p_y); + free(p_x); + free(p_y); + + return Polynomial_create(p_mul); +} + +static PyObject* +Variable_mul(PyObject* self, PyObject* other) { + // Integer addition + if (PyLong_or_Int_Check(other)) { + return Variable_mul_number(self, other); + } else if (PyLong_or_Int_Check(self)) { + return Variable_mul_number(other, self); + } else if (PyVariable_CHECK(other)) { + return Variable_mul_Variable(other, self); + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static PyObject* +Variable_pow(PyObject* self, PyObject* other) { + // Check arguments + if (!PyVariable_CHECK(self) || !PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } else { + long n = PyLong_AsLong(other); + if (n < 0) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } else { + const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); + Variable* var = (Variable*) self; + lp_integer_t one; + lp_integer_construct_from_int(lp_Z, &one, 1); + lp_polynomial_t* pow_x = lp_polynomial_alloc(); + lp_polynomial_construct_simple(pow_x, ctx, &one, var->x, n); + lp_integer_destruct(&one); + return Polynomial_create(pow_x); + } + } +} + +static PyObject * +Variable_richcompare(PyObject *self, PyObject *other, int op){ + PyObject *result = Py_NotImplemented; + + if (!PyVariable_CHECK(other)) { + if(op == Py_EQ){ return Py_False; } + if(op == Py_NE){ return Py_True; } + } else { + Variable* x = (Variable*) self; + Variable* y = (Variable*) other; + + switch (op) { + case Py_LT: + result = (x->x < y->x ? Py_True : Py_False); + break; + case Py_LE: + result = (x->x <= y->x ? Py_True : Py_False); + break; + case Py_EQ: + result = (x->x == y->x ? Py_True : Py_False); + break; + case Py_NE: + result = (x->x != y->x ? Py_True : Py_False); + break; + case Py_GT: + result = (x->x > y->x ? Py_True : Py_False); + break; + case Py_GE: + result = (x->x >= y->x ? Py_True : Py_False); + break; + default: + assert(0); + } + } + return result; +} diff --git a/python/polypyVariable.h b/python/polypyVariable.h index 1b63cdb6..fbb311a7 100644 --- a/python/polypyVariable.h +++ b/python/polypyVariable.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include #include diff --git a/python/polypyVariable2.c b/python/polypyVariable2.c deleted file mode 100644 index a1e044db..00000000 --- a/python/polypyVariable2.c +++ /dev/null @@ -1,500 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyVariable.h" -#include "polypyInteger.h" -#include "polypyPolynomial.h" - -#include - -/** Default variable database */ -static lp_variable_db_t* default_var_db = 0; - -void Variable_init_default_db(void) { - if (default_var_db) { - lp_variable_db_detach(default_var_db); - } - default_var_db = lp_variable_db_new(); -} - -lp_variable_db_t* Variable_get_default_db(void) { - if (!default_var_db) { - Variable_init_default_db(); - } - return default_var_db; -} - -static PyObject* -Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Variable_init(Variable* self, PyObject* args); - -static void -Variable_dealloc(Variable* self); - -static PyObject* -Variable_str(PyObject* self); - -static int -Variable_cmp(PyObject* self, PyObject* other); - -static PyObject* -Variable_repr(PyObject* self); - -static long -Variable_hash(PyObject* self); - -PyMethodDef Variable_methods[] = { - {NULL} /* Sentinel */ -}; - -static PyObject* -Variable_add(PyObject* self, PyObject* args); - -static PyObject* -Variable_neg(PyObject* self); - -static PyObject* -Variable_sub(PyObject* self, PyObject* args); - -static PyObject* -Variable_mul(PyObject* self, PyObject* args); - -static PyObject* -Variable_pow(PyObject* self, PyObject* args); - -PyNumberMethods Variable_NumberMethods = { - Variable_add, // binaryfunc nb_add; - Variable_sub, // binaryfunc nb_subtract; - Variable_mul, // binaryfunc nb_multiply; - 0, // binaryfunc nb_divide; - 0, // binaryfunc nb_remainder; - 0, // binaryfunc nb_divmod; - (ternaryfunc)Variable_pow, // ternaryfunc nb_power; - Variable_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - 0, // inquiry nb_nonzero; /* Used by PyObject_IsTrue */ - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // coercion nb_coerce; /* Used by the coerce() function */ - 0, // unaryfunc nb_int; - 0, // unaryfunc nb_long; - 0, // unaryfunc nb_float; - 0, // unaryfunc nb_oct; - 0, // unaryfunc nb_hex; - - /* Added in release 2.0 */ - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_divide; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - - /* Added in release 2.2 */ - 0, // binaryfunc nb_floor_divide; - 0, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - - /* Added in release 2.5 */ - 0 // unaryfunc nb_index; -}; - -PyTypeObject VariableType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.Variable", /*tp_name*/ - sizeof(Variable), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Variable_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - Variable_cmp, /*tp_compare*/ - Variable_repr, /*tp_repr*/ - &Variable_NumberMethods, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - Variable_hash, /*tp_hash */ - 0, /*tp_call*/ - Variable_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "Variable objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Variable_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Variable_init, /* tp_init */ - 0, /* tp_alloc */ - Variable_new, /* tp_new */ -}; - -PyObject* -PyVariable_create(lp_variable_t x) { - Variable *self; - self = (Variable*)VariableType.tp_alloc(&VariableType, 0); - if (self != NULL) { - self->x = x; - } - return (PyObject *)self; -} - -static PyObject* -Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyVariable_create(0); -} - -static int -Variable_init(Variable* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* obj = PyTuple_GetItem(args, 0); - if (PyString_Check(obj)) { - const char* c_str = PyString_AsString(obj); - lp_variable_t x = lp_variable_db_new_variable(Variable_get_default_db(), c_str); - self->x = x; - } else { - return -1; - } - } else { - return -1; - } - return 0; -} - -static void -Variable_dealloc(Variable* self) -{ - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject* Variable_str(PyObject* self) { - Variable* x = (Variable*) self; - const char* x_str = lp_variable_db_get_name(Variable_get_default_db(), x->x); - PyObject* str = PyString_FromString(x_str); - return str; -} - -static int Variable_cmp(PyObject* self, PyObject* other) { - Variable* x = (Variable*) self; - if (PyVariable_CHECK(other)) { - Variable* y = (Variable*) other; - if (x->x > y->x) { - return 1; - } else if (x->x == y->x) { - return 0; - } else { - return -1; - } - } else { - return -1; - } -} - - -static PyObject* Variable_repr(PyObject* self) { - Variable* x = (Variable*) self; - const char* x_str = lp_variable_db_get_name(Variable_get_default_db(), x->x); - char* x_repr = malloc(strlen(x_str) + strlen(VariableType.tp_name) + 5); - sprintf(x_repr, "%s('%s')", VariableType.tp_name, x_str); - PyObject* str = PyString_FromString(x_repr); - free(x_repr); - return str; -} - -static long Variable_hash(PyObject* self) { - Variable* x = (Variable*) self; - return x->x; -} - -static -lp_polynomial_t* PyLong_Or_Int_to_polynomial(PyObject* number) { - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - lp_integer_t c; - PyLong_or_Int_to_integer(number, 0, &c); - lp_polynomial_t* p_c = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_c, ctx, &c, 0, 0); - lp_integer_destruct(&c); - return p_c; -} - -static -lp_polynomial_t* Variable_to_polynomial(PyObject* var) { - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - Variable* x = (Variable*) var; - lp_integer_t one; - lp_integer_construct_from_int(lp_Z, &one, 1); - lp_polynomial_t* p_x = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_x, ctx, &one, x->x, 1); - lp_integer_destruct(&one); - return p_x; -} - -static PyObject* -Variable_add_number(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_sum = lp_polynomial_new(ctx); - lp_polynomial_add(p_sum, p_x, p_c); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_c); - free(p_x); - free(p_c); - - return Polynomial_create(p_sum); -} - -static PyObject* -Variable_add_Variable(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_y = Variable_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_sum = lp_polynomial_new(ctx); - lp_polynomial_add(p_sum, p_x, p_y); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_y); - free(p_x); - free(p_y); - - return Polynomial_create(p_sum); -} - -static PyObject* -Variable_add(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return Variable_add_number(self, other); - } else if (PyLong_or_Int_Check(self)) { - return Variable_add_number(other, self); - } else if (PyVariable_CHECK(other)) { - return Variable_add_Variable(self, other); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Variable_neg(PyObject* self) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - - // -x polynomial - lp_polynomial_t* p_neg = lp_polynomial_new(ctx); - lp_polynomial_neg(p_neg, p_x); - - // Remove temporaries - lp_polynomial_destruct(p_x); - free(p_x); - - return Polynomial_create(p_neg); -} - -static PyObject* -Variable_sub_number(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_sub = lp_polynomial_new(ctx); - lp_polynomial_sub(p_sub, p_x, p_c); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_c); - free(p_x); - free(p_c); - - return Polynomial_create(p_sub); -} - -static PyObject* -Variable_sub_Variable(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_y = Variable_to_polynomial(other); - - // x - y polynomial - lp_polynomial_t* p_sub = lp_polynomial_new(ctx); - lp_polynomial_sub(p_sub, p_x, p_y); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_y); - free(p_x); - free(p_y); - - return Polynomial_create(p_sub); -} - -static PyObject* -Variable_sub(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return Variable_sub_number(self, other); - } else if (PyLong_or_Int_Check(self)) { - Polynomial* result = (Polynomial*) Variable_sub_number(other, self); - lp_polynomial_neg(result->p, result->p); - return (PyObject*) result; - } else if (PyVariable_CHECK(other)) { - return Variable_sub_Variable(self, other); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Variable_mul_number(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_mul = lp_polynomial_new(ctx); - lp_polynomial_mul(p_mul, p_x, p_c); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_c); - free(p_x); - free(p_c); - - return Polynomial_create(p_mul); -} - -static PyObject* -Variable_mul_Variable(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_y = Variable_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_mul = lp_polynomial_new(ctx); - lp_polynomial_mul(p_mul, p_x, p_y); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_y); - free(p_x); - free(p_y); - - return Polynomial_create(p_mul); -} - -static PyObject* -Variable_mul(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return Variable_mul_number(self, other); - } else if (PyLong_or_Int_Check(self)) { - return Variable_mul_number(other, self); - } else if (PyVariable_CHECK(other)) { - return Variable_mul_Variable(other, self); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Variable_pow(PyObject* self, PyObject* other) { - // Check arguments - if (!PyVariable_CHECK(self) || !PyInt_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } else { - long n = PyInt_AsLong(other); - if (n < 0) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } else { - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - Variable* var = (Variable*) self; - lp_integer_t one; - lp_integer_construct_from_int(lp_Z, &one, 1); - lp_polynomial_t* pow_x = lp_polynomial_alloc(); - lp_polynomial_construct_simple(pow_x, ctx, &one, var->x, n); - lp_integer_destruct(&one); - return Polynomial_create(pow_x); - } - } -} diff --git a/python/polypyVariable3.c b/python/polypyVariable3.c deleted file mode 100644 index 4d49e967..00000000 --- a/python/polypyVariable3.c +++ /dev/null @@ -1,520 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyVariable.h" -#include "polypyInteger.h" -#include "polypyPolynomial.h" -#include "utils.h" - -#include - -/** Default variable database */ -static lp_variable_db_t* default_var_db = 0; - -void Variable_init_default_db(void) { - if (default_var_db) { - lp_variable_db_detach(default_var_db); - } - default_var_db = lp_variable_db_new(); -} - -lp_variable_db_t* Variable_get_default_db(void) { - if (!default_var_db) { - Variable_init_default_db(); - } - return default_var_db; -} - -static PyObject* -Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -Variable_init(Variable* self, PyObject* args); - -static void -Variable_dealloc(Variable* self); - -static PyObject* -Variable_str(PyObject* self); - -static PyObject* -Variable_repr(PyObject* self); - -static Py_hash_t -Variable_hash(PyObject* self); - -static PyObject * -Variable_richcompare(PyObject *self, PyObject *other, int op); - -PyMethodDef Variable_methods[] = { - {NULL} /* Sentinel */ -}; - -static PyObject* -Variable_add(PyObject* self, PyObject* args); - -static PyObject* -Variable_neg(PyObject* self); - -static PyObject* -Variable_sub(PyObject* self, PyObject* args); - -static PyObject* -Variable_mul(PyObject* self, PyObject* args); - -static PyObject* -Variable_pow(PyObject* self, PyObject* args); - -PyNumberMethods Variable_NumberMethods = { - Variable_add, // binaryfunc nb_add; - Variable_sub, // binaryfunc nb_subtract; - Variable_mul, // binaryfunc nb_multiply; - 0, // binaryfunc nb_remainder; - 0, // binaryfunc nb_divmod; - (ternaryfunc)Variable_pow, // ternaryfunc nb_power; - Variable_neg, // unaryfunc nb_negative; - 0, // unaryfunc nb_positive; - 0, // unaryfunc nb_absolute; - 0, // inquiry nb_bool; - 0, // unaryfunc nb_invert; - 0, // binaryfunc nb_lshift; - 0, // binaryfunc nb_rshift; - 0, // binaryfunc nb_and; - 0, // binaryfunc nb_xor; - 0, // binaryfunc nb_or; - 0, // unaryfunc nb_int; - 0, // void *nb_reserved; - 0, // unaryfunc nb_float; - 0, // binaryfunc nb_inplace_add; - 0, // binaryfunc nb_inplace_subtract; - 0, // binaryfunc nb_inplace_multiply; - 0, // binaryfunc nb_inplace_remainder; - 0, // ternaryfunc nb_inplace_power; - 0, // binaryfunc nb_inplace_lshift; - 0, // binaryfunc nb_inplace_rshift; - 0, // binaryfunc nb_inplace_and; - 0, // binaryfunc nb_inplace_xor; - 0, // binaryfunc nb_inplace_or; - 0, // binaryfunc nb_floor_divide; - 0, // binaryfunc nb_true_divide; - 0, // binaryfunc nb_inplace_floor_divide; - 0, // binaryfunc nb_inplace_true_divide; - 0, // unaryfunc nb_index; - 0, // binaryfunc nb_matrix_multiply; - 0, // binaryfunc nb_inplace_matrix_multiply; -}; - -PyTypeObject VariableType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.Variable", // const char *tp_name; - sizeof(Variable), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)Variable_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - Variable_repr, // reprfunc tp_repr; - &Variable_NumberMethods, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - Variable_hash, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - Variable_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "Variable objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - Variable_richcompare, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - Variable_methods, // struct PyMethodDef *tp_methods; - 0, // istruct PyMemberDef *tp_members; - 0, // istruct PyGetSetDef *tp_getset; - 0, // istruct _typeobject *tp_base; - 0, // iPyObject *tp_dict; - 0, // idescrgetfunc tp_descr_get; - 0, // idescrsetfunc tp_descr_set; - 0, // iPy_ssize_t tp_dictoffset; - (initproc)Variable_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - Variable_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -PyObject* -PyVariable_create(lp_variable_t x) { - Variable *self; - self = (Variable*)VariableType.tp_alloc(&VariableType, 0); - if (self != NULL) { - self->x = x; - } - return (PyObject *)self; -} - -static PyObject* -Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return PyVariable_create(0); -} - -static int -Variable_init(Variable* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* obj = PyTuple_GetItem(args, 0); - if (PyUnicode_Check(obj) || PyBytes_Check(obj)) { - const char* c_str = pythonObject2CharStar(obj); - lp_variable_t x = lp_variable_db_new_variable(Variable_get_default_db(), c_str); - self->x = x; - } else { - return -1; - } - } else { - return -1; - } - return 0; -} - -static void -Variable_dealloc(Variable* self) -{ - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -static PyObject* Variable_str(PyObject* self) { - Variable* x = (Variable*) self; - const char* x_str = lp_variable_db_get_name(Variable_get_default_db(), x->x); - PyObject* str = PyUnicode_FromString(x_str); - return str; -} - -static PyObject* Variable_repr(PyObject* self) { - Variable* x = (Variable*) self; - const char* x_str = lp_variable_db_get_name(Variable_get_default_db(), x->x); - char* x_repr = malloc(strlen(x_str) + strlen(VariableType.tp_name) + 5); - sprintf(x_repr, "%s('%s')", VariableType.tp_name, x_str); - PyObject* str = PyUnicode_FromString(x_repr); - free(x_repr); - return str; -} - -static Py_hash_t Variable_hash(PyObject* self) { - Variable* x = (Variable*) self; - return x->x; -} - -static -lp_polynomial_t* PyLong_Or_Int_to_polynomial(PyObject* number) { - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - lp_integer_t c; - PyLong_or_Int_to_integer(number, 0, &c); - lp_polynomial_t* p_c = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_c, ctx, &c, 0, 0); - lp_integer_destruct(&c); - return p_c; -} - -static -lp_polynomial_t* Variable_to_polynomial(PyObject* var) { - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - Variable* x = (Variable*) var; - lp_integer_t one; - lp_integer_construct_from_int(lp_Z, &one, 1); - lp_polynomial_t* p_x = lp_polynomial_alloc(); - lp_polynomial_construct_simple(p_x, ctx, &one, x->x, 1); - lp_integer_destruct(&one); - return p_x; -} - -static PyObject* -Variable_add_number(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_sum = lp_polynomial_new(ctx); - lp_polynomial_add(p_sum, p_x, p_c); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_c); - free(p_x); - free(p_c); - - return Polynomial_create(p_sum); -} - -static PyObject* -Variable_add_Variable(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_y = Variable_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_sum = lp_polynomial_new(ctx); - lp_polynomial_add(p_sum, p_x, p_y); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_y); - free(p_x); - free(p_y); - - return Polynomial_create(p_sum); -} - -static PyObject* -Variable_add(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return Variable_add_number(self, other); - } else if (PyLong_or_Int_Check(self)) { - return Variable_add_number(other, self); - } else if (PyVariable_CHECK(other)) { - return Variable_add_Variable(self, other); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Variable_neg(PyObject* self) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - - // -x polynomial - lp_polynomial_t* p_neg = lp_polynomial_new(ctx); - lp_polynomial_neg(p_neg, p_x); - - // Remove temporaries - lp_polynomial_destruct(p_x); - free(p_x); - - return Polynomial_create(p_neg); -} - -static PyObject* -Variable_sub_number(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_sub = lp_polynomial_new(ctx); - lp_polynomial_sub(p_sub, p_x, p_c); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_c); - free(p_x); - free(p_c); - - return Polynomial_create(p_sub); -} - -static PyObject* -Variable_sub_Variable(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_y = Variable_to_polynomial(other); - - // x - y polynomial - lp_polynomial_t* p_sub = lp_polynomial_new(ctx); - lp_polynomial_sub(p_sub, p_x, p_y); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_y); - free(p_x); - free(p_y); - - return Polynomial_create(p_sub); -} - -static PyObject* -Variable_sub(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return Variable_sub_number(self, other); - } else if (PyLong_or_Int_Check(self)) { - Polynomial* result = (Polynomial*) Variable_sub_number(other, self); - lp_polynomial_neg(result->p, result->p); - return (PyObject*) result; - } else if (PyVariable_CHECK(other)) { - return Variable_sub_Variable(self, other); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Variable_mul_number(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_c = PyLong_Or_Int_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_mul = lp_polynomial_new(ctx); - lp_polynomial_mul(p_mul, p_x, p_c); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_c); - free(p_x); - free(p_c); - - return Polynomial_create(p_mul); -} - -static PyObject* -Variable_mul_Variable(PyObject* self, PyObject* other) { - - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - - // The x polynomial - lp_polynomial_t* p_x = Variable_to_polynomial(self); - // The c polynomial - lp_polynomial_t* p_y = Variable_to_polynomial(other); - - // x + c polynomial - lp_polynomial_t* p_mul = lp_polynomial_new(ctx); - lp_polynomial_mul(p_mul, p_x, p_y); - - // Remove temporaries - lp_polynomial_destruct(p_x); - lp_polynomial_destruct(p_y); - free(p_x); - free(p_y); - - return Polynomial_create(p_mul); -} - -static PyObject* -Variable_mul(PyObject* self, PyObject* other) { - // Integer addition - if (PyLong_or_Int_Check(other)) { - return Variable_mul_number(self, other); - } else if (PyLong_or_Int_Check(self)) { - return Variable_mul_number(other, self); - } else if (PyVariable_CHECK(other)) { - return Variable_mul_Variable(other, self); - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static PyObject* -Variable_pow(PyObject* self, PyObject* other) { - // Check arguments - if (!PyVariable_CHECK(self) || !PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } else { - long n = PyLong_AsLong(other); - if (n < 0) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } else { - const lp_polynomial_context_t* ctx = Polynomial_get_default_context(); - Variable* var = (Variable*) self; - lp_integer_t one; - lp_integer_construct_from_int(lp_Z, &one, 1); - lp_polynomial_t* pow_x = lp_polynomial_alloc(); - lp_polynomial_construct_simple(pow_x, ctx, &one, var->x, n); - lp_integer_destruct(&one); - return Polynomial_create(pow_x); - } - } -} - -static PyObject * -Variable_richcompare(PyObject *self, PyObject *other, int op){ - PyObject *result = Py_NotImplemented; - - if (!PyVariable_CHECK(other)) { - if(op == Py_EQ){ return Py_False; } - if(op == Py_NE){ return Py_True; } - } else { - Variable* x = (Variable*) self; - Variable* y = (Variable*) other; - - switch (op) { - case Py_LT: - result = (x->x < y->x ? Py_True : Py_False); - break; - case Py_LE: - result = (x->x <= y->x ? Py_True : Py_False); - break; - case Py_EQ: - result = (x->x == y->x ? Py_True : Py_False); - break; - case Py_NE: - result = (x->x != y->x ? Py_True : Py_False); - break; - case Py_GT: - result = (x->x > y->x ? Py_True : Py_False); - break; - case Py_GE: - result = (x->x >= y->x ? Py_True : Py_False); - break; - } - } - return result; -} - diff --git a/python/polypyVariableOrder.c b/python/polypyVariableOrder.c index fd0b4eff..11f75741 100644 --- a/python/polypyVariableOrder.c +++ b/python/polypyVariableOrder.c @@ -17,12 +17,265 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" -#if PY_MAJOR_VERSION >= 3 -#include "polypyVariableOrder3.c" -#else -#include "polypyVariableOrder2.c" -#endif +#include "polypyVariableOrder.h" +#include "polypyVariable.h" +#include +#include + +/** Default variable database */ +static lp_variable_order_t* default_var_order = NULL; + +lp_variable_order_t* VariableOrder_get_default_order(void) { + if (!default_var_order) { + default_var_order = lp_variable_order_new(); + } + return default_var_order; +} + +static PyObject* +VariableOrder_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +VariableOrder_init(VariableOrder* self, PyObject* args); + +static void +VariableOrder_dealloc(VariableOrder* self); + +static PyObject* +VariableOrder_str(PyObject* self); + +static PyObject* +VariableOrder_repr(PyObject* self); + +static PyObject* +VariableOrder_push(PyObject* self, PyObject* args); + +static PyObject* +VariableOrder_pop(PyObject* self); + +static PyObject* +VariableOrder_set(PyObject* self, PyObject* args); + +static PyObject* +VariableOrder_cmp(PyObject* self, PyObject* args); + +PyMethodDef VariableOrder_methods[] = { + {"push", (PyCFunction)VariableOrder_push, METH_VARARGS, "Add a variable to the top of the order"}, + {"pop", (PyCFunction)VariableOrder_pop, METH_NOARGS, "Remove the top variable from the order"}, + {"cmp", (PyCFunction)VariableOrder_cmp, METH_VARARGS, "Compare two variables"}, + {"set", (PyCFunction)VariableOrder_set, METH_VARARGS, "Set the order to the given list of variables"}, + {NULL} /* Sentinel */ +}; + +PyTypeObject VariableOrderType = { + {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD + "polypy.VariableOrder", // const char *tp_name; + sizeof(VariableOrder), // Py_ssize_t tp_basicsize; + 0, // Py_ssize_t tp_itemsize; + (destructor)VariableOrder_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + NULL, // getattrfunc tp_getattr; + NULL, // setattrfunc tp_setattr; + NULL, // PyAsyncMethods *tp_as_async; + VariableOrder_repr, // reprfunc tp_repr; + NULL, // PyNumberMethods *tp_as_number; + NULL, // PySequenceMethods *tp_as_sequence; + NULL, // PyMappingMethods *tp_as_mapping; + NULL, // hashfunc tp_hash; + NULL, // ternaryfunc tp_call; + VariableOrder_str, // reprfunc tp_str; + NULL, // getattrofunc tp_getattro; + NULL, // setattrofunc tp_setattro; + NULL, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; + "VariableOrder objects", // const char *tp_doc; + NULL, // traverseproc tp_traverse; + NULL, // inquiry tp_clear; + NULL, // richcmpfunc tp_richcompare; + 0, // Py_ssize_t tp_weaklistoffset; + NULL, // getiterfunc tp_iter; + NULL, // iternextfunc tp_iternext; + VariableOrder_methods, // struct PyMethodDef *tp_methods; + NULL, // struct PyMemberDef *tp_members; + NULL, // struct PyGetSetDef *tp_getset; + NULL, // struct _typeobject *tp_base; + NULL, // PyObject *tp_dict; + NULL, // descrgetfunc tp_descr_get; + NULL, // descrsetfunc tp_descr_set; + 0, // Py_ssize_t tp_dictoffset; + (initproc)VariableOrder_init, // initproc tp_init; + NULL, // allocfunc tp_alloc; + VariableOrder_new, // newfunc tp_new; + NULL, // freefunc tp_free; + NULL, // inquiry tp_is_gc; + NULL, // PyObject *tp_bases; + NULL, // PyObject *tp_mro; + NULL, // PyObject *tp_cache; + NULL, // PyObject *tp_subclasses; + NULL, // PyObject *tp_weaklist; + NULL, // destructor tp_del; + 0, // unsigned int tp_version_tag; + NULL, // destructor tp_finalize; +}; + +PyObject* +VariableOrder_create(lp_variable_order_t* var_order) { + VariableOrder *self = (VariableOrder*)VariableOrderType.tp_alloc(&VariableOrderType, 0); + if (self != NULL) { + self->var_order = var_order; + } + return (PyObject *)self; +} + +static PyObject* +VariableOrder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + return VariableOrder_create(NULL); +} + +static PyObject* +VariableOrder_set(PyObject* self, PyObject* args) { + + VariableOrder* order = (VariableOrder*) self; + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* list = PyTuple_GetItem(args, 0); + if (PyList_Check(list)) { + int i; + for (i = 0; i < PyList_Size(list); ++ i) { + if (!PyVariable_CHECK(PyList_GetItem(list, i))) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } + // Clear the current order + lp_variable_order_clear(order->var_order); + // Fill the order + for (i = 0; i < PyList_Size(list); ++ i) { + lp_variable_t var = ((Variable*) PyList_GetItem(list, i))->x; + if (!lp_variable_order_contains(order->var_order, var)) { + lp_variable_order_push(order->var_order, var); + } + } + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + Py_RETURN_NONE; +} + +static int +VariableOrder_init(VariableOrder* self, PyObject* args) +{ + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* list = PyTuple_GetItem(args, 0); + if (PyList_Check(list)) { + int i; + for (i = 0; i < PyList_Size(list); ++ i) { + if (!PyVariable_CHECK(PyList_GetItem(list, i))) { + return -1; + } + } + self->var_order = lp_variable_order_new(); + for (i = 0; i < PyList_Size(list); ++ i) { + lp_variable_t var = ((Variable*) PyList_GetItem(list, i))->x; + lp_variable_order_push(self->var_order, var); + } + } else { + return -1; + } + } else { + return -1; + } + return 0; +} + +static void +VariableOrder_dealloc(VariableOrder* self) +{ + if (self->var_order) { + lp_variable_order_detach(self->var_order); + } + ((PyObject*)self)->ob_type->tp_free((PyObject*)self); +} + +static PyObject* +VariableOrder_str(PyObject* self) { + VariableOrder* var_order = (VariableOrder*) self; + char* var_order_str = lp_variable_order_to_string(var_order->var_order, Variable_get_default_db()); + PyObject* str = PyUnicode_FromString(var_order_str); + free(var_order_str); + return str; +} + +static PyObject* +VariableOrder_repr(PyObject* self) { + VariableOrder* var_order = (VariableOrder*) self; + char* var_order_str = lp_variable_order_to_string(var_order->var_order, Variable_get_default_db()); + char* var_order_repr = malloc(strlen(var_order_str) + strlen(VariableOrderType.tp_name) + 3); + sprintf(var_order_repr, "%s(%s)", VariableOrderType.tp_name, var_order_str); + PyObject* str = PyUnicode_FromString(var_order_repr); + free(var_order_repr); + free(var_order_str); + return str; +} + +static PyObject* +VariableOrder_push(PyObject* self, PyObject* args) { + int error = 0; + if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { + PyObject* variable = PyTuple_GetItem(args, 0); + if (PyVariable_CHECK(variable)) { + lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; + lp_variable_t x = ((Variable*) variable)->x; + if (!lp_variable_order_contains(var_order, x)) { + lp_variable_order_push(var_order, x); + } + } else { + error = 1; + } + } else { + error = 1; + } + if (error) { + PyErr_SetString(PyExc_BaseException, "Only variables can be pushed"); + } + + Py_RETURN_NONE; +} + + +static PyObject* +VariableOrder_cmp(PyObject* self, PyObject* args) { + if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { + PyObject* x_var = PyTuple_GetItem(args, 0); + PyObject* y_var = PyTuple_GetItem(args, 1); + if (PyVariable_CHECK(x_var) && PyVariable_CHECK(y_var)) { + lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; + lp_variable_t x = ((Variable*) x_var)->x; + lp_variable_t y = ((Variable*) y_var)->x; + int cmp = lp_variable_order_cmp(var_order, x, y); + if (cmp < 0) return PyLong_FromLong(-1); + else if (cmp > 0) return PyLong_FromLong(1); + else return PyLong_FromLong(0); + } + } + PyErr_SetString(PyExc_BaseException, "Only variables can be pushed"); + Py_RETURN_NONE; +} + + +static PyObject* +VariableOrder_pop(PyObject* self) { + lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; + if (lp_variable_order_size(var_order) > 0) { + lp_variable_order_pop(var_order); + } + Py_RETURN_NONE; +} diff --git a/python/polypyVariableOrder.h b/python/polypyVariableOrder.h index 8e049c49..f1164256 100644 --- a/python/polypyVariableOrder.h +++ b/python/polypyVariableOrder.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include #include diff --git a/python/polypyVariableOrder2.c b/python/polypyVariableOrder2.c deleted file mode 100644 index 5f4216ba..00000000 --- a/python/polypyVariableOrder2.c +++ /dev/null @@ -1,278 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyVariableOrder.h" -#include "polypyVariable.h" - -#include -#include - -/** Default variable database */ -static lp_variable_order_t* default_var_order = 0; - -lp_variable_order_t* VariableOrder_get_default_order(void) { - if (!default_var_order) { - default_var_order = lp_variable_order_new(); - } - return default_var_order; -} - -static PyObject* -VariableOrder_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -VariableOrder_init(VariableOrder* self, PyObject* args); - -static void -VariableOrder_dealloc(VariableOrder* self); - -static PyObject* -VariableOrder_str(PyObject* self); - -static PyObject* -VariableOrder_repr(PyObject* self); - -static PyObject* -VariableOrder_push(PyObject* self, PyObject* args); - -static PyObject* -VariableOrder_pop(PyObject* self); - -static PyObject* -VariableOrder_set(PyObject* self, PyObject* args); - -static PyObject* -VariableOrder_cmp(PyObject* self, PyObject* args); - -PyMethodDef VariableOrder_methods[] = { - {"push", (PyCFunction)VariableOrder_push, METH_VARARGS, "Add a variable to the top of the order"}, - {"pop", (PyCFunction)VariableOrder_pop, METH_NOARGS, "Remove the top variable from the order"}, - {"cmp", (PyCFunction)VariableOrder_cmp, METH_VARARGS, "Compare two variables"}, - {"set", (PyCFunction)VariableOrder_set, METH_VARARGS, "Set the order to the given list of variables"}, - {NULL} /* Sentinel */ -}; - -PyTypeObject VariableOrderType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "polypy.VariableOrder", /*tp_name*/ - sizeof(VariableOrder), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)VariableOrder_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - VariableOrder_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - VariableOrder_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "VariableOrder objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - VariableOrder_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)VariableOrder_init, /* tp_init */ - 0, /* tp_alloc */ - VariableOrder_new, /* tp_new */ -}; - -PyObject* -VariableOrder_create(lp_variable_order_t* var_order) { - VariableOrder *self = (VariableOrder*)VariableOrderType.tp_alloc(&VariableOrderType, 0); - if (self != NULL) { - self->var_order = var_order; - } - return (PyObject *)self; -} - -static PyObject* -VariableOrder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return VariableOrder_create(0); -} - -static PyObject* -VariableOrder_set(PyObject* self, PyObject* args) { - - VariableOrder* order = (VariableOrder*) self; - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* list = PyTuple_GetItem(args, 0); - if (PyList_Check(list)) { - int i; - for (i = 0; i < PyList_Size(list); ++ i) { - if (!PyVariable_CHECK(PyList_GetItem(list, i))) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - // Clear the current order - lp_variable_order_clear(order->var_order); - // Fill the order - for (i = 0; i < PyList_Size(list); ++ i) { - lp_variable_t var = ((Variable*) PyList_GetItem(list, i))->x; - if (!lp_variable_order_contains(order->var_order, var)) { - lp_variable_order_push(order->var_order, var); - } - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Py_RETURN_NONE; -} - -static int -VariableOrder_init(VariableOrder* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* list = PyTuple_GetItem(args, 0); - if (PyList_Check(list)) { - int i; - for (i = 0; i < PyList_Size(list); ++ i) { - if (!PyVariable_CHECK(PyList_GetItem(list, i))) { - return -1; - } - } - self->var_order = lp_variable_order_new(); - for (i = 0; i < PyList_Size(list); ++ i) { - lp_variable_t var = ((Variable*) PyList_GetItem(list, i))->x; - lp_variable_order_push(self->var_order, var); - } - } else { - return -1; - } - } else { - return -1; - } - return 0; -} - -static void -VariableOrder_dealloc(VariableOrder* self) -{ - if (self->var_order) { - lp_variable_order_detach(self->var_order); - } - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject* -VariableOrder_str(PyObject* self) { - VariableOrder* var_order = (VariableOrder*) self; - char* var_order_str = lp_variable_order_to_string(var_order->var_order, Variable_get_default_db()); - PyObject* str = PyString_FromString(var_order_str); - free(var_order_str); - return str; -} - -static PyObject* -VariableOrder_repr(PyObject* self) { - VariableOrder* var_order = (VariableOrder*) self; - char* var_order_str = lp_variable_order_to_string(var_order->var_order, Variable_get_default_db()); - char* var_order_repr = malloc(strlen(var_order_str) + strlen(VariableOrderType.tp_name) + 3); - sprintf(var_order_repr, "%s(%s)", VariableOrderType.tp_name, var_order_str); - PyObject* str = PyString_FromString(var_order_repr); - free(var_order_repr); - free(var_order_str); - return str; -} - -static PyObject* -VariableOrder_push(PyObject* self, PyObject* args) { - int error = 0; - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* variable = PyTuple_GetItem(args, 0); - if (PyVariable_CHECK(variable)) { - lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; - lp_variable_t x = ((Variable*) variable)->x; - if (!lp_variable_order_contains(var_order, x)) { - lp_variable_order_push(var_order, x); - } - } else { - error = 1; - } - } else { - error = 1; - } - if (error) { - PyErr_SetString(PyExc_BaseException, "Only variables can be pushed"); - } - - Py_RETURN_NONE; -} - - -static PyObject* -VariableOrder_cmp(PyObject* self, PyObject* args) { - int error = 0; - if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { - PyObject* x_var = PyTuple_GetItem(args, 0); - PyObject* y_var = PyTuple_GetItem(args, 1); - if (PyVariable_CHECK(x_var) && PyVariable_CHECK(y_var)) { - lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; - lp_variable_t x = ((Variable*) x_var)->x; - lp_variable_t y = ((Variable*) y_var)->x; - int cmp = lp_variable_order_cmp(var_order, x, y); - if (cmp < 0) return PyInt_FromLong(-1); - else if (cmp > 0) return PyInt_FromLong(1); - else return PyInt_FromLong(0); - } else { - error = 1; - } - } else { - error = 1; - } - if (error) { - PyErr_SetString(PyExc_BaseException, "Only variables can be pushed"); - } - - Py_RETURN_NONE; -} - - -static PyObject* -VariableOrder_pop(PyObject* self) { - lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; - if (lp_variable_order_size(var_order) > 0) { - lp_variable_order_pop(var_order); - } - Py_RETURN_NONE; -} diff --git a/python/polypyVariableOrder3.c b/python/polypyVariableOrder3.c deleted file mode 100644 index 7818cbd0..00000000 --- a/python/polypyVariableOrder3.c +++ /dev/null @@ -1,287 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "polypyVariableOrder.h" -#include "polypyVariable.h" - -#include -#include - -/** Default variable database */ -static lp_variable_order_t* default_var_order = 0; - -lp_variable_order_t* VariableOrder_get_default_order(void) { - if (!default_var_order) { - default_var_order = lp_variable_order_new(); - } - return default_var_order; -} - -static PyObject* -VariableOrder_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static int -VariableOrder_init(VariableOrder* self, PyObject* args); - -static void -VariableOrder_dealloc(VariableOrder* self); - -static PyObject* -VariableOrder_str(PyObject* self); - -static PyObject* -VariableOrder_repr(PyObject* self); - -static PyObject* -VariableOrder_push(PyObject* self, PyObject* args); - -static PyObject* -VariableOrder_pop(PyObject* self); - -static PyObject* -VariableOrder_set(PyObject* self, PyObject* args); - -static PyObject* -VariableOrder_cmp(PyObject* self, PyObject* args); - -PyMethodDef VariableOrder_methods[] = { - {"push", (PyCFunction)VariableOrder_push, METH_VARARGS, "Add a variable to the top of the order"}, - {"pop", (PyCFunction)VariableOrder_pop, METH_NOARGS, "Remove the top variable from the order"}, - {"cmp", (PyCFunction)VariableOrder_cmp, METH_VARARGS, "Compare two variables"}, - {"set", (PyCFunction)VariableOrder_set, METH_VARARGS, "Set the order to the given list of variables"}, - {NULL} /* Sentinel */ -}; - -PyTypeObject VariableOrderType = { - {PyObject_HEAD_INIT(NULL)}, // PyObject_VAR_HEAD - "polypy.VariableOrder", // const char *tp_name; - sizeof(VariableOrder), // Py_ssize_t tp_basicsize; - 0, // Py_ssize_t tp_itemsize; - (destructor)VariableOrder_dealloc, // destructor tp_dealloc; - 0, // printfunc tp_print; - 0, // getattrfunc tp_getattr; - 0, // setattrfunc tp_setattr; - 0, // PyAsyncMethods *tp_as_async; - VariableOrder_repr, // reprfunc tp_repr; - 0, // PyNumberMethods *tp_as_number; - 0, // PySequenceMethods *tp_as_sequence; - 0, // PyMappingMethods *tp_as_mapping; - 0, // hashfunc tp_hash; - 0, // ternaryfunc tp_call; - VariableOrder_str, // reprfunc tp_str; - 0, // getattrofunc tp_getattro; - 0, // setattrofunc tp_setattro; - 0, // PyBufferProcs *tp_as_buffer; - Py_TPFLAGS_DEFAULT, // unsigned long tp_flags; - "VariableOrder objects", // const char *tp_doc; - 0, // traverseproc tp_traverse; - 0, // inquiry tp_clear; - 0, // richcmpfunc tp_richcompare; - 0, // Py_ssize_t tp_weaklistoffset; - 0, // getiterfunc tp_iter; - 0, // iternextfunc tp_iternext; - VariableOrder_methods, // struct PyMethodDef *tp_methods; - 0, // struct PyMemberDef *tp_members; - 0, // struct PyGetSetDef *tp_getset; - 0, // struct _typeobject *tp_base; - 0, // PyObject *tp_dict; - 0, // descrgetfunc tp_descr_get; - 0, // descrsetfunc tp_descr_set; - 0, // Py_ssize_t tp_dictoffset; - (initproc)VariableOrder_init, // initproc tp_init; - 0, // allocfunc tp_alloc; - VariableOrder_new, // newfunc tp_new; - 0, // freefunc tp_free; - 0, // inquiry tp_is_gc; - 0, // PyObject *tp_bases; - 0, // PyObject *tp_mro; - 0, // PyObject *tp_cache; - 0, // PyObject *tp_subclasses; - 0, // PyObject *tp_weaklist; - 0, // destructor tp_del; - 0, // unsigned int tp_version_tag; - 0, // destructor tp_finalize; -}; - -PyObject* -VariableOrder_create(lp_variable_order_t* var_order) { - VariableOrder *self = (VariableOrder*)VariableOrderType.tp_alloc(&VariableOrderType, 0); - if (self != NULL) { - self->var_order = var_order; - } - return (PyObject *)self; -} - -static PyObject* -VariableOrder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return VariableOrder_create(0); -} - -static PyObject* -VariableOrder_set(PyObject* self, PyObject* args) { - - VariableOrder* order = (VariableOrder*) self; - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* list = PyTuple_GetItem(args, 0); - if (PyList_Check(list)) { - int i; - for (i = 0; i < PyList_Size(list); ++ i) { - if (!PyVariable_CHECK(PyList_GetItem(list, i))) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } - // Clear the current order - lp_variable_order_clear(order->var_order); - // Fill the order - for (i = 0; i < PyList_Size(list); ++ i) { - lp_variable_t var = ((Variable*) PyList_GetItem(list, i))->x; - if (!lp_variable_order_contains(order->var_order, var)) { - lp_variable_order_push(order->var_order, var); - } - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - } else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - Py_RETURN_NONE; -} - -static int -VariableOrder_init(VariableOrder* self, PyObject* args) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* list = PyTuple_GetItem(args, 0); - if (PyList_Check(list)) { - int i; - for (i = 0; i < PyList_Size(list); ++ i) { - if (!PyVariable_CHECK(PyList_GetItem(list, i))) { - return -1; - } - } - self->var_order = lp_variable_order_new(); - for (i = 0; i < PyList_Size(list); ++ i) { - lp_variable_t var = ((Variable*) PyList_GetItem(list, i))->x; - lp_variable_order_push(self->var_order, var); - } - } else { - return -1; - } - } else { - return -1; - } - return 0; -} - -static void -VariableOrder_dealloc(VariableOrder* self) -{ - if (self->var_order) { - lp_variable_order_detach(self->var_order); - } - ((PyObject*)self)->ob_type->tp_free((PyObject*)self); -} - -static PyObject* -VariableOrder_str(PyObject* self) { - VariableOrder* var_order = (VariableOrder*) self; - char* var_order_str = lp_variable_order_to_string(var_order->var_order, Variable_get_default_db()); - PyObject* str = PyUnicode_FromString(var_order_str); - free(var_order_str); - return str; -} - -static PyObject* -VariableOrder_repr(PyObject* self) { - VariableOrder* var_order = (VariableOrder*) self; - char* var_order_str = lp_variable_order_to_string(var_order->var_order, Variable_get_default_db()); - char* var_order_repr = malloc(strlen(var_order_str) + strlen(VariableOrderType.tp_name) + 3); - sprintf(var_order_repr, "%s(%s)", VariableOrderType.tp_name, var_order_str); - PyObject* str = PyUnicode_FromString(var_order_repr); - free(var_order_repr); - free(var_order_str); - return str; -} - -static PyObject* -VariableOrder_push(PyObject* self, PyObject* args) { - int error = 0; - if (PyTuple_Check(args) && PyTuple_Size(args) == 1) { - PyObject* variable = PyTuple_GetItem(args, 0); - if (PyVariable_CHECK(variable)) { - lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; - lp_variable_t x = ((Variable*) variable)->x; - if (!lp_variable_order_contains(var_order, x)) { - lp_variable_order_push(var_order, x); - } - } else { - error = 1; - } - } else { - error = 1; - } - if (error) { - PyErr_SetString(PyExc_BaseException, "Only variables can be pushed"); - } - - Py_RETURN_NONE; -} - - -static PyObject* -VariableOrder_cmp(PyObject* self, PyObject* args) { - int error = 0; - if (PyTuple_Check(args) && PyTuple_Size(args) == 2) { - PyObject* x_var = PyTuple_GetItem(args, 0); - PyObject* y_var = PyTuple_GetItem(args, 1); - if (PyVariable_CHECK(x_var) && PyVariable_CHECK(y_var)) { - lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; - lp_variable_t x = ((Variable*) x_var)->x; - lp_variable_t y = ((Variable*) y_var)->x; - int cmp = lp_variable_order_cmp(var_order, x, y); - if (cmp < 0) return PyLong_FromLong(-1); - else if (cmp > 0) return PyLong_FromLong(1); - else return PyLong_FromLong(0); - } else { - error = 1; - } - } else { - error = 1; - } - if (error) { - PyErr_SetString(PyExc_BaseException, "Only variables can be pushed"); - } - - Py_RETURN_NONE; -} - - -static PyObject* -VariableOrder_pop(PyObject* self) { - lp_variable_order_t* var_order = ((VariableOrder*) self)->var_order; - if (lp_variable_order_size(var_order) > 0) { - lp_variable_order_pop(var_order); - } - Py_RETURN_NONE; -} diff --git a/python/python.h b/python/python.h new file mode 100644 index 00000000..cb09fcf2 --- /dev/null +++ b/python/python.h @@ -0,0 +1,26 @@ +/** +* Copyright 2015, SRI International. +* +* This file is part of LibPoly. +* +* LibPoly is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* LibPoly is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with LibPoly. If not, see . +*/ + +#pragma once + +/** use this file to include Python.h to ensure that required defines + * are present. */ + +#define PY_SSIZE_T_CLEAN +#include diff --git a/python/utils.c b/python/utils.c index 7e395e4b..cc7c79c4 100644 --- a/python/utils.c +++ b/python/utils.c @@ -17,11 +17,100 @@ * along with LibPoly. If not, see . */ -#define PY_SSIZE_T_CLEAN -#include "Python.h" - -#if PY_MAJOR_VERSION >= 3 -#include "utils3.c" -#else -#include "utils2.c" -#endif +#include "python.h" + +#include "utils.h" + +const char* pythonObject2CharStar(PyObject *pyobj){ + const char* retval = NULL; + if(!pyobj){ + return retval; + } else if(PyBytes_Check(pyobj)){ + retval = PyBytes_AsString(pyobj); + return retval; + } else if(PyUnicode_Check(pyobj)) { + PyObject* str = PyUnicode_AsEncodedString(pyobj, "utf-8", "?"); + retval = PyBytes_AS_STRING(str); + Py_XDECREF(str); + } else { + PyObject* pyob_str = PyObject_Str(pyobj); + PyObject* str = PyUnicode_AsEncodedString(pyob_str, "utf-8", "?"); + retval = PyBytes_AS_STRING(str); + Py_XDECREF(pyob_str); + Py_XDECREF(str); + } + return retval; +} + +int PyLong_or_Int_Check(PyObject* o) { + if (PyLong_Check(o)) { + return 1; + } + return 0; +} + +void PyLong_or_Int_to_integer(PyObject* o, const lp_int_ring_t* K, lp_integer_t* c) { + if (PyLong_Check(o)) { + long c_long = PyLong_AsLong(o); + lp_integer_construct_from_int(K, c, c_long); + } +} + +//IAM: unused in the python3 world +PyObject* integer_to_PyInt(const lp_integer_t* x) { + char* str = lp_integer_to_string(x); + char* str_p = NULL; + PyObject* result = PyLong_FromString(str, &str_p, 10); + free(str); + return result; +} + +PyObject* integer_to_PyLong(const lp_integer_t* x) { + char* str = lp_integer_to_string(x); + char* str_p = NULL; + PyObject* result = PyLong_FromString(str, &str_p, 10); + free(str); + return result; +} + +void PyFloat_to_dyadic_rational(PyObject* o, lp_dyadic_rational_t* x) { + double o_double = PyFloat_AsDouble(o); + lp_dyadic_rational_construct_from_double(x, o_double); +} + +PyObject* dyadic_rational_to_PyFloat(const lp_dyadic_rational_t* x) { + double x_double = lp_dyadic_rational_to_double(x); + return PyFloat_FromDouble(x_double); +} + + +PyObject* algebraic_number_to_PyFloat(const lp_algebraic_number_t* x) { + double x_double = lp_algebraic_number_to_double(x); + return PyFloat_FromDouble(x_double); +} + +int PyLong_or_Int_or_Float_Check(PyObject* o) { + if (PyLong_Check(o)) { + return 1; + } + if (PyFloat_Check(o)) { + return 1; + } + return 0; +} + +void PyLong_or_Int_or_float_to_value(PyObject* o, lp_value_t* v) { + if (PyLong_or_Int_Check(o)) { + lp_integer_t v_int; + PyLong_or_Int_to_integer(o, lp_Z, &v_int); + lp_value_construct(v, LP_VALUE_INTEGER, &v_int); + lp_integer_destruct(&v_int); + } else if (PyFloat_Check(o)) { + lp_dyadic_rational_t v_dy_q; + PyFloat_to_dyadic_rational(o, &v_dy_q); + lp_value_construct(v, LP_VALUE_INTEGER, &v_dy_q); + lp_dyadic_rational_destruct(&v_dy_q); + } else { + lp_value_construct(v, LP_VALUE_NONE, NULL); + } +} diff --git a/python/utils.h b/python/utils.h index 69d6b083..080dbae0 100644 --- a/python/utils.h +++ b/python/utils.h @@ -19,8 +19,7 @@ #pragma once -#define PY_SSIZE_T_CLEAN -#include +#include "python.h" #include "integer.h" #include "rational.h" diff --git a/python/utils2.c b/python/utils2.c deleted file mode 100644 index 5874fc2e..00000000 --- a/python/utils2.c +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "utils.h" - -const char* pythonObject2CharStar(PyObject *pyobj){ - const char* retval = NULL; - if(!pyobj){ - return retval; - } else if(PyString_Check(pyobj)){ - retval = PyString_AsString(pyobj); - return retval; - } else { - PyObject* pyobj_str = PyObject_Str(pyobj); - retval = PyString_AsString(pyobj_str); - } - return retval; -} - -int PyLong_or_Int_Check(PyObject* o) { - if (PyInt_Check(o)) { - return 1; - } - if (PyLong_Check(o)) { - return 1; - } - return 0; -} - -void PyLong_or_Int_to_integer(PyObject* o, const lp_int_ring_t* K, lp_integer_t* c) { - if (PyInt_Check(o)) { - long c_long = PyInt_AsLong(o); - lp_integer_construct_from_int(K, c, c_long); - } - if (PyLong_Check(o)) { - PyObject* o_str = PyObject_Str(o); - char* o_cstr = PyString_AsString(o_str); - lp_integer_construct_from_string(K, c, o_cstr, 10); - Py_DECREF(o_str); - } -} - -PyObject* integer_to_PyInt(const lp_integer_t* x) { - char* str = lp_integer_to_string(x); - char* str_p = 0; - PyObject* result = PyInt_FromString(str, &str_p, 10); - free(str); - return result; -} - -PyObject* integer_to_PyLong(const lp_integer_t* x) { - char* str = lp_integer_to_string(x); - char* str_p = 0; - PyObject* result = PyLong_FromString(str, &str_p, 10); - free(str); - return result; -} - -void PyFloat_to_dyadic_rational(PyObject* o, lp_dyadic_rational_t* x) { - double o_double = PyFloat_AsDouble(o); - lp_dyadic_rational_construct_from_double(x, o_double); -} - -PyObject* dyadic_rational_to_PyFloat(const lp_dyadic_rational_t* x) { - double x_double = lp_dyadic_rational_to_double(x); - return PyFloat_FromDouble(x_double); -} - - -PyObject* algebraic_number_to_PyFloat(const lp_algebraic_number_t* x) { - double x_double = lp_algebraic_number_to_double(x); - return PyFloat_FromDouble(x_double); -} - -int PyLong_or_Int_or_Float_Check(PyObject* o) { - if (PyInt_Check(o)) { - return 1; - } - if (PyLong_Check(o)) { - return 1; - } - if (PyFloat_Check(o)) { - return 1; - } - return 0; -} - -void PyLong_or_Int_or_float_to_value(PyObject* o, lp_value_t* v) { - if (PyLong_or_Int_Check(o)) { - lp_integer_t v_int; - PyLong_or_Int_to_integer(o, lp_Z, &v_int); - lp_value_construct(v, LP_VALUE_INTEGER, &v_int); - lp_integer_destruct(&v_int); - } else if (PyFloat_Check(o)) { - lp_dyadic_rational_t v_dy_q; - PyFloat_to_dyadic_rational(o, &v_dy_q); - lp_value_construct(v, LP_VALUE_INTEGER, &v_dy_q); - lp_dyadic_rational_destruct(&v_dy_q); - } else { - lp_value_construct(v, LP_VALUE_NONE, 0); - } -} diff --git a/python/utils3.c b/python/utils3.c deleted file mode 100644 index b40c6c0b..00000000 --- a/python/utils3.c +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright 2015, SRI International. - * - * This file is part of LibPoly. - * - * LibPoly is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LibPoly is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with LibPoly. If not, see . - */ - -#include "utils.h" - -const char* pythonObject2CharStar(PyObject *pyobj){ - const char* retval = NULL; - if(!pyobj){ - return retval; - } else if(PyBytes_Check(pyobj)){ - retval = PyBytes_AsString(pyobj); - return retval; - } else if(PyUnicode_Check(pyobj)) { - PyObject* str = PyUnicode_AsEncodedString(pyobj, "utf-8", "?"); - retval = PyBytes_AS_STRING(str); - Py_XDECREF(str); - } else { - PyObject* pyob_str = PyObject_Str(pyobj); - PyObject* str = PyUnicode_AsEncodedString(pyob_str, "utf-8", "?"); - retval = PyBytes_AS_STRING(str); - Py_XDECREF(pyob_str); - Py_XDECREF(str); - } - return retval; -} - -int PyLong_or_Int_Check(PyObject* o) { - if (PyLong_Check(o)) { - return 1; - } - return 0; -} - -void PyLong_or_Int_to_integer(PyObject* o, const lp_int_ring_t* K, lp_integer_t* c) { - if (PyLong_Check(o)) { - long c_long = PyLong_AsLong(o); - lp_integer_construct_from_int(K, c, c_long); - } -} - -//IAM: unused in the python3 world -PyObject* integer_to_PyInt(const lp_integer_t* x) { - char* str = lp_integer_to_string(x); - char* str_p = 0; - PyObject* result = PyLong_FromString(str, &str_p, 10); - free(str); - return result; -} - -PyObject* integer_to_PyLong(const lp_integer_t* x) { - char* str = lp_integer_to_string(x); - char* str_p = 0; - PyObject* result = PyLong_FromString(str, &str_p, 10); - free(str); - return result; -} - -void PyFloat_to_dyadic_rational(PyObject* o, lp_dyadic_rational_t* x) { - double o_double = PyFloat_AsDouble(o); - lp_dyadic_rational_construct_from_double(x, o_double); -} - -PyObject* dyadic_rational_to_PyFloat(const lp_dyadic_rational_t* x) { - double x_double = lp_dyadic_rational_to_double(x); - return PyFloat_FromDouble(x_double); -} - - -PyObject* algebraic_number_to_PyFloat(const lp_algebraic_number_t* x) { - double x_double = lp_algebraic_number_to_double(x); - return PyFloat_FromDouble(x_double); -} - -int PyLong_or_Int_or_Float_Check(PyObject* o) { - if (PyLong_Check(o)) { - return 1; - } - if (PyFloat_Check(o)) { - return 1; - } - return 0; -} - -void PyLong_or_Int_or_float_to_value(PyObject* o, lp_value_t* v) { - if (PyLong_or_Int_Check(o)) { - lp_integer_t v_int; - PyLong_or_Int_to_integer(o, lp_Z, &v_int); - lp_value_construct(v, LP_VALUE_INTEGER, &v_int); - lp_integer_destruct(&v_int); - } else if (PyFloat_Check(o)) { - lp_dyadic_rational_t v_dy_q; - PyFloat_to_dyadic_rational(o, &v_dy_q); - lp_value_construct(v, LP_VALUE_INTEGER, &v_dy_q); - lp_dyadic_rational_destruct(&v_dy_q); - } else { - lp_value_construct(v, LP_VALUE_NONE, 0); - } -} diff --git a/src/polynomial/feasibility_set_int.c b/src/polynomial/feasibility_set_int.c index b791635f..9c9ea0e5 100644 --- a/src/polynomial/feasibility_set_int.c +++ b/src/polynomial/feasibility_set_int.c @@ -231,7 +231,7 @@ void lp_feasibility_set_int_pick_value(const lp_feasibility_set_int_t* set, lp_i // TODO proper implementation // get random element between (incl.) 0 and (|K| - size) // find and add number of <= element - assert(false); + assert(0); } } diff --git a/test/python/CMakeLists.txt b/test/python/CMakeLists.txt index 05932920..523ce22c 100644 --- a/test/python/CMakeLists.txt +++ b/test/python/CMakeLists.txt @@ -1,7 +1,7 @@ if(LIBPOLY_BUILD_PYTHON_API) add_custom_target(check COMMAND - PYTHONPATH=${CMAKE_BINARY_DIR}/python ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check.py + PYTHONPATH=$ENV{PYTHONPATH}:${CMAKE_BINARY_DIR}/python ${Python3_INTERPRETER} ${CMAKE_CURRENT_SOURCE_DIR}/check.py DEPENDS polypy WORKING_DIRECTORY diff --git a/test/python/check.py b/test/python/check.py index 60cf1456..4250cd7d 100755 --- a/test/python/check.py +++ b/test/python/check.py @@ -5,7 +5,7 @@ def forkexec(test, env): - if sys.version_info >= (3,0): #IAM: (3, 2) might be more accurate... + if sys.version_info >= (3,2): with open(test) as testf: code = compile(testf.read(), test, 'exec') #IAM: explicit compile makes debugging easier. exec(code, env, env)