python-sat 1.9.dev2__tar.gz → 1.9.dev4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-sat might be problematic. Click here for more details.

Files changed (113) hide show
  1. {python_sat-1.9.dev2/python_sat.egg-info → python_sat-1.9.dev4}/PKG-INFO +1 -1
  2. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/README.rst +2 -0
  3. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/pycard.cc +348 -111
  4. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/rc2.py +50 -23
  5. python_sat-1.9.dev4/formula/pf_parse.cc +466 -0
  6. python_sat-1.9.dev4/formula/pf_plus.cc +213 -0
  7. python_sat-1.9.dev4/formula/pf_weight.cc +45 -0
  8. python_sat-1.9.dev4/formula/pyformula.cc +153 -0
  9. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/__init__.py +1 -1
  10. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/_fileio.py +15 -0
  11. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/formula.py +84 -3
  12. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/integer.py +906 -245
  13. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/solvers.py +1898 -760
  14. {python_sat-1.9.dev2 → python_sat-1.9.dev4/python_sat.egg-info}/PKG-INFO +1 -1
  15. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/python_sat.egg-info/SOURCES.txt +8 -0
  16. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/python_sat.egg-info/top_level.txt +1 -0
  17. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/setup.py +19 -6
  18. python_sat-1.9.dev4/solvers/cadical300.tar.gz +0 -0
  19. python_sat-1.9.dev4/solvers/patches/cadical300.patch +4212 -0
  20. python_sat-1.9.dev4/solvers/patches/minisatep.patch +1620 -0
  21. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/prepare.py +212 -1
  22. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/pysolvers.cc +5385 -2531
  23. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_accum_stats.py +3 -1
  24. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_atmost1.py +6 -4
  25. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_atmostk.py +6 -4
  26. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_boolengine.py +5 -3
  27. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_cnf.py +3 -1
  28. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_equals1.py +7 -4
  29. python_sat-1.9.dev4/tests/test_formula_parsing.py +70 -0
  30. python_sat-1.9.dev4/tests/test_integer.py +626 -0
  31. python_sat-1.9.dev4/tests/test_propagate.py +109 -0
  32. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_unique_model.py +3 -1
  33. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_warmstart.py +1 -1
  34. python_sat-1.9.dev2/tests/test_integer.py +0 -305
  35. python_sat-1.9.dev2/tests/test_propagate.py +0 -36
  36. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/LICENSE.txt +0 -0
  37. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/MANIFEST.in +0 -0
  38. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/allies/__init__.py +0 -0
  39. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/allies/approxmc.py +0 -0
  40. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/allies/unigen.py +0 -0
  41. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/bitwise.hh +0 -0
  42. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/card.hh +0 -0
  43. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/clset.hh +0 -0
  44. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/common.hh +0 -0
  45. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/itot.hh +0 -0
  46. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/ladder.hh +0 -0
  47. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/mto.hh +0 -0
  48. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/pairwise.hh +0 -0
  49. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/ptypes.hh +0 -0
  50. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/seqcounter.hh +0 -0
  51. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/sortcard.hh +0 -0
  52. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/cardenc/utils.hh +0 -0
  53. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/__init__.py +0 -0
  54. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/bbscan.py +0 -0
  55. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/bica.py +0 -0
  56. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/fm.py +0 -0
  57. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/genhard.py +0 -0
  58. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/hitman.py +0 -0
  59. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/lbx.py +0 -0
  60. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/lsu.py +0 -0
  61. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/mcsls.py +0 -0
  62. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/models.py +0 -0
  63. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/musx.py +0 -0
  64. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/optux.py +0 -0
  65. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/primer.py +0 -0
  66. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/examples/usage.py +0 -0
  67. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/_utils.py +0 -0
  68. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/card.py +0 -0
  69. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/engines.py +0 -0
  70. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/pb.py +0 -0
  71. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/pysat/process.py +0 -0
  72. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/python_sat.egg-info/dependency_links.txt +0 -0
  73. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/python_sat.egg-info/requires.txt +0 -0
  74. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/requirements.txt +0 -0
  75. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/setup.cfg +0 -0
  76. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/cadical103.tar.gz +0 -0
  77. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/cadical153.tar.gz +0 -0
  78. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/cadical195.tar.gz +0 -0
  79. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/glucose30.tar.gz +0 -0
  80. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/glucose41.tar.gz +0 -0
  81. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/glucose421.tar.gz +0 -0
  82. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/lingeling.tar.gz +0 -0
  83. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/maplechrono.zip +0 -0
  84. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/maplecm.zip +0 -0
  85. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/maplesat.zip +0 -0
  86. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/mergesat3.tar.gz +0 -0
  87. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/minicard.tar.gz +0 -0
  88. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/minisat22.tar.gz +0 -0
  89. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/minisatgh.zip +0 -0
  90. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/cadical103.patch +0 -0
  91. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/cadical153.patch +0 -0
  92. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/cadical195.patch +0 -0
  93. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/glucose30.patch +0 -0
  94. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/glucose41.patch +0 -0
  95. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/glucose421.patch +0 -0
  96. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/gluecard30.patch +0 -0
  97. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/gluecard41.patch +0 -0
  98. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/kissat404.patch +0 -0
  99. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/lingeling.patch +0 -0
  100. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/maplechrono.patch +0 -0
  101. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/maplecm.patch +0 -0
  102. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/maplesat.patch +0 -0
  103. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/mergesat3.patch +0 -0
  104. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/minicard.patch +0 -0
  105. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/minisat22.patch +0 -0
  106. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/solvers/patches/minisatgh.patch +0 -0
  107. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_atmost.py +0 -0
  108. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_clausification.py +0 -0
  109. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_encode_pb_conditional.py +0 -0
  110. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_formula_unique.py +0 -0
  111. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_idpool.py +0 -0
  112. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_process.py +0 -0
  113. {python_sat-1.9.dev2 → python_sat-1.9.dev4}/tests/test_unique_mus.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-sat
