gdp-wired 0.18.0 → 0.19.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.
@@ -1,6 +1,6 @@
1
1
  import { add, k, refuteFast, scale, solve, sub, v } from "../core/solver.js";
2
2
  import { checkRefutation } from "../core/check.js";
3
- import { crossCyclic, cyclicMachine, cyclicOn, machineNodes, proveCyclic } from "../core/cyclic.js";
3
+ import { allowNode, certCyclic, certMs, certOn, certSearch, closingInsts, crossCyclic, cyclicOn, cycLog, hasQuantified, machineNodes, proveCyclic, qflagNodes, reqTS, searchedStepNodes, skMachine, timedKind, withWitness, translatedProof, uncoveredWhy } from "../core/cyclic.js";
4
4
  import { assumed, atomOf, boundOf, canon, canonFlip, columnTerm, decided, factorsOf, isCell, isMonomial, stepZone, check, checkLaws, checkStepLaws, historyMachine, leafConstraints, leafConstraintsReusing, reusing, linear, livenessHelpful, livenessParts, obligations, plainKey, progressObligations, stepLawObligations, trueC, truth, unreachable, witnessesOf, withProducts } from "./kernel.js";
5
5
  // The atoms the path leaves open, in evaluation order: deciding any of them makes progress.
6
6
  function openE(e, path, out) {
@@ -1362,15 +1362,54 @@ function proveLawsAsGiven(m, laws) {
1362
1362
  focus: [...(law.forall ? [`${law.forall}#`] : []), ...(law.keys ?? [])],
1363
1363
  });
1364
1364
  });
1365
- const t0 = performance.now(), out = proveThinned(m, laws, { ...instances }), usualMs = performance.now() - t0;
1365
+ // (GDP_CERT=cyclic: a covered machine's certificate is its cyclic proof, core/cyclic.ts's certCyclic; the usual trees
1366
+ // are its input, not checked again)
1367
+ // (what no instance covers, read only where a cyclic mode is on: the usual route's own proofs, inferLaws' trial ones
1368
+ // among them, do nothing more than before)
1369
+ // A machine with a history: its laws are its plain machine's (historyMachine; the record goals leaf goals beside them).
1370
+ const modes = cyclicOn() || certOn(), hist = modes && m.history ? historyMachine(m) : undefined, mc = hist ? hist.machine : m;
1371
+ const why = modes ? uncoveredWhy(mc, laws) : undefined;
1372
+ // (flags that hold at every key: searched, where GDP_CERT_SEARCH=1)
1373
+ const q = why === 'a flag at every key' && certOn() && certSearch(), cert = certOn() && (!why || q);
1374
+ usualCheck.on = !cert || q;
1375
+ const t0 = performance.now(), out = (() => { try {
1376
+ return proveThinned(m, laws, { ...instances });
1377
+ }
1378
+ finally {
1379
+ usualCheck.on = true;
1380
+ } })(), usualMs = performance.now() - t0;
1381
+ if (out.proof)
1382
+ usualProof.last = { m, laws, proof: out.proof };
1383
+ const inst = out.proof?.instances ?? instances;
1384
+ const searched = () => { const { facts, specs } = q ? qflagNodes(mc, laws, inst) : machineNodes(mc, laws, inst); return proveCyclic(facts, specs); };
1385
+ const translated = !q && out.proof ? ((st) => translatedProof(() => JSON.stringify(['machine', mc, laws, inst]), () => timedKind('instance', 0, () => machineNodes(mc, laws, inst, out.proof, st)), st)) : undefined;
1366
1386
  if (cyclicOn()) {
1367
- if (cyclicMachine(m, laws))
1368
- crossCyclic('machine', m.name, out.proven && out.checked, () => { const { facts, specs } = machineNodes(m, laws, instances); return proveCyclic(facts, specs); }, usualMs);
1387
+ if (!why)
1388
+ crossCyclic('machine', m.name, out.proven && out.checked, searched, usualMs, translated);
1369
1389
  else
1370
- console.error(`cyclic: ${JSON.stringify({ kind: 'machine', name: m.name, usual: out.proven && out.checked, uncovered: true })}`);
1390
+ cycLog({ kind: 'machine', name: m.name, usual: out.proven && out.checked, uncovered: true, why });
1391
+ }
1392
+ if (cert && out.proven && out.proof) {
1393
+ const until = performance.now() + certMs(), c = q ? withDeadline(until, () => certCyclic('machine', m.name, undefined, searched, usualMs)) : certCyclic('machine', m.name, translated, searched, usualMs);
1394
+ if (q && !c.checked)
1395
+ uncovered('machine', m.name, `${why}: no cyclic proof found${performance.now() > until ? ` within ${certMs()} ms` : ''}`);
1396
+ else {
1397
+ // (a history's record goals checked as they are: leaf goals)
1398
+ const records = !hist || hist.goals.every(g => out.proof.trees[g.name] !== undefined && check(g, out.proof.trees[g.name]));
1399
+ out.checked = c.checked && records;
1400
+ Object.assign(out.proof, { cyclic: c.proof });
1401
+ }
1371
1402
  }
