Commit 70efd855 authored by VIGNET Pierre's avatar VIGNET Pierre
Browse files

[lib] C: Refactor shift_clause & forward_code

Remove calls to python functions and replace them with much more efficient pure C functions
parent 02dd9d96
......@@ -116,55 +116,13 @@ int raw_get_unshift_code(int* var_num, int* shift_step)
return var_code * ((*var_num < 0) ? -1 : 1);
}
PyDoc_STRVAR(shift_clause_doc,
"shift_clause(numeric_clause, shift_step)\n\
Implementation of the shift operator. Shift a numeric clause in one step.\n\
\n\
Basically, `shift_step` is added to positive variables and subtracted\n\
from negative variables in `numeric_clause`.\n\
\n\
.. warning:: Before the call you MUST lock the unfolder with:\n\
\"self.__locked = True\".\n\
\n\
:param numeric_clause: DIMACS clause (list of literals)\n\
:param shift_step: Shift step dependant on the run\n\
:return: DIMACS literal coding of x_0 with same value\n\
:type numeric_clause: <list <int>>\n\
:type shift_step: <int>\n\
:rtype: <list>"
);
static PyObject* shift_clause(PyObject *self, PyObject *args, PyObject *kwds)
static int _shift_clause(PyObject *self, PyObject *numeric_clause, PyObject *shifted_clause, int* shift_step)
{
// https://docs.python.org/2/c-api/iter.html
#ifndef NDEBUG
/* Debugging code */
printf("shift clause\n");
#endif
int shift_step;
PyObject *numeric_clause;
static char* kwlist[] = {"numeric_clause", "shift_step", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist,
&numeric_clause,
&shift_step)) {
return NULL;
}
PyObject *numeric_clause_iterator = PyObject_GetIter(numeric_clause);
if (numeric_clause_iterator == NULL) {
/* propagate error */
PyErr_SetString(PyExc_SystemError, "could not create iterator on clause");
return NULL;
}
// Declare a new list with the size of the given one
PyObject *shifted_clause = PyList_New(PySequence_Size(numeric_clause));
if (shifted_clause == NULL) {
PyErr_SetString(PyExc_SystemError, "failed to create a list");
return NULL;
return 0;
}
PyObject *lit;
......@@ -176,7 +134,9 @@ static PyObject* shift_clause(PyObject *self, PyObject *args, PyObject *kwds)
/* Debugging code */
if (!IS_INT(lit)) {
PyErr_SetString(PyExc_TypeError, "integer expected in list");
return NULL;
Py_DECREF(numeric_clause_iterator);
Py_DECREF(lit);
return 0;
}
#endif
......@@ -185,15 +145,15 @@ static PyObject* shift_clause(PyObject *self, PyObject *args, PyObject *kwds)
if (lit_val > 0) {
#ifdef IS_PY3K
shifted_lit = PyLong_FromLong(lit_val + shift_step);
shifted_lit = PyLong_FromLong(lit_val + *shift_step);
#else
shifted_lit = PyInt_FromLong(lit_val + shift_step);
shifted_lit = PyInt_FromLong(lit_val + *shift_step);
#endif
} else {
#ifdef IS_PY3K
shifted_lit = PyLong_FromLong(lit_val - shift_step);
shifted_lit = PyLong_FromLong(lit_val - *shift_step);
#else
shifted_lit = PyInt_FromLong(lit_val - shift_step);
shifted_lit = PyInt_FromLong(lit_val - *shift_step);
#endif
}
......@@ -215,73 +175,88 @@ static PyObject* shift_clause(PyObject *self, PyObject *args, PyObject *kwds)
if (PyErr_Occurred()) {
/* propagate error */
Py_DECREF(shifted_clause);
return PyErr_SetFromErrno(outofconflerr);
return 0;
}
// Return list of all shifted literals
return shifted_clause;
return 1;
}
PyDoc_STRVAR(forward_code_doc,
"forward_code(clause, var_code_table, shift_step)\n\
Translation from names to num codes. The translation depends on the shift direction.\n\
PyDoc_STRVAR(shift_clause_doc,
"shift_clause(numeric_clause, shift_step)\n\
Implementation of the shift operator. Shift a numeric clause in one step.\n\
\n\
Numerically code a clause with the numeric codes found in self.__var_code_table for\n\
a base variable x and numeric_code + shift_step for x'\n\
variable integer coding increases in future steps.\n\
Basically, `shift_step` is added to positive variables and subtracted\n\
from negative variables in `numeric_clause`.\n\
\n\
..note:: Future variables x' are noted \"name`\" in Literal names.\n\
Values of variables increases of __shift_step in future steps.\n\
.. warning:: Before the call you MUST lock the unfolder with:\n\
\"self.__locked = True\".\n\
\n\
:param clause: a Clause object\n\
:param var_code_table: Var code table from the model\n\
:param numeric_clause: DIMACS clause (list of literals)\n\
:param shift_step: Shift step dependant on the run\n\
:return: the DIMACS coding of the forward shifted clause\n\
:type clause: <list <int>>\n\
:type var_code_table: <dict>\n\
:return: DIMACS literal coding of x_0 with same value\n\
:type numeric_clause: <list <int>>\n\
:type shift_step: <int>\n\
:rtype: <list>"
);
static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
static PyObject* shift_clause(PyObject *self, PyObject *args, PyObject *kwds)
{
// https://docs.python.org/2/c-api/iter.html
#ifndef NDEBUG
/* Debugging code */
printf("forward code\n");
printf("shift clause\n");
#endif
int shift_step;
PyObject *clause;
PyObject *var_code_table;
PyObject *numeric_clause;
static char* kwlist[] = {"clause", "var_code_table", "shift_step", NULL};
static char* kwlist[] = {"numeric_clause", "shift_step", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi", kwlist,
&clause,
&var_code_table,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist,
&numeric_clause,
&shift_step)) {
return NULL;
}
// Declare a new list with the size of the given one
PyObject *shifted_clause = PyList_New(PySequence_Size(numeric_clause));
if (shifted_clause == NULL) {
PyErr_SetString(PyExc_SystemError, "failed to create a list");
return NULL;
}
// Shift clause and fill shifted_clause (new ref)
int ret = _shift_clause(self, numeric_clause, shifted_clause, &shift_step);
if (ret == 0 || PyErr_Occurred()) {
/* propagate error */
Py_XDECREF(shifted_clause);
return PyErr_SetFromErrno(outofconflerr);
}
// Return list of all shifted literals
return shifted_clause;
}
static int _forward_code(PyObject *self, PyObject *clause, PyObject **numeric_clause, PyObject *var_code_table, int* shift_step)
{
// Get attr literals of clause object
PyObject* literals = PyObject_GetAttrString(clause, "literals");
if (literals == NULL) {
PyErr_SetString(PyExc_SystemError, "failed get attribute 'literals' on clause object");
return NULL;
return 0;
}
PyObject *literals_iterator = PyObject_GetIter(literals);
if (literals_iterator == NULL) {
PyErr_SetString(PyExc_SystemError, "could not create iterator on 'literals' attribute");
return NULL;
return 0;
}
// Declare a new list with the size of 'literals'
PyObject *numeric_clause = PyList_New(PySequence_Size(literals));
if (numeric_clause == NULL) {
*numeric_clause = PyList_New(PySequence_Size(literals));
if (*numeric_clause == NULL) {
PyErr_SetString(PyExc_SystemError, "failed to create a list");
return NULL;
return 0;
}
// Append does not steal a reference, so we need Py_DECREF
// SET_ITEM steals a reference, so: no Py_DECREF on items !
......@@ -295,12 +270,10 @@ static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *multiply_result;
#ifdef IS_PY3K
PyObject *last_char = PyUnicode_FromString("`");
PyObject *py_shift_step = PyLong_FromLong(shift_step);
PyObject *minus_one = PyLong_FromLong(-1);
PyObject *py_shift_step = PyLong_FromLong(*shift_step);
#else
PyObject *last_char = PyString_FromString("`");
PyObject *py_shift_step = PyInt_FromLong(shift_step);
PyObject *minus_one = PyInt_FromLong(-1);
PyObject *py_shift_step = PyInt_FromLong(*shift_step);
#endif
Py_ssize_t i = 0;
Py_ssize_t name_size = 0;
......@@ -320,8 +293,16 @@ static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
// Borrowed reference
variable_value = PyDict_GetItem(var_code_table, lit_name);
if (variable_value == NULL) {
Py_DECREF(lit_name);
Py_DECREF(lit_sign);
Py_DECREF(lit);
Py_DECREF(literals);
Py_DECREF(literals_iterator);
Py_DECREF(last_char);
Py_DECREF(py_shift_step);
PyErr_SetString(PyExc_KeyError, "lit_name not found in dict");
return NULL;
return 0;
}
// Because variable_value reference IS borrowed (owned by PyDict_GetItem)
// we don't do Py_DECREF(variable_value);
......@@ -334,7 +315,7 @@ static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
// t+1 variable
// Add shift_step to the value corresponding to the given name
lit_val = PyLong_AsLong(variable_value) + shift_step;
lit_val = PyLong_AsLong(variable_value) + *shift_step;
// Ret of PyObject_Not is: 1 if lit is false, -1 on failure
#ifdef IS_PY3K
......@@ -358,7 +339,7 @@ static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
}
// Because PyList_SET_ITEM steals the reference of multiply_result, we don't do Py_DECREF(multiply_result);
PyList_SET_ITEM(numeric_clause, i, multiply_result);
PyList_SET_ITEM(*numeric_clause, i, multiply_result);
// Note:
// Add new lit_cod (use SET_ITEM instead of PyList_Append)
......@@ -381,11 +362,62 @@ static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
Py_DECREF(literals_iterator);
Py_DECREF(last_char);
Py_DECREF(py_shift_step);
Py_DECREF(minus_one);
if (PyErr_Occurred()) {
/* propagate error */
Py_DECREF(numeric_clause);
return 0;
}
return 1;
}
PyDoc_STRVAR(forward_code_doc,
"forward_code(clause, var_code_table, shift_step)\n\
Translation from names to num codes. The translation depends on the shift direction.\n\
\n\
Numerically code a clause with the numeric codes found in self.__var_code_table for\n\
a base variable x and numeric_code + shift_step for x'\n\
variable integer coding increases in future steps.\n\
\n\
..note:: Future variables x' are noted \"name`\" in Literal names.\n\
Values of variables increases of __shift_step in future steps.\n\
\n\
:param clause: a Clause object\n\
:param var_code_table: Var code table from the model\n\
:param shift_step: Shift step dependant on the run\n\
:return: the DIMACS coding of the forward shifted clause\n\
:type clause: <list <int>>\n\
:type var_code_table: <dict>\n\
:type shift_step: <int>\n\
:rtype: <list>"
);
static PyObject* forward_code(PyObject *self, PyObject *args, PyObject *kwds)
{
#ifndef NDEBUG
/* Debugging code */
printf("forward code\n");
#endif
int shift_step;
PyObject *clause;
PyObject *var_code_table;
static char* kwlist[] = {"clause", "var_code_table", "shift_step", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi", kwlist,
&clause,
&var_code_table,
&shift_step)) {
return NULL;
}
PyObject *numeric_clause = NULL;
// Shift clause and fill shifted_clause (new ref)
int ret = _forward_code(self, clause, &numeric_clause, var_code_table, &shift_step);
if (ret == 0 || PyErr_Occurred()) {
/* propagate error */
Py_XDECREF(numeric_clause);
return PyErr_SetFromErrno(outofconflerr);
}
......@@ -460,18 +492,25 @@ static PyObject* forward_init_dynamic(PyObject *self, PyObject *args, PyObject *
}
PyObject *clause;
PyObject *arglist;
Py_ssize_t i = 0;
PyObject *numeric_clause = NULL;
while ((clause = PyIter_Next(clauses_iterator)) != NULL) {
// Build parameters of forward_code
// {"clause", "var_code_table", "shift_step", NULL};
arglist = Py_BuildValue("(OOi)", clause, var_code_table, shift_step);
PyList_SET_ITEM(numeric_clauses, i, forward_code(self, arglist, NULL));
// Forward code the non numeric clause to numeric_clause (new ref)
int ret = _forward_code(self, clause, &numeric_clause, var_code_table, &shift_step);
if (ret == 0 || PyErr_Occurred()) {
/* propagate error */
Py_XDECREF(numeric_clause);
Py_DECREF(clauses_iterator);
Py_DECREF(clause);
Py_DECREF(numeric_clauses);
return PyErr_SetFromErrno(outofconflerr);
}
PyList_SET_ITEM(numeric_clauses, i, numeric_clause);
/* release reference when done */
// no DECREF on the return of forward_code, because PyList_SET_ITEM steals reference
Py_DECREF(arglist);
Py_DECREF(clause);
i++;
......@@ -491,14 +530,21 @@ static PyObject* forward_init_dynamic(PyObject *self, PyObject *args, PyObject *
while ((clause = PyIter_Next(clauses_iterator)) != NULL) {
// Build parameters of forward_code
// {"clause", "var_code_table", "shift_step", NULL};
arglist = Py_BuildValue("(OOi)", clause, var_code_table, shift_step);
PyList_SET_ITEM(numeric_clauses, i, forward_code(self, arglist, NULL));
// Forward code the non numeric clause to numeric_clause (new ref)
int ret = _forward_code(self, clause, &numeric_clause, var_code_table, &shift_step);
if (ret == 0 || PyErr_Occurred()) {
/* propagate error */
Py_XDECREF(numeric_clause);
Py_DECREF(clauses_iterator);
Py_DECREF(clause);
Py_DECREF(numeric_clauses);
return PyErr_SetFromErrno(outofconflerr);
}
PyList_SET_ITEM(numeric_clauses, i, numeric_clause);
/* release reference when done */
// no DECREF on the return of forward_code, because PyList_SET_ITEM steals reference
Py_DECREF(arglist);
Py_DECREF(clause);
i++;
......@@ -585,21 +631,25 @@ static PyObject* shift_dynamic(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *shifted_clause;
PyObject *clause;
PyObject *arglist;
Py_ssize_t i = 0;
while ((clause = PyIter_Next(numeric_clauses_iterator)) != NULL) {
// Build parameters of shift_clause
// shifted_clause = shift_clause(self, clause, shift_step);
arglist = Py_BuildValue("(Oi)", clause, shift_step);
shifted_clause = shift_clause(self, arglist, NULL); // new ref
Py_DECREF(arglist);
// Declare a new list with the size of the given one
shifted_clause = PyList_New(PySequence_Size(clause));
if (shifted_clause == NULL) {
PyErr_SetString(PyExc_SystemError, "failed to create a list");
return NULL;
}
if(shifted_clause == NULL) {
/* Pass error back */
// Shift clause and fill shifted_clause (new ref)
int ret = _shift_clause(self, clause, shifted_clause, &shift_step);
if (ret == 0 || PyErr_Occurred()) {
/* propagate error */
Py_XDECREF(shifted_clause);
Py_DECREF(shifted_numeric_clauses);
Py_DECREF(numeric_clauses_iterator);
return NULL;
Py_DECREF(clause);
return PyErr_SetFromErrno(outofconflerr);
}
PyList_SET_ITEM(shifted_numeric_clauses, i, shifted_clause);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment