python-sat 1.9.dev4__tar.gz → 1.9.dev5__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.
Files changed (116) hide show
  1. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/MANIFEST.in +1 -0
  2. {python_sat-1.9.dev4/python_sat.egg-info → python_sat-1.9.dev5}/PKG-INFO +1 -1
  3. python_sat-1.9.dev5/formula/pf_plus.hh +36 -0
  4. python_sat-1.9.dev5/formula/pf_py.hh +185 -0
  5. python_sat-1.9.dev5/formula/pf_scan.hh +181 -0
  6. python_sat-1.9.dev5/formula/pf_weight.hh +93 -0
  7. python_sat-1.9.dev5/formula/pyformula.hh +99 -0
  8. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/__init__.py +1 -1
  9. {python_sat-1.9.dev4 → python_sat-1.9.dev5/python_sat.egg-info}/PKG-INFO +1 -1
  10. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/SOURCES.txt +5 -0
  11. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/LICENSE.txt +0 -0
  12. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/README.rst +0 -0
  13. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/allies/__init__.py +0 -0
  14. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/allies/approxmc.py +0 -0
  15. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/allies/unigen.py +0 -0
  16. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/bitwise.hh +0 -0
  17. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/card.hh +0 -0
  18. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/clset.hh +0 -0
  19. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/common.hh +0 -0
  20. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/itot.hh +0 -0
  21. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/ladder.hh +0 -0
  22. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/mto.hh +0 -0
  23. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/pairwise.hh +0 -0
  24. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/ptypes.hh +0 -0
  25. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/pycard.cc +0 -0
  26. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/seqcounter.hh +0 -0
  27. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/sortcard.hh +0 -0
  28. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/utils.hh +0 -0
  29. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/__init__.py +0 -0
  30. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/bbscan.py +0 -0
  31. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/bica.py +0 -0
  32. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/fm.py +0 -0
  33. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/genhard.py +0 -0
  34. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/hitman.py +0 -0
  35. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/lbx.py +0 -0
  36. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/lsu.py +0 -0
  37. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/mcsls.py +0 -0
  38. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/models.py +0 -0
  39. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/musx.py +0 -0
  40. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/optux.py +0 -0
  41. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/primer.py +0 -0
  42. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/rc2.py +0 -0
  43. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/usage.py +0 -0
  44. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pf_parse.cc +0 -0
  45. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pf_plus.cc +0 -0
  46. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pf_weight.cc +0 -0
  47. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pyformula.cc +0 -0
  48. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/_fileio.py +0 -0
  49. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/_utils.py +0 -0
  50. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/card.py +0 -0
  51. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/engines.py +0 -0
  52. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/formula.py +0 -0
  53. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/integer.py +0 -0
  54. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/pb.py +0 -0
  55. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/process.py +0 -0
  56. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/solvers.py +0 -0
  57. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/dependency_links.txt +0 -0
  58. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/requires.txt +0 -0
  59. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/top_level.txt +0 -0
  60. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/requirements.txt +0 -0
  61. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/setup.cfg +0 -0
  62. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/setup.py +0 -0
  63. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical103.tar.gz +0 -0
  64. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical153.tar.gz +0 -0
  65. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical195.tar.gz +0 -0
  66. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical300.tar.gz +0 -0
  67. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/glucose30.tar.gz +0 -0
  68. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/glucose41.tar.gz +0 -0
  69. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/glucose421.tar.gz +0 -0
  70. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/lingeling.tar.gz +0 -0
  71. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/maplechrono.zip +0 -0
  72. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/maplecm.zip +0 -0
  73. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/maplesat.zip +0 -0
  74. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/mergesat3.tar.gz +0 -0
  75. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/minicard.tar.gz +0 -0
  76. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/minisat22.tar.gz +0 -0
  77. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/minisatgh.zip +0 -0
  78. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical103.patch +0 -0
  79. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical153.patch +0 -0
  80. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical195.patch +0 -0
  81. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical300.patch +0 -0
  82. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/glucose30.patch +0 -0
  83. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/glucose41.patch +0 -0
  84. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/glucose421.patch +0 -0
  85. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/gluecard30.patch +0 -0
  86. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/gluecard41.patch +0 -0
  87. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/kissat404.patch +0 -0
  88. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/lingeling.patch +0 -0
  89. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/maplechrono.patch +0 -0
  90. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/maplecm.patch +0 -0
  91. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/maplesat.patch +0 -0
  92. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/mergesat3.patch +0 -0
  93. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minicard.patch +0 -0
  94. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minisat22.patch +0 -0
  95. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minisatep.patch +0 -0
  96. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minisatgh.patch +0 -0
  97. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/prepare.py +0 -0
  98. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/pysolvers.cc +0 -0
  99. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_accum_stats.py +0 -0
  100. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_atmost.py +0 -0
  101. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_atmost1.py +0 -0
  102. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_atmostk.py +0 -0
  103. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_boolengine.py +0 -0
  104. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_clausification.py +0 -0
  105. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_cnf.py +0 -0
  106. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_encode_pb_conditional.py +0 -0
  107. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_equals1.py +0 -0
  108. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_formula_parsing.py +0 -0
  109. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_formula_unique.py +0 -0
  110. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_idpool.py +0 -0
  111. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_integer.py +0 -0
  112. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_process.py +0 -0
  113. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_propagate.py +0 -0
  114. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_unique_model.py +0 -0
  115. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_unique_mus.py +0 -0
  116. {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_warmstart.py +0 -0
@@ -6,3 +6,4 @@ recursive-include cardenc *.hh
6
6
  include solvers/prepare.py
7
7
  recursive-include solvers *.patch
8
8
  recursive-include solvers *.zip *.tar.gz
9
+ recursive-include formula *.hh
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-sat
3
- Version: 1.9.dev4
3
+ Version: 1.9.dev5
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
@@ -0,0 +1,36 @@
1
+ /*
2
+ * pf_plus.hh
3
+ *
4
+ * Created on: May 19, 2025
5
+ * Author: Alexey Ignatiev
6
+ * E-mail: alexey.ignatiev@monash.edu
7
+ */
8
+
9
+ #ifndef __PF_PLUS_HH__
10
+ #define __PF_PLUS_HH__
11
+
12
+ #include "pyformula.hh"
13
+
14
+ // reset the temporary state used for CNF+/WCNF+ bodies
15
+ //=============================================================================
16
+ static inline void init_plus_body(plus_body &body)
17
+ {
18
+ body.weighted = false;
19
+ body.clause = false;
20
+ body.rhs = 0;
21
+ body.sumw = 0;
22
+ body.lits.clear();
23
+ body.wght.clear();
24
+ }
25
+
26
+ // normalize a >= constraint into an equivalent <= form
27
+ //=============================================================================
28
+ static inline void normalize_ge(plus_body &body)
29
+ {
30
+ for (size_t i = 0; i < body.lits.size(); ++i)
31
+ body.lits[i] = -body.lits[i];
32
+
33
+ body.rhs = body.sumw - body.rhs;
34
+ }
35
+
36
+ #endif
@@ -0,0 +1,185 @@
1
+ /*
2
+ * pf_py.hh
3
+ *
4
+ * Created on: May 19, 2025
5
+ * Author: Alexey Ignatiev
6
+ * E-mail: alexey.ignatiev@monash.edu
7
+ */
8
+
9
+ #ifndef __PF_PY_HH__
10
+ #define __PF_PY_HH__
11
+
12
+ #include "pyformula.hh"
13
+ #include "pf_scan.hh"
14
+
15
+ // tiny integer cache for repeated literals/weights
16
+ //=============================================================================
17
+ // hash an integer for the tiny object cache
18
+ static inline uint32_t pyint_cache_hash(long long v)
19
+ {
20
+ return ((uint32_t)v * 2654435761u) & (PYINT_CACHE_SIZE - 1u);
21
+ }
22
+
23
+ // fetch a cached Python integer or create it on demand
24
+ //=============================================================================
25
+ static inline PyObject *pyint_cache_get_or_make(int_cache *cache, long long v)
26
+ {
27
+ uint32_t idx = pyint_cache_hash(v);
28
+ int_cache_ent *e = &cache->slots[idx];
29
+ if (e->used && e->key == v) {
30
+ Py_INCREF(e->obj);
31
+ return e->obj;
32
+ }
33
+
34
+ PyObject *obj = PyLong_FromLongLong(v);
35
+ if (obj == NULL)
36
+ return NULL;
37
+
38
+ if (e->used)
39
+ Py_DECREF(e->obj);
40
+ else
41
+ cache->used_idx[cache->used_count++] = (uint16_t)idx;
42
+
43
+ e->used = 1;
44
+ e->key = v;
45
+ e->obj = obj;
46
+
47
+ Py_INCREF(obj);
48
+ return obj;
49
+ }
50
+
51
+ // release all Python integers stored in the cache
52
+ //=============================================================================
53
+ static inline void pyint_cache_clear(int_cache *cache)
54
+ {
55
+ for (size_t i = 0; i < cache->used_count; ++i) {
56
+ int_cache_ent *e = &cache->slots[cache->used_idx[i]];
57
+ if (e->used) {
58
+ Py_DECREF(e->obj);
59
+ e->obj = NULL;
60
+ e->used = 0;
61
+ }
62
+ }
63
+
64
+ cache->used_count = 0;
65
+ }
66
+
67
+ // generic helpers
68
+ //=============================================================================
69
+ // build a fast lookup table for comment lead characters
70
+ static inline void init_comment_mask(PyObject *comment_lead, bool mask[256])
71
+ {
72
+ memset(mask, 0, sizeof(bool) * 256);
73
+ mask[(unsigned char)'p'] = true;
74
+
75
+ if (comment_lead == NULL)
76
+ return;
77
+
78
+ PyObject *iter = PyObject_GetIter(comment_lead);
79
+ if (iter == NULL) {
80
+ PyErr_Clear();
81
+ return;
82
+ }
83
+
84
+ PyObject *item;
85
+ while ((item = PyIter_Next(iter)) != NULL) {
86
+ if (PyUnicode_Check(item)) {
87
+ Py_ssize_t size = 0;
88
+ const char *s = PyUnicode_AsUTF8AndSize(item, &size);
89
+ if (s && size > 0)
90
+ mask[(unsigned char)s[0]] = true;
91
+ }
92
+ #if PY_MAJOR_VERSION < 3
93
+ else if (PyString_Check(item)) {
94
+ char *s = NULL;
95
+ Py_ssize_t size = 0;
96
+ if (PyString_AsStringAndSize(item, &s, &size) == 0 && s && size > 0)
97
+ mask[(unsigned char)s[0]] = true;
98
+ }
99
+ #endif
100
+ Py_DECREF(item);
101
+ }
102
+
103
+ Py_DECREF(iter);
104
+ PyErr_Clear();
105
+ }
106
+
107
+ // expose a Python string/bytes object as a contiguous text buffer
108
+ //=============================================================================
109
+ static inline bool get_text_view(PyObject *obj, const char **ptr,
110
+ Py_ssize_t *len)
111
+ {
112
+ if (PyUnicode_Check(obj)) {
113
+ *ptr = PyUnicode_AsUTF8AndSize(obj, len);
114
+ return *ptr != NULL;
115
+ }
116
+ else if (PyBytes_Check(obj)) {
117
+ return PyBytes_AsStringAndSize(obj, (char **)ptr, len) == 0;
118
+ }
119
+ #if PY_MAJOR_VERSION < 3
120
+ else if (PyString_Check(obj)) {
121
+ return PyString_AsStringAndSize(obj, (char **)ptr, len) == 0;
122
+ }
123
+ #endif
124
+
125
+ PyErr_SetString(PyExc_TypeError, "string or bytes expected");
126
+ return false;
127
+ }
128
+
129
+ // create a Python string from a line span
130
+ //=============================================================================
131
+ static inline PyObject *mk_line(const char *beg, const char *end)
132
+ {
133
+ return PyUnicode_FromStringAndSize(beg, end - beg);
134
+ }
135
+
136
+ // append a raw comment line to the comments list
137
+ //=============================================================================
138
+ static inline bool append_comment(PyObject *comments, const char *beg,
139
+ const char *end)
140
+ {
141
+ PyObject *line = mk_line(beg, end);
142
+ if (line == NULL)
143
+ return false;
144
+
145
+ int ok = PyList_Append(comments, line);
146
+ Py_DECREF(line);
147
+ return ok >= 0;
148
+ }
149
+
150
+ // update the current maximum variable identifier
151
+ //=============================================================================
152
+ static inline void update_nv(long long lit, long long &nv)
153
+ {
154
+ long long a = lit < 0 ? -lit : lit;
155
+ if (a > nv)
156
+ nv = a;
157
+ }
158
+
159
+ // convert a vector of integers into a Python list
160
+ //=============================================================================
161
+ static inline PyObject *mk_llist(const vector<long long> &vals,
162
+ int_cache *cache, long long *nv)
163
+ {
164
+ PyObject *lst = PyList_New((Py_ssize_t)vals.size());
165
+ if (lst == NULL)
166
+ return NULL;
167
+
168
+ for (Py_ssize_t i = 0; i < (Py_ssize_t)vals.size(); ++i) {
169
+ long long v = vals[(size_t)i];
170
+ if (nv)
171
+ update_nv(v, *nv);
172
+
173
+ PyObject *obj = pyint_cache_get_or_make(cache, v);
174
+ if (obj == NULL) {
175
+ Py_DECREF(lst);
176
+ return NULL;
177
+ }
178
+
179
+ PyList_SET_ITEM(lst, i, obj);
180
+ }
181
+
182
+ return lst;
183
+ }
184
+
185
+ #endif
@@ -0,0 +1,181 @@
1
+ /*
2
+ * pf_scan.hh
3
+ *
4
+ * Created on: May 19, 2025
5
+ * Author: Alexey Ignatiev
6
+ * E-mail: alexey.ignatiev@monash.edu
7
+ */
8
+
9
+ #ifndef __PF_SCAN_HH__
10
+ #define __PF_SCAN_HH__
11
+
12
+ #include "pyformula.hh"
13
+
14
+ // low-level cursor helpers
15
+ //=============================================================================
16
+ // skip inline whitespace while advancing the cursor
17
+ static inline void skip_ws(const char * &p, const char *end)
18
+ {
19
+ while (p < end && ((*p >= 9 && *p <= 13) || *p == 32))
20
+ ++p;
21
+ }
22
+
23
+ // check whether a bounded span matches a C string exactly
24
+ //=============================================================================
25
+ static inline bool span_eq(const char *beg, const char *end, const char *s)
26
+ {
27
+ size_t n = strlen(s);
28
+ return (Py_ssize_t)n == end - beg && memcmp(beg, s, n) == 0;
29
+ }
30
+
31
+ // check whether a line starts with a fixed prefix
32
+ //=============================================================================
33
+ static inline bool line_starts(const char *beg, const char *end,
34
+ const char *prefix)
35
+ {
36
+ size_t n = strlen(prefix);
37
+ return (Py_ssize_t)n <= end - beg && memcmp(beg, prefix, n) == 0;
38
+ }
39
+
40
+ // test whether a trimmed line is empty
41
+ //=============================================================================
42
+ static inline bool line_empty(const char *beg, const char *end)
43
+ {
44
+ return end <= beg;
45
+ }
46
+
47
+ // split the input into trimmed logical lines
48
+ //=============================================================================
49
+ static inline bool next_line(const char * &p, const char *end,
50
+ const char * &beg, const char * &lend)
51
+ {
52
+ if (p >= end)
53
+ return false;
54
+
55
+ beg = p;
56
+ while (p < end && *p != '\n')
57
+ ++p;
58
+
59
+ lend = p;
60
+ if (p < end)
61
+ ++p;
62
+
63
+ while (lend > beg && isspace((unsigned char)lend[-1]))
64
+ --lend;
65
+
66
+ return true;
67
+ }
68
+
69
+ // read the next whitespace-delimited token span
70
+ //=============================================================================
71
+ static inline bool read_span(const char * &p, const char *end,
72
+ const char * &beg, const char * &tend)
73
+ {
74
+ skip_ws(p, end);
75
+ if (p >= end)
76
+ return false;
77
+
78
+ beg = p;
79
+ while (p < end && !isspace((unsigned char)*p))
80
+ ++p;
81
+
82
+ tend = p;
83
+ return true;
84
+ }
85
+
86
+ // check whether a span has the syntax of a signed integer
87
+ //=============================================================================
88
+ static inline bool span_is_integer_like(const char *beg, const char *end)
89
+ {
90
+ if (beg >= end)
91
+ return false;
92
+
93
+ if (*beg == '+' || *beg == '-')
94
+ ++beg;
95
+ if (beg >= end)
96
+ return false;
97
+
98
+ for (; beg < end; ++beg) {
99
+ if (*beg < '0' || *beg > '9')
100
+ return false;
101
+ }
102
+
103
+ return true;
104
+ }
105
+
106
+ // parse a bounded signed integer without copying
107
+ //=============================================================================
108
+ static inline bool parse_ll_span(const char *beg, const char *end,
109
+ long long &out)
110
+ {
111
+ if (beg >= end)
112
+ return false;
113
+
114
+ bool neg = false;
115
+ if (*beg == '+' || *beg == '-') {
116
+ neg = (*beg == '-');
117
+ ++beg;
118
+ }
119
+ if (beg >= end)
120
+ return false;
121
+
122
+ unsigned long long lim = neg ? (unsigned long long)LLONG_MAX + 1ULL
123
+ : (unsigned long long)LLONG_MAX;
124
+ unsigned long long val = 0;
125
+
126
+ for (; beg < end; ++beg) {
127
+ unsigned char ch = (unsigned char)*beg;
128
+ if (ch < '0' || ch > '9')
129
+ return false;
130
+
131
+ unsigned long long dig = (unsigned long long)(ch - '0');
132
+ if (val > (lim - dig) / 10ULL)
133
+ return false;
134
+
135
+ val = val * 10ULL + dig;
136
+ }
137
+
138
+ if (neg) {
139
+ if (val == (unsigned long long)LLONG_MAX + 1ULL)
140
+ out = LLONG_MIN;
141
+ else
142
+ out = -(long long)val;
143
+ }
144
+ else {
145
+ out = (long long)val;
146
+ }
147
+
148
+ return true;
149
+ }
150
+
151
+ // parse the next integer directly from the cursor
152
+ //=============================================================================
153
+ static inline bool read_int(const char *&p, const char *end, long long &out)
154
+ {
155
+ skip_ws(p, end);
156
+ if (p >= end) {
157
+ PyErr_SetString(PyExc_ValueError,
158
+ "unexpected end of input while parsing integer");
159
+ return false;
160
+ }
161
+
162
+ const char *beg = p;
163
+ if (*p == '+' || *p == '-')
164
+ ++p;
165
+ if (p >= end || *p < '0' || *p > '9') {
166
+ PyErr_SetString(PyExc_ValueError, "invalid integer token");
167
+ return false;
168
+ }
169
+
170
+ while (p < end && *p >= '0' && *p <= '9')
171
+ ++p;
172
+
173
+ if (!parse_ll_span(beg, p, out)) {
174
+ PyErr_SetString(PyExc_ValueError, "invalid integer token");
175
+ return false;
176
+ }
177
+
178
+ return true;
179
+ }
180
+
181
+ #endif
@@ -0,0 +1,93 @@
1
+ /*
2
+ * pf_weight.hh
3
+ *
4
+ * Created on: May 19, 2025
5
+ * Author: Alexey Ignatiev
6
+ * E-mail: alexey.ignatiev@monash.edu
7
+ */
8
+
9
+ #ifndef __PF_WEIGHT_HH__
10
+ #define __PF_WEIGHT_HH__
11
+
12
+ #include "pyformula.hh"
13
+ #include "pf_scan.hh"
14
+
15
+ // weights and preambles
16
+ //=============================================================================
17
+ // parse a clause or top weight as h, int, or decimal.Decimal
18
+ static inline PyObject *parse_wght_span(const char *beg, const char *end)
19
+ {
20
+ if (span_eq(beg, end, "h")) {
21
+ Py_RETURN_NONE;
22
+ }
23
+
24
+ if (span_is_integer_like(beg, end)) {
25
+ long long val;
26
+ if (!parse_ll_span(beg, end, val)) {
27
+ PyErr_SetString(PyExc_ValueError, "invalid integer weight");
28
+ return NULL;
29
+ }
30
+
31
+ return PyLong_FromLongLong(val);
32
+ }
33
+
34
+ PyObject *text = PyUnicode_FromStringAndSize(beg, end - beg);
35
+ if (text == NULL)
36
+ return NULL;
37
+
38
+ PyObject *d = PyObject_CallFunctionObjArgs(dec_cls, text, NULL);
39
+ Py_DECREF(text);
40
+ if (d == NULL)
41
+ return NULL;
42
+
43
+ PyObject *inf = PyObject_CallMethod(d, (char *)"is_infinite", NULL);
44
+ if (inf == NULL) {
45
+ Py_DECREF(d);
46
+ return NULL;
47
+ }
48
+
49
+ int is_inf = PyObject_IsTrue(inf);
50
+ Py_DECREF(inf);
51
+ if (is_inf < 0) {
52
+ Py_DECREF(d);
53
+ return NULL;
54
+ }
55
+ if (is_inf)
56
+ return d;
57
+
58
+ PyObject *ival = PyObject_CallMethod(d, (char *)"to_integral_value", NULL);
59
+ if (ival == NULL) {
60
+ Py_DECREF(d);
61
+ return NULL;
62
+ }
63
+
64
+ int is_eq = PyObject_RichCompareBool(d, ival, Py_EQ);
65
+ Py_DECREF(ival);
66
+ if (is_eq < 0) {
67
+ Py_DECREF(d);
68
+ return NULL;
69
+ }
70
+
71
+ if (is_eq) {
72
+ PyObject *res = PyNumber_Long(d);
73
+ Py_DECREF(d);
74
+ return res;
75
+ }
76
+
77
+ return d;
78
+ }
79
+
80
+ // parse a weighted literal of the form w*l
81
+ //=============================================================================
82
+ static inline bool parse_wlit_span(const char *beg, const char *end,
83
+ long long &w, long long &l)
84
+ {
85
+ const char *star = (const char *)memchr(beg, '*', (size_t)(end - beg));
86
+ if (star == NULL)
87
+ return false;
88
+
89
+ return parse_ll_span(beg, star, w) &&
90
+ parse_ll_span(star + 1, end, l) && l != 0;
91
+ }
92
+
93
+ #endif
@@ -0,0 +1,99 @@
1
+ /*
2
+ * pyformula.hh
3
+ *
4
+ * Created on: May 19, 2025
5
+ * Author: Alexey Ignatiev
6
+ * E-mail: alexey.ignatiev@monash.edu
7
+ */
8
+
9
+ #ifndef __PYFORMULA_HH__
10
+ #define __PYFORMULA_HH__
11
+
12
+ #define PY_SSIZE_T_CLEAN
13
+
14
+ #include <Python.h>
15
+ #include <ctype.h>
16
+ #include <limits.h>
17
+ #include <stdint.h>
18
+ #include <string.h>
19
+ #include <vector>
20
+
21
+ using namespace std;
22
+
23
+ // parser overview
24
+ //=============================================================================
25
+ // The code below follows one cursor-based parsing style throughout.
26
+ // The aim is to replicate the former PySAT's parsers for all *CNF? formats.
27
+ //
28
+ // Generic path:
29
+ // next_line() -> split the input into trimmed lines
30
+ // read_span() -> scan the next token on a line
31
+ // parse_ll_span() -> parse a bounded integer token/span
32
+ // read_int() -> parse the next integer directly from a cursor
33
+ //
34
+ // Formula-specific path:
35
+ // CNF : parse_clause_body() -> mk_llist()
36
+ // WCNF : read weight with parse_wght_span(), parse clause body,
37
+ // classify with append_weighted_clause()
38
+ // CNF+ : parse_plus_body() -> clause or AtMost/PB constraint
39
+ // WCNF+ : parse weight with parse_wght_span(), then parse_plus_body(),
40
+ // then route either to append_weighted_clause() or mk_atm()
41
+ //
42
+ // Weight parsing:
43
+ // parse_wght_span() parses clause/top weights as hard-marker 'h', integer,
44
+ // or decimal.Decimal; parse_wlit_span() parses weighted PB literals w*l.
45
+ //
46
+ // Public wrappers are py_parse_*(); parse_*_impl() contain the actual parser
47
+ // implementations used by those wrappers.
48
+ //
49
+ // Note that preambles are only recognized enough to distinguish the format
50
+ // and, for weighted formats, extract the optional top weight.
51
+
52
+ #define PYINT_CACHE_SIZE (1u << 10)
53
+
54
+ extern PyObject *formula_err;
55
+ extern PyObject *dec_cls;
56
+ extern PyObject *dec_inf;
57
+
58
+ typedef struct {
59
+ long long key;
60
+ PyObject *obj;
61
+ unsigned char used;
62
+ } int_cache_ent;
63
+
64
+ typedef struct {
65
+ int_cache_ent slots[PYINT_CACHE_SIZE];
66
+ uint16_t used_idx[PYINT_CACHE_SIZE];
67
+ size_t used_count;
68
+ } int_cache;
69
+
70
+ typedef struct {
71
+ bool weighted;
72
+ bool clause;
73
+ long long rhs;
74
+ long long sumw;
75
+ vector<long long> lits;
76
+ vector<long long> wght;
77
+ } plus_body;
78
+
79
+ bool parse_weight_preamble(const char *beg, const char *end, const char *kind,
80
+ const char *errmsg, PyObject **topw);
81
+
82
+ bool parse_clause_body(const char *p, const char *end,
83
+ vector<long long> &lits);
84
+
85
+ bool parse_plus_body(const char *first_beg, const char *first_end,
86
+ const char *p, const char *end, plus_body &body);
87
+
88
+ PyObject *mk_atm(const plus_body &body, int_cache *cache, long long &nv);
89
+
90
+ bool append_weighted_clause(PyObject *hard, PyObject *soft, PyObject *wght,
91
+ PyObject *negs, PyObject *topw, PyObject *zero, PyObject *cl,
92
+ PyObject *wt);
93
+
94
+ PyObject *parse_cnf_impl (PyObject *txt_obj, PyObject *comment_lead);
95
+ PyObject *parse_wcnf_impl (PyObject *txt_obj, PyObject *comment_lead);
96
+ PyObject *parse_cnfplus_impl (PyObject *txt_obj, PyObject *comment_lead);
97
+ PyObject *parse_wcnfplus_impl(PyObject *txt_obj, PyObject *comment_lead);
98
+
99
+ #endif
@@ -10,7 +10,7 @@
10
10
 
11
11
  # current version
12
12
  #==============================================================================
13
- VERSION = (1, 9, 'dev', 4)
13
+ VERSION = (1, 9, 'dev', 5)
14
14
 
15
15
 
16
16
  # PEP440 Format
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-sat
3
- Version: 1.9.dev4
3
+ Version: 1.9.dev5
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
@@ -37,8 +37,13 @@ examples/rc2.py
37
37
  examples/usage.py
38
38
  formula/pf_parse.cc
39
39
  formula/pf_plus.cc
40
+ formula/pf_plus.hh
41
+ formula/pf_py.hh
42
+ formula/pf_scan.hh
40
43
  formula/pf_weight.cc
44
+ formula/pf_weight.hh
41
45
  formula/pyformula.cc
46
+ formula/pyformula.hh
42
47
  pysat/__init__.py
43
48
  pysat/_fileio.py
44
49
  pysat/_utils.py
File without changes
File without changes
File without changes
File without changes
File without changes