gdp-wired 0.17.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.
- package/README.md +10 -3
- package/dist/core/cycles.d.ts +73 -0
- package/dist/core/cycles.js +899 -0
- package/dist/core/cyclic.d.ts +106 -6
- package/dist/core/cyclic.js +1138 -52
- package/dist/core/data.d.ts +258 -0
- package/dist/core/data.js +1858 -0
- package/dist/core/dsl.d.ts +7 -1
- package/dist/core/dsl.js +43 -10
- package/dist/core/translate.d.ts +30 -0
- package/dist/core/translate.js +572 -0
- package/dist/kernel/prove.d.ts +18 -0
- package/dist/kernel/prove.js +272 -15
- package/dist/lean-kernel/emit.d.ts +95 -1
- package/dist/lean-kernel/emit.js +615 -83
- package/dist/lean-kernel/library.js +4 -1
- package/package.json +10 -2
package/dist/core/dsl.d.ts
CHANGED
|
@@ -781,6 +781,7 @@ export declare class LoopRule<P extends Obj = {}, I extends Obj = {}, S extends
|
|
|
781
781
|
law(name: string, f: (env: P & S) => Cond): Law;
|
|
782
782
|
private env;
|
|
783
783
|
get loop(): Loop;
|
|
784
|
+
get hasRank(): boolean;
|
|
784
785
|
get rankTerms(): E[];
|
|
785
786
|
randomParams(rand: Rand, bound: number): Record<string, number>;
|
|
786
787
|
randomInput(rand: Rand, bound: number): Record<string, number>;
|
|
@@ -810,10 +811,13 @@ export type Found = {
|
|
|
810
811
|
lemmas?: string[];
|
|
811
812
|
between?: string[];
|
|
812
813
|
}>;
|
|
814
|
+
facts?: string[];
|
|
815
|
+
rank?: string;
|
|
813
816
|
};
|
|
814
817
|
export type ProveOptions = {
|
|
815
818
|
search?: boolean | {
|
|
816
819
|
ms?: number;
|
|
820
|
+
cycles?: boolean;
|
|
817
821
|
};
|
|
818
822
|
};
|
|
819
823
|
export declare class Unproven extends Error {
|
|
@@ -834,7 +838,9 @@ export declare function crossCheckDecision(d: Decision, opts?: {
|
|
|
834
838
|
checked: number;
|
|
835
839
|
failure?: string;
|
|
836
840
|
};
|
|
837
|
-
export declare const proveLoop: (l: LoopRule<Obj, Obj, Obj>, laws: Law[]
|
|
841
|
+
export declare const proveLoop: (l: LoopRule<Obj, Obj, Obj>, laws: Law[], opts?: {
|
|
842
|
+
ms?: number;
|
|
843
|
+
}) => Verdict;
|
|
838
844
|
export type TreeValue<I> = {
|
|
839
845
|
leaf: I;
|
|
840
846
|
} | {
|
package/dist/core/dsl.js
CHANGED
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
import { carriedView, compileFunction, evalC, evalE, interpret, loadJs, numbersOf, pairedArgs } from "./machine.js";
|
|
19
19
|
import { allowed, keysOf, requestEnv, watch } from "./watch.js";
|
|
20
20
|
import { check, foldObligations, loopObligations } from "../kernel/kernel.js";
|
|
21
|
-
import { factsFor, grow, proveLaws, proveLiveness, proveStepLaws, withDeadline } from "../kernel/prove.js";
|
|
22
|
-
import { crossCyclic, cyclicOn, foldNodes, proveCyclic, quietly, recurNodes } from "./cyclic.js";
|
|
21
|
+
import { factsFor, grow, proveLaws, proveLiveness, proveStepLaws, usualProof, withDeadline } from "../kernel/prove.js";
|
|
22
|
+
import { certCyclic, certOn, crossCyclic, cyclicOn, cycLog, foldNodes, proveCyclic, quietly, recurNodes, translatedProof } from "./cyclic.js";
|
|
23
23
|
import { discover } from "./discover.js";
|
|
24
24
|
import { inferLaws } from "./infer.js";
|
|
25
|
+
import { cycleLemmas, findRank } from "./cycles.js";
|
|
25
26
|
// --- terms and conditions -------------------------------------------------------------------------------------------
|
|
26
27
|
const naturalConst = (v) => {
|
|
27
28
|
if (!Number.isSafeInteger(v) || v < 0)
|
|
@@ -1409,6 +1410,10 @@ export const recur = (name, def, lemmas = {}, between = {}) => {
|
|
|
1409
1410
|
// The lemmas: x counting up from 0 and fx its value, each lemma a law of that machine.
|
|
1410
1411
|
let verdict = { proven: true, checked: true };
|
|
1411
1412
|
const proofs = {};
|
|
1413
|
+
// The usual proofs, to translate (core/cyclic.ts's recurNodes): the lemmas' machine's, the laws between's.
|
|
1414
|
+
let lemmaProof;
|
|
1415
|
+
const translatedRecur = (u) => (u.lemmas || !stated.length)
|
|
1416
|
+
? st => translatedProof(() => JSON.stringify(['recurrence', recurCase(u.between ? pairs : [])]), () => recurNodes(recurCase(u.between ? pairs : []), u, st), st) : undefined;
|
|
1412
1417
|
if (stated.length) {
|
|
1413
1418
|
// A start that reads a function is a param given as that start by a fact (a start reads the params alone).
|
|
1414
1419
|
const zeroReads = JSON.stringify(zero).includes('"op":"get"');
|
|
@@ -1420,9 +1425,13 @@ export const recur = (name, def, lemmas = {}, between = {}) => {
|
|
|
1420
1425
|
const laws = Object.entries(lemmas).map(([n, f]) => r.law(n, (env) => f(env.x, env.fx, envAt(args.map(a => env[a])))));
|
|
1421
1426
|
// (Its machine's proof timed alone: the recurrence is compared below as its own instance.)
|
|
1422
1427
|
const t0 = performance.now();
|
|
1428
|
+
usualProof.last = undefined;
|
|
1423
1429
|
verdict = quietly(() => proveRule(r, laws, { search: false }));
|
|
1430
|
+
lemmaProof = usualProof.last;
|
|
1424
1431
|
if (cyclicOn())
|
|
1425
|
-
crossCyclic('recurrence', name, verdict.proven && verdict.checked, () => { const { facts, specs } = recurNodes(recurCase([])); return proveCyclic(facts, specs); }, performance.now() - t0);
|
|
1432
|
+
crossCyclic('recurrence', name, verdict.proven && verdict.checked, () => { const { facts, specs } = recurNodes(recurCase([])); return proveCyclic(facts, specs); }, performance.now() - t0, translatedRecur({ lemmas: lemmaProof }));
|
|
1433
|
+
if (certOn() && verdict.proven && verdict.checked)
|
|
1434
|
+
verdict = { ...verdict, checked: certCyclic('recurrence', name, translatedRecur({ lemmas: lemmaProof }), () => { const { facts, specs } = recurNodes(recurCase([])); return proveCyclic(facts, specs); }, performance.now() - t0).checked };
|
|
1426
1435
|
failed('lemmas', verdict);
|
|
1427
1436
|
proofs.lemmas = { machine: r.machine, laws };
|
|
1428
1437
|
}
|
|
@@ -1459,9 +1468,12 @@ export const recur = (name, def, lemmas = {}, between = {}) => {
|
|
|
1459
1468
|
.step((env) => ({ y: env.y.plus(1), fy: def.next(env.y, env.fy, envAt(at(env))) }));
|
|
1460
1469
|
const laws = [...Object.entries(lemmas).map(([n, l]) => r.law(`${n} at y`, (env) => l(env.y, env.fy, envAt(at(env))))),
|
|
1461
1470
|
...Object.entries(between).map(([n, l]) => r.law(n, (env) => l(env.x, env.fx, env.y, env.fy, envAt(at(env)))))];
|
|
1462
|
-
|
|
1471
|
+
usualProof.last = undefined;
|
|
1472
|
+
const t0 = performance.now(), v = quietly(() => proveRule(r, laws, { search: false })), usualMs = performance.now() - t0, betweenProof = usualProof.last;
|
|
1463
1473
|
if (cyclicOn())
|
|
1464
|
-
crossCyclic('recurrence, between', name, v.proven && v.checked, () => { const { facts, specs } = recurNodes(recurCase(pairs)); return proveCyclic(facts, specs); }, usualMs);
|
|
1474
|
+
crossCyclic('recurrence, between', name, v.proven && v.checked, () => { const { facts, specs } = recurNodes(recurCase(pairs)); return proveCyclic(facts, specs); }, usualMs, betweenProof && translatedRecur({ lemmas: lemmaProof, between: betweenProof }));
|
|
1475
|
+
if (certOn() && v.proven && v.checked)
|
|
1476
|
+
v.checked = certCyclic('recurrence, between', name, betweenProof && translatedRecur({ lemmas: lemmaProof, between: betweenProof }), () => { const { facts, specs } = recurNodes(recurCase(pairs)); return proveCyclic(facts, specs); }, usualMs).checked;
|
|
1465
1477
|
failed('laws between two points', v);
|
|
1466
1478
|
proofs.between = { machine: r.machine, laws };
|
|
1467
1479
|
verdict = { proven: true, checked: verdict.checked && v.checked };
|
|
@@ -2483,6 +2495,7 @@ export class LoopRule {
|
|
|
2483
2495
|
...(assume.length ? { assume: assume.length === 1 ? assume[0] : { op: 'and', xs: assume } } : {}),
|
|
2484
2496
|
};
|
|
2485
2497
|
}
|
|
2498
|
+
get hasRank() { return !!this.spec.rank; }
|
|
2486
2499
|
get rankTerms() {
|
|
2487
2500
|
if (!this.spec.rank)
|
|
2488
2501
|
throw new Error(`${this.spec.name}: no rank`);
|
|
@@ -2502,7 +2515,7 @@ export class Unproven extends Error {
|
|
|
2502
2515
|
this.verdict = verdict;
|
|
2503
2516
|
}
|
|
2504
2517
|
}
|
|
2505
|
-
const goalsVerdict = (goals) => {
|
|
2518
|
+
const goalsVerdict = (goals, checkIt = true) => {
|
|
2506
2519
|
const trees = {};
|
|
2507
2520
|
for (const g of goals) {
|
|
2508
2521
|
const out = grow(g);
|
|
@@ -2510,7 +2523,7 @@ const goalsVerdict = (goals) => {
|
|
|
2510
2523
|
return { proven: false, checked: false, goal: g.name, stuck: out.stuck, ...(out.witness ? { witness: out.witness } : {}), ...(out.why ? { why: out.why } : {}) };
|
|
2511
2524
|
trees[g.name] = out.tree;
|
|
2512
2525
|
}
|
|
2513
|
-
return { proven: true, checked: goals.every(g => check(g, trees[g.name])), trees };
|
|
2526
|
+
return { proven: true, checked: !checkIt || goals.every(g => check(g, trees[g.name])), trees };
|
|
2514
2527
|
};
|
|
2515
2528
|
// The kinds' laws first, those the caller didn't pass already (by name).
|
|
2516
2529
|
const withKinds = (r, laws) => [...r.kindLaws().filter(k => !laws.some(l => l.name === k.name)), ...laws];
|
|
@@ -2624,6 +2637,13 @@ function searched(r, laws, stepLaws, v, opts) {
|
|
|
2624
2637
|
if (Object.keys(d.found).length)
|
|
2625
2638
|
(rule = d.rule, lemmas = d.found);
|
|
2626
2639
|
}
|
|
2640
|
+
// Functions known by their facts alone (not a recurrence): lemmas about them, fitted to their values and proven from
|
|
2641
|
+
// the facts as cyclic claims, the laws proven with them as facts.
|
|
2642
|
+
if ((typeof opts.search !== 'object' || opts.search.cycles !== false) && fns.some(([, d]) => !recurOf(d)) && rule.machine.facts?.length && until - performance.now() > 500) {
|
|
2643
|
+
const c = withDeadline(until, () => cycleLemmas(rule.machine, withKinds(rule, laws), stepLaws, { ms: (until - performance.now()) / 2 }));
|
|
2644
|
+
if (c.proven && c.checked)
|
|
2645
|
+
return { proven: true, checked: true, found: { ...(lemmas ? { lemmas } : {}), facts: c.found.map(f => f.text) } };
|
|
2646
|
+
}
|
|
2627
2647
|
const ms = until - performance.now();
|
|
2628
2648
|
if (ms < 500)
|
|
2629
2649
|
return v;
|
|
@@ -2667,7 +2687,17 @@ export function crossCheckDecision(d, opts = {}) {
|
|
|
2667
2687
|
}
|
|
2668
2688
|
return { checked };
|
|
2669
2689
|
}
|
|
2670
|
-
|
|
2690
|
+
// With no rank stated, the rank is searched for from the loop's runs (core/cycles.ts's findRank), with the invariants it
|
|
2691
|
+
// needs (inferLaws), within `ms` (10 s); the verdict is the kernel's on the rank and the laws found, in `found`.
|
|
2692
|
+
export const proveLoop = (l, laws, opts = {}) => {
|
|
2693
|
+
if (cyclicOn() || certOn())
|
|
2694
|
+
cycLog({ kind: 'loop', name: l.loop.name, uncovered: true, why: 'a claim about runs that never end' });
|
|
2695
|
+
if (l.hasRank)
|
|
2696
|
+
return goalsVerdict(loopObligations(l.loop, laws, l.rankTerms));
|
|
2697
|
+
const out = findRank(l.loop, laws, opts);
|
|
2698
|
+
return { proven: out.proven, checked: out.checked, ...(out.trees ? { trees: out.trees } : {}), ...(out.goal ? { goal: out.goal, stuck: out.stuck } : {}), ...(out.witness ? { witness: out.witness } : {}), ...(out.why ? { why: out.why } : {}),
|
|
2699
|
+
...(out.found ? { found: { rank: out.found.rank, ...(out.laws?.length ? { laws: out.laws.map((law, i) => ({ law, text: out.found.laws[i] ?? law.name })) } : {}) } } : {}) };
|
|
2700
|
+
};
|
|
2671
2701
|
export class FoldRule {
|
|
2672
2702
|
spec;
|
|
2673
2703
|
constructor(spec) {
|
|
@@ -2783,9 +2813,12 @@ export class FoldRule {
|
|
|
2783
2813
|
export const fold = (name) => new FoldRule({ name, params: [], inputs: [], pre: [], assume: [] });
|
|
2784
2814
|
// A fold's laws proven over every tree (a rose fold's own laws, its children's lemmas, with them).
|
|
2785
2815
|
export const proveFold = (f, laws) => {
|
|
2786
|
-
|
|
2816
|
+
// (GDP_CERT=cyclic: the certificate a cyclic proof, core/cyclic.ts's certCyclic, the usual trees its input)
|
|
2817
|
+
const all = [...(f.lemmas ?? []), ...laws], t0 = performance.now(), v = goalsVerdict(foldObligations(f.fold, all), !certOn()), usualMs = performance.now() - t0;
|
|
2787
2818
|
if (cyclicOn())
|
|
2788
|
-
crossCyclic('fold', f.fold.name, v.proven && v.checked, () => { const { facts, specs } = foldNodes(f.fold, all); return proveCyclic(facts, specs); }, usualMs);
|
|
2819
|
+
crossCyclic('fold', f.fold.name, v.proven && v.checked, () => { const { facts, specs } = foldNodes(f.fold, all); return proveCyclic(facts, specs); }, usualMs, v.trees && (st => translatedProof(() => JSON.stringify(['fold', f.fold, all]), () => foldNodes(f.fold, all, v.trees, st), st)));
|
|
2820
|
+
if (certOn() && v.proven)
|
|
2821
|
+
v.checked = certCyclic('fold', f.fold.name, v.trees && (st => translatedProof(() => JSON.stringify(['fold', f.fold, all]), () => foldNodes(f.fold, all, v.trees, st), st)), () => { const { facts, specs } = foldNodes(f.fold, all); return proveCyclic(facts, specs); }, usualMs).checked;
|
|
2789
2822
|
return v;
|
|
2790
2823
|
};
|
|
2791
2824
|
const asTerm = (t) => (t instanceof Term ? t : lit(t));
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { C, E } from './machine.js';
|
|
2
|
+
import { type Lin } from './solver.js';
|
|
3
|
+
import { type Goal, type Path, type Subst, type Tree } from '../kernel/kernel.js';
|
|
4
|
+
export type Rename = {
|
|
5
|
+
s: Subst;
|
|
6
|
+
cells?: Record<string, {
|
|
7
|
+
to: string;
|
|
8
|
+
at: E;
|
|
9
|
+
}>;
|
|
10
|
+
};
|
|
11
|
+
export type Renamer = (lin: Lin, wp: Path) => Lin | undefined;
|
|
12
|
+
export declare function renamer(r: Rename): Renamer;
|
|
13
|
+
export type TStats = {
|
|
14
|
+
leaves: number;
|
|
15
|
+
regrown: number;
|
|
16
|
+
splits: number;
|
|
17
|
+
carried: number;
|
|
18
|
+
uncarried: number;
|
|
19
|
+
cached: number;
|
|
20
|
+
};
|
|
21
|
+
export declare const tstats: () => TStats;
|
|
22
|
+
export declare function translate(part: Goal, whole: Goal, tree: Tree, ren0: Renamer, st: TStats, until: number, pp?: Path, wp?: Path, swaps?: [string, string][]): Tree | undefined;
|
|
23
|
+
export type Reads = {
|
|
24
|
+
k: E;
|
|
25
|
+
w: E;
|
|
26
|
+
}[];
|
|
27
|
+
export declare function readsFirst(whole: Goal, reads: Reads, ren: Renamer, inner: (wp: Path, swaps: [string, string][]) => Tree | undefined, st: TStats, until: number, wp?: Path, swaps?: [string, string][]): Tree | undefined;
|
|
28
|
+
export declare function decide(whole: Goal, conds: C[], inner: (wp: Path) => Tree | undefined, st: TStats, until: number, wp?: Path): Tree | undefined;
|
|
29
|
+
export declare function close(g: Goal, wp: Path, st: TStats, until: number): Tree | undefined;
|
|
30
|
+
export declare function carry(g: Goal, nFacts: number, nUses: number, st: TStats, until: number): Tree | undefined;
|