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 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, and laws about every key of a map), each proven by the kernel with yours and handed back as the
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, but a recursive datatype as a value is Lean's), and shipping an arbitrary algorithm as its proved source (gdp-wired ships the rule as JavaScript; Bend
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)`). Each is two naturals underneath, so the kernel and the Lean
301
- twin see nothing new; `rule.decode(state)` reads them back as numbers.
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)))`), `min`, `max`, `when(cond, a, b)`, `count(cond)`;
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/`) |
@@ -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 {};