3
- Version: 1.9.dev2
3
+ Version: 1.9.dev4
4
4
  Summary: A Python library for prototyping with SAT oracles
5
5
  Home-page: https://github.com/pysathq/pysat
6
6
  Author: Alexey Ignatiev, Joao Marques-Silva, Antonio Morgado
@@ -66,6 +66,7 @@ Minisat-based solvers only *core* versions are integrated):
66
66
  - CaDiCaL (`rel-1.0.3 <https://github.com/arminbiere/cadical>`__)
67
67
  - CaDiCaL (`rel-1.5.3 <https://github.com/arminbiere/cadical>`__)
68
68
  - CaDiCaL (`rel-1.9.5 <https://github.com/arminbiere/cadical>`__)
69
+ - CaDiCaL (`rel-3.0.0 <https://github.com/arminbiere/cadical>`__)
69
70
  - Glucose (`3.0 <http://www.labri.fr/perso/lsimon/glucose/>`__)
70
71
  - Glucose (`4.1 <http://www.labri.fr/perso/lsimon/glucose/>`__)
71
72
  - Glucose (`4.2.1 <http://www.labri.fr/perso/lsimon/glucose/>`__)
@@ -78,6 +79,7 @@ Minisat-based solvers only *core* versions are integrated):
78
79
  - Minicard (`1.2 <https://github.com/liffiton/minicard>`__)
79
80
  - Minisat (`2.2 release <http://minisat.se/MiniSat.html>`__)
80
81
  - Minisat (`GitHub version <https://github.com/niklasso/minisat>`__)
82
+ - Minisat (`with IPASIR-UP support <https://github.com/hchenqide/minisat>`__)
81
83
 
82
84
  In order to make SAT-based prototyping easier, PySAT integrates a variety of
83
85
  cardinality encodings. All of them are implemented from scratch in C++. The
@@ -11,6 +11,7 @@
11
11
  #include <setjmp.h>
12
12
  #include <signal.h>
13
13
  #include <stdio.h>
14
+ #include <stdint.h>
14
15
  #include <Python.h>
15
16
 
16
17
  #include "card.hh"
@@ -18,6 +19,10 @@
18
19
 
19
20
  using namespace std;
20
21
 
22
+ #ifndef PYCARD_ENABLE_PYINT_CACHE
23
+ #define PYCARD_ENABLE_PYINT_CACHE 1
24
+ #endif
25
+
21
26
  // docstrings
