gdp-wired 0.12.4 → 0.12.5

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
@@ -234,7 +234,9 @@ const soon = retry.law('the next try is at most 64 after the last request', ({ne
234
234
  lemmas too, at the list's end and wherever it reads the list. A lemma reads the folds, the prefix's length and the
235
235
  params, not the items: a fact about every item is a fold's (a count of the items that meet it). A fold's start and
236
236
  step, and a lemma, may read the params (`{from: ({fee}) => fee, step: (acc, line, {ceil}) => acc.plus(min(line.amount, ceil))}`); a request is then
237
- encoded with them, `rule.encodeInput(values, params)` (`examples/invoices.ts`).
237
+ encoded with them, `rule.encodeInput(values, params)` (`examples/invoices.ts`). `rule.foldsOf({Lines: [...]}, params)`
238
+ gives each fold at the list's end, computed the same way, without running the rule (to compare a decision's folds
239
+ with the code it describes).
238
240
  - **Folds over trees** (`fold(name).params(...).inputs(...).leaf(env => ({...})).node((env, left, right) => ({...}))`,
239
241
  `proveFold`): a tree as a value (`{leaf: inputs}` or `{node: inputs, left, right}`), each leaf's values from its inputs
240
242
  and each node's from its own and its children's; a law about the values is proven by induction over the tree (the
@@ -598,6 +598,11 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
598
598
  }, params?: {
599
599
  [k in keyof P]: Raw;
600
600
  }): Request;
601
+ foldsOf(values: {
602
+ [k in keyof I]?: I[k] extends CarriedList<any, any> ? readonly Raw[] : never;
603
+ }, params?: {
604
+ [k in keyof P]: Raw;
605
+ }): Record<string, Record<string, number>>;
601
606
  randomParams(rand: Rand, bound: number): Record<string, number>;
602
607
  private paramValues;
603
608
  randomInput(rand: Rand, bound: number, ps?: Record<string, number>): Request;
package/dist/core/dsl.js CHANGED
@@ -2160,6 +2160,16 @@ export class Rule {
2160
2160
  }
2161
2161
  return out;
2162
2162
  }
2163
+ // Each carried list's folds at its end (what `L.fold.<f>` reads), computed from its items as encodeInput computes
2164
+ // them, without running the rule: `foldsOf({Lines: [...]})` → {Lines: {total: 30}}. Only the lists given.
2165
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2166
+ foldsOf(values, params) {
2167
+ const at = params && this.paramValues(this.encodeParams(params));
2168
+ return Object.fromEntries((this.spec.lists2 ?? []).filter(([n]) => n in values).map(([n, k, fs]) => {
2169
+ const { maps, len } = new CarriedList(n, k, v(`${n}_len`), fs, part => new MapRef(part, 0), {}, at).encode(values[n]);
2170
+ return [n, Object.fromEntries(Object.keys(fs).map(f => [f, maps[`${n}$${f}`].get(len) ?? 0]))];
2171
+ }));
2172
+ }
2163
2173
  // Random params and inputs that meet their kinds (not the user's `pre` or `assume`, which a caller checks).
2164
2174
  randomParams(rand, bound) { return Object.assign({}, ...this.spec.params.map(([n, k]) => k.random(n, rand, bound))); }
2165
2175
  // The params' values by their kinds, as constants (what a fold that reads them is computed with).
@@ -667,14 +667,15 @@ const flagInstances = (m, keys, focus = []) => Object.fromEntries(Object.entries
667
667
  }));
668
668
  // A k-step law whose steps keep a condition (a flag that holds at one step and is read again at the next) fails at a
669
669
  // later step's witness only where the condition held before: so, per quantified flag over one key, the instances at the
670
- // law's own keys and that flag's witness at every step (a later step's witness is a key an earlier frame may name, as a
671
- // flag holds at every key: kernel.ts's checkStepLaws). Few instances, where the shared ones are many and mostly idle.
670
+ // law's own keys and that flag's witness at every step (a later step's input or witness is a key an earlier frame may
671
+ // name, as a flag holds at every key: kernel.ts's checkStepLaws). Few instances, where the shared ones are many and
672
+ // mostly idle.
672
673
  const keptAcross = (m, laws, inst, own, k) => k < 2 ? [] : Object.entries(m.step.flags ?? {}).flatMap(([f, c]) => {
673
674
  if (c.op !== 'all' || c.keys?.length)
674
675
  return [];
675
676
  const ws = Array.from({ length: k }, (_, i) => ({ op: 'var', name: i ? `w?${f}@${i + 1}` : `w?${f}` })), keys = [...own, ...ws.slice(0, 1)];
676
677
  const keep = new Set(keys.map(e => JSON.stringify(e)));
677
- return [Object.fromEntries(Object.entries(inst).map(([n, ks]) => [n, arity(m, laws, n) === 1 ? [...ks.filter(e => keep.has(JSON.stringify(e))), ...(n === `?${f}` ? ws.slice(1) : [])] : ks]))];
678
+ return [Object.fromEntries(Object.entries(inst).map(([n, ks]) => [n, n === `?${f}` ? [...keys, ...ws.slice(1)].filter((e, i, all) => all.findIndex(o => JSON.stringify(o) === JSON.stringify(e)) === i) : arity(m, laws, n) === 1 ? ks.filter(e => keep.has(JSON.stringify(e))) : ks]))];
678
679
  });
679
680
  const pairFlags = (m) => Object.values(m.step.flags ?? {}).some(c => c.op === 'all' && !!c.keys?.length);
680
681
  // How many keys each instance of a name takes: a law's, or a quantified flag's (?f).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdp-wired",
3
- "version": "0.12.4",
3
+ "version": "0.12.5",
4
4
  "description": "An automatic prover for stateful rules (budgets, caps, windows, workflows, policies): laws proven with no proof to write, checked again in Lean, counterexamples found on the GPU, the rule shipped as code",
5
5
  "keywords": [
6
6
  "verification",