cdclkit 0.1.3__tar.gz → 0.1.5__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 (46) hide show
  1. {cdclkit-0.1.3 → cdclkit-0.1.5}/PKG-INFO +9 -6
  2. {cdclkit-0.1.3 → cdclkit-0.1.5}/README.md +5 -3
  3. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/__init__.py +1 -1
  4. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/solver.py +20 -4
  5. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit.egg-info/PKG-INFO +9 -6
  6. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit.egg-info/SOURCES.txt +3 -1
  7. cdclkit-0.1.5/cdclkit.egg-info/requires.txt +4 -0
  8. {cdclkit-0.1.3 → cdclkit-0.1.5}/pyproject.toml +4 -3
  9. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_packaging.py +25 -0
  10. cdclkit-0.1.5/tests/test_readme.py +91 -0
  11. cdclkit-0.1.5/tests/test_target_scaling.py +78 -0
  12. cdclkit-0.1.3/cdclkit.egg-info/requires.txt +0 -4
  13. {cdclkit-0.1.3 → cdclkit-0.1.5}/LICENSE +0 -0
  14. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/__main__.py +0 -0
  15. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/brute.py +0 -0
  16. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/cli.py +0 -0
  17. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/encodings.py +0 -0
  18. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/heap.py +0 -0
  19. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/model.py +0 -0
  20. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/mus.py +0 -0
  21. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/native.py +0 -0
  22. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/pipeline.py +0 -0
  23. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/portfolio.py +0 -0
  24. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/preprocess.py +0 -0
  25. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/py.typed +0 -0
  26. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit/pyeq.py +0 -0
  27. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit.egg-info/dependency_links.txt +0 -0
  28. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit.egg-info/entry_points.txt +0 -0
  29. {cdclkit-0.1.3 → cdclkit-0.1.5}/cdclkit.egg-info/top_level.txt +0 -0
  30. {cdclkit-0.1.3 → cdclkit-0.1.5}/setup.cfg +0 -0
  31. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_adaptive_proof.py +0 -0
  32. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_agent_docs.py +0 -0
  33. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_brute.py +0 -0
  34. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_cli_defaults.py +0 -0
  35. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_core.py +0 -0
  36. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_encodings.py +0 -0
  37. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_integration.py +0 -0
  38. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_mus.py +0 -0
  39. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_native.py +0 -0
  40. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_native_solver.py +0 -0
  41. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_pipeline.py +0 -0
  42. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_portfolio.py +0 -0
  43. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_preprocess.py +0 -0
  44. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_proof.py +0 -0
  45. {cdclkit-0.1.3 → cdclkit-0.1.5}/tests/test_pyeq.py +0 -0
  46. {cdclkit-0.1.3 → cdclkit-0.1.5}/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
3
+ Version: 0.1.5
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
@@ -17,14 +17,15 @@ Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: 3.15
20
21
  Classifier: Programming Language :: Rust
21
22
  Classifier: Topic :: Scientific/Engineering :: Mathematics
22
23
  Requires-Python: >=3.10
23
24
  Description-Content-Type: text/markdown
24
25
  License-File: LICENSE
25
- Requires-Dist: dratify>=0.1.4
26
+ Requires-Dist: dratify>=0.1.7
26
27
  Provides-Extra: native
27
- Requires-Dist: cdclkit-native==0.1.3; extra == "native"
28
+ Requires-Dist: cdclkit-native==0.1.5; extra == "native"
28
29
  Dynamic: license-file
29
30
 
30
31
  # cdclkit