1403
+ else if (certOn() && why && out.proven)
1404
+ cycLog({ kind: 'machine', name: m.name, cert: true, uncovered: true, why });
1372
1405
  return out;
1373
1406
  }
1407
+ // A proof of a kind no cyclic instance covers, counted (`cyclic: {..., uncovered: true}`).
1408
+ const uncovered = (kind, name, why) => cycLog({ kind, name, uncovered: true, why });
1409
+ // Whether the usual proof's trees are checked (off while GDP_CERT=cyclic makes the certificate a cyclic proof).
1410
+ export const usualCheck = { on: true };
1411
+ // The last machine proof made (core/dsl.ts's recurrences read their machine's, to translate it: core/cyclic.ts).
1412
+ export const usualProof = {};
1374
1413
  // Each law with its instances thinned (`triggered`) where that proves it, else with all of them.
1375
1414
  function proveThinned(m, laws, instances) {
1376
1415
  const trees = {}, fulls = { ...instances };
@@ -1416,7 +1455,7 @@ function proveThinned(m, laws, instances) {
1416
1455
  leaves += countLeaves(out.tree);
1417
1456
  }
1418
1457
  const proof = { instances, trees };
1419
- return { proven: true, nodes, leaves, checked: checkLaws(m, laws, proof), proof };
1458
+ return { proven: true, nodes, leaves, checked: !usualCheck.on || checkLaws(m, laws, proof), proof };
1420
1459
  }
1421
1460
  // Every goal of the laws with these instances.
1422
1461
  function proveWith(m, laws, instances) {
@@ -1431,7 +1470,7 @@ function proveWith(m, laws, instances) {
1431
1470
  leaves += countLeaves(out.tree);
1432
1471
  }
1433
1472
  const proof = { instances, trees };
1434
- return { proven: true, nodes, leaves, checked: checkLaws(m, laws, proof), proof };
1473
+ return { proven: true, nodes, leaves, checked: !usualCheck.on || checkLaws(m, laws, proof), proof };
1435
1474
  }