22
27
  //=============================================================================
23
28
  static char module_docstring[] = "This module provides an interface for "
@@ -37,6 +42,78 @@ static char itot_del_docstring[] = "Delete an iterative totalizer object";
37
42
  static PyObject *CardError;
38
43
  static jmp_buf env;
39
44
 
45
+ // forward declaration (implemented in Python2/Python3 branches below)
46
+ extern "C" {
47
+ static PyObject *pyint_from_cint(int i);
48
+ }
49
+
50
+ #define PYINT_CACHE_SIZE (1u << 8)
51
+
52
+ typedef struct {
53
+ int key;
54
+ PyObject *obj; // cache-owned reference
55
+ unsigned char used;
56
+ } PyIntCacheEntry;
57
+
58
+ typedef struct {
59
+ PyIntCacheEntry slots[PYINT_CACHE_SIZE];
60
+ uint16_t used_idx[PYINT_CACHE_SIZE];
61
+ size_t used_count;
62
+ } PyIntCache;
63
+
64
+ static inline uint32_t pyint_cache_hash(int v)
65
+ {
66
+ return ((uint32_t)v * 2654435761u) & (PYINT_CACHE_SIZE - 1u);
67
+ }
68
+
69
+ static PyObject *pyint_cache_get_or_make(PyIntCache *cache, int v)
70
+ {
71
+ #if PYCARD_ENABLE_PYINT_CACHE
72
+ uint32_t idx = pyint_cache_hash(v);
73
+ PyIntCacheEntry *e = &cache->slots[idx];
74
+ if (e->used && e->key == v) {
75
+ Py_INCREF(e->obj); // caller gets one ref
76
+ return e->obj;
77
+ }
78
+
79
+ PyObject *obj = pyint_from_cint(v);
80
+ if (obj == NULL)
81
+ return NULL;
82
+
83
+ if (e->used)
84
+ Py_DECREF(e->obj);
85
+ else
86
+ cache->used_idx[cache->used_count++] = (uint16_t)idx;
87
+
88
+ e->used = 1;
89
+ e->key = v;
90
+ e->obj = obj; // cache keeps one ref
91
+
92
+ Py_INCREF(obj); // caller gets one ref
93
+ return obj;
94
+ #else
95
+ (void)cache;
96
+ return pyint_from_cint(v);
97
+ #endif
98
+ }
99
+
100
+ static void pyint_cache_clear(PyIntCache *cache)
101
+ {
102
+ #if PYCARD_ENABLE_PYINT_CACHE
103
+ for (size_t i = 0; i < cache->used_count; ++i) {
104
+ PyIntCacheEntry *e = &cache->slots[cache->used_idx[i]];
105
+ if (e->used) {
106
+ Py_DECREF(e->obj);
107
+ e->obj = NULL;
108
+ e->used = 0;
109
+ }
110
+ }
111
+ cache->used_count = 0;
112
+ #else
113
+ (void)cache;
114
+ #endif
115
+ }
116
+
40
117
  // function declaration for functions available in module
41
118
  //=============================================================================