@@ -142,9 +143,11 @@ An optional Rust engine ([`cdclkit-native`](https://pypi.org/project/cdclkit-nat
142
143
  is **bit-exact** with the Python one — identical conflicts, decisions and
143
144
  propagations on every instance — and about **20x faster**: the geometric mean
144
145
  of per-instance ratios over the 17 benchmark instances is 20.1x, ranging from
145
- 11x to 51x. Regenerate it with `make history` (the `python` and `native`
146
- checkpoints in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for
147
- the method. The pure-Python path has zero third-party
146
+ 11x to 51x. That comes from two checkpoints recorded 34 seconds apart at the
147
+ same commit, one sample per instance — good enough for the mean, not for any
148
+ single row. Regenerate it with `make history` (the `python` and `native`
149
+ entries in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for the
150
+ method. The pure-Python path has zero third-party
148
151
  dependencies and is the one that must never break.
149
152
 
150
153
  ## 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. Regenerate it with `make history` (the `python` and `native`
117
- checkpoints in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for
118
- the method. The pure-Python path has zero third-party
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.3"
55
+ __version__ = "0.1.5"
56
56
 
57
57
  __all__ = [
58
58
  "CNF",
@@ -392,6 +392,11 @@ class Solver:
392
392
  #: depth. Only meaningful when cfg.target_phase is on.
393
393
  self._target = bytearray()
394
394
  self._target_size = 0
395
+ #: how much of the current trail the target already records: for every
396
+ #: i < _target_synced, _target holds trail[i]'s value. The trail only
397
+ #: grows by appending and only shrinks in _cancel_until, so a prefix
398
+ #: that has been copied stays copied until a backtrack cuts into it.
399
+ self._target_synced = 0
395
400
  self._walk_best = 1 << 30
396
401
  self._walk_stale = 0
397
402
  self.frozen = bytearray() # variables excluded from decisions
@@ -605,6 +610,8 @@ class Solver:
605
610
  del trail[bound:]
606
611
  del self.trail_lim[level:]
607
612
  self.qhead = len(trail)
613
+ if self._target_synced > bound:
614
+ self._target_synced = bound
608
615
 
609
616
  # ------------------------------------------------------------ propagation
610
617
 
@@ -1154,6 +1161,7 @@ class Solver:
1154
1161
  self._target[:] = best
1155
1162
  self.polarity[:] = best
1156
1163
  self._target_size = 0 # the target now describes the walk, not a trail
1164
+ self._target_synced = 0
1157
1165
 
1158
1166
  # -------------------------------------------------------------- restarts
1159
1167
 
@@ -1229,13 +1237,21 @@ class Solver:
1229
1237
  self._reduce_db()
1230
1238
  else:
1231
1239
  # A new deepest conflict-free trail: remember the assignment
1232
- # that reached it. Copying costs O(|trail|), but only on a
1233
- # strict improvement, and improvements become rare quickly.
1240
+ # that reached it -- copying only what the target does not
1241
+ # already hold. This used to copy the whole trail on every
1242
+ # improvement, on the theory that improvements become rare
1243
+ # quickly. They do once conflicts start; a search that makes
1244
+ # many decisions without one improves on every decision, and
1245
+ # n of them cost O(n^2) (tests/test_target_scaling.py). The
1246
+ # target ends up byte-for-byte what the full copy produced.
1234
1247
  if self.cfg.target_phase and len(self.trail) > self._target_size:
1235
- self._target_size = len(self.trail)
1248
+ trail = self.trail
1249
+ self._target_size = len(trail)
1236
1250
  target = self._target
1237
- for t in self.trail:
1251
+ for i in range(self._target_synced, len(trail)):
1252
+ t = trail[i]
1238
1253
  target[t >> 1] = 0 if (t & 1) else 1
1254
+ self._target_synced = len(trail)
1239
1255
 
1240
1256
  if max_conflicts is not None and conflicts >= max_conflicts:
1241
1257
  self._cancel_until(len(self.assumptions_applied))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdclkit
3
- Version: 0.1.3
3
+ Version: 0.1.5
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
@@ -17,14 +17,15 @@ Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: 3.15
20
21
  Classifier: Programming Language :: Rust
21
22
  Classifier: Topic :: Scientific/Engineering :: Mathematics
22
23
  Requires-Python: >=3.10
23
24
  Description-Content-Type: text/markdown
24
25
  License-File: LICENSE
25
- Requires-Dist: dratify>=0.1.4
26
+ Requires-Dist: dratify>=0.1.7
26
27
  Provides-Extra: native
27
- Requires-Dist: cdclkit-native==0.1.3; extra == "native"
28
+ Requires-Dist: cdclkit-native==0.1.5; extra == "native"
28
29
  Dynamic: license-file
29
30
 
30
31
  # cdclkit
@@ -142,9 +143,11 @@ An optional Rust engine ([`cdclkit-native`](https://pypi.org/project/cdclkit-nat
142
143
  is **bit-exact** with the Python one — identical conflicts, decisions and
143
144
  propagations on every instance — and about **20x faster**: the geometric mean
144
145
  of per-instance ratios over the 17 benchmark instances is 20.1x, ranging from
145
- 11x to 51x. Regenerate it with `make history` (the `python` and `native`
146
- checkpoints in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for
147
- the method. The pure-Python path has zero third-party
146
+ 11x to 51x. That comes from two checkpoints recorded 34 seconds apart at the
147
+ same commit, one sample per instance — good enough for the mean, not for any
148
+ single row. Regenerate it with `make history` (the `python` and `native`
149
+ entries in `bench/history.jsonl`); see [BENCHMARKS.md](BENCHMARKS.md) for the
150
+ method. The pure-Python path has zero third-party
148
151
  dependencies and is the one that must never break.
149
152
 
150
153
  ## Relationship to dratify
@@ -38,4 +38,6 @@ tests/test_portfolio.py
38
38
  tests/test_preprocess.py
39
39
  tests/test_proof.py
40
40
  tests/test_pyeq.py
41
- tests/test_solver.py
41
+ tests/test_readme.py
42
+ tests/test_solver.py
43
+ tests/test_target_scaling.py
@@ -0,0 +1,4 @@
1
+ dratify>=0.1.7
2
+
3
+ [native]
4
+ cdclkit-native==0.1.5
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cdclkit"
7
- version = "0.1.3"
7
+ version = "0.1.5"
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"
@@ -22,6 +22,7 @@ classifiers = [
22
22
  "Programming Language :: Python :: 3.12",
23
23
  "Programming Language :: Python :: 3.13",
24
24
  "Programming Language :: Python :: 3.14",
25
+ "Programming Language :: Python :: 3.15",
25
26
  "Programming Language :: Rust",
26
27
  "Topic :: Scientific/Engineering :: Mathematics",
27
28
  ]
@@ -29,13 +30,13 @@ classifiers = [
29
30
  # The only dependency is the proof checker, which itself has none. The solver
30
31
  # uses it to check its own refutations, so the checker is exercised by every
31
32
  # test run here as well as by its own suite.
32
- dependencies = ["dratify>=0.1.4"]
33
+ dependencies = ["dratify>=0.1.7"]
33
34
 
34
35
  [project.optional-dependencies]
35
36
  # The Rust accelerator, as abi3 wheels for Linux and macOS. Pinned exactly:
36
37
  # the two are bit-exact by construction and a mismatched pair is a divergence
37
38
  # nobody would look for. tests/test_packaging.py enforces the pin.
38
- native = ["cdclkit-native==0.1.3"]
39
+ native = ["cdclkit-native==0.1.5"]
39
40
 
40
41
  [project.scripts]
41
42
  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()
@@ -0,0 +1,78 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2026 Carlo Perassi. Licensed under the Apache License 2.0.
3
+ """Target phases must not make the search quadratic in the number of variables.
4
+
5
+ With target phases on (the default), each time the trail reached a new depth
6
+ the solver copied the whole trail into the target. The comment beside it said
7
+ improvements "become rare quickly". That holds only once conflicts happen. A
8
+ search that makes many decisions without a conflict improves on every one, so
9
+ n decisions copied 1, 2, ..., n entries.
10
+
11
+ Measured on the Python engine, solving one unit clause in a formula that
12
+ declares n variables: 4,096 took 0.8 s, 16,384 took 10.6 s and 65,536 took
13
+ 144 s -- each 4x costing about 13x. Turning target phases off made 16,384
14
+ take 0.11 s. Since dratify 0.1.7 a header may declare up to 2^20 variables
15
+ from a file of any length, so a 22-byte file cost hours of CPU.
16
+
17
+ The test compares scaling rather than absolute time, which shared CI runners
18
+ cannot be trusted with: quadrupling the variables should cost about 4x when
19
+ the search is linear and about 16x when it is quadratic. The threshold sits
20
+ between them, and each size takes the best of three runs to damp noise.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import time
26
+ import unittest
27
+
28
+ from cdclkit import native
29
+ from cdclkit.solver import Solver
30
+
31
+
32
+ def _solve(nvars: int, engine: str) -> bool:
33
+ """One unit clause, `nvars` declared: every other variable is a decision."""
34
+ if engine == "native":
35
+ s = native.require().Solver(nvars) # defaults match Config
36
+ else:
37
+ s = Solver(nvars)
38
+ s.add_clause([0])
39
+ return s.solve()
40
+
41
+
42
+ def _seconds(nvars: int, engine: str) -> float:
43
+ best = float("inf")
44
+ for _ in range(3):
45
+ t0 = time.perf_counter()
46
+ sat = _solve(nvars, engine)
47
+ best = min(best, time.perf_counter() - t0)
48
+ assert sat
49
+ return best
50
+
51
+
52
+ class TestUnusedVariablesCostLinearTime(unittest.TestCase):
53
+ #: quadrupling: ~4x if linear, ~16x if quadratic
54
+ LIMIT = 8.0
55
+
56
+ def _check(self, engine: str, small: int):
57
+ t_small = _seconds(small, engine)
58
+ t_large = _seconds(4 * small, engine)
59
+ ratio = t_large / max(t_small, 1e-4)
60
+ self.assertLess(
61
+ ratio, self.LIMIT,
62
+ f"{engine}: {small:,} vars took {t_small:.3f}s and "
63
+ f"{4 * small:,} took {t_large:.3f}s, a {ratio:.1f}x increase for "
64
+ f"4x the variables. Linear is ~4x; this is closer to quadratic.")
65
+
66
+ def test_python_engine(self):
67
+ self._check("python", 4096)
68
+
69
+ @unittest.skipUnless(native.available(),
70
+ "native engine not built for this interpreter")
71
+ def test_native_engine(self):
72
+ # Rust is fast enough that the quadratic term only dominates at
73
+ # larger sizes.
74
+ self._check("native", 32768)
75
+
76
+
77
+ if __name__ == "__main__":
78
+ unittest.main()
@@ -1,4 +0,0 @@
1
- dratify>=0.1.4
2
-
3
- [native]
4
- cdclkit-native==0.1.3
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