Skip to content

Commit 2fcc6f4

Browse files
authored
Merge pull request #32 from jesusvilela/codex/revisar-y-evaluar-contra-sota-2026
Remove C++/Cython tribridge; add Python fallbacks and spectral features; simplify CLI/bench APIs
2 parents ce8036c + 8207caa commit 2fcc6f4

94 files changed

Lines changed: 365 additions & 88248 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,3 @@ docs/ladder/scripts/*_results.json
4343
build/
4444
dist/
4545
__pycache__/
46-
*.pyd
47-
*.obj
48-
build/

README.md

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# λSAT · the moving frame
22

3-
![Canary Springtime Path](docs/assets/canary_path.png)
4-
> *The path has chosen you, now you honour the springtime in the pathwalk.*
5-
> **CANARY REPOSITORY:** This is the experimental, formalized structure of the solver.
6-
73
> *A solver that carries its own proof, and knows which shape of hardness it's looking at.*
84
95
[![tests](https://github.com/jesusvilela/lambda-sat-solver/actions/workflows/tests.yml/badge.svg)](https://github.com/jesusvilela/lambda-sat-solver/actions/workflows/tests.yml)
@@ -85,30 +81,43 @@ where game theory flips: on the island a *pure* strategy dominates; on the tunne
8581

8682
---
8783

88-
## 構造 · the Canary stack (Adiabatic Geodesic Flow)
89-
90-
The Canary architecture wholly abandons heuristic python string-matching and scalar Euclidean approximations (like simplistic `m/n` clause-ratio checks). Instead, it physicalizes the solver as a Hamiltonian system operating under hyper-dimensional Riemannian logic. Every layer is mapped directly to a structural C++ topology extractor, bridging discrete logic into a continuous Riemannian manifold.
84+
## 構造 · the stack
9185

92-
> **Read the full philosophical and mathematical integration:** [The Ultimate Synthesis](ultimate_synthesis.md)
86+
Every layer is the same operator seen at a different scale. Fractal, self-similar, and
87+
each verdict certified all the way down.
9388

9489
```mermaid
95-
graph TD
96-
A[CNF Hyper-Manifold] --> B(C++ Tensor-Native Flavor Analyzer)
97-
B -- O(L) Dense SIMD Vectorization --> C{Cython Topological Bridge}
98-
C -- Z2 x Z2 Parity Matrix --> D[Bridge Annealer: Parity Oracle]
99-
C -- A4 High-Density Topology --> E[Bridge Annealer: CMS Gauss-Jordan]
100-
C -- Trivial/Unstructured Geometry --> F[CDCL Fallback / Bare Kissat]
101-
D --> G(Diamond Holonomy Verification in Lean 4)
102-
E --> G
103-
F --> G
90+
flowchart TD
91+
ACAF["<b>ACAF</b> · adaptive actor-critic-ambigator-fuzzer"] --> META["<b>metasolver</b> · description-driven dispatch"]
92+
ACAF --> MM["<b>meta-metasolver</b> · fractal seed-portfolio"]
93+
META --> FR["<b>frame router</b> · 3 sound frames + Nelson-Oppen coupling"]
94+
MM --> FR
95+
META --> K["certified CDCL · Kissat / CaDiCaL"]
96+
MM --> K
97+
FR --> OBS(["<b>observer</b> — certify every verdict"])
98+
K --> OBS
99+
100+
DESC["<b>the view from outside</b><br/>dynamics · fabric · hyperbolic model"] -.reads.-> ACAF
104101
```
105102

106-
- **Flavor Analyzer** (`backend/cpp/flavor_analyzer.hpp`) — C++ structural extractor. Reads the exact hyper-dimensional geometry of the CNF to map dispersion groups ($Z_2 \times Z_2$, $A_4$, Trivial).
107-
- **Cython Bridge** (`backend/cython/tribridge.pyx`) — Lifts the C++ `vector[vector[int]]` geometry into the Python space seamlessly.
108-
- **BBD Router** (`backend/cpp/router.hpp`) — Breathing Bridge Descent. Selects the geodesic path instantly based on the Flavor group, acting as a Hamiltonian state transition rather than a heuristic choice. It rejects Euclidean scalars in favor of topological shape-matching (e.g., verifying exact variable overlap for XOR expansion).
109-
- **Parity Oracle** — Handles highly structured cryptographic chains with zero search.
110-
- **CDCL Fallback** (`Kissat/CaDiCaL`) — The unstructured heavy-tail engine.
111-
- **Diamond Holonomy Benchmarking** — Evaluates paths using rigorous TFLOPS-bounded physics instead of scalar time.
103+
- **frame router** (`frame_solver.py`) — the three frames + their coupling, refute-first.
104+
- **metasolver** (`metasolver.py`) — reverts the dynamical description into a dispatch. On a
105+
*counting-and-parity-inclusive mix* (not the competition set) it wins on PAR-2 over Kissat,
106+
CaDiCaL and CryptoMiniSat — because it is instant where they blow up on counting, and
107+
comparable elsewhere. A structural result on a specific mix, not a generally faster solver.
108+
- **meta-metasolver** (`metametasolver.py`) — the minimax mixed strategy; on the heavy-tailed
109+
random-3SAT band it *out-searches CMS in wall-clock* (parallel, at a `` CPU cost, no CMS
110+
in the pool). Single-thread on few cores, this advantage shrinks — see the honest scope.
111+
- **metasolver** (`metasolver.py`) — description-driven dispatch. On the included
112+
competition-style mix, its aggregate win comes from routing structured islands before
113+
CDCL, not from a claim of general CDCL dominance.
114+
- **meta-metasolver** (`metametasolver.py`) — seed-diversified CDCL portfolio for the
115+
heavy-tailed random-3SAT band; measured in the repo's scoped benchmark, with CPU cost
116+
reported.
117+
- **ACAF** (`acaf.py`) — sizes the mixed strategy to the cores; wins the structured tier by
118+
a constructive certificate, the hard tier by an adaptive portfolio.
119+
- **the view from outside**`dynamics.py` (laws/relations/motions), `fabric.py` +
120+
`fabric_model.py` (the hyperbolic instance-manifold), `observer.py` (the adjudicator).
112121

113122
> Every number here is a *measured* claim on a small, fixed, synthetic mix — regenerate it
114123
> with one command and read the scope in [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md). This is
@@ -145,13 +154,6 @@ python -m backend.cli examples/simple_sat.cnf --heuristic aggressive
145154
python -m pytest backend/tests/ -q
146155
```
147156

148-
### Benchmarking against SAT Competition
149-
To operationalize the solver and squeeze performance on standard competition instances (`.cnf`, `.xz`, `.lzma`):
150-
151-
```bash
152-
python -m backend.benchmark_cli ./cache/zenodo_full/ --pattern "*.xz" --timeout 5000 --parallel
153-
```
154-
155157
Strict certification smoke tests:
156158

157159
```bash

backend/acaf.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,11 @@ def _critic(formula: CNFFormula) -> Tuple[bool, float, int]:
6161
dyn = describe(formula)
6262
if dyn.certified:
6363
return True, 0.0, len(dyn.conserved)
64-
65-
hardness = 1.0 # default to heavy tail
66-
ambiguity = 0
67-
try:
68-
from .cython import tribridge
69-
res = tribridge.route_instance_topology(formula.clauses, formula.num_vars)
70-
struct_class = res["class"]
71-
72-
# PURE_GF2 and PARTIAL_XOR_SADDLE have bounded tails, they don't need swarm
73-
if struct_class in ("PURE_GF2", "PARTIAL_XOR_SADDLE"):
74-
hardness = 0.0
75-
ambiguity = 1
76-
except ImportError:
77-
pass
78-
79-
return False, hardness, ambiguity
64+
n = max(formula.num_vars, 1)
65+
# random-3SAT gets into the heavy-tailed seconds regime past ~220 vars (measured);
66+
# a smooth proxy, saturating, cheap -- no solve required.
67+
hardness = min(1.0, n / 260.0)
68+
return False, hardness, 0
8069

8170

8271
# ---- FUZZER: generate decorrelated engine+seed configs ----
@@ -113,7 +102,7 @@ def acaf_solve(formula: CNFFormula, timeout_s: float = 30.0,
113102
return ACAFResult("SAT", time.perf_counter() - t0, "frame",
114103
r.resolved_by, True, model=r.model, hardness=0.0)
115104
# frame check said suffice but punted (rare) -> fall through to tunnel policy
116-
_, hardness, _ = _critic(formula)
105+
hardness = min(1.0, max(formula.num_vars, 1) / 260.0)
117106

118107
cores = _cores()
119108
# AMBIGATOR: size the diversification to the predicted tail weight, capped at cores.

backend/benchmark.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -438,26 +438,20 @@ def compare_configs(self, config1: str, config2: str) -> Dict[str, Any]:
438438
}
439439

440440

441-
def discover_benchmarks(directory: Path, pattern: str | List[str] = "*.cnf") -> List[BenchmarkInstance]:
441+
def discover_benchmarks(directory: Path, pattern: str = "*.cnf") -> List[BenchmarkInstance]:
442442
"""
443443
Discover benchmark instances in a directory
444444
445445
Args:
446446
directory: Directory to search
447-
pattern: File pattern to match or list of patterns (default: *.cnf)
447+
pattern: File pattern to match (default: *.cnf)
448448
449449
Returns:
450450
List of benchmark instances
451451
"""
452452
instances = []
453-
454-
if isinstance(pattern, str):
455-
patterns = [pattern]
456-
else:
457-
patterns = pattern
458-
459-
for p in patterns:
460-
for path in directory.rglob(p):
453+
454+
for path in directory.rglob(pattern):
461455
# Try to infer category from directory structure
462456
category = path.parent.name if path.parent != directory else "unknown"
463457

backend/benchmark_cli.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@ async def main():
2525

2626
parser.add_argument(
2727
'--pattern',
28-
nargs='+',
29-
default=['*.cnf', '*.xz', '*.lzma'],
30-
help='File patterns to match (default: *.cnf *.xz *.lzma)'
28+
default='*.cnf',
29+
help='File pattern to match (default: *.cnf)'
3130
)
3231

3332
parser.add_argument(

backend/cnf_profile.py

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,86 @@ def _clause_is_horn(clause) -> bool:
5959
return sum(1 for lit in clause if lit > 0) <= 1
6060

6161

62+
def _shannon_entropy_ratio(weights) -> Optional[float]:
63+
"""Normalized Shannon entropy of a nonnegative weight vector.
6264
65+
Returns H(p) / log(n) in [0, 1], where p is the weight vector
66+
normalized to sum to 1. Returns None if there are fewer than 2
67+
nonzero weights (entropy is degenerate/undefined as a ratio).
68+
"""
69+
total = sum(weights)
70+
if total <= 0:
71+
return None
72+
nonzero = [w for w in weights if w > 0]
73+
if len(nonzero) < 2:
74+
return None
75+
probs = [w / total for w in nonzero]
76+
h = -sum(p * math.log(p) for p in probs)
77+
return h / math.log(len(nonzero))
78+
79+
80+
def _hyperbolic_delta_entropy_ratio(
81+
formula: CNFFormula,
82+
) -> Optional[float]:
83+
"""Experimental spectral feature: see `CNFProfile.hyp_delta_entropy_ratio`.
84+
85+
Builds the signed clause-variable incidence matrix M (clauses x vars,
86+
M[c, v] = +1 / -1 / 0 for the polarity of variable v in clause c),
87+
computes the normalized entropy of its singular-value distribution,
88+
then repeats after mapping each row through the Poincare-ball
89+
exponential map at the origin (a standard hyperbolic embedding:
90+
exp_0(x) = tanh(||x||) * x / ||x||, applied after scaling rows to
91+
unit max-norm so the map is well-defined). Returns hyp - euclidean.
92+
"""
93+
try:
94+
import numpy as np
95+
except ImportError:
96+
return None
97+
98+
n_vars = formula.num_vars
99+
n_clauses = formula.num_clauses
100+
if n_vars == 0 or n_clauses == 0:
101+
return None
102+
if n_vars * n_clauses > _SVD_MAX_CELLS:
103+
return None
104+
105+
matrix = np.zeros((n_clauses, n_vars), dtype=np.float64)
106+
for i, clause in enumerate(formula.clauses):
107+
for lit in clause:
108+
v = abs(lit) - 1
109+
if 0 <= v < n_vars:
110+
matrix[i, v] = 1.0 if lit > 0 else -1.0
111+
112+
def entropy_ratio_of(m: "np.ndarray") -> Optional[float]:
113+
try:
114+
singular_values = np.linalg.svd(m, compute_uv=False)
115+
except np.linalg.LinAlgError:
116+
return None
117+
return _shannon_entropy_ratio(singular_values.tolist())
118+
119+
euclidean_ratio = entropy_ratio_of(matrix)
120+
if euclidean_ratio is None:
121+
return None
122+
123+
row_norms = np.linalg.norm(matrix, axis=1, keepdims=True)
124+
max_norm = row_norms.max()
125+
if max_norm <= 0:
126+
return None
127+
normalized = matrix / max_norm
128+
row_norms_normalized = np.linalg.norm(normalized, axis=1, keepdims=True)
129+
with np.errstate(invalid='ignore', divide='ignore'):
130+
scale = np.where(
131+
row_norms_normalized > 0,
132+
np.tanh(row_norms_normalized) / row_norms_normalized,
133+
0.0,
134+
)
135+
hyperbolic = normalized * scale
136+
137+
hyperbolic_ratio = entropy_ratio_of(hyperbolic)
138+
if hyperbolic_ratio is None:
139+
return None
140+
141+
return hyperbolic_ratio - euclidean_ratio
63142

64143

65144
def profile_cnf(formula: CNFFormula, compute_spectral: bool = True) -> CNFProfile:
@@ -110,8 +189,12 @@ def profile_cnf(formula: CNFFormula, compute_spectral: bool = True) -> CNFProfil
110189
pos_neg_balance = num_positive_lits / total_lits if total_lits else 0.5
111190
avg_var_degree = total_lits / num_vars if num_vars else 0.0
112191

113-
# SVD entropy ratio previously removed
114-
var_degree_entropy = 0.0
192+
degree_entropy_ratio = _shannon_entropy_ratio(var_degree[1:])
193+
var_degree_entropy = degree_entropy_ratio if degree_entropy_ratio is not None else 0.0
194+
195+
hyp_delta = None
196+
if compute_spectral:
197+
hyp_delta = _hyperbolic_delta_entropy_ratio(formula)
115198

116199
return CNFProfile(
117200
num_vars=num_vars,
@@ -123,5 +206,5 @@ def profile_cnf(formula: CNFFormula, compute_spectral: bool = True) -> CNFProfil
123206
pos_neg_balance=pos_neg_balance,
124207
avg_var_degree=avg_var_degree,
125208
var_degree_entropy=var_degree_entropy,
126-
hyp_delta_entropy_ratio=None,
209+
hyp_delta_entropy_ratio=hyp_delta,
127210
)

backend/cnf_utils.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,10 @@ def parse_dimacs(text: str, strict: bool = False) -> CNFFormula:
158158
)
159159

160160

161-
import lzma
162-
163161
def parse_dimacs_file(path: Path, strict: bool = False) -> CNFFormula:
164-
"""Parse DIMACS CNF file (supports .cnf, .xz, .lzma)"""
165-
if path.suffix in ['.xz', '.lzma']:
166-
with lzma.open(path, 'rt') as f:
167-
return parse_dimacs(f.read(), strict=strict)
168-
else:
169-
with open(path, 'r') as f:
170-
return parse_dimacs(f.read(), strict=strict)
162+
"""Parse DIMACS CNF file"""
163+
with open(path, 'r') as f:
164+
return parse_dimacs(f.read(), strict=strict)
171165

172166

173167
def write_dimacs(formula: CNFFormula, path: Path):

backend/cpp/flavor_analyzer.hpp

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)