gdp-wired 0.14.2 → 0.15.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/dist/core/dsl.js CHANGED
@@ -1416,8 +1416,12 @@ export const recur = (name, def, lemmas = {}, between = {}) => {
1416
1416
  proofs.between = { machine: r.machine, laws };
1417
1417
  verdict = { proven: true, checked: verdict.checked && v.checked };
1418
1418
  }
1419
- return { ...base, verdict, facts: facts(true) };
1419
+ const out = { ...base, verdict, facts: facts(true) };
1420
+ recurDefs.set(out, { name, def: def, lemmas: lemmas, between: between });
1421
+ return out;
1420
1422
  };
1423
+ const recurDefs = new WeakMap();
1424
+ export const recurOf = (d) => recurDefs.get(d);
1421
1425
  const distinctNames = (what, names) => { if (new Set(names).size !== names.length)
1422
1426
  throw new Error(`${what}: a name given twice`); };
1423
1427
  // A recurrence as JavaScript: a function of its arguments, the functions it reads inlined (each called on its arguments,
@@ -1527,6 +1531,21 @@ export class Rule {
1527
1531
  }
1528
1532
  with(more) { return new Rule({ ...this.spec, ...more }); }
1529
1533
  get name() { return this.spec.name; }
1534
+ // For core/discover.ts: the functions and carried lists the rule reads, and the same rule with functions made again
1535
+ // and lemmas added to its lists' folds (each proven here, as carriesList proves its own).
1536
+ get parts() {
1537
+ return { params: this.spec.params, fns: this.spec.fns ?? [], lists: this.spec.lists2 ?? [] };
1538
+ }
1539
+ withParts(fns, listLemmas = {}) {
1540
+ const lists = (this.spec.lists2 ?? []).map(([n, k, fs, ls]) => [n, k, fs, { ...ls, ...(listLemmas[n] ?? {}) }]);
1541
+ for (const [n, k, fs, ls] of lists)
1542
+ if (listLemmas[n]) {
1543
+ const v2 = new CarriedList(n, k, v(`${n}_len`), fs, part => new MapRef(part, 0), ls, undefined, this.spec.params).prove();
1544
+ if (!(v2.proven && v2.checked))
1545
+ throw new Unproven(`${n}'s fold lemmas`, v2);
1546
+ }
1547
+ return this.with({ fns: (this.spec.fns ?? []).map(([n, d]) => [n, fns[n] ?? d]), lists2: lists });
1548
+ }
1530
1549
  params(kinds) { return this.with({ params: [...this.spec.params, ...Object.entries(kinds)] }); }
1531
1550
  inputs(kinds) { return this.with({ inputs: [...this.spec.inputs, ...Object.entries(kinds)] }); }
1532
1551
  // Each variable starts at a natural or at a term over the params, or is declared by a kind and starts where `from`
