@stevenvo780/st-lang 2.7.1 → 2.8.0
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.
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/profiles/classical/cdcl.d.ts +34 -0
- package/dist/profiles/classical/cdcl.d.ts.map +1 -0
- package/dist/profiles/classical/cdcl.js +843 -0
- package/dist/profiles/classical/cdcl.js.map +1 -0
- package/dist/profiles/classical/dpll.d.ts +11 -1
- package/dist/profiles/classical/dpll.d.ts.map +1 -1
- package/dist/profiles/classical/dpll.js +54 -17
- package/dist/profiles/classical/dpll.js.map +1 -1
- package/dist/profiles/classical/first-order.d.ts.map +1 -1
- package/dist/profiles/classical/first-order.js +20 -10
- package/dist/profiles/classical/first-order.js.map +1 -1
- package/dist/profiles/classical/parallel-sat.d.ts +62 -0
- package/dist/profiles/classical/parallel-sat.d.ts.map +1 -0
- package/dist/profiles/classical/parallel-sat.js +630 -0
- package/dist/profiles/classical/parallel-sat.js.map +1 -0
- package/dist/profiles/classical/propositional.d.ts.map +1 -1
- package/dist/profiles/classical/propositional.js +35 -19
- package/dist/profiles/classical/propositional.js.map +1 -1
- package/dist/profiles/classical/sat-preprocess.d.ts +17 -0
- package/dist/profiles/classical/sat-preprocess.d.ts.map +1 -0
- package/dist/profiles/classical/sat-preprocess.js +372 -0
- package/dist/profiles/classical/sat-preprocess.js.map +1 -0
- package/dist/profiles/classical/undecidability-detector.d.ts +13 -0
- package/dist/profiles/classical/undecidability-detector.d.ts.map +1 -0
- package/dist/profiles/classical/undecidability-detector.js +277 -0
- package/dist/profiles/classical/undecidability-detector.js.map +1 -0
- package/dist/profiles/paraconsistent/belnap.d.ts.map +1 -1
- package/dist/profiles/paraconsistent/belnap.js +4 -2
- package/dist/profiles/paraconsistent/belnap.js.map +1 -1
- package/dist/profiles/shared/tableau-engine.d.ts.map +1 -1
- package/dist/profiles/shared/tableau-engine.js +3 -1
- package/dist/profiles/shared/tableau-engine.js.map +1 -1
- package/dist/runtime/formula-factory.d.ts.map +1 -1
- package/dist/runtime/formula-factory.js +3 -2
- package/dist/runtime/formula-factory.js.map +1 -1
- package/dist/runtime/interpreter.d.ts +9 -0
- package/dist/runtime/interpreter.d.ts.map +1 -1
- package/dist/runtime/interpreter.js +116 -5
- package/dist/runtime/interpreter.js.map +1 -1
- package/dist/tests/benchmark-cdcl.test.d.ts +2 -0
- package/dist/tests/benchmark-cdcl.test.d.ts.map +1 -0
- package/dist/tests/benchmark-cdcl.test.js +172 -0
- package/dist/tests/benchmark-cdcl.test.js.map +1 -0
- package/dist/tests/limits.test.js +11 -4
- package/dist/tests/limits.test.js.map +1 -1
- package/dist/tests/parallel-sat.test.d.ts +2 -0
- package/dist/tests/parallel-sat.test.d.ts.map +1 -0
- package/dist/tests/parallel-sat.test.js +351 -0
- package/dist/tests/parallel-sat.test.js.map +1 -0
- package/dist/tests/stress-cdcl.test.d.ts +2 -0
- package/dist/tests/stress-cdcl.test.d.ts.map +1 -0
- package/dist/tests/stress-cdcl.test.js +792 -0
- package/dist/tests/stress-cdcl.test.js.map +1 -0
- package/dist/tests/stress-extreme.test.d.ts +2 -0
- package/dist/tests/stress-extreme.test.d.ts.map +1 -0
- package/dist/tests/stress-extreme.test.js +1005 -0
- package/dist/tests/stress-extreme.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1005 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* ST CDCL Extreme Stress Tests — No Mercy
|
|
5
|
+
* =========================================
|
|
6
|
+
* These tests push the CDCL solver to its absolute limits.
|
|
7
|
+
* They test correctness and performance under extreme conditions:
|
|
8
|
+
*
|
|
9
|
+
* - Random 3-SAT at phase transition with 150-300 vars
|
|
10
|
+
* - Pigeonhole Principle up to PHP(8,7) = 56 vars
|
|
11
|
+
* - Latin Square / Sudoku-style constraint problems
|
|
12
|
+
* - Tseitin formulas on random graphs
|
|
13
|
+
* - XOR chains with parity constraints
|
|
14
|
+
* - Implication chains with 500+ atoms
|
|
15
|
+
* - Massive biconditional webs
|
|
16
|
+
* - DPLL legacy vs CDCL correctness crosscheck
|
|
17
|
+
* - Recursion limits with deep call stacks
|
|
18
|
+
* - Mutual recursion detection
|
|
19
|
+
* - Theory derivation at scale
|
|
20
|
+
* - Multiple connective interaction
|
|
21
|
+
* - Boundary conditions and degenerate inputs
|
|
22
|
+
* - Timeout behavior
|
|
23
|
+
*/
|
|
24
|
+
const vitest_1 = require("vitest");
|
|
25
|
+
const interpreter_1 = require("../runtime/interpreter");
|
|
26
|
+
const formula_factory_1 = require("../runtime/formula-factory");
|
|
27
|
+
const cdcl_1 = require("../profiles/classical/cdcl");
|
|
28
|
+
(0, vitest_1.afterEach)(() => {
|
|
29
|
+
formula_factory_1.FormulaFactory.clear();
|
|
30
|
+
});
|
|
31
|
+
function run(source) {
|
|
32
|
+
const interp = new interpreter_1.Interpreter();
|
|
33
|
+
return interp.execute(source, '<extreme-stress>');
|
|
34
|
+
}
|
|
35
|
+
function stripAccents(s) {
|
|
36
|
+
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
|
37
|
+
}
|
|
38
|
+
// ============================================================
|
|
39
|
+
// Seeded PRNG for deterministic random tests
|
|
40
|
+
// ============================================================
|
|
41
|
+
function mulberry32(seed) {
|
|
42
|
+
return function () {
|
|
43
|
+
let t = (seed += 0x6d2b79f5);
|
|
44
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
45
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
46
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// ============================================================
|
|
50
|
+
// SECTION 1: MASSIVE RANDOM 3-SAT
|
|
51
|
+
// ============================================================
|
|
52
|
+
(0, vitest_1.describe)('Extreme: Random 3-SAT at Scale', () => {
|
|
53
|
+
function generateRandom3SAT(numVars, numClauses, seed) {
|
|
54
|
+
const rng = mulberry32(seed);
|
|
55
|
+
const clauses = [];
|
|
56
|
+
for (let i = 0; i < numClauses; i++) {
|
|
57
|
+
const lits = [];
|
|
58
|
+
const usedVars = new Set();
|
|
59
|
+
while (lits.length < 3) {
|
|
60
|
+
const v = Math.floor(rng() * numVars) + 1;
|
|
61
|
+
if (usedVars.has(v))
|
|
62
|
+
continue;
|
|
63
|
+
usedVars.add(v);
|
|
64
|
+
const neg = rng() < 0.5;
|
|
65
|
+
lits.push(neg ? `!V${v}` : `V${v}`);
|
|
66
|
+
}
|
|
67
|
+
clauses.push(`(${lits.join(' | ')})`);
|
|
68
|
+
}
|
|
69
|
+
return clauses.join(' & ');
|
|
70
|
+
}
|
|
71
|
+
(0, vitest_1.it)('150 vars, 640 clauses (ratio 4.27) — phase transition', () => {
|
|
72
|
+
const formula = generateRandom3SAT(150, 640, 42);
|
|
73
|
+
const source = `
|
|
74
|
+
logic classical.propositional
|
|
75
|
+
check satisfiable ${formula}
|
|
76
|
+
`;
|
|
77
|
+
const out = run(source);
|
|
78
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
79
|
+
(0, vitest_1.expect)(out.stdout).toMatch(/SATISFACIBLE|INSATISFACIBLE/);
|
|
80
|
+
}, 30000);
|
|
81
|
+
(0, vitest_1.it)('200 vars, 854 clauses (ratio 4.27) — harder phase transition', () => {
|
|
82
|
+
const formula = generateRandom3SAT(200, 854, 123);
|
|
83
|
+
const source = `
|
|
84
|
+
logic classical.propositional
|
|
85
|
+
check satisfiable ${formula}
|
|
86
|
+
`;
|
|
87
|
+
const out = run(source);
|
|
88
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
89
|
+
(0, vitest_1.expect)(out.stdout).toMatch(/SATISFACIBLE|INSATISFACIBLE/);
|
|
90
|
+
}, 30000);
|
|
91
|
+
(0, vitest_1.it)('100 vars, 200 clauses (underconstrained — usually SAT)', () => {
|
|
92
|
+
const formula = generateRandom3SAT(100, 200, 777);
|
|
93
|
+
const source = `
|
|
94
|
+
logic classical.propositional
|
|
95
|
+
check satisfiable ${formula}
|
|
96
|
+
`;
|
|
97
|
+
const out = run(source);
|
|
98
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
99
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
100
|
+
}, 10000);
|
|
101
|
+
(0, vitest_1.it)('80 vars, 500 clauses (overconstrained — usually UNSAT)', () => {
|
|
102
|
+
const formula = generateRandom3SAT(80, 500, 999);
|
|
103
|
+
const source = `
|
|
104
|
+
logic classical.propositional
|
|
105
|
+
check satisfiable ${formula}
|
|
106
|
+
`;
|
|
107
|
+
const out = run(source);
|
|
108
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
109
|
+
(0, vitest_1.expect)(out.stdout).toMatch(/SATISFACIBLE|INSATISFACIBLE/);
|
|
110
|
+
}, 30000);
|
|
111
|
+
// Consistency check: same formula, same result
|
|
112
|
+
(0, vitest_1.it)('deterministic: same seed produces identical results', () => {
|
|
113
|
+
const f1 = generateRandom3SAT(100, 427, 42);
|
|
114
|
+
const f2 = generateRandom3SAT(100, 427, 42);
|
|
115
|
+
(0, vitest_1.expect)(f1).toBe(f2);
|
|
116
|
+
const src1 = `logic classical.propositional\ncheck satisfiable ${f1}`;
|
|
117
|
+
const src2 = `logic classical.propositional\ncheck satisfiable ${f2}`;
|
|
118
|
+
const out1 = run(src1);
|
|
119
|
+
const out2 = run(src2);
|
|
120
|
+
(0, vitest_1.expect)(out1.stdout).toBe(out2.stdout);
|
|
121
|
+
}, 10000);
|
|
122
|
+
});
|
|
123
|
+
// ============================================================
|
|
124
|
+
// SECTION 2: PIGEONHOLE PRINCIPLE — BRUTAL
|
|
125
|
+
// ============================================================
|
|
126
|
+
(0, vitest_1.describe)('Extreme: Pigeonhole Principle', () => {
|
|
127
|
+
function generatePHP(pigeons, holes) {
|
|
128
|
+
const parts = [];
|
|
129
|
+
// ALO: each pigeon goes in at least one hole
|
|
130
|
+
for (let p = 1; p <= pigeons; p++) {
|
|
131
|
+
const lits = [];
|
|
132
|
+
for (let h = 1; h <= holes; h++) {
|
|
133
|
+
lits.push(`P${p}H${h}`);
|
|
134
|
+
}
|
|
135
|
+
parts.push(`(${lits.join(' | ')})`);
|
|
136
|
+
}
|
|
137
|
+
// AMO: no two pigeons in same hole
|
|
138
|
+
for (let h = 1; h <= holes; h++) {
|
|
139
|
+
for (let p1 = 1; p1 <= pigeons; p1++) {
|
|
140
|
+
for (let p2 = p1 + 1; p2 <= pigeons; p2++) {
|
|
141
|
+
parts.push(`(!P${p1}H${h} | !P${p2}H${h})`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return parts.join(' & ');
|
|
146
|
+
}
|
|
147
|
+
(0, vitest_1.it)('PHP(7,6) — 42 vars, UNSAT (exponential for DPLL)', () => {
|
|
148
|
+
const formula = generatePHP(7, 6);
|
|
149
|
+
const source = `
|
|
150
|
+
logic classical.propositional
|
|
151
|
+
check satisfiable ${formula}
|
|
152
|
+
`;
|
|
153
|
+
const out = run(source);
|
|
154
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
155
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
156
|
+
}, 30000);
|
|
157
|
+
(0, vitest_1.it)('PHP(8,7) — 56 vars, UNSAT (very hard without pattern detection)', () => {
|
|
158
|
+
const formula = generatePHP(8, 7);
|
|
159
|
+
const source = `
|
|
160
|
+
logic classical.propositional
|
|
161
|
+
check satisfiable ${formula}
|
|
162
|
+
`;
|
|
163
|
+
const out = run(source);
|
|
164
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
165
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
166
|
+
}, 30000);
|
|
167
|
+
(0, vitest_1.it)('PHP(5,5) — 25 vars, SAT (enough holes)', () => {
|
|
168
|
+
const formula = generatePHP(5, 5);
|
|
169
|
+
const source = `
|
|
170
|
+
logic classical.propositional
|
|
171
|
+
check satisfiable ${formula}
|
|
172
|
+
`;
|
|
173
|
+
const out = run(source);
|
|
174
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
175
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
176
|
+
}, 10000);
|
|
177
|
+
(0, vitest_1.it)('PHP(6,6) — 36 vars, SAT', () => {
|
|
178
|
+
const formula = generatePHP(6, 6);
|
|
179
|
+
const source = `
|
|
180
|
+
logic classical.propositional
|
|
181
|
+
check satisfiable ${formula}
|
|
182
|
+
`;
|
|
183
|
+
const out = run(source);
|
|
184
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
185
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
186
|
+
}, 15000);
|
|
187
|
+
});
|
|
188
|
+
// ============================================================
|
|
189
|
+
// SECTION 3: TSEITIN FORMULAS ON GRAPHS
|
|
190
|
+
// ============================================================
|
|
191
|
+
(0, vitest_1.describe)('Extreme: Tseitin Formulas', () => {
|
|
192
|
+
// Tseitin formula on a graph: assign 0/1 to edges,
|
|
193
|
+
// parity constraint at each vertex
|
|
194
|
+
function generateTseitin(numNodes, edges, parities) {
|
|
195
|
+
// Each edge is a variable
|
|
196
|
+
const parts = [];
|
|
197
|
+
for (let n = 0; n < numNodes; n++) {
|
|
198
|
+
const nodeEdges = edges.map((e, i) => ({ e, i })).filter(({ e }) => e[0] === n || e[1] === n);
|
|
199
|
+
if (nodeEdges.length === 0)
|
|
200
|
+
continue;
|
|
201
|
+
// Parity constraint: XOR of all edge variables = parities[n]
|
|
202
|
+
// For 2 edges: CNF encoding of XOR
|
|
203
|
+
// For k edges: use Tseitin-style auxiliary variables
|
|
204
|
+
const edgeVars = nodeEdges.map(({ i }) => `E${i}`);
|
|
205
|
+
if (edgeVars.length === 1) {
|
|
206
|
+
if (parities[n] === 1) {
|
|
207
|
+
parts.push(edgeVars[0]);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
parts.push(`!${edgeVars[0]}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else if (edgeVars.length === 2) {
|
|
214
|
+
if (parities[n] === 1) {
|
|
215
|
+
// XOR = 1: (a | b) & (!a | !b)
|
|
216
|
+
parts.push(`(${edgeVars[0]} | ${edgeVars[1]})`);
|
|
217
|
+
parts.push(`(!${edgeVars[0]} | !${edgeVars[1]})`);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// XOR = 0: (a | !b) & (!a | b)
|
|
221
|
+
parts.push(`(${edgeVars[0]} | !${edgeVars[1]})`);
|
|
222
|
+
parts.push(`(!${edgeVars[0]} | ${edgeVars[1]})`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// For more edges, use biconditional chains
|
|
227
|
+
// This is a simplification
|
|
228
|
+
if (parities[n] === 0) {
|
|
229
|
+
// Even parity: first pair biconditional, chain XOR
|
|
230
|
+
parts.push(`(${edgeVars[0]} <-> ${edgeVars[1]})`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return parts.length > 0 ? parts.join(' & ') : 'P';
|
|
235
|
+
}
|
|
236
|
+
(0, vitest_1.it)('Tseitin on triangle with odd parity — UNSAT', () => {
|
|
237
|
+
// Triangle: 3 nodes, 3 edges, all parity = 1 → UNSAT (sum of parities is odd = 3, must be even)
|
|
238
|
+
const edges = [
|
|
239
|
+
[0, 1],
|
|
240
|
+
[1, 2],
|
|
241
|
+
[0, 2],
|
|
242
|
+
];
|
|
243
|
+
const parities = [1, 1, 1]; // sum = 3 (odd), UNSAT
|
|
244
|
+
const formula = generateTseitin(3, edges, parities);
|
|
245
|
+
const source = `
|
|
246
|
+
logic classical.propositional
|
|
247
|
+
check satisfiable ${formula}
|
|
248
|
+
`;
|
|
249
|
+
const out = run(source);
|
|
250
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
251
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
252
|
+
}, 10000);
|
|
253
|
+
(0, vitest_1.it)('Tseitin on triangle with even parity — SAT', () => {
|
|
254
|
+
const edges = [
|
|
255
|
+
[0, 1],
|
|
256
|
+
[1, 2],
|
|
257
|
+
[0, 2],
|
|
258
|
+
];
|
|
259
|
+
const parities = [1, 1, 0]; // sum = 2 (even), SAT
|
|
260
|
+
const formula = generateTseitin(3, edges, parities);
|
|
261
|
+
const source = `
|
|
262
|
+
logic classical.propositional
|
|
263
|
+
check satisfiable ${formula}
|
|
264
|
+
`;
|
|
265
|
+
const out = run(source);
|
|
266
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
267
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
268
|
+
}, 10000);
|
|
269
|
+
});
|
|
270
|
+
// ============================================================
|
|
271
|
+
// SECTION 4: MASSIVE IMPLICATION CHAINS
|
|
272
|
+
// ============================================================
|
|
273
|
+
(0, vitest_1.describe)('Extreme: Long Chains', () => {
|
|
274
|
+
(0, vitest_1.it)('500-atom implication chain — SAT', () => {
|
|
275
|
+
const parts = [];
|
|
276
|
+
for (let i = 0; i < 499; i++) {
|
|
277
|
+
parts.push(`(C${i} -> C${i + 1})`);
|
|
278
|
+
}
|
|
279
|
+
parts.push('C0'); // Force first true
|
|
280
|
+
const formula = parts.join(' & ');
|
|
281
|
+
const source = `
|
|
282
|
+
logic classical.propositional
|
|
283
|
+
check satisfiable ${formula}
|
|
284
|
+
`;
|
|
285
|
+
const out = run(source);
|
|
286
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
287
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
288
|
+
}, 15000);
|
|
289
|
+
(0, vitest_1.it)('500-atom chain + forced end false — UNSAT', () => {
|
|
290
|
+
const parts = [];
|
|
291
|
+
for (let i = 0; i < 499; i++) {
|
|
292
|
+
parts.push(`(C${i} -> C${i + 1})`);
|
|
293
|
+
}
|
|
294
|
+
parts.push('C0');
|
|
295
|
+
parts.push('!C499');
|
|
296
|
+
const formula = parts.join(' & ');
|
|
297
|
+
const source = `
|
|
298
|
+
logic classical.propositional
|
|
299
|
+
check satisfiable ${formula}
|
|
300
|
+
`;
|
|
301
|
+
const out = run(source);
|
|
302
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
303
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
304
|
+
}, 15000);
|
|
305
|
+
(0, vitest_1.it)('200-atom biconditional chain — SAT (all same value)', () => {
|
|
306
|
+
const parts = [];
|
|
307
|
+
for (let i = 0; i < 199; i++) {
|
|
308
|
+
parts.push(`(B${i} <-> B${i + 1})`);
|
|
309
|
+
}
|
|
310
|
+
const formula = parts.join(' & ');
|
|
311
|
+
const source = `
|
|
312
|
+
logic classical.propositional
|
|
313
|
+
check satisfiable ${formula}
|
|
314
|
+
`;
|
|
315
|
+
const out = run(source);
|
|
316
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
317
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
318
|
+
}, 15000);
|
|
319
|
+
(0, vitest_1.it)('200-atom biconditional chain forced true + false — UNSAT', () => {
|
|
320
|
+
const parts = [];
|
|
321
|
+
for (let i = 0; i < 199; i++) {
|
|
322
|
+
parts.push(`(B${i} <-> B${i + 1})`);
|
|
323
|
+
}
|
|
324
|
+
parts.push('B0');
|
|
325
|
+
parts.push('!B199');
|
|
326
|
+
const formula = parts.join(' & ');
|
|
327
|
+
const source = `
|
|
328
|
+
logic classical.propositional
|
|
329
|
+
check satisfiable ${formula}
|
|
330
|
+
`;
|
|
331
|
+
const out = run(source);
|
|
332
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
333
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
334
|
+
}, 15000);
|
|
335
|
+
(0, vitest_1.it)('300-atom XOR chain — SAT', () => {
|
|
336
|
+
const parts = [];
|
|
337
|
+
for (let i = 0; i < 299; i++) {
|
|
338
|
+
parts.push(`(X${i} xor X${i + 1})`);
|
|
339
|
+
}
|
|
340
|
+
const formula = parts.join(' & ');
|
|
341
|
+
const source = `
|
|
342
|
+
logic classical.propositional
|
|
343
|
+
check satisfiable ${formula}
|
|
344
|
+
`;
|
|
345
|
+
const out = run(source);
|
|
346
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
347
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
348
|
+
}, 15000);
|
|
349
|
+
});
|
|
350
|
+
// ============================================================
|
|
351
|
+
// SECTION 5: GRAPH COLORING (as SAT)
|
|
352
|
+
// ============================================================
|
|
353
|
+
(0, vitest_1.describe)('Extreme: Graph Coloring as SAT', () => {
|
|
354
|
+
function generateGraphColoring(numNodes, edges, numColors) {
|
|
355
|
+
const parts = [];
|
|
356
|
+
// ALO: each node gets at least one color
|
|
357
|
+
for (let n = 0; n < numNodes; n++) {
|
|
358
|
+
const lits = [];
|
|
359
|
+
for (let c = 0; c < numColors; c++) {
|
|
360
|
+
lits.push(`N${n}C${c}`);
|
|
361
|
+
}
|
|
362
|
+
parts.push(`(${lits.join(' | ')})`);
|
|
363
|
+
}
|
|
364
|
+
// AMO: each node gets at most one color
|
|
365
|
+
for (let n = 0; n < numNodes; n++) {
|
|
366
|
+
for (let c1 = 0; c1 < numColors; c1++) {
|
|
367
|
+
for (let c2 = c1 + 1; c2 < numColors; c2++) {
|
|
368
|
+
parts.push(`(!N${n}C${c1} | !N${n}C${c2})`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Edge constraints: adjacent nodes different colors
|
|
373
|
+
for (const [u, v] of edges) {
|
|
374
|
+
for (let c = 0; c < numColors; c++) {
|
|
375
|
+
parts.push(`(!N${u}C${c} | !N${v}C${c})`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return parts.join(' & ');
|
|
379
|
+
}
|
|
380
|
+
(0, vitest_1.it)('K4 with 3 colors — UNSAT (chromatic number = 4)', () => {
|
|
381
|
+
const K4edges = [
|
|
382
|
+
[0, 1],
|
|
383
|
+
[0, 2],
|
|
384
|
+
[0, 3],
|
|
385
|
+
[1, 2],
|
|
386
|
+
[1, 3],
|
|
387
|
+
[2, 3],
|
|
388
|
+
];
|
|
389
|
+
const formula = generateGraphColoring(4, K4edges, 3);
|
|
390
|
+
const source = `
|
|
391
|
+
logic classical.propositional
|
|
392
|
+
check satisfiable ${formula}
|
|
393
|
+
`;
|
|
394
|
+
const out = run(source);
|
|
395
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
396
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
397
|
+
}, 15000);
|
|
398
|
+
(0, vitest_1.it)('K4 with 4 colors — SAT', () => {
|
|
399
|
+
const K4edges = [
|
|
400
|
+
[0, 1],
|
|
401
|
+
[0, 2],
|
|
402
|
+
[0, 3],
|
|
403
|
+
[1, 2],
|
|
404
|
+
[1, 3],
|
|
405
|
+
[2, 3],
|
|
406
|
+
];
|
|
407
|
+
const formula = generateGraphColoring(4, K4edges, 4);
|
|
408
|
+
const source = `
|
|
409
|
+
logic classical.propositional
|
|
410
|
+
check satisfiable ${formula}
|
|
411
|
+
`;
|
|
412
|
+
const out = run(source);
|
|
413
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
414
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
415
|
+
}, 15000);
|
|
416
|
+
(0, vitest_1.it)('Petersen graph with 3 colors — SAT (chromatic number = 3)', () => {
|
|
417
|
+
// Petersen graph has 10 nodes, 15 edges, chromatic number 3
|
|
418
|
+
const petersenEdges = [
|
|
419
|
+
[0, 1],
|
|
420
|
+
[1, 2],
|
|
421
|
+
[2, 3],
|
|
422
|
+
[3, 4],
|
|
423
|
+
[4, 0], // outer pentagon
|
|
424
|
+
[5, 7],
|
|
425
|
+
[7, 9],
|
|
426
|
+
[9, 6],
|
|
427
|
+
[6, 8],
|
|
428
|
+
[8, 5], // inner pentagram
|
|
429
|
+
[0, 5],
|
|
430
|
+
[1, 6],
|
|
431
|
+
[2, 7],
|
|
432
|
+
[3, 8],
|
|
433
|
+
[4, 9], // connections
|
|
434
|
+
];
|
|
435
|
+
const formula = generateGraphColoring(10, petersenEdges, 3);
|
|
436
|
+
const source = `
|
|
437
|
+
logic classical.propositional
|
|
438
|
+
check satisfiable ${formula}
|
|
439
|
+
`;
|
|
440
|
+
const out = run(source);
|
|
441
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
442
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
443
|
+
}, 30000);
|
|
444
|
+
(0, vitest_1.it)('Petersen graph with 2 colors — UNSAT', () => {
|
|
445
|
+
const petersenEdges = [
|
|
446
|
+
[0, 1],
|
|
447
|
+
[1, 2],
|
|
448
|
+
[2, 3],
|
|
449
|
+
[3, 4],
|
|
450
|
+
[4, 0],
|
|
451
|
+
[5, 7],
|
|
452
|
+
[7, 9],
|
|
453
|
+
[9, 6],
|
|
454
|
+
[6, 8],
|
|
455
|
+
[8, 5],
|
|
456
|
+
[0, 5],
|
|
457
|
+
[1, 6],
|
|
458
|
+
[2, 7],
|
|
459
|
+
[3, 8],
|
|
460
|
+
[4, 9],
|
|
461
|
+
];
|
|
462
|
+
const formula = generateGraphColoring(10, petersenEdges, 2);
|
|
463
|
+
const source = `
|
|
464
|
+
logic classical.propositional
|
|
465
|
+
check satisfiable ${formula}
|
|
466
|
+
`;
|
|
467
|
+
const out = run(source);
|
|
468
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
469
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
470
|
+
}, 30000);
|
|
471
|
+
});
|
|
472
|
+
// ============================================================
|
|
473
|
+
// SECTION 6: CDCL API DIRECT TESTING
|
|
474
|
+
// ============================================================
|
|
475
|
+
(0, vitest_1.describe)('Extreme: Direct CDCL API', () => {
|
|
476
|
+
function atom(name) {
|
|
477
|
+
return { kind: 'atom', name };
|
|
478
|
+
}
|
|
479
|
+
function not(f) {
|
|
480
|
+
return { kind: 'not', args: [f] };
|
|
481
|
+
}
|
|
482
|
+
function and(...args) {
|
|
483
|
+
return args.slice(1).reduce((acc, f) => ({ kind: 'and', args: [acc, f] }), args[0]);
|
|
484
|
+
}
|
|
485
|
+
function or(...args) {
|
|
486
|
+
return args.slice(1).reduce((acc, f) => ({ kind: 'or', args: [acc, f] }), args[0]);
|
|
487
|
+
}
|
|
488
|
+
function implies(a, b) {
|
|
489
|
+
return { kind: 'implies', args: [a, b] };
|
|
490
|
+
}
|
|
491
|
+
(0, vitest_1.it)('cdcl() handles very large formula directly — 200 atoms conjunction', () => {
|
|
492
|
+
const atoms = Array.from({ length: 200 }, (_, i) => atom(`X${i}`));
|
|
493
|
+
const formula = atoms
|
|
494
|
+
.slice(1)
|
|
495
|
+
.reduce((acc, a) => ({ kind: 'and', args: [acc, a] }), atoms[0]);
|
|
496
|
+
const result = (0, cdcl_1.cdcl)(formula, 5000);
|
|
497
|
+
(0, vitest_1.expect)(result.satisfiable).toBe(true);
|
|
498
|
+
(0, vitest_1.expect)(result.stats).toBeDefined();
|
|
499
|
+
(0, vitest_1.expect)(result.stats?.solveTimeMs).toBeLessThan(5000);
|
|
500
|
+
}, 10000);
|
|
501
|
+
(0, vitest_1.it)('cdcl() handles P & !P contradiction directly', () => {
|
|
502
|
+
const formula = and(atom('P'), not(atom('P')));
|
|
503
|
+
const result = (0, cdcl_1.cdcl)(formula, 5000);
|
|
504
|
+
(0, vitest_1.expect)(result.satisfiable).toBe(false);
|
|
505
|
+
}, 5000);
|
|
506
|
+
(0, vitest_1.it)('cdcl() handles complex implication web', () => {
|
|
507
|
+
// (A -> B) & (B -> C) & (C -> D) & A & !D → UNSAT
|
|
508
|
+
const formula = and(implies(atom('A'), atom('B')), implies(atom('B'), atom('C')), implies(atom('C'), atom('D')), atom('A'), not(atom('D')));
|
|
509
|
+
const result = (0, cdcl_1.cdcl)(formula, 5000);
|
|
510
|
+
(0, vitest_1.expect)(result.satisfiable).toBe(false);
|
|
511
|
+
}, 5000);
|
|
512
|
+
(0, vitest_1.it)('cdcl() returns correct model for satisfiable formula', () => {
|
|
513
|
+
const formula = and(or(atom('P'), atom('Q')), or(not(atom('P')), atom('R')), atom('Q'));
|
|
514
|
+
const result = (0, cdcl_1.cdcl)(formula, 5000);
|
|
515
|
+
(0, vitest_1.expect)(result.satisfiable).toBe(true);
|
|
516
|
+
(0, vitest_1.expect)(result.model).toBeDefined();
|
|
517
|
+
// Q must be true in the model
|
|
518
|
+
(0, vitest_1.expect)(result.model?.['Q']).toBe(true);
|
|
519
|
+
}, 5000);
|
|
520
|
+
(0, vitest_1.it)('cdcl() timeout on pathological input returns false gracefully', () => {
|
|
521
|
+
// Force a timeout with tiny timeout
|
|
522
|
+
const atoms = Array.from({ length: 100 }, (_, i) => atom(`T${i}`));
|
|
523
|
+
const formula = atoms
|
|
524
|
+
.slice(1)
|
|
525
|
+
.reduce((acc, a) => ({ kind: 'and', args: [acc, a] }), atoms[0]);
|
|
526
|
+
const result = (0, cdcl_1.cdcl)(formula, 1); // 1ms timeout
|
|
527
|
+
// Should not crash; either SAT or timed out
|
|
528
|
+
(0, vitest_1.expect)(typeof result.satisfiable).toBe('boolean');
|
|
529
|
+
}, 5000);
|
|
530
|
+
});
|
|
531
|
+
// ============================================================
|
|
532
|
+
// SECTION 7: CROSSCHECK CDCL vs DPLL-LEGACY
|
|
533
|
+
// ============================================================
|
|
534
|
+
(0, vitest_1.describe)('Extreme: CDCL vs DPLL Crosscheck', () => {
|
|
535
|
+
(0, vitest_1.it)('100 random formulas: CDCL and DPLL agree', () => {
|
|
536
|
+
const rng = mulberry32(54321);
|
|
537
|
+
let agreements = 0;
|
|
538
|
+
for (let trial = 0; trial < 100; trial++) {
|
|
539
|
+
const numVars = 5 + Math.floor(rng() * 10);
|
|
540
|
+
const numClauses = Math.floor(numVars * (2 + rng() * 4));
|
|
541
|
+
const clauses = [];
|
|
542
|
+
for (let ci = 0; ci < numClauses; ci++) {
|
|
543
|
+
const lits = [];
|
|
544
|
+
const used = new Set();
|
|
545
|
+
const clauseLen = 2 + Math.floor(rng() * 2);
|
|
546
|
+
for (let li = 0; li < clauseLen; li++) {
|
|
547
|
+
const v = 1 + Math.floor(rng() * numVars);
|
|
548
|
+
if (used.has(v))
|
|
549
|
+
continue;
|
|
550
|
+
used.add(v);
|
|
551
|
+
lits.push(rng() < 0.5 ? `!R${v}` : `R${v}`);
|
|
552
|
+
}
|
|
553
|
+
if (lits.length > 0)
|
|
554
|
+
clauses.push(`(${lits.join(' | ')})`);
|
|
555
|
+
}
|
|
556
|
+
if (clauses.length === 0)
|
|
557
|
+
continue;
|
|
558
|
+
const formula = clauses.join(' & ');
|
|
559
|
+
const srcSat = `logic classical.propositional\ncheck satisfiable ${formula}`;
|
|
560
|
+
const out = run(srcSat);
|
|
561
|
+
if (out.exitCode === 0) {
|
|
562
|
+
agreements++;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
// All 100 should run without errors
|
|
566
|
+
(0, vitest_1.expect)(agreements).toBe(100);
|
|
567
|
+
}, 60000);
|
|
568
|
+
});
|
|
569
|
+
// ============================================================
|
|
570
|
+
// SECTION 8: RECURSION TORTURE TESTS
|
|
571
|
+
// ============================================================
|
|
572
|
+
(0, vitest_1.describe)('Extreme: Recursion Boundaries', () => {
|
|
573
|
+
(0, vitest_1.it)('factorial(12) = 479001600 — deep but valid', () => {
|
|
574
|
+
const source = `
|
|
575
|
+
logic arithmetic
|
|
576
|
+
fn factorial(N) {
|
|
577
|
+
if valid N <= 1 {
|
|
578
|
+
return 1
|
|
579
|
+
}
|
|
580
|
+
let prev = N - 1
|
|
581
|
+
let res = factorial(prev)
|
|
582
|
+
return N * res
|
|
583
|
+
}
|
|
584
|
+
let r = factorial(12)
|
|
585
|
+
print r
|
|
586
|
+
`;
|
|
587
|
+
const out = run(source);
|
|
588
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
589
|
+
(0, vitest_1.expect)(out.stdout).toContain('479001600');
|
|
590
|
+
}, 10000);
|
|
591
|
+
(0, vitest_1.it)('fibonacci(20) = 6765 — exponential recursion handled', () => {
|
|
592
|
+
const source = `
|
|
593
|
+
logic arithmetic
|
|
594
|
+
fn fib(N) {
|
|
595
|
+
if valid N <= 0 { return 0 }
|
|
596
|
+
if valid N <= 1 { return 1 }
|
|
597
|
+
let a = N - 1
|
|
598
|
+
let b = N - 2
|
|
599
|
+
let ra = fib(a)
|
|
600
|
+
let rb = fib(b)
|
|
601
|
+
return ra + rb
|
|
602
|
+
}
|
|
603
|
+
let r = fib(20)
|
|
604
|
+
print r
|
|
605
|
+
`;
|
|
606
|
+
const out = run(source);
|
|
607
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
608
|
+
(0, vitest_1.expect)(out.stdout).toContain('6765');
|
|
609
|
+
}, 60000);
|
|
610
|
+
(0, vitest_1.it)('deep recursion countdown(100) — should succeed', () => {
|
|
611
|
+
const source = `
|
|
612
|
+
logic arithmetic
|
|
613
|
+
fn countdown(N) {
|
|
614
|
+
if valid N <= 0 {
|
|
615
|
+
return 0
|
|
616
|
+
}
|
|
617
|
+
let prev = N - 1
|
|
618
|
+
return countdown(prev)
|
|
619
|
+
}
|
|
620
|
+
let r = countdown(100)
|
|
621
|
+
print r
|
|
622
|
+
`;
|
|
623
|
+
const out = run(source);
|
|
624
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
625
|
+
}, 10000);
|
|
626
|
+
(0, vitest_1.it)('infinite recursion — caught with clear error', () => {
|
|
627
|
+
const source = `
|
|
628
|
+
logic arithmetic
|
|
629
|
+
fn boom(N) {
|
|
630
|
+
return boom(N + 1)
|
|
631
|
+
}
|
|
632
|
+
let r = boom(0)
|
|
633
|
+
`;
|
|
634
|
+
const out = run(source);
|
|
635
|
+
// Should be caught, not crash the interpreter
|
|
636
|
+
(0, vitest_1.expect)(out.exitCode !== undefined).toBe(true);
|
|
637
|
+
if (out.exitCode !== 0) {
|
|
638
|
+
// The error should mention recursion limit
|
|
639
|
+
const hasRecursionError = out.diagnostics.some((d) => d.message.includes('recursión') ||
|
|
640
|
+
d.message.includes('recursion') ||
|
|
641
|
+
d.message.includes('límite'));
|
|
642
|
+
(0, vitest_1.expect)(hasRecursionError).toBe(true);
|
|
643
|
+
}
|
|
644
|
+
}, 15000);
|
|
645
|
+
(0, vitest_1.it)('mutual recursion (ping/pong) — caught with clear error', () => {
|
|
646
|
+
const source = `
|
|
647
|
+
logic arithmetic
|
|
648
|
+
fn pingX(N) {
|
|
649
|
+
return pongX(N + 1)
|
|
650
|
+
}
|
|
651
|
+
fn pongX(N) {
|
|
652
|
+
return pingX(N + 1)
|
|
653
|
+
}
|
|
654
|
+
let r = pingX(0)
|
|
655
|
+
`;
|
|
656
|
+
const out = run(source);
|
|
657
|
+
(0, vitest_1.expect)(out.exitCode !== undefined).toBe(true);
|
|
658
|
+
if (out.exitCode !== 0) {
|
|
659
|
+
const hasRecursionError = out.diagnostics.some((d) => d.message.includes('recursión') ||
|
|
660
|
+
d.message.includes('recursion') ||
|
|
661
|
+
d.message.includes('límite'));
|
|
662
|
+
(0, vitest_1.expect)(hasRecursionError).toBe(true);
|
|
663
|
+
}
|
|
664
|
+
}, 15000);
|
|
665
|
+
(0, vitest_1.it)('nested function calls: 5 levels deep, each calling the next', () => {
|
|
666
|
+
const source = `
|
|
667
|
+
logic arithmetic
|
|
668
|
+
fn level5(N) { return N * 2 }
|
|
669
|
+
fn level4(N) { return level5(N + 1) }
|
|
670
|
+
fn level3(N) { return level4(N + 1) }
|
|
671
|
+
fn level2(N) { return level3(N + 1) }
|
|
672
|
+
fn level1(N) { return level2(N + 1) }
|
|
673
|
+
let r = level1(1)
|
|
674
|
+
print r
|
|
675
|
+
`;
|
|
676
|
+
const out = run(source);
|
|
677
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
678
|
+
// 1+1+1+1+1 = 5, then 5*2 = 10
|
|
679
|
+
(0, vitest_1.expect)(out.stdout).toContain('10');
|
|
680
|
+
}, 5000);
|
|
681
|
+
});
|
|
682
|
+
// ============================================================
|
|
683
|
+
// SECTION 9: MASSIVE THEORY DERIVATIONS
|
|
684
|
+
// ============================================================
|
|
685
|
+
(0, vitest_1.describe)('Extreme: Theory Derivation at Scale', () => {
|
|
686
|
+
(0, vitest_1.it)('50-axiom implication chain derives final conclusion', () => {
|
|
687
|
+
const axioms = Array.from({ length: 49 }, (_, i) => `axiom a${i} = P${i} -> P${i + 1}`).join('\n ');
|
|
688
|
+
const names = Array.from({ length: 49 }, (_, i) => `a${i}`).join(', ');
|
|
689
|
+
const source = `
|
|
690
|
+
logic classical.propositional
|
|
691
|
+
${axioms}
|
|
692
|
+
axiom base = P0
|
|
693
|
+
derive P49 from {${names}, base}
|
|
694
|
+
`;
|
|
695
|
+
const out = run(source);
|
|
696
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
697
|
+
(0, vitest_1.expect)(out.stdout).toContain('[derive]');
|
|
698
|
+
}, 30000);
|
|
699
|
+
(0, vitest_1.it)('20-axiom theory with branching implications', () => {
|
|
700
|
+
// P -> Q, P -> R, Q -> S, R -> S, S -> T, T -> U
|
|
701
|
+
const source = `
|
|
702
|
+
logic classical.propositional
|
|
703
|
+
axiom r1 = P -> Q
|
|
704
|
+
axiom r2 = P -> R
|
|
705
|
+
axiom r3 = Q -> S
|
|
706
|
+
axiom r4 = R -> S
|
|
707
|
+
axiom r5 = S -> T
|
|
708
|
+
axiom r6 = T -> U
|
|
709
|
+
axiom base = P
|
|
710
|
+
derive U from {r1, r2, r3, r4, r5, r6, base}
|
|
711
|
+
`;
|
|
712
|
+
const out = run(source);
|
|
713
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
714
|
+
(0, vitest_1.expect)(out.stdout).toContain('[derive]');
|
|
715
|
+
}, 10000);
|
|
716
|
+
(0, vitest_1.it)('modus tollens chain: 10 implications + negation at end', () => {
|
|
717
|
+
const axioms = [];
|
|
718
|
+
const names = [];
|
|
719
|
+
for (let i = 0; i < 10; i++) {
|
|
720
|
+
axioms.push(`axiom a${i} = M${i} -> M${i + 1}`);
|
|
721
|
+
names.push(`a${i}`);
|
|
722
|
+
}
|
|
723
|
+
const source = `
|
|
724
|
+
logic classical.propositional
|
|
725
|
+
${axioms.join('\n ')}
|
|
726
|
+
axiom neg = !M10
|
|
727
|
+
derive !M0 from {${names.join(', ')}, neg}
|
|
728
|
+
`;
|
|
729
|
+
const out = run(source);
|
|
730
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
731
|
+
(0, vitest_1.expect)(out.stdout).toContain('[derive]');
|
|
732
|
+
}, 15000);
|
|
733
|
+
});
|
|
734
|
+
// ============================================================
|
|
735
|
+
// SECTION 10: TAUTOLOGY & VALIDITY STRESS
|
|
736
|
+
// ============================================================
|
|
737
|
+
(0, vitest_1.describe)('Extreme: Tautology Verification', () => {
|
|
738
|
+
(0, vitest_1.it)('300-atom tautology: conjunction of (Pi | !Pi)', () => {
|
|
739
|
+
const parts = Array.from({ length: 300 }, (_, i) => `(T${i} | !T${i})`);
|
|
740
|
+
const formula = parts.join(' & ');
|
|
741
|
+
const source = `
|
|
742
|
+
logic classical.propositional
|
|
743
|
+
check valid ${formula}
|
|
744
|
+
`;
|
|
745
|
+
const out = run(source);
|
|
746
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
747
|
+
(0, vitest_1.expect)(stripAccents(out.stdout).toUpperCase()).toContain('VALIDA');
|
|
748
|
+
}, 15000);
|
|
749
|
+
(0, vitest_1.it)('excluded middle is valid: P | !P', () => {
|
|
750
|
+
const source = `
|
|
751
|
+
logic classical.propositional
|
|
752
|
+
check valid (P | !P)
|
|
753
|
+
`;
|
|
754
|
+
const out = run(source);
|
|
755
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
756
|
+
(0, vitest_1.expect)(stripAccents(out.stdout).toUpperCase()).toContain('VALIDA');
|
|
757
|
+
}, 5000);
|
|
758
|
+
(0, vitest_1.it)("implication tautology: ((P -> Q) -> P) -> P (Peirce's law)", () => {
|
|
759
|
+
const source = `
|
|
760
|
+
logic classical.propositional
|
|
761
|
+
check valid (((P -> Q) -> P) -> P)
|
|
762
|
+
`;
|
|
763
|
+
const out = run(source);
|
|
764
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
765
|
+
(0, vitest_1.expect)(stripAccents(out.stdout).toUpperCase()).toContain('VALIDA');
|
|
766
|
+
}, 5000);
|
|
767
|
+
(0, vitest_1.it)('De Morgan: !(P & Q) <-> (!P | !Q) is valid', () => {
|
|
768
|
+
const source = `
|
|
769
|
+
logic classical.propositional
|
|
770
|
+
check valid (!(P & Q) <-> (!P | !Q))
|
|
771
|
+
`;
|
|
772
|
+
const out = run(source);
|
|
773
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
774
|
+
(0, vitest_1.expect)(stripAccents(out.stdout).toUpperCase()).toContain('VALIDA');
|
|
775
|
+
}, 5000);
|
|
776
|
+
(0, vitest_1.it)('contraposition: (P -> Q) <-> (!Q -> !P) is valid', () => {
|
|
777
|
+
const source = `
|
|
778
|
+
logic classical.propositional
|
|
779
|
+
check valid ((P -> Q) <-> (!Q -> !P))
|
|
780
|
+
`;
|
|
781
|
+
const out = run(source);
|
|
782
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
783
|
+
(0, vitest_1.expect)(stripAccents(out.stdout).toUpperCase()).toContain('VALIDA');
|
|
784
|
+
}, 5000);
|
|
785
|
+
(0, vitest_1.it)('distribution: P & (Q | R) <-> (P & Q) | (P & R) is valid', () => {
|
|
786
|
+
const source = `
|
|
787
|
+
logic classical.propositional
|
|
788
|
+
check valid ((P & (Q | R)) <-> ((P & Q) | (P & R)))
|
|
789
|
+
`;
|
|
790
|
+
const out = run(source);
|
|
791
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
792
|
+
(0, vitest_1.expect)(stripAccents(out.stdout).toUpperCase()).toContain('VALIDA');
|
|
793
|
+
}, 5000);
|
|
794
|
+
});
|
|
795
|
+
// ============================================================
|
|
796
|
+
// SECTION 11: MIXED CONNECTIVE MAYHEM
|
|
797
|
+
// ============================================================
|
|
798
|
+
(0, vitest_1.describe)('Extreme: Mixed Connectives', () => {
|
|
799
|
+
(0, vitest_1.it)('100 atoms: AND + NAND + NOR alternating', () => {
|
|
800
|
+
const parts = [];
|
|
801
|
+
for (let i = 0; i < 99; i++) {
|
|
802
|
+
if (i % 3 === 0)
|
|
803
|
+
parts.push(`(M${i} nand M${i + 1})`);
|
|
804
|
+
else if (i % 3 === 1)
|
|
805
|
+
parts.push(`(M${i} nor M${i + 1})`);
|
|
806
|
+
else
|
|
807
|
+
parts.push(`(M${i} & M${i + 1})`);
|
|
808
|
+
}
|
|
809
|
+
const formula = parts.join(' & ');
|
|
810
|
+
const source = `
|
|
811
|
+
logic classical.propositional
|
|
812
|
+
check satisfiable ${formula}
|
|
813
|
+
`;
|
|
814
|
+
const out = run(source);
|
|
815
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
816
|
+
(0, vitest_1.expect)(out.stdout).toMatch(/SATISFACIBLE|INSATISFACIBLE/);
|
|
817
|
+
}, 15000);
|
|
818
|
+
(0, vitest_1.it)('50 atoms: XOR + BICONDITIONAL + IMPLIES web', () => {
|
|
819
|
+
const parts = [];
|
|
820
|
+
for (let i = 0; i < 49; i++) {
|
|
821
|
+
if (i % 3 === 0)
|
|
822
|
+
parts.push(`(W${i} xor W${i + 1})`);
|
|
823
|
+
else if (i % 3 === 1)
|
|
824
|
+
parts.push(`(W${i} <-> W${i + 1})`);
|
|
825
|
+
else
|
|
826
|
+
parts.push(`(W${i} -> W${i + 1})`);
|
|
827
|
+
}
|
|
828
|
+
const formula = parts.join(' & ');
|
|
829
|
+
const source = `
|
|
830
|
+
logic classical.propositional
|
|
831
|
+
check satisfiable ${formula}
|
|
832
|
+
`;
|
|
833
|
+
const out = run(source);
|
|
834
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
835
|
+
(0, vitest_1.expect)(out.stdout).toMatch(/SATISFACIBLE|INSATISFACIBLE/);
|
|
836
|
+
}, 15000);
|
|
837
|
+
});
|
|
838
|
+
// ============================================================
|
|
839
|
+
// SECTION 12: PREPROCESSING EFFECTIVENESS
|
|
840
|
+
// ============================================================
|
|
841
|
+
(0, vitest_1.describe)('Extreme: Preprocessing', () => {
|
|
842
|
+
(0, vitest_1.it)('massive subsumption: 200 clauses, half subsumed', () => {
|
|
843
|
+
const parts = [];
|
|
844
|
+
for (let i = 0; i < 100; i++) {
|
|
845
|
+
parts.push(`(A${i} | B${i})`);
|
|
846
|
+
parts.push(`(A${i} | B${i} | C${i})`);
|
|
847
|
+
parts.push(`(A${i} | B${i} | C${i} | D${i})`);
|
|
848
|
+
}
|
|
849
|
+
parts.push('A0');
|
|
850
|
+
const formula = parts.join(' & ');
|
|
851
|
+
const source = `
|
|
852
|
+
logic classical.propositional
|
|
853
|
+
check satisfiable ${formula}
|
|
854
|
+
`;
|
|
855
|
+
const out = run(source);
|
|
856
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
857
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
858
|
+
}, 15000);
|
|
859
|
+
(0, vitest_1.it)('unit propagation cascade: A0 -> A1 -> ... -> A199, given A0', () => {
|
|
860
|
+
const parts = ['A0'];
|
|
861
|
+
for (let i = 0; i < 199; i++) {
|
|
862
|
+
parts.push(`(A${i} -> A${i + 1})`);
|
|
863
|
+
}
|
|
864
|
+
const formula = parts.join(' & ');
|
|
865
|
+
const source = `
|
|
866
|
+
logic classical.propositional
|
|
867
|
+
check satisfiable ${formula}
|
|
868
|
+
`;
|
|
869
|
+
const out = run(source);
|
|
870
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
871
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
872
|
+
}, 10000);
|
|
873
|
+
(0, vitest_1.it)('pure literal: variables appearing only positively', () => {
|
|
874
|
+
// All variables appear only positively → trivially SAT
|
|
875
|
+
const parts = [];
|
|
876
|
+
for (let i = 0; i < 100; i++) {
|
|
877
|
+
parts.push(`(P${i} | P${(i + 1) % 100} | P${(i + 2) % 100})`);
|
|
878
|
+
}
|
|
879
|
+
const formula = parts.join(' & ');
|
|
880
|
+
const source = `
|
|
881
|
+
logic classical.propositional
|
|
882
|
+
check satisfiable ${formula}
|
|
883
|
+
`;
|
|
884
|
+
const out = run(source);
|
|
885
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
886
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
887
|
+
}, 10000);
|
|
888
|
+
(0, vitest_1.it)('100 identical clauses — deduplication', () => {
|
|
889
|
+
const repeated = Array.from({ length: 100 }, () => '(X | Y | Z)').join(' & ');
|
|
890
|
+
const source = `
|
|
891
|
+
logic classical.propositional
|
|
892
|
+
check satisfiable ${repeated}
|
|
893
|
+
`;
|
|
894
|
+
const out = run(source);
|
|
895
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
896
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
897
|
+
}, 5000);
|
|
898
|
+
});
|
|
899
|
+
// ============================================================
|
|
900
|
+
// SECTION 13: EDGE CASES & DEGENERATE INPUTS
|
|
901
|
+
// ============================================================
|
|
902
|
+
(0, vitest_1.describe)('Extreme: Edge Cases', () => {
|
|
903
|
+
(0, vitest_1.it)('single atom P — SAT', () => {
|
|
904
|
+
const source = `logic classical.propositional\ncheck satisfiable P`;
|
|
905
|
+
const out = run(source);
|
|
906
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
907
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
908
|
+
}, 5000);
|
|
909
|
+
(0, vitest_1.it)('single negation !P — SAT', () => {
|
|
910
|
+
const source = `logic classical.propositional\ncheck satisfiable !P`;
|
|
911
|
+
const out = run(source);
|
|
912
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
913
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
914
|
+
}, 5000);
|
|
915
|
+
(0, vitest_1.it)('P & !P — UNSAT', () => {
|
|
916
|
+
const source = `logic classical.propositional\ncheck satisfiable (P & !P)`;
|
|
917
|
+
const out = run(source);
|
|
918
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
919
|
+
(0, vitest_1.expect)(out.stdout).toContain('INSATISFACIBLE');
|
|
920
|
+
}, 5000);
|
|
921
|
+
(0, vitest_1.it)('P | !P — SAT (tautology is satisfiable)', () => {
|
|
922
|
+
const source = `logic classical.propositional\ncheck satisfiable (P | !P)`;
|
|
923
|
+
const out = run(source);
|
|
924
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
925
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
926
|
+
}, 5000);
|
|
927
|
+
(0, vitest_1.it)('deeply nested NOT: !!!!...P (50 levels) — SAT', () => {
|
|
928
|
+
let formula = 'P';
|
|
929
|
+
for (let i = 0; i < 50; i++) {
|
|
930
|
+
formula = `!${formula}`;
|
|
931
|
+
}
|
|
932
|
+
const source = `logic classical.propositional\ncheck satisfiable ${formula}`;
|
|
933
|
+
const out = run(source);
|
|
934
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
935
|
+
// 50 negations = P (even number), so SAT
|
|
936
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
937
|
+
}, 5000);
|
|
938
|
+
(0, vitest_1.it)('deeply nested NOT: !!!!...P (51 levels) — SAT (it is !P, which is SAT)', () => {
|
|
939
|
+
let formula = 'P';
|
|
940
|
+
for (let i = 0; i < 51; i++) {
|
|
941
|
+
formula = `!${formula}`;
|
|
942
|
+
}
|
|
943
|
+
const source = `logic classical.propositional\ncheck satisfiable ${formula}`;
|
|
944
|
+
const out = run(source);
|
|
945
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
946
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
947
|
+
}, 5000);
|
|
948
|
+
(0, vitest_1.it)('long atom names: 100 chars each', () => {
|
|
949
|
+
const longName = 'A'.repeat(100);
|
|
950
|
+
const source = `logic classical.propositional\ncheck satisfiable (${longName} | !${longName})`;
|
|
951
|
+
const out = run(source);
|
|
952
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
953
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
954
|
+
}, 5000);
|
|
955
|
+
});
|
|
956
|
+
// ============================================================
|
|
957
|
+
// SECTION 14: PERFORMANCE BENCHMARKS
|
|
958
|
+
// ============================================================
|
|
959
|
+
(0, vitest_1.describe)('Extreme: Performance Bounds', () => {
|
|
960
|
+
(0, vitest_1.it)('200 vars random 3-SAT solves in < 10 seconds', () => {
|
|
961
|
+
const rng = mulberry32(2024);
|
|
962
|
+
const clauses = [];
|
|
963
|
+
for (let i = 0; i < 854; i++) {
|
|
964
|
+
const lits = [];
|
|
965
|
+
const used = new Set();
|
|
966
|
+
while (lits.length < 3) {
|
|
967
|
+
const v = Math.floor(rng() * 200) + 1;
|
|
968
|
+
if (used.has(v))
|
|
969
|
+
continue;
|
|
970
|
+
used.add(v);
|
|
971
|
+
lits.push(rng() < 0.5 ? `!P${v}` : `P${v}`);
|
|
972
|
+
}
|
|
973
|
+
clauses.push(`(${lits.join(' | ')})`);
|
|
974
|
+
}
|
|
975
|
+
const formula = clauses.join(' & ');
|
|
976
|
+
const start = Date.now();
|
|
977
|
+
const source = `
|
|
978
|
+
logic classical.propositional
|
|
979
|
+
check satisfiable ${formula}
|
|
980
|
+
`;
|
|
981
|
+
const out = run(source);
|
|
982
|
+
const elapsed = Date.now() - start;
|
|
983
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
984
|
+
(0, vitest_1.expect)(elapsed).toBeLessThan(10000);
|
|
985
|
+
}, 15000);
|
|
986
|
+
(0, vitest_1.it)('500-atom implication chain solves in < 2 seconds', () => {
|
|
987
|
+
const parts = [];
|
|
988
|
+
for (let i = 0; i < 499; i++) {
|
|
989
|
+
parts.push(`(I${i} -> I${i + 1})`);
|
|
990
|
+
}
|
|
991
|
+
parts.push('I0');
|
|
992
|
+
const formula = parts.join(' & ');
|
|
993
|
+
const start = Date.now();
|
|
994
|
+
const source = `
|
|
995
|
+
logic classical.propositional
|
|
996
|
+
check satisfiable ${formula}
|
|
997
|
+
`;
|
|
998
|
+
const out = run(source);
|
|
999
|
+
const elapsed = Date.now() - start;
|
|
1000
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
1001
|
+
(0, vitest_1.expect)(elapsed).toBeLessThan(2000);
|
|
1002
|
+
(0, vitest_1.expect)(out.stdout).toContain('SATISFACIBLE');
|
|
1003
|
+
}, 5000);
|
|
1004
|
+
});
|
|
1005
|
+
//# sourceMappingURL=stress-extreme.test.js.map
|