42
119
  extern "C" {
@@ -195,6 +272,40 @@ PyMODINIT_FUNC initpycard(void)
195
272
  //=============================================================================
196
273
  static bool pyiter_to_vector(PyObject *obj, vector<int>& vect)
197
274
  {
275
+ // Fast path for sequences (list/tuple and sequence-like objects).
276
+ // This avoids iterator protocol overhead and allows up-front reservation.
277
+ PyObject *seq = PySequence_Fast(obj, NULL);
278
+ if (seq != NULL) {
279
+ Py_ssize_t n = PySequence_Fast_GET_SIZE(seq);
280
+ if (n > 0)
281
+ vect.reserve(vect.size() + (size_t)n);
282
+
283
+ PyObject **items = PySequence_Fast_ITEMS(seq);
284
+ for (Py_ssize_t i = 0; i < n; ++i) {
285
+ PyObject *l_obj = items[i];
286
+ if (!pyint_check(l_obj)) {
287
+ Py_DECREF(seq);
288
+ PyErr_SetString(PyExc_TypeError, "integer expected");
289
+ return false;
290
+ }
291
+
292
+ int l = pyint_to_cint(l_obj);
293
+ if (l == 0) {
294
+ Py_DECREF(seq);
295
+ PyErr_SetString(PyExc_ValueError, "non-zero integer expected");
296
+ return false;
297
+ }
298
+
299
+ vect.push_back(l);
300
+ }
301
+
302
+ Py_DECREF(seq);
303
+ return true;
304
+ }
305
+
306
+ // If this failed because object is not a sequence, continue with iterator path.
307
+ PyErr_Clear();
308
+
198
309
  PyObject *i_obj = PyObject_GetIter(obj);
199
310
 
200
311
  if (i_obj == NULL) {
@@ -203,6 +314,19 @@ static bool pyiter_to_vector(PyObject *obj, vector<int>& vect)
203
314
  return false;
204
315
  }
205
316
 
317
+ PyObject *hint_obj = PyObject_CallMethod(i_obj, "__length_hint__", NULL);
318
+ if (hint_obj != NULL) {
319
+ if (pyint_check(hint_obj)) {
320
+ int hint = pyint_to_cint(hint_obj);
321
+ if (hint > 0)
322
+ vect.reserve(vect.size() + (size_t)hint);
323
+ }
324
+ Py_DECREF(hint_obj);
325
+ }
326
+ else {
327
+ PyErr_Clear();
328
+ }
329
+
206
330
  PyObject *l_obj;
207
331
  while ((l_obj = PyIter_Next(i_obj)) != NULL) {
208
332
  if (!pyint_check(l_obj)) {
@@ -224,10 +348,72 @@ static bool pyiter_to_vector(PyObject *obj, vector<int>& vect)
224
348
  vect.push_back(l);
225
349
  }
226
350
 
351
+ if (PyErr_Occurred()) {
352
+ Py_DECREF(i_obj);
353
+ return false;
354
+ }
355
+
227
356
  Py_DECREF(i_obj);
228
357
  return true;
229
358
  }
230
359
 
360
+ // Auxiliary function for translating ClauseSet to Python list of lists
361
+ //=============================================================================
362
+ static PyObject *clauseset_to_pylist(ClauseSet& dest, PyIntCache *cache)
363
+ {
364
+ Py_ssize_t ncls = (Py_ssize_t)dest.size();
365
+ PyObject *dest_obj = PyList_New(ncls);
366
+ if (dest_obj == NULL)
367
+ return NULL;
368
+
369
+ for (Py_ssize_t i = 0; i < ncls; ++i) {
370
+ const vector<int> &cl = dest[(size_t)i];
371
+ Py_ssize_t nlit = (Py_ssize_t)cl.size();
372
+ PyObject *cl_obj = PyList_New(nlit);
373
+ if (cl_obj == NULL) {
374
+ Py_DECREF(dest_obj);
375
+ return NULL;
376
+ }
377
+
378
+ for (Py_ssize_t j = 0; j < nlit; ++j) {
379
+ PyObject *lit_obj = pyint_cache_get_or_make(cache, cl[(size_t)j]);
380
+ if (lit_obj == NULL) {
381
+ Py_DECREF(cl_obj);
382
+ Py_DECREF(dest_obj);
383
+ return NULL;
384
+ }
385
+
386
+ PyList_SET_ITEM(cl_obj, j, lit_obj);
387
+ }
388
+
389
+ PyList_SET_ITEM(dest_obj, i, cl_obj);
390
+ }
391
+
392
+ return dest_obj;
393
+ }
394
+
395
+ // Auxiliary function for translating vector<int> to Python list
396
+ //=============================================================================
397
+ static PyObject *vector_to_pylist(const vector<int>& vals)
398
+ {
399
+ Py_ssize_t n = (Py_ssize_t)vals.size();
400
+ PyObject *lst = PyList_New(n);
401
+ if (lst == NULL)
402
+ return NULL;
403
+
404
+ for (Py_ssize_t i = 0; i < n; ++i) {
405
+ PyObject *v_obj = pyint_from_cint(vals[(size_t)i]);
406
+ if (v_obj == NULL) {
407
+ Py_DECREF(lst);
408
+ return NULL;
409
+ }
410
+
411
+ PyList_SET_ITEM(lst, i, v_obj);
412
+ }
413
+
414
+ return lst;
415
+ }
416
+
231
417
  //
232
418
  //=============================================================================
233
419
  static PyObject *py_encode_atmost(PyObject *self, PyObject *args)
@@ -263,22 +449,28 @@ static PyObject *py_encode_atmost(PyObject *self, PyObject *args)
263
449
  if (main_thread)
264
450
  PyOS_setsig(SIGINT, sig_save);
265
451
 
266
- // creating the resulting clause set
267
- PyObject *dest_obj = PyList_New(dest.size());
268
- for (size_t i = 0; i < dest.size(); ++i) {
269
- PyObject *cl_obj = PyList_New(dest[i].size());
452
+ PyIntCache cache = {};
453
+ PyObject *dest_obj = clauseset_to_pylist(dest, &cache);
454
+ pyint_cache_clear(&cache);
455
+ if (dest_obj == NULL)
456
+ return NULL;
270
457
 
271
- for (size_t j = 0; j < dest[i].size(); ++j) {
272
- PyObject *lit_obj = pyint_from_cint(dest[i][j]);
273
- PyList_SetItem(cl_obj, j, lit_obj);
458
+ if (dest.size()) {
459
+ PyObject *ret = PyTuple_New(2);
460
+ if (ret == NULL) {
461
+ Py_DECREF(dest_obj);
462
+ return NULL;
274
463
  }
275
464
 
276
- PyList_SetItem(dest_obj, i, cl_obj);
277
- }
465
+ PyObject *top_obj = pyint_from_cint(top);
466
+ if (top_obj == NULL) {
467
+ Py_DECREF(dest_obj);
468
+ Py_DECREF(ret);
469
+ return NULL;
470
+ }
278
471
 
279
- if (dest.size()) {
280
- PyObject *ret = Py_BuildValue("On", dest_obj, (Py_ssize_t)top);
281
- Py_DECREF(dest_obj);
472
+ PyTuple_SET_ITEM(ret, 0, dest_obj);
473
+ PyTuple_SET_ITEM(ret, 1, top_obj);
282
474
  return ret;
283
475
  }
284
476
  else {
@@ -322,30 +514,34 @@ static PyObject *py_encode_atleast(PyObject *self, PyObject *args)
322
514
  if (main_thread)
323
515
  PyOS_setsig(SIGINT, sig_save);
324
516
 
325
- // creating the resulting clause set
326
- PyObject *dest_obj = PyList_New(dest.size());
327
- for (size_t i = 0; i < dest.size(); ++i) {
328
- PyObject *cl_obj = PyList_New(dest[i].size());
517
+ PyIntCache cache = {};
518
+ PyObject *dest_obj = clauseset_to_pylist(dest, &cache);
519
+ pyint_cache_clear(&cache);
520
+ if (dest_obj == NULL)
521
+ return NULL;
329
522
 
330
- for (size_t j = 0; j < dest[i].size(); ++j) {
331
- PyObject *lit_obj = pyint_from_cint(dest[i][j]);
332
- PyList_SetItem(cl_obj, j, lit_obj);
523
+ if (dest.size()) {
524
+ PyObject *ret = PyTuple_New(2);
525
+ if (ret == NULL) {
526
+ Py_DECREF(dest_obj);
527
+ return NULL;
333
528
  }
334
529
 
335
- PyList_SetItem(dest_obj, i, cl_obj);
336
- }
530
+ PyObject *top_obj = pyint_from_cint(top);
531
+ if (top_obj == NULL) {
532
+ Py_DECREF(dest_obj);
533
+ Py_DECREF(ret);
534
+ return NULL;
535
+ }
337
536
 
338
- if (dest.size()) {
339
- PyObject *ret = Py_BuildValue("On", dest_obj, (Py_ssize_t)top);
340
- Py_DECREF(dest_obj);
537
+ PyTuple_SET_ITEM(ret, 0, dest_obj);
538
+ PyTuple_SET_ITEM(ret, 1, top_obj);
341
539
  return ret;
342
-
343
540
  }
344
541
  else {
345
542
  Py_DECREF(dest_obj);
346
543
  Py_RETURN_NONE;
347
544
  }
348
-
349
545
  }
350
546
 
351
547
  //
@@ -381,31 +577,43 @@ static PyObject *py_itot_new(PyObject *self, PyObject *args)
381
577
  if (main_thread)
382
578
  PyOS_setsig(SIGINT, sig_save);
383
579
 
384
- // creating the resulting clause set
385
- PyObject *dest_obj = PyList_New(dest.size());
386
- for (size_t i = 0; i < dest.size(); ++i) {
387
- PyObject *cl_obj = PyList_New(dest[i].size());
388
-
389
- for (size_t j = 0; j < dest[i].size(); ++j) {
390
- PyObject *lit_obj = pyint_from_cint(dest[i][j]);
391
- PyList_SetItem(cl_obj, j, lit_obj);
392
- }
580
+ PyIntCache cache = {};
581
+ PyObject *dest_obj = clauseset_to_pylist(dest, &cache);
582
+ pyint_cache_clear(&cache);
583
+ if (dest_obj == NULL)
584
+ return NULL;
393
585
 
394
- PyList_SetItem(dest_obj, i, cl_obj);
586
+ PyObject *ubs_obj = vector_to_pylist(tree->vars);
587
+ if (ubs_obj == NULL) {
588
+ Py_DECREF(dest_obj);
589
+ return NULL;
395
590
  }
396
-
397
- // creating the upper-bounds (right-hand side)
398
- PyObject *ubs_obj = PyList_New(tree->vars.size());
399
- for (size_t i = 0; i < tree->vars.size(); ++i) {
400
- PyObject *ub_obj = pyint_from_cint(tree->vars[i]);
401
- PyList_SetItem(ubs_obj, i, ub_obj);
591
+ PyObject *tree_obj = void_to_pyobj((void *)tree);
592
+ if (tree_obj == NULL) {
593
+ Py_DECREF(dest_obj);
594
+ Py_DECREF(ubs_obj);
595
+ return NULL;
596
+ }
597
+ PyObject *top_obj = pyint_from_cint(top);
598
+ if (top_obj == NULL) {
599
+ Py_DECREF(dest_obj);
600
+ Py_DECREF(ubs_obj);
601
+ Py_DECREF(tree_obj);
602
+ return NULL;
402
603
  }
403
604
 
404
- PyObject *ret = Py_BuildValue("OOOn", void_to_pyobj((void *)tree),
405
- dest_obj, ubs_obj, (Py_ssize_t)top);
406
-
407
- Py_DECREF(dest_obj);
408
- Py_DECREF( ubs_obj);
605
+ PyObject *ret = PyTuple_New(4);
606
+ if (ret == NULL) {
607
+ Py_DECREF(dest_obj);
608
+ Py_DECREF(ubs_obj);
609
+ Py_DECREF(tree_obj);
610
+ Py_DECREF(top_obj);
611
+ return NULL;
612
+ }
613
+ PyTuple_SET_ITEM(ret, 0, tree_obj);
614
+ PyTuple_SET_ITEM(ret, 1, dest_obj);
615
+ PyTuple_SET_ITEM(ret, 2, ubs_obj);
616
+ PyTuple_SET_ITEM(ret, 3, top_obj);
409
617
  return ret;
410
618
  }
411
619
 
@@ -441,30 +649,34 @@ static PyObject *py_itot_inc(PyObject *self, PyObject *args)
441
649
  if (main_thread)
442
650
  PyOS_setsig(SIGINT, sig_save);
443
651
 
444
- // creating the resulting clause set
445
- PyObject *dest_obj = PyList_New(dest.size());
446
- for (size_t i = 0; i < dest.size(); ++i) {
447
- PyObject *cl_obj = PyList_New(dest[i].size());
448
-
449
- for (size_t j = 0; j < dest[i].size(); ++j) {
450
- PyObject *lit_obj = pyint_from_cint(dest[i][j]);
451
- PyList_SetItem(cl_obj, j, lit_obj);
452
- }
652
+ PyIntCache cache = {};
653
+ PyObject *dest_obj = clauseset_to_pylist(dest, &cache);
654
+ pyint_cache_clear(&cache);
655
+ if (dest_obj == NULL)
656
+ return NULL;
453
657
 
454
- PyList_SetItem(dest_obj, i, cl_obj);
658
+ PyObject *ubs_obj = vector_to_pylist(tree->vars);
659
+ if (ubs_obj == NULL) {
660
+ Py_DECREF(dest_obj);
661
+ return NULL;
455
662
  }
456
-
457
- // creating the upper-bounds (right-hand side)
458
- PyObject *ubs_obj = PyList_New(tree->vars.size());
459
- for (size_t i = 0; i < tree->vars.size(); ++i) {
460
- PyObject *ub_obj = pyint_from_cint(tree->vars[i]);
461
- PyList_SetItem(ubs_obj, i, ub_obj);
663
+ PyObject *top_obj = pyint_from_cint(top);
664
+ if (top_obj == NULL) {
665
+ Py_DECREF(dest_obj);
666
+ Py_DECREF(ubs_obj);
667
+ return NULL;
462
668
  }
463
669
 
464
- PyObject *ret = Py_BuildValue("OOn", dest_obj, ubs_obj, (Py_ssize_t)top);
465
-
466
- Py_DECREF(dest_obj);
467
- Py_DECREF( ubs_obj);
670
+ PyObject *ret = PyTuple_New(3);
671
+ if (ret == NULL) {
672
+ Py_DECREF(dest_obj);
673
+ Py_DECREF(ubs_obj);
674
+ Py_DECREF(top_obj);
675
+ return NULL;
676
+ }
677
+ PyTuple_SET_ITEM(ret, 0, dest_obj);
678
+ PyTuple_SET_ITEM(ret, 1, ubs_obj);
679
+ PyTuple_SET_ITEM(ret, 2, top_obj);
468
680
  return ret;
469
681
  }
470
682
 
@@ -506,31 +718,43 @@ static PyObject *py_itot_ext(PyObject *self, PyObject *args)
506
718
  if (main_thread)
507
719
  PyOS_setsig(SIGINT, sig_save);
508
720
 
509
- // creating the resulting clause set
510
- PyObject *dest_obj = PyList_New(dest.size());
511
- for (size_t i = 0; i < dest.size(); ++i) {
512
- PyObject *cl_obj = PyList_New(dest[i].size());
513
-
514
- for (size_t j = 0; j < dest[i].size(); ++j) {
515
- PyObject *lit_obj = pyint_from_cint(dest[i][j]);
516
- PyList_SetItem(cl_obj, j, lit_obj);
517
- }
721
+ PyIntCache cache = {};
722
+ PyObject *dest_obj = clauseset_to_pylist(dest, &cache);
723
+ pyint_cache_clear(&cache);
724
+ if (dest_obj == NULL)
725
+ return NULL;
518
726
 
519
- PyList_SetItem(dest_obj, i, cl_obj);
727
+ PyObject *ubs_obj = vector_to_pylist(tree->vars);
728
+ if (ubs_obj == NULL) {
729
+ Py_DECREF(dest_obj);
730
+ return NULL;
520
731
  }
521
-
522
- // creating the upper-bounds (right-hand side)
523
- PyObject *ubs_obj = PyList_New(tree->vars.size());
524
- for (size_t i = 0; i < tree->vars.size(); ++i) {
525
- PyObject *ub_obj = pyint_from_cint(tree->vars[i]);
526
- PyList_SetItem(ubs_obj, i, ub_obj);
732
+ PyObject *tree_obj = void_to_pyobj((void *)tree);
733
+ if (tree_obj == NULL) {
734
+ Py_DECREF(dest_obj);
735
+ Py_DECREF(ubs_obj);
736
+ return NULL;
737
+ }
738
+ PyObject *top_obj = pyint_from_cint(top);
739
+ if (top_obj == NULL) {
740
+ Py_DECREF(dest_obj);
741
+ Py_DECREF(ubs_obj);
742
+ Py_DECREF(tree_obj);
743
+ return NULL;
527
744
  }
528
745
 
529
- PyObject *ret = Py_BuildValue("OOOn", void_to_pyobj((void *)tree),
530
- dest_obj, ubs_obj, (Py_ssize_t)top);
531
-
532
- Py_DECREF(dest_obj);
533
- Py_DECREF( ubs_obj);
746
+ PyObject *ret = PyTuple_New(4);
747
+ if (ret == NULL) {
748
+ Py_DECREF(dest_obj);
749
+ Py_DECREF(ubs_obj);
750
+ Py_DECREF(tree_obj);
751
+ Py_DECREF(top_obj);
752
+ return NULL;
753
+ }
754
+ PyTuple_SET_ITEM(ret, 0, tree_obj);
755
+ PyTuple_SET_ITEM(ret, 1, dest_obj);
756
+ PyTuple_SET_ITEM(ret, 2, ubs_obj);
757
+ PyTuple_SET_ITEM(ret, 3, top_obj);
534
758
  return ret;
535
759
  }
536
760
 
@@ -569,39 +793,52 @@ static PyObject *py_itot_mrg(PyObject *self, PyObject *args)
569
793
  if (main_thread)
570
794
  PyOS_setsig(SIGINT, sig_save);
571
795
 
572
- // creating the resulting clause set
573
- PyObject *dest_obj = PyList_New(dest.size());
574
- for (size_t i = 0; i < dest.size(); ++i) {
575
- PyObject *cl_obj = PyList_New(dest[i].size());
576
-
577
- for (size_t j = 0; j < dest[i].size(); ++j) {
578
- PyObject *lit_obj = pyint_from_cint(dest[i][j]);
579
- PyList_SetItem(cl_obj, j, lit_obj);
580
- }
581
-
582
- PyList_SetItem(dest_obj, i, cl_obj);
583
- }
796
+ PyIntCache cache = {};
797
+ PyObject *dest_obj = clauseset_to_pylist(dest, &cache);
798
+ pyint_cache_clear(&cache);
799
+ if (dest_obj == NULL)
800
+ return NULL;
584
801
 
585
- // creating the upper-bounds (right-hand side)
586
- PyObject *ubs_obj = PyList_New(tree1->vars.size());
587
- for (size_t i = 0; i < tree1->vars.size(); ++i) {
588
- PyObject *ub_obj = pyint_from_cint(tree1->vars[i]);
589
- PyList_SetItem(ubs_obj, i, ub_obj);
802
+ PyObject *ubs_obj = vector_to_pylist(tree1->vars);
803
+ if (ubs_obj == NULL) {
804
+ Py_DECREF(dest_obj);
805
+ return NULL;
590
806
  }
591
807
 
592
808
  if (dest.size()) {
593
- PyObject *ret = Py_BuildValue("OOOn", void_to_pyobj((void *)tree1),
594
- dest_obj, ubs_obj, (Py_ssize_t)top);
595
- Py_DECREF(dest_obj);
596
- Py_DECREF( ubs_obj);
809
+ PyObject *tree_obj = void_to_pyobj((void *)tree1);
810
+ if (tree_obj == NULL) {
811
+ Py_DECREF(dest_obj);
812
+ Py_DECREF(ubs_obj);
813
+ return NULL;
814
+ }
815
+ PyObject *top_obj = pyint_from_cint(top);
816
+ if (top_obj == NULL) {
817
+ Py_DECREF(dest_obj);
818
+ Py_DECREF(ubs_obj);
819
+ Py_DECREF(tree_obj);
820
+ return NULL;
821
+ }
822
+
823
+ PyObject *ret = PyTuple_New(4);
824
+ if (ret == NULL) {
825
+ Py_DECREF(dest_obj);
826
+ Py_DECREF(ubs_obj);
827
+ Py_DECREF(tree_obj);
828
+ Py_DECREF(top_obj);
829
+ return NULL;
830
+ }
831
+ PyTuple_SET_ITEM(ret, 0, tree_obj);
832
+ PyTuple_SET_ITEM(ret, 1, dest_obj);
833
+ PyTuple_SET_ITEM(ret, 2, ubs_obj);
834
+ PyTuple_SET_ITEM(ret, 3, top_obj);
597
835
  return ret;
598
836
  }
599
837
  else {
600
838
  Py_DECREF(dest_obj);
601
- Py_DECREF( ubs_obj);
839
+ Py_DECREF(ubs_obj);
602
840
  Py_RETURN_NONE;
603
841
  }
604
-
605
842
  }
606
843
 
607
844
  //