@@ -1758,6 +1777,8 @@ export class Rule {
1758
1777
  // A decision: whenever the params and the request meet `given`, `then` holds. Decisions don't read the state; the
1759
1778
  // functions' facts are assumed at the arguments the decision reads them at, and a carried list's equations (each
1760
1779
  // fold's start, its step and its lemmas) at the list's end, the key before it and every key the decision reads it at.
1780
+ // A condition about every key (`everyKey`, `subsetOf`, ...) in `given` or `then` makes the decision a step law of
1781
+ // this rule (its conditions as flags, the step left as it is): the flags' quantifiers are what the kernel closes.
1761
1782
  decide(name, given, then) {
1762
1783
  const env = this.env({ flags: false, state: false, queries: false });
1763
1784
  const g = given(env), hyps = [...this.kindAssumptions(), ...this.spec.pre.map(f => f(env).c), ...this.spec.assume.map(f => f(env).c), ...(Array.isArray(g) ? g : [g]).map(c => c.c)];
@@ -1766,7 +1787,14 @@ export class Rule {
1766
1787
  const listed = lists.flatMap(l => l.equationsAt(uniqueTerms([l.len, l.len.minus(1), ...keysRead([...hyps, t], l.maps)])).map(c => c.c));
1767
1788
  const goal = { name, hyps: [...listed, ...hyps, { op: 'not', x: t }] };
1768
1789
  const facts = this.spec.fns?.length || this.spec.facts?.length ? factsFor(this.machine, goal) : [];
1769
- return withSource({ name, rule: this, given: hyps, then: t, goal: { name, hyps: [...facts, ...goal.hyps] } }, { decision: { given: given, then: then, own: Array.isArray(g) ? g.length : 1 } });
1790
+ const d = { name, rule: this, given: hyps, then: t, goal: { name, hyps: [...facts, ...goal.hyps] } };
1791
+ if ([...(Array.isArray(g) ? g : [g]).map(c => c.c), t].some(quantifiedIn)) {
1792
+ const conds = (e) => { const own = given(e); return { given$: all(...(Array.isArray(own) ? own : [own])), then$: then(e) }; };
1793
+ const r = (this.spec.step ? this : this.step(() => ({}))).flags(conds);
1794
+ const flag = (f) => (env) => env[f];
1795
+ d.steps = { rule: r, law: r.stepLaw(name, flag('then$'), flag('given$')) };
1796
+ }
1797
+ return withSource(d, { decision: { given: given, then: then, own: Array.isArray(g) ? g.length : 1 } });
1770
1798
  }
1771
1799
  // A decision about two requests under the same params (noninterference, say: requests that differ only in a secret
1772
1800
  // are decided alike). `given` and `then` read both; the second request's inputs are named b.<input> in a witness.
@@ -2249,6 +2277,8 @@ const expandParts = (updates) => {
2249
2277
  };
2250
2278
  const encode = (kinds, values) => Object.assign({}, ...kinds.map(([n, k]) => k.encode(n, values[n])));
2251
2279
  export const rule = (name) => new Rule({ name, params: [], inputs: [], state: [], maps: [], flags: [], pre: [], assume: [], sums: [], queries: [] });
2280
+ const quantifiedE = (e) => e.op === 'if' ? quantifiedIn(e.c) || quantifiedE(e.then) || quantifiedE(e.else) : 'a' in e && typeof e.a === 'object' ? quantifiedE(e.a) || ('b' in e && typeof e.b === 'object' && quantifiedE(e.b)) : false;
2281
+ const quantifiedIn = (c) => c.op === 'all' || (c.op === 'not' ? quantifiedIn(c.x) : c.op === 'and' || c.op === 'or' ? c.xs.some(quantifiedIn) : c.op === 'flag' ? false : quantifiedE(c.a) || quantifiedE(c.b));
2252
2282
  // The kind a result field is kept in.
2253
2283
  const kindOf = (t) => (t instanceof Cond ? bool : t instanceof Int ? int : t instanceof Decimal ? decimal(t.places) : t instanceof Choice ? oneOf(...t.values) : t instanceof Str ? str({ like: t.patterns })
2254
2284
  : t instanceof Variant ? t.kind : t instanceof Maybe ? maybe(kindOf(t.inner)) : isRecord(t) ? record(Object.fromEntries(Object.entries(t).map(([f, x]) => [f, kindOf(x)]))) : nat);
@@ -2487,7 +2517,7 @@ export function proveLeadsTo(r, laws, l) {
2487
2517
  const out = proveLiveness(r.machine, withKinds(r, laws), l);
2488
2518
  return { proven: out.proven, checked: out.checked, ...(out.failed ? { goal: out.failed.goal, stuck: out.failed.stuck, ...(out.failed.witness ? { witness: out.failed.witness } : {}), ...(out.failed.why ? { why: out.failed.why } : {}) } : {}) };
2489
2519
  }
2490
- export const proveDecision = (d) => goalsVerdict([d.goal]);
2520
+ export const proveDecision = (d) => (d.steps ? proveSteps(d.steps.rule, [], [d.steps.law]) : goalsVerdict([d.goal]));
2491
2521
  const seeded = (seed) => { let x = seed; return k => { x = (x * 1103515245 + 12345) % 2 ** 31; return Math.floor(x / 2 ** 31 * k); }; };
2492
2522
  // A decision's callbacks against its condition, on random params and requests: `given` and `then` each run with every
2493
2523
  // value known, against what the interpreter evaluates of the decision built from them.
@@ -0,0 +1,29 @@
1
+ import { type Law, type Machine, type State } from './machine.js';
2
+ import { type StepLaw, type Verdict, proveRule } from './dsl.js';
3
+ type AnyRule = Parameters<typeof proveRule>[0];
4
+ export type InferOptions = {
5
+ ms?: number;
6
+ runsMs?: number;
7
+ seen?: State[];
8
+ constants?: number[];
9
+ maxCandidates?: number;
10
+ first?: Verdict;
11
+ progress?: (phase: string, info: Record<string, number | string>) => void;
12
+ };
13
+ export type Found = {
14
+ law: Law;
15
+ text: string;
16
+ source?: string;
17
+ };
18
+ export type Inferred = Verdict & {
19
+ found: Found[];
20
+ stats: {
21
+ samples: number;
22
+ candidates: number;
23
+ alive: number;
24
+ proofs: number;
25
+ ms: number;
26
+ };
27
+ };
28
+ export declare function inferLaws(target: AnyRule | Machine, laws: Law[], stepLaws?: StepLaw[], opts?: InferOptions): Inferred;
29
+ export {};