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/README.md
CHANGED
|
@@ -76,8 +76,14 @@ All of these are proven automatically, and each proof is also a Lean theorem:
|
|
|
76
76
|
proved them, as laws and lemmas with the source to paste.
|
|
77
77
|
- **Invariants nobody wrote** (`gdp-wired/infer`): `inferLaws(rule, laws)` proves a law that holds but isn't inductive
|
|
78
78
|
alone, with the laws it finds (bounds, sums and differences over the state, the same where a flag or a choice holds
|
|
79
|
-
one value,
|
|
79
|
+
one value, remainders of a value or of a sum or difference of two, x mod 2 = 0 for a counter stepping by 2, and laws
|
|
80
|
+
about every key of a map), each proven by the kernel with yours and handed back as the
|
|
80
81
|
`r.law(...)` call that states it; a false law comes back with the run that breaks it (`examples/infer.ts`).
|
|
82
|
+
- **There exists**: laws that say some value is a witness, `exists(k => x.eq(k.times(2)))` ("x is even"), over
|
|
83
|
+
naturals, integers, yes/nos or a map's keys, each proven through a witness the prover finds from the kernel's
|
|
84
|
+
counterexamples (a term of the state, or a ghost the run carries: the witness before, moved by the request's values)
|
|
85
|
+
or the one given; an existential in the assumption is a value each request brings, and `inferLaws` finds parities
|
|
86
|
+
and multiples this way. Lean states each as `∃ w, ...`, proven by ⟨witness, proof⟩ (`examples/exists.ts`).
|
|
81
87
|
- **Orderings at any distance**: "a refund never follows a release", through ghost state that watches the rule.
|
|
82
88
|
- **Liveness**: "every ticket issued is served", in every run that keeps sending the requests that help, including under
|
|
83
89
|
weak fairness (`examples/liveness.ts`).
|
|
@@ -97,6 +103,12 @@ All of these are proven automatically, and each proof is also a Lean theorem:
|
|
|
97
103
|
goal reads), and the lemma a stuck one needs (g(x, 0) = 2x through g(x, a) = a + 2x; a bound on another function);
|
|
98
104
|
`proveLoop` with no rank finds it (two phases' (x, y)) and the invariants it needs; the kernel checks the cyclic
|
|
99
105
|
proof (`examples/cycles.ts`).
|
|
106
|
+
- **Recursive datatypes as values** (`gdp-wired/data`): lists, trees, rose trees and their forests, declared by their
|
|
107
|
+
constructors; functions over them by structural recursion, or by any recursion whose termination is proven first (a
|
|
108
|
+
merge of two lists, a quicksort: the measure found, (size xs, size ys) or a sum of sizes, and each call's decrease
|
|
109
|
+
proven by the kernel before the function's equation is used; one that doesn't terminate is refused with the reason);
|
|
110
|
+
`proveData` finds the induction (structural, mutual, or the function's own call graph ranked by its measure) and the
|
|
111
|
+
lemmas, each proof checked in Lean against the `inductive` and the functions as declared (`examples/data.ts`).
|
|
100
112
|
- **Records and variants**: inputs, state, results, map cells and list items made of named fields, or one of several
|
|
101
113
|
cases each with fields of its own (a payment by card or in cash, a seat free, held or sold), every case covered
|
|
102
114
|
(`examples/datatypes.ts`).
|
|
@@ -115,7 +127,9 @@ When a law is false, the GPU search finds a real run that breaks it. When a law
|
|
|
115
127
|
**What it leaves to Lean or Bend.** Two things, and neither is a gap the next feature closes: proofs the prover would
|
|
116
128
|
have to invent (induction over a recursive structure whose proof needs a lemma nobody stated and `discover` doesn't find, and arithmetic with
|
|
117
129
|
products of unknowns beyond what products of facts and sums of squares give; integer arithmetic with induction or
|
|
118
|
-
with products is undecidable; a lemma you state about a recurrence is proven,
|
|
130
|
+
with products is undecidable; a lemma you state about a recurrence is proven, and `proveData` finds the induction and lemmas for a recursive datatype as a value, up to six symbols a lemma, for
|
|
131
|
+
functions structural or whose termination it proves, its values naturals, integers (`integer`, Lean's `Int`, beside
|
|
132
|
+
`natural`) and datatypes), and shipping an arbitrary algorithm as its proved source (gdp-wired ships the rule as JavaScript; Bend
|
|
119
133
|
compiles the proved source itself). The full list of what is and isn't in scope is in
|
|
120
134
|
[`docs/comparison.md`](docs/comparison.md#gdp-wireds-scope-in-detail).
|
|
121
135
|
|
|
@@ -297,14 +311,20 @@ const soon = retry.law('the next try is at most 64 after the last request', ({ne
|
|
|
297
311
|
reads them back as runtime values.
|
|
298
312
|
- **Integers and decimals**: `int` and `decimal(places)` inputs, `.ints({...})` and `.decimals(places, {...})` state;
|
|
299
313
|
`plus`, `minus`, `negate`, `times(k)` (k may be negative), `min`, `max`, `abs`, `isNegative`, comparisons with numbers
|
|
300
|
-
(a decimal's literals are scaled: `price.atMost(19.99)`)
|
|
301
|
-
|
|
314
|
+
(a decimal's literals are scaled: `price.atMost(19.99)`), and `modBy(k)`, `divBy(k)` by Euclid's rule (−7 div 2 is
|
|
315
|
+
−4, −7 mod 2 is 1, as SMT-LIB and Lean's `Int` read them). Each is two naturals underneath, so the kernel twin sees
|
|
316
|
+
nothing new; the Lean export states each law about integers again over `Int` (`law0_int`, proven from the law over
|
|
317
|
+
the naturals by `omega`), and `rule.decode(state)` reads them back as numbers. A natural's `minus` stays truncated:
|
|
318
|
+
an integer is a kind of its own, chosen where a value may go below 0 (`examples/arith.ts`).
|
|
302
319
|
- **Strings**: `str({like: ['*.internal'], maxLength: 64})`. A string is its interned name, its length and a bit per
|
|
303
320
|
declared pattern (Cedar's glob), all computed from the string itself when the input is encoded. `s.like(pattern)`,
|
|
304
321
|
`s.eq('admin')` (which carries the literal's length and pattern bits, so laws reason from either), `s.isEmpty`,
|
|
305
322
|
`s.length`; sets of strings are carried maps keyed by `s.id`.
|
|
306
323
|
- **Arithmetic** over the naturals: `plus`, `minus` (truncated), `times(k)`, `mul` (a product of two terms, a map's
|
|
307
|
-
cell among them: `Used.at(k).atMost(per.mul(Seats.at(k)))`), `
|
|
324
|
+
cell among them: `Used.at(k).atMost(per.mul(Seats.at(k)))`), `modBy(k)` and `divBy(k)` by a constant k ≥ 1 (the rule's
|
|
325
|
+
functions mod$k and div$k, known to the kernel by x = k·(x div k) + x mod k and x mod k < k, Presburger arithmetic it
|
|
326
|
+
already decides; Lean's `%` and `/`, both facts proven by `omega`; division by a term isn't offered: x = y·q + r is a
|
|
327
|
+
product of two unknowns), `min`, `max`, `when(cond, a, b)`, `count(cond)`;
|
|
308
328
|
conditions `lt`, `atMost`, `eq`, `and`, `or`, `not`, `implies`. Where a law with products isn't linear in its
|
|
309
329
|
monomials, the prover multiplies facts together and adds squares, as Lean's `nlinarith` does: (x − y)² for each
|
|
310
330
|
product x·y the law reads, its factors as the step leaves them, and for each monomial split in two halves
|
|
@@ -313,6 +333,17 @@ const soon = retry.law('the next try is at most 64 after the last request', ({ne
|
|
|
313
333
|
`disjointFrom`, `sameAs`) anywhere in a step or inside a law, `everyKey((i, j) => ...)` in a step for every two keys
|
|
314
334
|
(each read on its own, compared with the other plainly: `i.lt(j)`), `M.each(k => ...)` to write every key, and
|
|
315
335
|
`someKey(k => ..., witness?)` for "some key where", proven through a witness the prover finds or the one given.
|
|
336
|
+
- **There exists** (`exists(kind?, f, witness?)`, core/exists.ts): "some value of the kind (nat, int, bool, upTo(k))
|
|
337
|
+
where f holds", anywhere in a law where it reads so (under no `not`, not before `implies`), after its `forall` key if
|
|
338
|
+
it has one. The kernel never sees it: the law it proves is f with a witness term in place (a term of the state, for
|
|
339
|
+
each bound value), or f over ghosts the machine gains (a value at the start, and after each step one over the
|
|
340
|
+
witness before, the request and the state before), chosen by the kernel's counterexamples among what f's own atoms
|
|
341
|
+
solve for, 0, the state, the params, the request's values and shifts of the witness before, per case of the step; a
|
|
342
|
+
witness given, `exists(k => ..., lo)` or `{start, step: (k, env) => ...}`, is the only one tried. The verdict's
|
|
343
|
+
`witnesses` says how each reads. In the assumption (`exists(int, k => amount.eq(k.times(5)))`) or a precondition, it
|
|
344
|
+
is an input or a param the runtimes find (`encodeInput`, `encodeParams`: exact where it is one natural or integer
|
|
345
|
+
read linearly); a request no witness fits is refused. A run refutes a false one where no value can be a witness,
|
|
346
|
+
decided the same way.
|
|
316
347
|
- **Functions** (`.fns({perMinute: divBy(60)})`, or `fn(arity, js, {facts, lean})` for your own): read like params that
|
|
317
348
|
take arguments, `perMinute(t)`; the kernel knows each only by its facts (`.facts(...)`, and a library function's
|
|
318
349
|
own), and the Lean export takes them as the hypothesis they are, proving them where the function has a Lean
|
|
@@ -395,7 +426,7 @@ Proving and checking: a law over 64 steps proves in about 5 s, and Lean checks i
|
|
|
395
426
|
| `core/` | Machines, the interpreter and JS compiler, the builders, composition (`compose.ts`), the linear solver and its checker, Houdini invariants, models, the first Lean export |
|
|
396
427
|
| `kernel/` | The trusted kernel and the untrusted prover, with soundness fuzz (`kernel.test.ts`, `history.test.ts`) |
|
|
397
428
|
| `lean-kernel/` | The kernel's Lean twin, its soundness proofs, and the exported trees |
|
|
398
|
-
| `examples/` | The builders at work: `domains/` (187 rules across 21 domains, each with laws and broken variants), `harness.ts` (the triple check), `readme.ts`, `guide.ts` (the guide's code), `groups.ts` (two groups decided at every pair), `budget.ts`, `gdp.ts` (gdp-ts's example, its checks proven), `datatypes.ts` (records and variants), `lemmas.ts` (recurrences and their lemmas), `invoices.ts` (lists a request carries), `folds.ts` (folds over trees), `trees.ts` (trees and lists of lists in the state), `composition.ts`, `sets.ts`, `quantifiers.ts`, `functions.ts`, `lists.ts`, `sizes.ts`, `liveness.ts`, `steps.ts` (laws over up to 64 steps), and `jev-fabric/` (a Bend project's 59 proven laws, ported) |
|
|
429
|
+
| `examples/` | The builders at work: `domains/` (187 rules across 21 domains, each with laws and broken variants), `harness.ts` (the triple check), `readme.ts`, `guide.ts` (the guide's code), `groups.ts` (two groups decided at every pair), `budget.ts`, `gdp.ts` (gdp-ts's example, its checks proven), `exists.ts` (laws with "there exists"), `datatypes.ts` (records and variants), `lemmas.ts` (recurrences and their lemmas), `invoices.ts` (lists a request carries), `folds.ts` (folds over trees), `trees.ts` (trees and lists of lists in the state), `composition.ts`, `sets.ts`, `quantifiers.ts`, `functions.ts`, `arith.ts` (division and remainder by a constant, integers in rules and datatypes), `lists.ts`, `sizes.ts`, `liveness.ts`, `steps.ts` (laws over up to 64 steps), and `jev-fabric/` (a Bend project's 59 proven laws, ported) |
|
|
399
430
|
| `docs/` | The comparison with Bend and Lean, and the full scope |
|
|
400
431
|
| `compare/` | The same three rules in gdp-wired, Bend and plain Lean, checked and measured |
|
|
401
432
|
| `research/` | Everything around the library ([`research/README.md`](research/README.md)): the GPU searches (`search/`, `hw/`, `modal-gpu/`), invariant and rank synthesis (`synth/`), relational laws and guard synthesis (`next/`), bit-vector laws (`sat/`), the enumeration and benchmarks (`enum/`, `gpu/`, `perf/`), the first Lean checker (`lean/`) and the first prototype, the audit path (`audit/`) |
|
package/dist/core/cycles.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { C, E, Law, Machine } from './machine.js';
|
|
2
|
-
import type { Loop, Tree } from '../kernel/kernel.js';
|
|
1
|
+
import type { C, E, Law, Machine, Request } from './machine.js';
|
|
2
|
+
import type { Liveness, Loop, Tree } from '../kernel/kernel.js';
|
|
3
3
|
import { type Cyclic, type Fact } from '../kernel/cyclic.js';
|
|
4
4
|
import { type NodeSpec } from './cyclic.js';
|
|
5
5
|
import type { StepLaw } from '../kernel/kernel.js';
|
|
@@ -37,6 +37,17 @@ export declare const argsKey: (args: E[]) => E;
|
|
|
37
37
|
export declare const linE: (coef: Record<string, number>, c: number) => E;
|
|
38
38
|
export declare const showE: (e: E) => string;
|
|
39
39
|
export declare const showC: (c: C) => string;
|
|
40
|
+
type Env = Record<string, number>;
|
|
41
|
+
export declare function ranksOfRuns(vars: string[], points: Env[], edges: {
|
|
42
|
+
s: Env;
|
|
43
|
+
t: Env;
|
|
44
|
+
}[], ms?: number): {
|
|
45
|
+
comps: {
|
|
46
|
+
coef: Record<string, number>;
|
|
47
|
+
c: number;
|
|
48
|
+
}[];
|
|
49
|
+
left: number;
|
|
50
|
+
};
|
|
40
51
|
export declare function claimInstances(facts: Fact[], claim: Claim, depth?: number): NodeSpec['insts'];
|
|
41
52
|
export declare function findCycles(facts: Fact[], claims: Claim[], opts?: CycleOptions): CycleVerdict;
|
|
42
53
|
export type RankVerdict = {
|
|
@@ -57,6 +68,27 @@ export type RankVerdict = {
|
|
|
57
68
|
export declare function findRank(l: Loop, laws?: Law[], opts?: {
|
|
58
69
|
ms?: number;
|
|
59
70
|
}): RankVerdict;
|
|
71
|
+
export type Sampler = {
|
|
72
|
+
params: (rand: (n: number) => number, bound: number) => Record<string, number>;
|
|
73
|
+
input: (rand: (n: number) => number, bound: number, ps: Record<string, number>) => Request;
|
|
74
|
+
};
|
|
75
|
+
export type LeadsVerdict = {
|
|
76
|
+
proven: boolean;
|
|
77
|
+
checked: boolean;
|
|
78
|
+
rank?: E[];
|
|
79
|
+
laws?: Law[];
|
|
80
|
+
found?: {
|
|
81
|
+
rank: string;
|
|
82
|
+
laws: string[];
|
|
83
|
+
};
|
|
84
|
+
goal?: string;
|
|
85
|
+
stuck?: string;
|
|
86
|
+
witness?: Record<string, number>;
|
|
87
|
+
why?: string;
|
|
88
|
+
};
|
|
89
|
+
export declare function findLeadsTo(m: Machine, laws: Law[], l: Liveness, sample: Sampler, opts?: {
|
|
90
|
+
ms?: number;
|
|
91
|
+
}): LeadsVerdict;
|
|
60
92
|
export type LemmaFound = {
|
|
61
93
|
law: Law;
|
|
62
94
|
text: string;
|
|
@@ -71,3 +103,4 @@ export declare function cycleLemmas(m: Machine, laws: Law[], stepLaws?: StepLaw[
|
|
|
71
103
|
proof?: Cyclic;
|
|
72
104
|
why?: string;
|
|
73
105
|
};
|
|
106
|
+
export {};
|