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.
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/MANIFEST.in +1 -0
- {python_sat-1.9.dev4/python_sat.egg-info → python_sat-1.9.dev5}/PKG-INFO +1 -1
- python_sat-1.9.dev5/formula/pf_plus.hh +36 -0
- python_sat-1.9.dev5/formula/pf_py.hh +185 -0
- python_sat-1.9.dev5/formula/pf_scan.hh +181 -0
- python_sat-1.9.dev5/formula/pf_weight.hh +93 -0
- python_sat-1.9.dev5/formula/pyformula.hh +99 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/__init__.py +1 -1
- {python_sat-1.9.dev4 → python_sat-1.9.dev5/python_sat.egg-info}/PKG-INFO +1 -1
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/SOURCES.txt +5 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/LICENSE.txt +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/README.rst +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/allies/__init__.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/allies/approxmc.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/allies/unigen.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/bitwise.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/card.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/clset.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/common.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/itot.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/ladder.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/mto.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/pairwise.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/ptypes.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/pycard.cc +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/seqcounter.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/sortcard.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/cardenc/utils.hh +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/__init__.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/bbscan.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/bica.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/fm.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/genhard.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/hitman.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/lbx.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/lsu.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/mcsls.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/models.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/musx.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/optux.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/primer.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/rc2.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/examples/usage.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pf_parse.cc +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pf_plus.cc +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pf_weight.cc +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/formula/pyformula.cc +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/_fileio.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/_utils.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/card.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/engines.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/formula.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/integer.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/pb.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/process.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/pysat/solvers.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/dependency_links.txt +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/requires.txt +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/python_sat.egg-info/top_level.txt +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/requirements.txt +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/setup.cfg +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/setup.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical103.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical153.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical195.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/cadical300.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/glucose30.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/glucose41.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/glucose421.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/lingeling.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/maplechrono.zip +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/maplecm.zip +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/maplesat.zip +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/mergesat3.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/minicard.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/minisat22.tar.gz +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/minisatgh.zip +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical103.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical153.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical195.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/cadical300.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/glucose30.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/glucose41.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/glucose421.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/gluecard30.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/gluecard41.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/kissat404.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/lingeling.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/maplechrono.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/maplecm.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/maplesat.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/mergesat3.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minicard.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minisat22.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minisatep.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/patches/minisatgh.patch +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/prepare.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/solvers/pysolvers.cc +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_accum_stats.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_atmost.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_atmost1.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_atmostk.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_boolengine.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_clausification.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_cnf.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_encode_pb_conditional.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_equals1.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_formula_parsing.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_formula_unique.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_idpool.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_integer.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_process.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_propagate.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_unique_model.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_unique_mus.py +0 -0
- {python_sat-1.9.dev4 → python_sat-1.9.dev5}/tests/test_warmstart.py +0 -0
|
@@ -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
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|