1436
1475
  export function proveStepLaws(m, given, stepLaws) {
1437
1476
  const base = proveLaws(m, given);
@@ -1451,6 +1490,7 @@ export function proveStepLaws(m, given, stepLaws) {
1451
1490
  function proveStepLawsAsGiven(m, laws, stepLaws, base) {
1452
1491
  if (!base.proof)
1453
1492
  return { proven: false, nodes: base.nodes, leaves: base.leaves, checked: false };
1493
+ const t0 = performance.now();
1454
1494
  const plain = m.history ? historyMachine(m).machine : m;
1455
1495
  // Each step law its own instances, from its own goal: the keys the step and the laws read, and its own (a k-step
1456
1496
  // law's later frames read keys no other step law has); where positions shift or a law is about several keys, the
@@ -1505,12 +1545,44 @@ function proveStepLawsAsGiven(m, laws, stepLaws, base) {
1505
1545
  leaves += countLeaves(out.tree);
1506
1546
  }
1507
1547
  const proof = { laws: base.proof, instances, ...(Object.keys(perStep).length ? { perStep } : {}), trees };
1508
- return { proven: true, nodes, leaves, checked: checkStepLaws(m, laws, stepLaws, proof), proof };
1548
+ const out = { proven: true, nodes, leaves, checked: checkStepLaws(m, laws, stepLaws, proof), proof };
1549
+ // Step laws of a machine the cyclic instances cover (one step, or several over no map) are translated with the laws
1550
+ // (core/cyclic.ts); the rest are counted as no instance's.
1551
+ if (!cyclicOn() && !certOn())
1552
+ return out;
1553
+ // (a machine with a history: its plain machine's; flags at every key and k-step laws over a map searched, where
1554
+ // GDP_CERT_SEARCH=1)
1555
+ const why = uncoveredWhy(plain, laws), one = stepLaws.filter(sl => (sl.steps ?? 1) === 1 || (!Object.keys(plain.maps ?? {}).length && !plain.inputMaps?.length));
1556
+ if (!why && one.length && out.checked) {
1557
+ const steps = one.map(sl => { const inst = perStep[sl.name] ?? instances, goal = stepLawObligations(m, laws, inst, sl)[0]; return { sl, inst, goal, tree: trees[goal.name] }; });
1558
+ const translated = (st) => translatedProof(() => JSON.stringify(['steps', plain, laws, base.proof.instances, steps.map(x => [x.sl, x.inst])]), reused => timedKind('instance', 0, () => machineNodes(plain, laws, base.proof.instances, { trees: base.proof.trees, steps, lawsMade: reused }, st)), st, () => JSON.stringify(['machine', plain, laws, base.proof.instances]));
1559
+ const usualMs = performance.now() - t0;
1560
+ if (cyclicOn())
1561
+ crossCyclic('step law', m.name, true, undefined, usualMs, translated);
1562
+ if (certOn())
1563
+ out.checked = certCyclic('step law', m.name, translated, undefined, usualMs).checked;
1564
+ }
1565
+ const rest = stepLaws.filter(sl => why || !one.includes(sl));
1566
+ if (certOn() && certSearch() && out.checked && rest.length && (!why || why === 'a flag at every key')) {
1567
+ // The rest searched: the laws' nodes (searched), each step law's node (core/cyclic.ts's stepLawNodes).
1568
+ const searchedSteps = () => {
1569
+ const b = why ? qflagNodes(plain, laws, base.proof.instances) : machineNodes(plain, laws, base.proof.instances);
1570
+ return proveCyclic(b.facts, [...b.specs, ...searchedStepNodes(plain, laws, rest.map(sl => ({ law: sl, instances: perStep[sl.name] ?? instances })), b.facts, b.specs)]);
1571
+ };
1572
+ const until = performance.now() + certMs(), c = withDeadline(until, () => certCyclic('step law', m.name, undefined, searchedSteps, performance.now() - t0));
1573
+ const none = `no cyclic proof found${performance.now() > until ? ` within ${certMs()} ms` : ''}`;
1574
+ for (const sl of c.checked ? [] : rest)
1575
+ uncovered((sl.steps ?? 1) > 1 ? 'k-step law' : 'step law', m.name, `${why ?? `${sl.steps} steps over a map`}: ${none}`);
1576
+ }
1577
+ else if (cyclicOn() || certOn())
1578
+ for (const sl of rest)
1579
+ uncovered((sl.steps ?? 1) > 1 ? 'k-step law' : 'step law', m.name, why ?? `${sl.steps} steps over a map`);
1580
+ return out;
1509
1581
  }
1510
1582
  // Progress (kernel.ts's progressObligations): the laws proven first, then each goal, the every-key laws assumed at every
1511
1583
  // key the goals read a map at.
1512
1584
  export function proveProgress(m, laws, p) {
1513
- const base = proveLaws(m, laws);
1585
+ const t0 = performance.now(), base = proveLaws(m, laws);
1514
1586
  if (!base.proven || !base.checked)
1515
1587
  return { proven: false, nodes: base.nodes, leaves: base.leaves, ...(base.failed ? { failed: base.failed } : {}), checked: false };
1516
1588
  const ls = base.laws ?? laws;
@@ -1525,12 +1597,42 @@ export function proveProgress(m, laws, p) {
1525
1597
  nodes += out.nodes;
1526
1598
  leaves += countLeaves(out.tree);
1527
1599
  }
1528
- return { proven: true, nodes, leaves, checked: progressObligations(m, ls, instances, p).every(g => check(g, trees[g.name])), instances, trees };
1600
+ const checked = progressObligations(m, ls, instances, p).every(g => check(g, trees[g.name]));
1601
+ // (GDP_CERT=cyclic with GDP_CERT_SEARCH=1: a request allowed whose claim is that alone, over a machine without a history
1602
+ // or carried maps, gets core/cyclic.ts's allowNode after the laws' nodes, BridgeRules.lean's cycAOk: from every
1603
+ // reachable state, every request meeting the region, its terms and the witnesses withWitness finds is allowed)
1604
+ const alone = JSON.stringify(p.then) === JSON.stringify(trueC) && !m.history && !m.inputMaps?.length && m.assume !== undefined;
1605
+ if (certOn() && certSearch() && alone && checked && base.proof) {
1606
+ const until = performance.now() + certMs(), lp = base.proof, q = hasQuantified(m);
1607
+ const allowed = () => {
1608
+ const b = q ? qflagNodes(m, ls, lp.instances) : machineNodes(m, ls, lp.instances, lp);
1609
+ if (b.why || (b.specs[0]?.rank.length ?? 2) < 2)
1610
+ return { proven: false, checked: false, node: m.name, goal: 'allowed', stuck: b.why ?? 'laws ranked by time alone' };
1611
+ let last = { proven: false, checked: false, node: m.name, goal: 'allowed', stuck: 'no witness' };
1612
+ const found = withWitness(m, p.request, wit => {
1613
+ if (performance.now() > until)
1614
+ return undefined;
1615
+ const w = { op: 'and', xs: [p.when, reqTS(Object.entries(p.request)), reqTS(wit)] };
1616
+ const spec = allowNode(skMachine(m), ls, instances, w, b.facts, b.specs, `${m.name}: allowed`, q ? closingInsts(m, b.facts, [instances, ...Object.values(lp.instances)], [{ op: 'var', name: 't$' }], ls) : []);
1617
+ last = proveCyclic(b.facts, [...b.specs, spec]);
1618
+ return last.proven && last.checked ? last : undefined;
1619
+ });
1620
+ return found?.out ?? last;
1621
+ };
1622
+ const c = withDeadline(until, () => certCyclic('progress', m.name, undefined, allowed, performance.now() - t0));
1623
+ if (!c.checked)
1624
+ uncovered('progress', m.name, `a request allowed: no cyclic proof found${performance.now() > until ? ` within ${certMs()} ms` : ''}`);
1625
+ }
1626
+ else if (cyclicOn() || certOn())
1627
+ uncovered('progress', m.name, alone ? 'a request allowed' : 'a request allowed and a claim after it');
1628
+ return { proven: true, nodes, leaves, checked, instances, trees };
1529
1629
  }
1530
1630
  // Liveness (kernel.ts's livenessParts): its step laws, proven together. The claim needs no more (a run takes the
1531
1631
  // request, so it is allowed); but a request never allowed would leave the claim about no run, so where a helpful request
1532
1632
  // names every input a client sends and carries no maps, it is proven allowed in its region too.
1533
1633
  export function proveLiveness(m, laws, l) {
1634
+ if (cyclicOn() || certOn())
1635
+ uncovered('liveness', m.name, 'a claim about runs that never end');
1534
1636
  const { stay, cover, helps } = livenessParts(m, l);
1535
1637
  const a = proveStepLaws(m, laws, [stay, cover, ...helps]);
1536
1638
  if (!a.proven || !a.checked)
@@ -101,6 +101,39 @@ export declare function smachineToLean(id: string, given: Machine, laws: Law[],
101
101
  };
102
102
  noFacts?: boolean;
103
103
  }): string;
104
+ export declare const cyclicCerts: () => boolean;
105
+ export declare const certReport: {
106
+ cyclic: string[];
107
+ usual: {
108
+ id: string;
109
+ why: string;
110
+ }[];
111
+ translatedSteps: string[];
112
+ };
113
+ export declare function cycMachineToLean(id: string, given: Machine, laws: Law[], opts?: {
114
+ stepLaws?: StepLaw[];
115
+ liveness?: Liveness[];
116
+ simp?: string[];
117
+ free?: string[];
118
+ ghosts?: string[];
119
+ after?: (ix: (name: string) => number) => string;
120
+ loop?: {
121
+ loop: Loop;
122
+ };
123
+ noFacts?: boolean;
124
+ refined?: {
125
+ impl: Machine;
126
+ spec: Machine;
127
+ wit: Record<string, E>;
128
+ stutter: C;
129
+ specPre: number;
130
+ step: StepLaw;
131
+ };
132
+ }): {
133
+ text: string;
134
+ } | {
135
+ why: string;
136
+ };
104
137
  type Uses = Record<string, {
105
138
  lean?: string;
106
139
  recur?: Recurrence;
@@ -168,6 +201,7 @@ export type LeanItem = {
168
201
  export declare function toLean(items: LeanItem[], opts?: {
169
202
  title?: string;
170
203
  native?: boolean;
204
+ cyclic?: boolean;
171
205
  }): string;
172
206
  export declare function leanProject(file: string, opts?: {
173
207
  name?: string;