gdp-wired 0.19.0 → 0.21.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 +37 -6
- package/dist/core/cycles.d.ts +35 -2
- package/dist/core/cycles.js +458 -51
- package/dist/core/cyclic.d.ts +18 -4
- package/dist/core/cyclic.js +319 -263
- package/dist/core/data.d.ts +196 -15
- package/dist/core/data.js +1284 -213
- package/dist/core/discover.js +54 -33
- package/dist/core/dsl.d.ts +31 -3
- package/dist/core/dsl.js +168 -38
- package/dist/core/exists.d.ts +26 -0
- package/dist/core/exists.js +625 -0
- package/dist/core/infer.d.ts +13 -0
- package/dist/core/infer.js +258 -41
- package/dist/core/machine.d.ts +27 -0
- package/dist/core/machine.js +45 -0
- package/dist/core/solver.d.ts +3 -0
- package/dist/core/solver.js +5 -0
- package/dist/core/transfer.d.ts +17 -0
- package/dist/core/transfer.js +468 -0
- package/dist/core/translate.js +10 -4
- package/dist/core/watch.js +5 -1
- package/dist/kernel/prove.d.ts +8 -1
- package/dist/kernel/prove.js +106 -55
- package/dist/lean-kernel/emit.d.ts +4 -1
- package/dist/lean-kernel/emit.js +336 -69
- package/dist/lean-kernel/library.js +2 -2
- package/package.json +2 -2
package/dist/core/discover.js
CHANGED
|
@@ -83,8 +83,8 @@ function linearCands(target, forms, samples, show) {
|
|
|
83
83
|
return dedupe(out.filter(c => samples.every(s => holds(c, s))));
|
|
84
84
|
}
|
|
85
85
|
const dedupe = (cs) => [...new Map(cs.map(c => [c.name, c])).values()];
|
|
86
|
-
// A polynomial in x of degree
|
|
87
|
-
//
|
|
86
|
+
// A polynomial in x of degree 3 at most, exact over the rationals, as d·f = a·x·x·x + b·x·x + c·x + e with whole
|
|
87
|
+
// numbers: fitted to four points (Newton's differences), kept when every sample meets it.
|
|
88
88
|
function closedForm(samples, show) {
|
|
89
89
|
const at = new Map();
|
|
90
90
|
for (const s of samples) {
|
|
@@ -95,22 +95,30 @@ function closedForm(samples, show) {
|
|
|
95
95
|
if (![0, 1, 2].every(x => at.has(x)))
|
|
96
96
|
return [];
|
|
97
97
|
const [f0, f1, f2] = [at.get(0), at.get(1), at.get(2)];
|
|
98
|
+
const keep = (lin) => {
|
|
99
|
+
const g = Object.values(lin).reduce((p, q) => gcd(p, Math.abs(q)), 0);
|
|
100
|
+
const c = { name: '', rel: '=', lin: Object.fromEntries(Object.entries(lin).map(([a, k]) => [a, k / g]).filter(([, k]) => k !== 0)) };
|
|
101
|
+
c.name = nameOf(c, show, 'f');
|
|
102
|
+
return samples.every(s => holds(c, s)) ? [c] : [];
|
|
103
|
+
};
|
|
98
104
|
// f = a x² + b x + c: c = f0, a = (f2 - 2 f1 + f0) / 2, b = f1 - f0 - a; times 2 to keep whole numbers.
|
|
99
105
|
const A = f2 - 2 * f1 + f0, B = 2 * (f1 - f0) - A, C = 2 * f0;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
const square = A === 0 ? [] : keep({ f: 2, xx: -A, x: -B, 1: -C });
|
|
107
|
+
if (square.length || !at.has(3))
|
|
108
|
+
return square;
|
|
109
|
+
// f = Δ0 + Δ1·x + Δ2·x(x − 1)/2 + Δ3·x(x − 1)(x − 2)/6, times 6: x³ by Δ3, x² by 3Δ2 − 3Δ3, x by 6Δ1 − 3Δ2 + 2Δ3.
|
|
110
|
+
const d1 = f1 - f0, d2 = f2 - 2 * f1 + f0, d3 = at.get(3) - 3 * f2 + 3 * f1 - f0;
|
|
111
|
+
if (d3 === 0)
|
|
112
|
+
return []; // degree 2 at most: above, or linear (the bounds find it)
|
|
113
|
+
return keep({ f: 6, xxx: -d3, xx: -(3 * d2 - 3 * d3), x: -(6 * d1 - 3 * d2 + 2 * d3), 1: -6 * f0 });
|
|
106
114
|
}
|
|
107
115
|
// The law a goal is of (the kernel names each goal after its law: '<law> @step').
|
|
108
116
|
const lawOfGoal = (goal) => goal.replace(/ @(start|step|step law|\d+ steps|leaf|node)$/, '');
|
|
109
117
|
const isGoalOf = (goal) => (c) => { const law = lawOfGoal(goal); return law === c.name || law === `${c.name} at y`; };
|
|
110
118
|
const gcd = (a, b) => (b === 0 ? Math.abs(a) : gcd(b, a % b));
|
|
111
119
|
// --- recurrences ---------------------------------------------------------------------------------------------------
|
|
112
|
-
const showRecur = (a) => (a === 'f' ? 'f(x)' : a === 'g' ? 'f(y)' : a === 'xx' ? 'x·x' : a);
|
|
113
|
-
const srcRecur = (a) => (a === 'xx' ? 'x.mul(x)' : a);
|
|
120
|
+
const showRecur = (a) => (a === 'f' ? 'f(x)' : a === 'g' ? 'f(y)' : a === 'xx' ? 'x·x' : a === 'xxx' ? 'x·x·x' : a);
|
|
121
|
+
const srcRecur = (a) => (a === 'xx' ? 'x.mul(x)' : a === 'xxx' ? 'x.mul(x).mul(x)' : a);
|
|
114
122
|
// The function's values: x from 0 to 40 at a few values of each further argument (all of them for two at most).
|
|
115
123
|
function recurSamples(d, args) {
|
|
116
124
|
const f = (typeof d.js === 'function' ? d.js : compileFunction([], `return (${d.js})`)());
|
|
@@ -128,7 +136,7 @@ function recurSamples(d, args) {
|
|
|
128
136
|
break;
|
|
129
137
|
throw e;
|
|
130
138
|
}
|
|
131
|
-
out.push({ x, f: y, xx: x * x, ...Object.fromEntries(args.map((a, i) => [a, t[i]])) });
|
|
139
|
+
out.push({ x, f: y, xx: x * x, xxx: x * x * x, ...Object.fromEntries(args.map((a, i) => [a, t[i]])) });
|
|
132
140
|
}
|
|
133
141
|
return out;
|
|
134
142
|
}
|
|
@@ -167,9 +175,9 @@ function recurCands(samples, args) {
|
|
|
167
175
|
c.name = nameOf(c, showRecur, 'g');
|
|
168
176
|
return { lemmas, between };
|
|
169
177
|
}
|
|
170
|
-
const recurAtoms = (args, x, f, env, y, g) => ({ x, f, xx: x.mul(x), ...(y && g ? { y, g } : {}), ...Object.fromEntries(args.map(a => [a, env[a]])) });
|
|
178
|
+
const recurAtoms = (args, x, f, env, y, g) => ({ x, f, xx: x.mul(x), xxx: x.mul(x).mul(x), ...(y && g ? { y, g } : {}), ...Object.fromEntries(args.map(a => [a, env[a]])) });
|
|
171
179
|
const recurSrc = (c, args, between) => {
|
|
172
|
-
const reads = (a) => Object.keys(c.lin).includes(a) || (a === 'x' && 'xx' in c.lin);
|
|
180
|
+
const reads = (a) => Object.keys(c.lin).includes(a) || (a === 'x' && ('xx' in c.lin || 'xxx' in c.lin));
|
|
173
181
|
const names = between ? ['x', 'f', 'y', 'g'] : ['x', 'f'];
|
|
174
182
|
let unused = 0;
|
|
175
183
|
const params = [...names.map(n => (reads(n) ? n : '_'.repeat(++unused))), ...(args.some(reads) ? [`{${args.filter(reads).join(', ')}}`] : [])];
|
|
@@ -268,27 +276,40 @@ function discoverSearch(r, laws, stepLaws, first) {
|
|
|
268
276
|
if (first.proven && first.checked)
|
|
269
277
|
return { verdict: first, rule: r, found: {} };
|
|
270
278
|
const { params, fns, lists } = r.parts, ps = natParams(params);
|
|
271
|
-
// Per function and per list: what is proven, made into the rule.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (out && out.kept.length) {
|
|
287
|
-
rule = out.rule;
|
|
288
|
-
listKept[part[0]] = out.kept;
|
|
279
|
+
// Per function and per list: what is proven, made into the rule. A function with a closed form (of degree 2 or 3,
|
|
280
|
+
// fitted exactly) first with it alone: it decides the function, and the bounds beside it, which the closed form
|
|
281
|
+
// implies only through products, are slow to prove by induction; the rest where the laws aren't proven with it.
|
|
282
|
+
const cands = new Map(fns.flatMap(([n, d]) => { const src = recurOf(d); if (!src)
|
|
283
|
+
return []; const args = [...(src.def.args ?? [])]; return [[n, recurCands(recurSamples(d, args), args)]]; }));
|
|
284
|
+
const exact = (c) => c.rel === '=' && ('xx' in c.lin || 'xxx' in c.lin);
|
|
285
|
+
const makeFns = (closedOnly) => {
|
|
286
|
+
const out = {};
|
|
287
|
+
for (const [n, d] of fns) {
|
|
288
|
+
const cs = cands.get(n);
|
|
289
|
+
if (!cs)
|
|
290
|
+
continue;
|
|
291
|
+
const closed = cs.lemmas.filter(exact), made = closedOnly && closed.length ? houdiniRecur(d, closed, []) : houdiniRecur(d, cs.lemmas, cs.between);
|
|
292
|
+
if (made && (made.lemmas.length || made.between.length))
|
|
293
|
+
out[n] = made;
|
|
289
294
|
}
|
|
290
|
-
|
|
291
|
-
|
|
295
|
+
return out;
|
|
296
|
+
};
|
|
297
|
+
const withLists = (fnMade) => {
|
|
298
|
+
let rule = r.withParts(Object.fromEntries(Object.entries(fnMade).map(([n, m]) => [n, m.d])));
|
|
299
|
+
const listKept = {};
|
|
300
|
+
for (const part of lists) {
|
|
301
|
+
const out = houdiniList(rule, part, listCands(part, params, listSamples(part, params)), ps);
|
|
302
|
+
if (out && out.kept.length) {
|
|
303
|
+
rule = out.rule;
|
|
304
|
+
listKept[part[0]] = out.kept;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { fnMade, rule, listKept, verdict: proveSteps(rule, laws, stepLaws, { search: false }) };
|
|
308
|
+
};
|
|
309
|
+
let made = [...cands.values()].some(cs => cs.lemmas.some(exact)) ? withLists(makeFns(true)) : undefined;
|
|
310
|
+
if (!made || !(made.verdict.proven && made.verdict.checked))
|
|
311
|
+
made = withLists(makeFns(false));
|
|
312
|
+
const { fnMade, rule, listKept, verdict } = made;
|
|
292
313
|
const found = () => ({
|
|
293
314
|
...Object.fromEntries(Object.entries(fnMade).map(([n, m]) => { const args = [...(recurOf(m.d).def.args ?? [])]; return [n, { ...(m.lemmas.length ? { lemmas: m.lemmas.map(c => recurSrc(c, args, false)) } : {}), ...(m.between.length ? { between: m.between.map(c => recurSrc(c, args, true)) } : {}) }]; })),
|
|
294
315
|
...Object.fromEntries(Object.entries(listKept).map(([n, cs]) => [n, { lemmas: cs.map(c => listSrc(c, Object.keys(lists.find(l => l[0] === n)[2]), ps, c.target)) }])),
|
package/dist/core/dsl.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export declare class Term {
|
|
|
10
10
|
minus(b: TermLike): Term;
|
|
11
11
|
times(k: number): Term;
|
|
12
12
|
mul(b: TermLike): Term;
|
|
13
|
+
modBy(k: number): Term;
|
|
14
|
+
divBy(k: number): Term;
|
|
13
15
|
lt(b: TermLike): Cond;
|
|
14
16
|
atMost(b: TermLike): Cond;
|
|
15
17
|
gt(b: TermLike): Cond;
|
|
@@ -20,7 +22,8 @@ export declare class Term {
|
|
|
20
22
|
export declare class Cond {
|
|
21
23
|
readonly c: C;
|
|
22
24
|
readonly ok?: boolean | undefined;
|
|
23
|
-
|
|
25
|
+
readonly ex?: readonly Bound[] | undefined;
|
|
26
|
+
constructor(c: C, ok?: boolean | undefined, ex?: readonly Bound[] | undefined);
|
|
24
27
|
and(...xs: Cond[]): Cond;
|
|
25
28
|
or(...xs: Cond[]): Cond;
|
|
26
29
|
not(): Cond;
|
|
@@ -94,6 +97,8 @@ export declare class Int {
|
|
|
94
97
|
min(b: IntLike): Int;
|
|
95
98
|
max(b: IntLike): Int;
|
|
96
99
|
get isNegative(): Cond;
|
|
100
|
+
modBy(k: number): Term;
|
|
101
|
+
divBy(k: number): Int;
|
|
97
102
|
get abs(): Term;
|
|
98
103
|
get clamped(): Term;
|
|
99
104
|
}
|
|
@@ -261,6 +266,20 @@ export type MapWrite = {
|
|
|
261
266
|
};
|
|
262
267
|
export declare const everyKey: (f: (key: Term, key2: Term, key3: Term) => Cond) => Cond;
|
|
263
268
|
export declare const someKey: (f: (key: Term) => Cond, witness?: TermLike) => Cond;
|
|
269
|
+
export type ExistsWitness<V> = V | number | {
|
|
270
|
+
start: V | number;
|
|
271
|
+
step: (before: V, env: never) => V | number;
|
|
272
|
+
};
|
|
273
|
+
type Bound = {
|
|
274
|
+
vars: string[];
|
|
275
|
+
body: C;
|
|
276
|
+
pos: boolean;
|
|
277
|
+
terms?: Record<string, E>;
|
|
278
|
+
start?: Record<string, E>;
|
|
279
|
+
step?: (env: Record<string, unknown>) => Record<string, E>;
|
|
280
|
+
};
|
|
281
|
+
export declare function exists(f: (x: Term) => Cond, witness?: ExistsWitness<Term>): Cond;
|
|
282
|
+
export declare function exists<V>(kind: Kind<V>, f: (x: V) => Cond, witness?: ExistsWitness<V>): Cond;
|
|
264
283
|
export declare class MapRef {
|
|
265
284
|
readonly name: string;
|
|
266
285
|
readonly init: number;
|
|
@@ -498,6 +517,7 @@ type Spec = {
|
|
|
498
517
|
lists2?: [string, Kind<unknown>, Record<string, ListFold<unknown>>, Record<string, ListLemma>][];
|
|
499
518
|
fns?: [string, FnDef][];
|
|
500
519
|
facts?: ((env: never) => Record<string, Cond | Forall>)[];
|
|
520
|
+
arith?: Set<number>;
|
|
501
521
|
flags: ((env: never) => Record<string, Cond>)[];
|
|
502
522
|
step?: (env: never) => Record<string, TermLike | MapWrite | undefined>;
|
|
503
523
|
pre: ((p: never) => Cond)[];
|
|
@@ -588,13 +608,17 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
588
608
|
prune(order: keyof R & string, after: (p: P) => TermLike): Rule<P, I, S, M, F, R, Su, Q>;
|
|
589
609
|
law(name: string, f: (env: P & S & M & Su) => Cond | Forall): Law;
|
|
590
610
|
private lawOf;
|
|
611
|
+
private someOf;
|
|
612
|
+
private divides;
|
|
613
|
+
dividesBy(...ks: number[]): this;
|
|
614
|
+
withDivisors(...ks: number[]): this;
|
|
591
615
|
kindLaws(): Law[];
|
|
592
616
|
stepLaw(name: string, then: (before: P & I & S & M & F & Su & Q, after: S & M & Su) => Cond | Forall, when?: (before: P & I & S & M & F & Su & Q) => Cond): StepLaw;
|
|
593
617
|
stepsLaw(name: string, k: number, then: (first: P & I & S & M & F & Su & Q, last: S & M & Su, requests: (I & Q)[]) => Cond | Forall, when?: (before: P & I & S & M & F & Su & Q, j: number) => Cond | undefined): StepLaw;
|
|
594
618
|
leadsTo(name: string, spec: {
|
|
595
619
|
from: (env: P & S & M & Su) => Cond;
|
|
596
620
|
to: (env: P & S & M & Su) => Cond;
|
|
597
|
-
rank
|
|
621
|
+
rank?: (env: P & S & M & Su) => TermLike | TermLike[];
|
|
598
622
|
helpful: ((env: P & S & M & Su) => Record<string, TermLike>) | {
|
|
599
623
|
when?: (env: P & S & M & Su) => Cond;
|
|
600
624
|
request: (env: P & S & M & Su) => Record<string, TermLike>;
|
|
@@ -631,6 +655,7 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
631
655
|
encodeParams(values: {
|
|
632
656
|
[k in keyof P]: Raw;
|
|
633
657
|
}): Record<string, number>;
|
|
658
|
+
private withSkolems;
|
|
634
659
|
encodeInput(values: {
|
|
635
660
|
[k in keyof I]: I[k] extends MapRef ? ReadonlySet<number> | readonly number[] | ReadonlyMap<number, number> : I[k] extends SeqRef ? readonly number[] : I[k] extends SeqTable ? readonly (readonly number[])[] : I[k] extends CarriedList<any, any> ? readonly Raw[] : Raw;
|
|
636
661
|
}, params?: {
|
|
@@ -800,6 +825,7 @@ export type Verdict = {
|
|
|
800
825
|
trace: Record<string, unknown>[];
|
|
801
826
|
};
|
|
802
827
|
found?: Found;
|
|
828
|
+
witnesses?: Record<string, string>;
|
|
803
829
|
};
|
|
804
830
|
export type Found = {
|
|
805
831
|
laws?: {
|
|
@@ -828,7 +854,9 @@ export declare function proveRule(r: Rule<Obj, Obj, Obj, Obj, Obj, Obj, Obj, Obj
|
|
|
828
854
|
export declare function proveSteps(r: Rule<Obj, Obj, Obj, Obj, Obj, Obj, Obj, Obj>, laws: Law[], stepLaws: StepLaw[], opts?: ProveOptions): Verdict;
|
|
829
855
|
export type { StepLaw };
|
|
830
856
|
export type { Liveness };
|
|
831
|
-
export declare function proveLeadsTo(r: Rule<Obj, Obj, Obj, Obj, Obj, Obj, Obj, Obj>, laws: Law[], l: Liveness
|
|
857
|
+
export declare function proveLeadsTo(r: Rule<Obj, Obj, Obj, Obj, Obj, Obj, Obj, Obj>, laws: Law[], l: Liveness, opts?: {
|
|
858
|
+
ms?: number;
|
|
859
|
+
}): Verdict;
|
|
832
860
|
export declare const proveDecision: (d: Decision) => Verdict;
|
|
833
861
|
export declare function crossCheckDecision(d: Decision, opts?: {
|
|
834
862
|
trials?: number;
|