cdclkit 0.1.3__tar.gz → 0.1.4__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.
- {cdclkit-0.1.3 → cdclkit-0.1.4}/PKG-INFO +8 -6
- {cdclkit-0.1.3 → cdclkit-0.1.4}/README.md +5 -3
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/__init__.py +1 -1
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit.egg-info/PKG-INFO +8 -6
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit.egg-info/SOURCES.txt +1 -0
- cdclkit-0.1.4/cdclkit.egg-info/requires.txt +4 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/pyproject.toml +3 -3
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_packaging.py +25 -0
- cdclkit-0.1.4/tests/test_readme.py +91 -0
- cdclkit-0.1.3/cdclkit.egg-info/requires.txt +0 -4
- {cdclkit-0.1.3 → cdclkit-0.1.4}/LICENSE +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/__main__.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/brute.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/cli.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/encodings.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/heap.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/model.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/mus.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/native.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/pipeline.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/portfolio.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/preprocess.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/py.typed +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/pyeq.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit/solver.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit.egg-info/dependency_links.txt +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit.egg-info/entry_points.txt +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/cdclkit.egg-info/top_level.txt +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/setup.cfg +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_adaptive_proof.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_agent_docs.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_brute.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_cli_defaults.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_core.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_encodings.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_integration.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_mus.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_native.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_native_solver.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_pipeline.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_portfolio.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_preprocess.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_proof.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_pyeq.py +0 -0
- {cdclkit-0.1.3 → cdclkit-0.1.4}/tests/test_solver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cdclkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A CDCL SAT solver, preprocessor, encoding library and modelling layer, written from scratch in readable Python. Every answer comes with a certificate.
|
|
5
5
|
Author: Carlo Perassi
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -22,9 +22,9 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: dratify>=0.1.
|
|
25
|
+
Requires-Dist: dratify>=0.1.7
|
|
26
26
|
Provides-Extra: native
|
|
27
|
-
Requires-Dist: cdclkit-native==0.1.
|
|
27
|
+
Requires-Dist: cdclkit-native==0.1.4; extra == "native"
|
|
28
28
|
Dynamic: license-file
|
|
29
29
|
|
|
30
30
|
# cdclkit
|
|
@@ -142,9 +142,11 @@ An optional Rust engine ([`cdclkit-native`](https://pypi.org/project/cdclkit-nat
|
|
|
142
142
|
is **bit-exact** with the Python one — identical conflicts, decisions and
|
|
143
143
|
propagations on every instance — and about **20x faster**: the geometric mean
|
|
144
144
|
of per-instance ratios over the 17 benchmark instances is 20.1x, ranging from
|
|
145
|
-
11x to 51x.
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
11x to 51x. That comes from two checkpoints recorded 34 seconds apart at the
|
|
146
|
+
same commit, one sample per instance — good enough for the mean, not for any
|
|
147
|
+
single row. Regenerate it with `make history` (the `python` and `native`
|
|
148
|
+
entries in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for the
|
|
149
|
+
method. The pure-Python path has zero third-party
|
|
148
150
|
dependencies and is the one that must never break.
|
|
149
151
|
|
|
150
152
|
## Relationship to dratify
|
|
@@ -113,9 +113,11 @@ An optional Rust engine ([`cdclkit-native`](https://pypi.org/project/cdclkit-nat
|
|
|
113
113
|
is **bit-exact** with the Python one — identical conflicts, decisions and
|
|
114
114
|
propagations on every instance — and about **20x faster**: the geometric mean
|
|
115
115
|
of per-instance ratios over the 17 benchmark instances is 20.1x, ranging from
|
|
116
|
-
11x to 51x.
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
11x to 51x. That comes from two checkpoints recorded 34 seconds apart at the
|
|
117
|
+
same commit, one sample per instance — good enough for the mean, not for any
|
|
118
|
+
single row. Regenerate it with `make history` (the `python` and `native`
|
|
119
|
+
entries in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for the
|
|
120
|
+
method. The pure-Python path has zero third-party
|
|
119
121
|
dependencies and is the one that must never break.
|
|
120
122
|
|
|
121
123
|
## Relationship to dratify
|
|
@@ -52,7 +52,7 @@ from .preprocess import Preprocessor, preprocess
|
|
|
52
52
|
from dratify.proof import DRATChecker, MemoryProof, ProofWriter, check_proof
|
|
53
53
|
from .solver import Config, SAT, Solver, Stats, UNKNOWN, UNSAT
|
|
54
54
|
|
|
55
|
-
__version__ = "0.1.
|
|
55
|
+
__version__ = "0.1.4"
|
|
56
56
|
|
|
57
57
|
__all__ = [
|
|
58
58
|
"CNF",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cdclkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A CDCL SAT solver, preprocessor, encoding library and modelling layer, written from scratch in readable Python. Every answer comes with a certificate.
|
|
5
5
|
Author: Carlo Perassi
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -22,9 +22,9 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: dratify>=0.1.
|
|
25
|
+
Requires-Dist: dratify>=0.1.7
|
|
26
26
|
Provides-Extra: native
|
|
27
|
-
Requires-Dist: cdclkit-native==0.1.
|
|
27
|
+
Requires-Dist: cdclkit-native==0.1.4; extra == "native"
|
|
28
28
|
Dynamic: license-file
|
|
29
29
|
|
|
30
30
|
# cdclkit
|
|
@@ -142,9 +142,11 @@ An optional Rust engine ([`cdclkit-native`](https://pypi.org/project/cdclkit-nat
|
|
|
142
142
|
is **bit-exact** with the Python one — identical conflicts, decisions and
|
|
143
143
|
propagations on every instance — and about **20x faster**: the geometric mean
|
|
144
144
|
of per-instance ratios over the 17 benchmark instances is 20.1x, ranging from
|
|
145
|
-
11x to 51x.
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
11x to 51x. That comes from two checkpoints recorded 34 seconds apart at the
|
|
146
|
+
same commit, one sample per instance — good enough for the mean, not for any
|
|
147
|
+
single row. Regenerate it with `make history` (the `python` and `native`
|
|
148
|
+
entries in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for the
|
|
149
|
+
method. The pure-Python path has zero third-party
|
|
148
150
|
dependencies and is the one that must never break.
|
|
149
151
|
|
|
150
152
|
## Relationship to dratify
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cdclkit"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
description = "A CDCL SAT solver, preprocessor, encoding library and modelling layer, written from scratch in readable Python. Every answer comes with a certificate."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -29,13 +29,13 @@ classifiers = [
|
|
|
29
29
|
# The only dependency is the proof checker, which itself has none. The solver
|
|
30
30
|
# uses it to check its own refutations, so the checker is exercised by every
|
|
31
31
|
# test run here as well as by its own suite.
|
|
32
|
-
dependencies = ["dratify>=0.1.
|
|
32
|
+
dependencies = ["dratify>=0.1.7"]
|
|
33
33
|
|
|
34
34
|
[project.optional-dependencies]
|
|
35
35
|
# The Rust accelerator, as abi3 wheels for Linux and macOS. Pinned exactly:
|
|
36
36
|
# the two are bit-exact by construction and a mismatched pair is a divergence
|
|
37
37
|
# nobody would look for. tests/test_packaging.py enforces the pin.
|
|
38
|
-
native = ["cdclkit-native==0.1.
|
|
38
|
+
native = ["cdclkit-native==0.1.4"]
|
|
39
39
|
|
|
40
40
|
[project.scripts]
|
|
41
41
|
cdclkit = "cdclkit.__main__:main"
|
|
@@ -103,6 +103,31 @@ class TestVersions(unittest.TestCase):
|
|
|
103
103
|
self.assertRegex(cdclkit.__version__, r"^\d+\.\d+\.\d+([.-]\w+)?$")
|
|
104
104
|
|
|
105
105
|
|
|
106
|
+
class TestSmokeTestIsCurrent(unittest.TestCase):
|
|
107
|
+
"""The post-install smoke test must ask for the modules that exist.
|
|
108
|
+
|
|
109
|
+
Its list named `cnf`, `lits` and `proof` long after they moved to
|
|
110
|
+
`dratify`, so `make smoke` failed on every run and nobody saw, because
|
|
111
|
+
nothing ran it automatically. CI now runs it; this keeps its list honest.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def test_the_smoke_module_list_matches_the_package(self):
|
|
115
|
+
import importlib.util
|
|
116
|
+
|
|
117
|
+
spec = importlib.util.spec_from_file_location(
|
|
118
|
+
"smoke_installed", ROOT / "tests" / "smoke_installed.py")
|
|
119
|
+
smoke = importlib.util.module_from_spec(spec)
|
|
120
|
+
spec.loader.exec_module(smoke)
|
|
121
|
+
|
|
122
|
+
on_disk = {p.stem for p in (ROOT / "cdclkit").glob("*.py")
|
|
123
|
+
if p.stem not in ("__init__", "__main__")}
|
|
124
|
+
self.assertEqual(
|
|
125
|
+
set(smoke.MODULES), on_disk,
|
|
126
|
+
"tests/smoke_installed.py MODULES does not match cdclkit/*.py. "
|
|
127
|
+
"A module added here and not there ships untested; one listed "
|
|
128
|
+
"there and not here makes the smoke test fail on every run.")
|
|
129
|
+
|
|
130
|
+
|
|
106
131
|
class TestEntryPoints(unittest.TestCase):
|
|
107
132
|
def test_console_script_target_exists_and_is_callable(self):
|
|
108
133
|
"""`cdclkit = "cdclkit.cli:main"` has to still resolve after a refactor."""
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2026 Carlo Perassi. Licensed under the Apache License 2.0.
|
|
3
|
+
"""Every Python example in the README has to run, and print what it says.
|
|
4
|
+
|
|
5
|
+
The README is the first code a visitor copies, and until this test existed
|
|
6
|
+
nothing executed it. The sibling project found its own example broken this
|
|
7
|
+
way: fine on the input its author tried, and failing on the first line for
|
|
8
|
+
the most common input there is.
|
|
9
|
+
|
|
10
|
+
Each ```python block runs in a fresh namespace from a temporary directory. A
|
|
11
|
+
`print(x) # value` line is an assertion: the printed value must match the
|
|
12
|
+
first word of the comment, so an example that runs but answers wrongly fails
|
|
13
|
+
too. A block preceded by `<!-- readme-test: skip ... -->` is not executed.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import contextlib
|
|
19
|
+
import io
|
|
20
|
+
import os
|
|
21
|
+
import pathlib
|
|
22
|
+
import re
|
|
23
|
+
import shutil
|
|
24
|
+
import tempfile
|
|
25
|
+
import unittest
|
|
26
|
+
|
|
27
|
+
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
28
|
+
|
|
29
|
+
SKIP = re.compile(r"<!--\s*readme-test:\s*skip")
|
|
30
|
+
EXPECT = re.compile(r"^\s*print\(.*\)\s*#\s*(\S+)")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def blocks(markdown: str) -> list[tuple[int, str, bool]]:
|
|
34
|
+
"""(line number, source, skipped) for every ```python block."""
|
|
35
|
+
lines = markdown.splitlines()
|
|
36
|
+
out, i = [], 0
|
|
37
|
+
while i < len(lines):
|
|
38
|
+
if lines[i].strip() == "```python":
|
|
39
|
+
start = i + 1
|
|
40
|
+
skipped = i > 0 and bool(SKIP.search(lines[i - 1]))
|
|
41
|
+
j = start
|
|
42
|
+
while lines[j].strip() != "```":
|
|
43
|
+
j += 1
|
|
44
|
+
out.append((start + 1, "\n".join(lines[start:j]) + "\n", skipped))
|
|
45
|
+
i = j
|
|
46
|
+
i += 1
|
|
47
|
+
return out
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def expected_output(source: str) -> list[str]:
|
|
51
|
+
return [m.group(1) for ln in source.splitlines()
|
|
52
|
+
if (m := EXPECT.match(ln))]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TestReadmeExamples(unittest.TestCase):
|
|
56
|
+
def setUp(self):
|
|
57
|
+
self.dir = pathlib.Path(tempfile.mkdtemp())
|
|
58
|
+
self.addCleanup(shutil.rmtree, self.dir)
|
|
59
|
+
self.all = blocks((ROOT / "README.md").read_text(encoding="utf-8"))
|
|
60
|
+
|
|
61
|
+
def test_the_readme_has_examples_to_test(self):
|
|
62
|
+
"""Guards the extractor: a regex that matches nothing passes everything."""
|
|
63
|
+
self.assertGreaterEqual(len(self.all), 1)
|
|
64
|
+
|
|
65
|
+
def test_every_example_runs_and_prints_what_it_promises(self):
|
|
66
|
+
ran = 0
|
|
67
|
+
for lineno, source, skipped in self.all:
|
|
68
|
+
if skipped:
|
|
69
|
+
continue
|
|
70
|
+
with self.subTest(line=lineno):
|
|
71
|
+
want = expected_output(source)
|
|
72
|
+
out = io.StringIO()
|
|
73
|
+
here = os.getcwd()
|
|
74
|
+
os.chdir(self.dir)
|
|
75
|
+
try:
|
|
76
|
+
with contextlib.redirect_stdout(out):
|
|
77
|
+
exec(compile(source, "README.md", "exec"),
|
|
78
|
+
{"__name__": "__readme__"})
|
|
79
|
+
finally:
|
|
80
|
+
os.chdir(here)
|
|
81
|
+
got = out.getvalue().split()
|
|
82
|
+
self.assertEqual(
|
|
83
|
+
got, want,
|
|
84
|
+
f"README.md:{lineno} printed {got}, but its comments "
|
|
85
|
+
f"promise {want}")
|
|
86
|
+
ran += 1
|
|
87
|
+
self.assertGreater(ran, 0, "no README example was run")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
unittest.main()
|
|
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
|