libpetri 2.13.0 → 3.0.1

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.
Files changed (48) hide show
  1. package/README.md +89 -130
  2. package/dist/chunk-6NH64RCU.js +1016 -0
  3. package/dist/chunk-6NH64RCU.js.map +1 -0
  4. package/dist/{chunk-7VJ5CYUU.js → chunk-JZIEWVAV.js} +905 -62
  5. package/dist/chunk-JZIEWVAV.js.map +1 -0
  6. package/dist/{chunk-JVI5HFRX.js → chunk-VCDOKWVU.js} +2 -2
  7. package/dist/{chunk-E3ZWB645.js → chunk-YVIPJ6KM.js} +1 -1
  8. package/dist/chunk-YVIPJ6KM.js.map +1 -0
  9. package/dist/debug/index.d.ts +2 -2
  10. package/dist/debug/index.js +2 -2
  11. package/dist/doclet/index.d.ts +12 -3
  12. package/dist/doclet/index.js +8 -4
  13. package/dist/doclet/index.js.map +1 -1
  14. package/dist/doclet/resources/petrinet-diagrams.css +21 -0
  15. package/dist/doclet/resources/petrinet-diagrams.js +3575 -3573
  16. package/dist/dot-exporter-3STXYK74.js +9 -0
  17. package/dist/{render-ZGZEZ5RK.js → elk-place-YVNQFGXI.js} +3 -258
  18. package/dist/elk-place-YVNQFGXI.js.map +1 -0
  19. package/dist/{event-store-DKTenPbC.d.ts → event-store-BFX_yJ8I.d.ts} +1 -1
  20. package/dist/export/index.d.ts +1 -1
  21. package/dist/export/index.js +2 -2
  22. package/dist/index.d.ts +91 -38
  23. package/dist/index.js +368 -294
  24. package/dist/index.js.map +1 -1
  25. package/dist/pan-zoom-Cp51IkDl.d.ts +33 -0
  26. package/dist/{petri-net-C3LSY-vm.d.ts → petri-net-WSScMyDL.d.ts} +43 -29
  27. package/dist/preprocess-FN3F75JR.js +193 -0
  28. package/dist/preprocess-FN3F75JR.js.map +1 -0
  29. package/dist/render-QOHGDWNE.js +78 -0
  30. package/dist/render-QOHGDWNE.js.map +1 -0
  31. package/dist/render-dom/index.d.ts +28 -29
  32. package/dist/render-dom/index.js +14 -21
  33. package/dist/render-dom/index.js.map +1 -1
  34. package/dist/verification/index.d.ts +273 -7
  35. package/dist/verification/index.js +7 -1
  36. package/dist/verification/index.js.map +1 -1
  37. package/dist/viewer/index.d.ts +24 -32
  38. package/dist/viewer/index.js +9 -1003
  39. package/dist/viewer/index.js.map +1 -1
  40. package/dist/viewer/viewer.css +21 -0
  41. package/dist/viewer/viewer.iife.js +3575 -3573
  42. package/package.json +2 -2
  43. package/dist/chunk-7VJ5CYUU.js.map +0 -1
  44. package/dist/chunk-E3ZWB645.js.map +0 -1
  45. package/dist/dot-exporter-SHBYMMJ3.js +0 -9
  46. package/dist/render-ZGZEZ5RK.js.map +0 -1
  47. /package/dist/{chunk-JVI5HFRX.js.map → chunk-VCDOKWVU.js.map} +0 -0
  48. /package/dist/{dot-exporter-SHBYMMJ3.js.map → dot-exporter-3STXYK74.js.map} +0 -0
@@ -1,28 +1,21 @@
1
+ import {
2
+ DEFAULT_PANZOOM_OPTS,
3
+ mount
4
+ } from "../chunk-6NH64RCU.js";
5
+
1
6
  // src/render-dom/index.ts
2
- import { instance as vizInstance } from "@viz-js/viz";
3
- import panzoom from "panzoom";
4
- var vizPromise = null;
5
- function getViz() {
6
- if (!vizPromise) vizPromise = vizInstance();
7
- return vizPromise;
8
- }
9
- var DEFAULT_PANZOOM_OPTS = {
10
- smoothScroll: false,
11
- zoomDoubleClickSpeed: 1,
12
- maxZoom: 1e3,
13
- minZoom: 0.02
14
- };
15
7
  async function renderDotToContainer(dotSource, container, opts = {}) {
16
- const viz = await getViz();
17
- const svg = viz.renderSVGElement(dotSource, { engine: "dot" });
18
- container.innerHTML = "";
19
- container.appendChild(svg);
20
8
  if (opts.previousPanzoom) {
21
- opts.previousPanzoom.dispose();
9
+ try {
10
+ opts.previousPanzoom.dispose();
11
+ } catch {
12
+ }
22
13
  }
23
- const panzoomOpts = { ...DEFAULT_PANZOOM_OPTS, ...opts.panzoom };
24
- const instance = panzoom(svg, panzoomOpts);
25
- return { svg, panzoom: instance };
14
+ const handle = await mount(dotSource, container, {
15
+ chrome: false,
16
+ panzoom: opts.panzoom
17
+ });
18
+ return { svg: handle.svg, panzoom: handle.panzoom };
26
19
  }
27
20
  export {
28
21
  DEFAULT_PANZOOM_OPTS,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/render-dom/index.ts"],"sourcesContent":["/**\n * DOM rendering helper for libpetri DOT diagrams.\n *\n * Single source of truth for the viz.js + panzoom pipeline used by both\n * debug-ui (live sessions) and the internal dev-preview Vite app\n * (sample.dot iteration loop). Doc generators (Javadoc taglet, Rustdoc\n * build.rs, TypeDoc plugin) take a different path they shell out to the\n * Graphviz `dot` binary at build time and do not consume this module.\n *\n * Browser-only: requires `@viz-js/viz` and `panzoom` as peer dependencies.\n *\n * @module render-dom\n */\n\nimport { instance as vizInstance } from '@viz-js/viz';\nimport panzoom from 'panzoom';\n\ntype Viz = Awaited<ReturnType<typeof vizInstance>>;\nexport type PanzoomInstance = ReturnType<typeof panzoom>;\n\nlet vizPromise: Promise<Viz> | null = null;\n\n/** Memoizes the viz.js instance so loading happens only once per page. */\nfunction getViz(): Promise<Viz> {\n if (!vizPromise) vizPromise = vizInstance();\n return vizPromise;\n}\n\nexport interface RenderDotOptions {\n /**\n * Existing panzoom instance to dispose before initializing a new one.\n * Pass the value previously returned from {@link renderDotToContainer}\n * so callers don't need to track it themselves.\n */\n readonly previousPanzoom?: PanzoomInstance | null;\n /**\n * Per-call panzoom overrides. Merged on top of {@link DEFAULT_PANZOOM_OPTS},\n * so partial overrides keep the unspecified defaults (e.g. passing only\n * `smoothScroll: true` retains `maxZoom: 1000` and `minZoom: 0.02`).\n */\n readonly panzoom?: Parameters<typeof panzoom>[1];\n}\n\nexport interface RenderDotResult {\n readonly svg: SVGSVGElement;\n readonly panzoom: PanzoomInstance;\n}\n\n/**\n * Default panzoom configuration shared by debug-ui and the dev preview.\n *\n * - `maxZoom: 1000` effectively unlimited; lets users dive into ~150-node\n * diagrams without hitting an artificial ceiling.\n * - `minZoom: 0.02` — allows fitting very large nets in a small viewport.\n * - `smoothScroll: false` — sharper interactive feel.\n * - `zoomDoubleClickSpeed: 1` — single-click double-zoom toggle.\n */\nexport const DEFAULT_PANZOOM_OPTS = {\n smoothScroll: false,\n zoomDoubleClickSpeed: 1,\n maxZoom: 1000,\n minZoom: 0.02,\n} as const satisfies Parameters<typeof panzoom>[1];\n\n/**\n * Render a DOT string into a container element and wrap it with panzoom.\n *\n * Engine is pinned to `'dot'` so layout is deterministic across reloads;\n * libpetri mappers emit byte-stable DOT (per spec EXP-014) and the `dot`\n * engine produces identical SVG for identical input.\n *\n * The container's existing children are removed before the new SVG is\n * appended.\n *\n * @returns the rendered SVG element and the panzoom instance, so callers\n * can build secondary indexes (node caches, highlighting state) on the SVG\n * and dispose the panzoom on the next render.\n */\nexport async function renderDotToContainer(\n dotSource: string,\n container: HTMLElement,\n opts: RenderDotOptions = {},\n): Promise<RenderDotResult> {\n const viz = await getViz();\n const svg = viz.renderSVGElement(dotSource, { engine: 'dot' });\n\n container.innerHTML = '';\n container.appendChild(svg);\n\n if (opts.previousPanzoom) {\n opts.previousPanzoom.dispose();\n }\n\n const panzoomOpts = { ...DEFAULT_PANZOOM_OPTS, ...opts.panzoom };\n const instance = panzoom(svg, panzoomOpts);\n\n return { svg, panzoom: instance };\n}\n"],"mappings":";AAcA,SAAS,YAAY,mBAAmB;AACxC,OAAO,aAAa;AAKpB,IAAI,aAAkC;AAGtC,SAAS,SAAuB;AAC9B,MAAI,CAAC,WAAY,cAAa,YAAY;AAC1C,SAAO;AACT;AA+BO,IAAM,uBAAuB;AAAA,EAClC,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,SAAS;AAAA,EACT,SAAS;AACX;AAgBA,eAAsB,qBACpB,WACA,WACA,OAAyB,CAAC,GACA;AAC1B,QAAM,MAAM,MAAM,OAAO;AACzB,QAAM,MAAM,IAAI,iBAAiB,WAAW,EAAE,QAAQ,MAAM,CAAC;AAE7D,YAAU,YAAY;AACtB,YAAU,YAAY,GAAG;AAEzB,MAAI,KAAK,iBAAiB;AACxB,SAAK,gBAAgB,QAAQ;AAAA,EAC/B;AAEA,QAAM,cAAc,EAAE,GAAG,sBAAsB,GAAG,KAAK,QAAQ;AAC/D,QAAM,WAAW,QAAQ,KAAK,WAAW;AAEzC,SAAO,EAAE,KAAK,SAAS,SAAS;AAClC;","names":[]}
1
+ {"version":3,"sources":["../../src/render-dom/index.ts"],"sourcesContent":["/**\n * Compatibility wrapper over the canonical viewer.\n *\n * This module predates `libpetri/viewer` and used to be the shared viz.js +\n * panzoom pipeline behind debug-ui and the dev-preview app. Both moved to the\n * canonical viewer at `274cb41`, and the doc generators (Javadoc taglet,\n * `libpetri-docgen`, TypeDoc plugin) never shelled out to a `dot` binary\n * again either: they embed the viewer IIFE and mount client-side.\n *\n * What was left behind was a public export that still pinned Graphviz\n * `engine: 'dot'`, so anything reaching for it got stock spline layout with\n * diagonal edges while every first-party surface rendered ELK-placed nodes\n * with orthogonal routes. `renderDotToContainer` now delegates to\n * {@link mount}, so all render paths agree.\n *\n * Prefer importing `libpetri/viewer` directly in new code: `mount()` returns a\n * {@link ViewerHandle} with cluster collapse, subnet toggling, filtering and\n * highlight control, of which this wrapper surfaces only the SVG and the\n * panzoom instance.\n *\n * Browser-only. Requires `@viz-js/viz`, `panzoom`, and `elkjs` (the viewer's\n * default layout) as peer dependencies.\n *\n * @module render-dom\n */\n\nimport {\n DEFAULT_PANZOOM_OPTS,\n mount,\n type PanzoomInstance,\n type PanzoomOptions,\n type ViewerHandle,\n} from '../viewer/index.js';\n\nexport type { PanzoomInstance, PanzoomOptions };\n\n/**\n * Default panzoom configuration.\n *\n * Re-exported from the viewer rather than redefined here; a second copy of\n * these numbers is exactly how the two render paths drifted apart in the first\n * place.\n */\nexport { DEFAULT_PANZOOM_OPTS };\n\nexport interface RenderDotOptions {\n /**\n * Existing panzoom instance to dispose before initializing a new one.\n * Pass the value previously returned from {@link renderDotToContainer}\n * so callers don't need to track it themselves.\n */\n readonly previousPanzoom?: PanzoomInstance | null;\n /**\n * Per-call panzoom overrides. Merged on top of {@link DEFAULT_PANZOOM_OPTS},\n * so partial overrides keep the unspecified defaults (e.g. passing only\n * `smoothScroll: true` retains `maxZoom: 1000` and `minZoom: 0.02`).\n */\n readonly panzoom?: PanzoomOptions;\n}\n\nexport interface RenderDotResult {\n readonly svg: SVGSVGElement;\n readonly panzoom: PanzoomInstance;\n}\n\n/**\n * Render a DOT string into a container element and wrap it with panzoom.\n *\n * Layout is the viewer default: ELK node placement plus ELK-computed\n * orthogonal edge routes, drawn by Graphviz `nop2`. Deterministic across\n * reloads, since libpetri mappers emit byte-stable DOT (spec EXP-014) and\n * neither stage introduces randomness.\n *\n * The container's existing children are removed before the new SVG is\n * appended.\n *\n * @returns the rendered SVG element and the panzoom instance, so callers\n * can build secondary indexes (node caches, highlighting state) on the SVG\n * and dispose the panzoom on the next render.\n */\nexport async function renderDotToContainer(\n dotSource: string,\n container: HTMLElement,\n opts: RenderDotOptions = {},\n): Promise<RenderDotResult> {\n // Disposed up front rather than after the swap (the pre-viewer ordering):\n // the old instance is bound to nodes `mount` is about to discard, and a\n // panzoom still listening on a detached subtree has nothing useful to do.\n if (opts.previousPanzoom) {\n try {\n opts.previousPanzoom.dispose();\n } catch {\n // Already detached, or panzoom raised on a missing root. Either way the\n // only goal was to stop the old instance.\n }\n }\n\n const handle: ViewerHandle = await mount(dotSource, container, {\n chrome: false,\n panzoom: opts.panzoom,\n });\n\n return { svg: handle.svg, panzoom: handle.panzoom };\n}\n"],"mappings":";;;;;;AAgFA,eAAsB,qBACpB,WACA,WACA,OAAyB,CAAC,GACA;AAI1B,MAAI,KAAK,iBAAiB;AACxB,QAAI;AACF,WAAK,gBAAgB,QAAQ;AAAA,IAC/B,QAAQ;AAAA,IAGR;AAAA,EACF;AAEA,QAAM,SAAuB,MAAM,MAAM,WAAW,WAAW;AAAA,IAC7D,QAAQ;AAAA,IACR,SAAS,KAAK;AAAA,EAChB,CAAC;AAED,SAAO,EAAE,KAAK,OAAO,KAAK,SAAS,OAAO,QAAQ;AACpD;","names":[]}
@@ -1,5 +1,5 @@
1
- import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aQ as MarkingState, aR as PInvariant, aS as MarkingStateBuilder, aT as SmtProperty, aU as SmtVerificationResult } from '../petri-net-C3LSY-vm.js';
2
- export { aV as BranchPlaceBound, aW as DeadlockFree, aX as JoinedOrDeadLettered, aY as MutualExclusion, aZ as PlaceBound, a_ as Proven, a$ as SmtStatistics, b0 as TokenSupplier, b1 as Unknown, b2 as Unreachable, b3 as Verdict, $ as VerificationHarness, a0 as VerificationResult, b4 as Violated, b5 as branchPlaceBound, b6 as deadlockFree, b7 as isProven, b8 as isViolated, b9 as joinedOrDeadLettered, ba as mutualExclusion, bb as pInvariant, bc as pInvariantToString, bd as placeBound, be as propertyDescription, bf as unreachable } from '../petri-net-C3LSY-vm.js';
1
+ import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aO as MarkingState, aP as PInvariant, aQ as SmtProperty, aR as MarkingStateBuilder, aS as SmtVerificationResult } from '../petri-net-WSScMyDL.js';
2
+ export { aT as BranchPlaceBound, aU as DeadlockFree, aV as JoinedOrDeadLettered, aW as MutualExclusion, aX as PlaceBound, aY as Proven, aZ as SmtStatistics, a_ as TokenSupplier, a$ as Unknown, b0 as Unreachable, b1 as Verdict, $ as VerificationHarness, a0 as VerificationResult, b2 as Violated, b3 as branchPlaceBound, b4 as deadlockFree, b5 as isProven, b6 as isViolated, b7 as joinedOrDeadLettered, b8 as mutualExclusion, b9 as pInvariant, ba as pInvariantToString, bb as placeBound, bc as propertyDescription, bd as unreachable } from '../petri-net-WSScMyDL.js';
3
3
  import { Expr, init, Bool, FuncDecl } from 'z3-solver';
4
4
 
5
5
  /**
@@ -259,6 +259,104 @@ declare function findMinimalSiphons(flatNet: FlatNet): ReadonlySet<number>[];
259
259
  */
260
260
  declare function findMaximalTrapIn(flatNet: FlatNet, places: ReadonlySet<number>): ReadonlySet<number>;
261
261
 
262
+ /**
263
+ * @module certificate-checker
264
+ *
265
+ * Independent re-validation of the inductive invariant Z3 Spacer synthesizes
266
+ * for a `proven` verdict (the IC3 certificate).
267
+ *
268
+ * A "proven" answer from the Fixedpoint engine is only as trustworthy as Z3
269
+ * plus the CHC encoder. This module re-checks the certificate with a plain
270
+ * `ctx.Solver()` in the same Z3 WASM context, against the UNSTRENGTHENED step
271
+ * relation ({@link encodeStepRelation} — no P-invariant conjuncts), so even a
272
+ * wrong-but-validated-looking invariant strengthening can never smuggle a
273
+ * false PROVEN through. Three validity conditions, each expected UNSAT:
274
+ *
275
+ * 1. **VC1 (init)**: `¬I(M₀)` — the initial marking satisfies the invariant
276
+ * 2. **VC2 (consecution)**: `I(M) ∧ M ≥ 0 ∧ T(M,M') ∧ ¬I(M')` — the invariant
277
+ * is inductive under the unstrengthened step relation
278
+ * 3. **VC3 (safety)**: `I(M) ∧ M ≥ 0 ∧ Bad(M)` — the invariant excludes every
279
+ * property-violating marking
280
+ *
281
+ * The `M ≥ 0` domain conjunct in VC2/VC3 is sound: the net's state space is
282
+ * ℕ^P (the initial marking is non-negative, transition steps constrain
283
+ * `M' ≥ 0`, and injection steps only increment), so restricting the check to
284
+ * ℕ^P checks exactly the states the system can inhabit — while the invariant
285
+ * itself is only required to over-approximate `Reachable`, which never leaves
286
+ * ℕ^P either.
287
+ *
288
+ * **Answer AST shapes** (`fp.getAnswer()` after an UNSAT query): typically a
289
+ * top-level `and` of one definition per relation, where the `Reachable`
290
+ * definition is `forall vars. Reachable(vars) = φ` (equivalence; `iff` and the
291
+ * over-approximating `Reachable(vars) => φ` are accepted too). A ground
292
+ * (unquantified) `Reachable(args) = φ` definition is handled as well. Inside a
293
+ * `forall` the arguments of the `Reachable` application are de Bruijn
294
+ * variables; argument position `j` names place `j`, and `ctx.substituteVars`
295
+ * maps de Bruijn index `i` to its `to[i]` — the mapping is built from
296
+ * `getVarIndex` per argument, so any bound-variable order is handled.
297
+ *
298
+ * **Candidate certificate**: Spacer synthesizes its invariant against CHC
299
+ * bodies that conjoin the exactly-validated P-invariants, so the plain answer
300
+ * `I` is often inductive only RELATIVE to that strengthening (e.g. `¬(B ≥ 2)`
301
+ * relying on `A + B = 1` — bare consecution fails). The checked candidate is
302
+ * therefore `R' := I ∧ (y·M = y·M₀ for each validated P-invariant)`, with all
303
+ * three VCs proven for `R'` from scratch against the same unstrengthened step
304
+ * relation (the design shared with the Rust and Java checkers). The
305
+ * strengthening is verified, never assumed: a poisoned P-invariant fails VC1
306
+ * (wrong constant) or VC2 (wrong weights) of `R'` and the verdict downgrades,
307
+ * while a genuine strengthening-dependent certificate passes.
308
+ *
309
+ * Outcomes are split the way the caller must treat them: `failed` names the
310
+ * first VC that was not UNSAT (with the solver status and, for SAT, a witness
311
+ * marking), `unavailable` means the check could not run at all (missing or
312
+ * unparseable answer, solver error). Both withhold PROVEN; neither throws.
313
+ */
314
+
315
+ /** Z3 high-level context. Typed as `any` because z3-solver's TS types are incomplete. */
316
+ type Z3Context$1 = any;
317
+ /** Label of a validity condition, as it appears in the downgrade reason. */
318
+ type CertificateVc = 'initiation (VC1)' | 'consecution (VC2)' | 'safety (VC3)';
319
+ /**
320
+ * Outcome of the certificate check.
321
+ *
322
+ * `passed` — all three validity conditions are UNSAT; the proven verdict is
323
+ * certified independently of the Fixedpoint engine.
324
+ * `failed` — a validity condition was not UNSAT; `detail` carries the solver
325
+ * status and, when the solver produced a model, a witness marking.
326
+ * `unavailable` — the check could not run (missing/unparseable answer, solver
327
+ * error), so no VC is implicated.
328
+ *
329
+ * The caller must withhold PROVEN on `failed` and `unavailable` alike.
330
+ */
331
+ type CertificateCheckOutcome = {
332
+ readonly type: 'passed';
333
+ readonly invariant: string;
334
+ } | {
335
+ readonly type: 'failed';
336
+ readonly vc: CertificateVc;
337
+ readonly detail: string;
338
+ readonly invariant: string;
339
+ } | {
340
+ readonly type: 'unavailable';
341
+ readonly reason: string;
342
+ readonly invariant: string | null;
343
+ };
344
+ /**
345
+ * Re-validates the IC3 certificate for a proven flat-encoding verdict.
346
+ *
347
+ * @param ctx the Z3 high-level context the answer was produced in
348
+ * @param answer the raw `fp.getAnswer()` AST (null when Z3 produced none)
349
+ * @param flatNet the flat net the CHC query was encoded from
350
+ * @param initialMarking the verified initial marking (VC1)
351
+ * @param property the verified property (VC3)
352
+ * @param invariants the exactly-validated P-invariants the CHC bodies were
353
+ * strengthened with; conjoined into the CANDIDATE certificate and re-proven
354
+ * by the three VCs (never conjoined into the step relation)
355
+ * @param sinkPlaces declared sink places (deadlock-freedom VC3)
356
+ * @param timeoutMs per-VC solver timeout in milliseconds
357
+ */
358
+ declare function checkCertificate(ctx: Z3Context$1, answer: Expr | null, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[], sinkPlaces: ReadonlySet<Place<any>>, timeoutMs: number): Promise<CertificateCheckOutcome>;
359
+
262
360
  /**
263
361
  * Name-correlation fragment classifier for the ν-aware state class graph
264
362
  * (NU-050, Route B). See the Rust/Java equivalents for the full contract.
@@ -341,9 +439,10 @@ type PrioritySemantics = 'none' | 'conflict';
341
439
  * - Operates on the marking projection (integer vectors) — no timing
342
440
  * - An untimed deadlock-freedom proof is stronger than needed
343
441
  * (timing can only restrict behavior)
344
- * - Guards are ignored over-approximation is sound for safety properties
345
- * - If a counterexample is found, it may be spurious in timed/guarded
346
- * semantics the report notes this
442
+ * - Input specifications are purely structural (IO-006) there is no per-arc
443
+ * predicate for the encoder to be blind to
444
+ * - If a counterexample is found, it may be spurious in timed semantics —
445
+ * the report notes this
347
446
  *
348
447
  * Verification Pipeline:
349
448
  * 1. Flatten — expand XOR, index places, build pre/post vectors
@@ -361,6 +460,8 @@ declare class SmtVerifier {
361
460
  private readonly _budgetPlaces;
362
461
  private _environmentMode;
363
462
  private _timeoutMs;
463
+ private _certificateCheck;
464
+ private _counterexampleReplay;
364
465
  private _nuMaxClasses;
365
466
  private _fragmentMode;
366
467
  private readonly _carrierPlaces;
@@ -387,6 +488,28 @@ declare class SmtVerifier {
387
488
  */
388
489
  budgetPlaces(...places: Place<any>[]): this;
389
490
  timeout(ms: number): this;
491
+ /**
492
+ * Enables/disables the independent IC3 certificate check (default: enabled).
493
+ *
494
+ * When a proven verdict comes from the IC3/Spacer path on the flat count
495
+ * encoding, the synthesized inductive invariant is re-validated with a plain
496
+ * solver against the UNSTRENGTHENED step relation — VC1 (init), VC2
497
+ * (consecution), VC3 (safety) — so a Spacer or encoder defect cannot certify
498
+ * a false PROVEN. A certificate that fails validation downgrades the verdict
499
+ * to unknown. Structural proofs and the coloured ν-encoding are unaffected.
500
+ */
501
+ certificateCheck(enabled: boolean): this;
502
+ /**
503
+ * Enables/disables abstract counterexample replay (default: enabled).
504
+ *
505
+ * When a violated verdict comes from the flat count encoding, the decoded
506
+ * counterexample states (an order-free set — the derivation tree is walked in
507
+ * traversal order, not firing order) are re-executed TS-side against the
508
+ * abstract semantics the encoder emits (Lean's `fireA`, Basic.lean), searching
509
+ * for a firing order from M₀ to a property-violating marking. See
510
+ * `SmtVerificationResult.counterexampleConfirmed` for how each outcome lands.
511
+ */
512
+ counterexampleReplay(enabled: boolean): this;
390
513
  /**
391
514
  * Sets the class-count cap for the ν-aware state-class-graph analysis (NU-050,
392
515
  * Route B). When the symbolic name-aware graph would exceed this, the analysis
@@ -461,6 +584,13 @@ interface QueryProven {
461
584
  readonly type: 'proven';
462
585
  readonly invariantFormula: string | null;
463
586
  readonly levelInvariants: readonly string[];
587
+ /**
588
+ * The raw `fp.getAnswer()` AST backing {@link invariantFormula} — the
589
+ * IC3-synthesized inductive invariant as a Z3 expression in the runner's
590
+ * context. Consumed by the certificate checker; `null` when the solver
591
+ * configuration produced no answer.
592
+ */
593
+ readonly answer: Expr | null;
464
594
  }
465
595
  /** Counterexample found (SAT). The answer is the derivation tree. */
466
596
  interface QueryViolated {
@@ -534,22 +664,158 @@ interface EncodingResult {
534
664
  */
535
665
  declare function encode(ctx: Z3Context, fp: Z3Fixedpoint, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[], sinkPlaces?: ReadonlySet<Place<any>>): EncodingResult;
536
666
 
667
+ /**
668
+ * Structured reason why decoding degraded (never thrown — decoding a
669
+ * counterexample must not crash a violated verdict).
670
+ */
671
+ type DecodeFailure = {
672
+ readonly kind: 'no-answer';
673
+ } | {
674
+ readonly kind: 'traversal-error';
675
+ readonly message: string;
676
+ } | {
677
+ readonly kind: 'non-concrete';
678
+ readonly skipped: number;
679
+ };
680
+ /** Human-readable form of a {@link DecodeFailure} (or of a clean-but-empty walk). */
681
+ declare function describeDecodeFailure(failure: DecodeFailure | null): string;
537
682
  /**
538
683
  * Result of counterexample decoding.
539
684
  */
540
685
  interface DecodedTrace {
686
+ /**
687
+ * Reachable states in derivation-TRAVERSAL order — NOT firing order (the
688
+ * derivation tree is walked recursively, so display order is fragile).
689
+ * May contain duplicates. Kept for raw reporting; the replayer consumes
690
+ * {@link states} instead.
691
+ */
541
692
  readonly trace: readonly MarkingState[];
693
+ /** Rule names encountered during the walk (same traversal-order caveat). */
542
694
  readonly transitions: readonly string[];
695
+ /**
696
+ * The decoded Reachable states as an order-free SET, deduplicated by
697
+ * marking. This is the shape the abstract replayer chains into firing order.
698
+ */
699
+ readonly states: ReadonlySet<MarkingState>;
700
+ /**
701
+ * Structured reason when decoding degraded (partial results are still
702
+ * returned); `null` when the walk completed cleanly.
703
+ */
704
+ readonly failure: DecodeFailure | null;
543
705
  }
544
706
  /**
545
707
  * Decodes Z3 Spacer counterexample answers into Petri net marking traces.
546
708
  *
547
709
  * When Spacer finds a counterexample (property violation), it produces
548
710
  * a derivation tree showing how the error state is reachable. This function
549
- * extracts the marking at each step to produce a human-readable trace.
711
+ * extracts the marking at each `Reachable` application. The derivation is
712
+ * walked in TRAVERSAL order, so `trace` is not a firing sequence; `states`
713
+ * carries the same markings as an order-free set for the abstract replayer
714
+ * to chain. Failures degrade gracefully and are surfaced via `failure`.
550
715
  */
551
716
  declare function decode(ctx: any, answer: Expr | null, flatNet: FlatNet): DecodedTrace;
552
717
 
718
+ /**
719
+ * @module abstract-replayer
720
+ *
721
+ * Pure TS-side replayer for Spacer counterexamples over the ABSTRACT
722
+ * (untimed, value-blind) count-vector semantics — the exact semantics the CHC
723
+ * encoder emits and the Lean development verifies:
724
+ *
725
+ * - {@link enabledA} mirrors `lean/Libpetri/Basic.lean` `enabledA` and the
726
+ * encoder's `encodeEnabled` arm (smt-encoder.ts): every input place holds at
727
+ * least `pre[p]` tokens, every inhibited place is empty, every read place is
728
+ * non-empty.
729
+ * - {@link fireA} mirrors `Basic.lean` `fireA` and the encoder's `encodeFire`
730
+ * arm: a reset or consume-all (`All`/`AtLeast`) place jumps to `post[p]`;
731
+ * every other place moves by `M[p] - pre[p] + post[p]`.
732
+ * - {@link successors} mirrors one disjunct of `encodeStepRelation`: a firing
733
+ * is a successor only when its `M'` also respects `environmentBounds` (the
734
+ * `envBounds(M')` conjunct every transition disjunct carries), and one
735
+ * injection per modeled environment place whose guard admits it.
736
+ * - {@link injectA} mirrors `encodeInjectionFire`/`encodeInjectionGuard`
737
+ * (VER-006): one environment injection adds one token to the env place,
738
+ * gated by `M[p] < k` for `Bounded(k)` and unguarded for `AlwaysAvailable`.
739
+ * - {@link satisfiesBad} mirrors `encodePropertyViolation` — including the
740
+ * relax-env deadlock enablement and the declared-sink exemption — as a
741
+ * direct TS evaluator, so confirming a counterexample never needs a Z3 call.
742
+ *
743
+ * Because the abstraction over-approximates the concrete timed/valued net
744
+ * (VER-004), a decoded counterexample can be spurious. This module therefore
745
+ * only ever REPORTS an outcome ({@link ReplayOutcome}) — nothing here is
746
+ * allowed to certify by crashing, and only the `no-chain` outcome (a fully
747
+ * explored search that found no chain) is strong enough to withdraw a verdict.
748
+ */
749
+
750
+ /** An abstract marking: token count per flat place index. */
751
+ type AbstractState = readonly number[];
752
+ /** One abstract step in a replayed chain. */
753
+ type ReplayStep = {
754
+ readonly kind: 'fire';
755
+ readonly transition: string;
756
+ } | {
757
+ readonly kind: 'inject';
758
+ readonly place: string;
759
+ };
760
+ /** Options for {@link replayCounterexample}. */
761
+ interface ReplayOptions {
762
+ /** Max abstract steps searched between decoded anchors (default 3). */
763
+ readonly segmentBudget?: number;
764
+ /**
765
+ * Max search nodes ADMITTED to the whole search (default 10_000).
766
+ *
767
+ * A node is admitted when it survives the segment budget and the domination
768
+ * check; dominated successors are never admitted and never counted. The root
769
+ * (`M₀`) counts as the first admitted node, and the search stops as soon as
770
+ * `nodeBudget` nodes have been admitted and another one is due — the same
771
+ * `>=`-before-admission rule the Rust and Java replayers apply, so the same
772
+ * nominal budget means the same effective search depth in all of them.
773
+ */
774
+ readonly nodeBudget?: number;
775
+ }
776
+ /**
777
+ * Outcome of an abstract replay attempt.
778
+ *
779
+ * `confirmed` — a genuine abstract chain `M₀ → … → Bad` was found.
780
+ * `no-chain` — the search ran to completion without truncation and no chain
781
+ * exists: the counterexample is spurious or the decoder mis-read the
782
+ * derivation, and ONLY this outcome may withdraw a `violated` verdict.
783
+ * `exhausted` — the search was cut short (node or segment budget, or `M₀` was
784
+ * not among the decoded states), so nothing was proved either way.
785
+ */
786
+ type ReplayOutcome = {
787
+ readonly kind: 'confirmed';
788
+ /** The replayed chain in FIRING order, `M₀ … M_bad` inclusive. */
789
+ readonly states: readonly AbstractState[];
790
+ /** One step per consecutive pair of {@link states}. */
791
+ readonly steps: readonly ReplayStep[];
792
+ readonly nodesExplored: number;
793
+ } | {
794
+ readonly kind: 'no-chain';
795
+ readonly nodesExplored: number;
796
+ } | {
797
+ readonly kind: 'exhausted';
798
+ readonly reason: string;
799
+ readonly nodesExplored: number;
800
+ };
801
+ /**
802
+ * Attempts to re-execute a decoded (order-free) counterexample state set in
803
+ * the abstract semantics.
804
+ *
805
+ * The decoder collects Spacer's `Reachable` applications in derivation
806
+ * TRAVERSAL order, which is not firing order; this search recovers a firing
807
+ * order or reports that none exists. It is a single global breadth-first
808
+ * search from `initial` over {@link successors}, where each node carries the
809
+ * number of steps taken since the last decoded state (`segment`, reset to 0
810
+ * whenever a decoded state is reached) and a node is expanded only while that
811
+ * counter is below `segmentBudget`. A state is re-entered only when reached
812
+ * with a strictly smaller segment counter (domination by `(state, segment)`),
813
+ * and the whole search shares one `nodeBudget` counting nodes ADMITTED to the
814
+ * search — non-dominated states only, the root included (see
815
+ * {@link ReplayOptions.nodeBudget}).
816
+ */
817
+ declare function replayCounterexample(flatNet: FlatNet, initial: AbstractState, decodedStates: readonly AbstractState[], property: SmtProperty, sinkPlaces: ReadonlySet<Place<any>>, options?: ReplayOptions): ReplayOutcome;
818
+
553
819
  /**
554
820
  * Difference Bound Matrix (DBM) for Time Petri Net state class analysis.
555
821
  *
@@ -739,4 +1005,4 @@ declare class TimePetriNetAnalyzerBuilder {
739
1005
  build(): TimePetriNetAnalyzer;
740
1006
  }
741
1007
 
742
- export { type EnvironmentAnalysisMode as AnalysisEnvironmentMode, type BranchEdge, DBM, type DecodedTrace, type EncodingResult, type EnvironmentAnalysisMode, type FlatNet, type FlatTransition, IncidenceMatrix, type LivenessResult, MarkingState, MarkingStateBuilder, PInvariant, type PrioritySemantics, type QueryProven, type QueryResult, type QueryUnknown, type QueryViolated, SmtProperty, SmtVerificationResult, SmtVerifier, type SpacerContext, StateClass, StateClassGraph, type StructuralCheckResult, TimePetriNetAnalyzer, TimePetriNetAnalyzerBuilder, type XorBranchAnalysis, type XorBranchInfo, alwaysAvailable, alwaysAvailable as analysisAlwaysAvailable, bounded as analysisBounded, ignore as analysisIgnore, bounded, computePInvariants, computePSemiflows, computeSCCs, createSpacerRunner, decode, encode, findMaximalTrapIn, findMinimalSiphons, findTerminalSCCs, flatNetIndexOf, flatNetPlaceCount, flatNetTransitionCount, flatTransition, flatten, ignore, isCoveredByInvariants, structuralCheck };
1008
+ export { type AbstractState, type EnvironmentAnalysisMode as AnalysisEnvironmentMode, type BranchEdge, type CertificateCheckOutcome, type CertificateVc, DBM, type DecodeFailure, type DecodedTrace, type EncodingResult, type EnvironmentAnalysisMode, type FlatNet, type FlatTransition, IncidenceMatrix, type LivenessResult, MarkingState, MarkingStateBuilder, PInvariant, type PrioritySemantics, type QueryProven, type QueryResult, type QueryUnknown, type QueryViolated, type ReplayOptions, type ReplayOutcome, type ReplayStep, SmtProperty, SmtVerificationResult, SmtVerifier, type SpacerContext, StateClass, StateClassGraph, type StructuralCheckResult, TimePetriNetAnalyzer, TimePetriNetAnalyzerBuilder, type XorBranchAnalysis, type XorBranchInfo, alwaysAvailable, alwaysAvailable as analysisAlwaysAvailable, bounded as analysisBounded, ignore as analysisIgnore, bounded, checkCertificate, computePInvariants, computePSemiflows, computeSCCs, createSpacerRunner, decode, describeDecodeFailure, encode, findMaximalTrapIn, findMinimalSiphons, findTerminalSCCs, flatNetIndexOf, flatNetPlaceCount, flatNetTransitionCount, flatTransition, flatten, ignore, isCoveredByInvariants, replayCounterexample, structuralCheck };
@@ -9,11 +9,13 @@ import {
9
9
  alwaysAvailable,
10
10
  bounded,
11
11
  branchPlaceBound,
12
+ checkCertificate,
12
13
  computePInvariants,
13
14
  computePSemiflows,
14
15
  createSpacerRunner,
15
16
  deadlockFree,
16
17
  decode,
18
+ describeDecodeFailure,
17
19
  encode,
18
20
  enumerateBranches,
19
21
  findMaximalTrapIn,
@@ -33,9 +35,10 @@ import {
33
35
  pInvariantToString,
34
36
  placeBound,
35
37
  propertyDescription,
38
+ replayCounterexample,
36
39
  structuralCheck,
37
40
  unreachable
38
- } from "../chunk-7VJ5CYUU.js";
41
+ } from "../chunk-JZIEWVAV.js";
39
42
  import "../chunk-ATT7U5H5.js";
40
43
 
41
44
  // src/verification/analysis/scc-analyzer.ts
@@ -401,12 +404,14 @@ export {
401
404
  ignore as analysisIgnore,
402
405
  bounded,
403
406
  branchPlaceBound,
407
+ checkCertificate,
404
408
  computePInvariants,
405
409
  computePSemiflows,
406
410
  computeSCCs,
407
411
  createSpacerRunner,
408
412
  deadlockFree,
409
413
  decode,
414
+ describeDecodeFailure,
410
415
  encode,
411
416
  findMaximalTrapIn,
412
417
  findMinimalSiphons,
@@ -426,6 +431,7 @@ export {
426
431
  pInvariantToString,
427
432
  placeBound,
428
433
  propertyDescription,
434
+ replayCounterexample,
429
435
  structuralCheck,
430
436
  unreachable
431
437
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/verification/analysis/scc-analyzer.ts","../../src/verification/analysis/time-petri-net-analyzer.ts"],"sourcesContent":["/**\n * Strongly Connected Component analysis using Tarjan's algorithm.\n * Generic over node type T. Uses a key function for Map-based lookups.\n */\n\n/** Computes all SCCs in a graph. O(V + E) via Tarjan's algorithm. */\nexport function computeSCCs<T>(\n nodes: Iterable<T>,\n successors: (node: T) => Iterable<T>,\n): Set<T>[] {\n const nodeArray = [...nodes];\n const indexMap = new Map<T, number>();\n const lowlink = new Map<T, number>();\n const onStack = new Set<T>();\n const stack: T[] = [];\n const sccs: Set<T>[] = [];\n let index = 0;\n\n function strongConnect(v: T): void {\n indexMap.set(v, index);\n lowlink.set(v, index);\n index++;\n stack.push(v);\n onStack.add(v);\n\n for (const w of successors(v)) {\n if (!indexMap.has(w)) {\n strongConnect(w);\n lowlink.set(v, Math.min(lowlink.get(v)!, lowlink.get(w)!));\n } else if (onStack.has(w)) {\n lowlink.set(v, Math.min(lowlink.get(v)!, indexMap.get(w)!));\n }\n }\n\n if (lowlink.get(v) === indexMap.get(v)) {\n const scc = new Set<T>();\n let w: T;\n do {\n w = stack.pop()!;\n onStack.delete(w);\n scc.add(w);\n } while (w !== v);\n sccs.push(scc);\n }\n }\n\n for (const node of nodeArray) {\n if (!indexMap.has(node)) {\n strongConnect(node);\n }\n }\n\n return sccs;\n}\n\n/** Finds terminal (bottom) SCCs — SCCs with no outgoing edges to other SCCs. */\nexport function findTerminalSCCs<T>(\n nodes: Iterable<T>,\n successors: (node: T) => Iterable<T>,\n): Set<T>[] {\n const allSCCs = computeSCCs(nodes, successors);\n\n const terminal: Set<T>[] = [];\n for (const scc of allSCCs) {\n let isTerminal = true;\n for (const node of scc) {\n for (const succ of successors(node)) {\n if (!scc.has(succ)) {\n isTerminal = false;\n break;\n }\n }\n if (!isTerminal) break;\n }\n if (isTerminal) {\n terminal.push(scc);\n }\n }\n\n return terminal;\n}\n","import type { Place } from '../../core/place.js';\nimport type { EnvironmentPlace } from '../../core/place.js';\nimport type { Transition } from '../../core/transition.js';\nimport type { PetriNet } from '../../core/petri-net.js';\nimport { enumerateBranches } from '../../core/out.js';\nimport { MarkingState } from '../marking-state.js';\nimport { StateClassGraph } from './state-class-graph.js';\nimport type { StateClass } from './state-class.js';\nimport { computeSCCs, findTerminalSCCs } from './scc-analyzer.js';\nimport type { EnvironmentAnalysisMode } from './environment-analysis-mode.js';\nimport { ignore } from './environment-analysis-mode.js';\n\n/** Result of liveness analysis. */\nexport interface LivenessResult {\n readonly stateClassGraph: StateClassGraph;\n readonly allSCCs: Set<StateClass>[];\n readonly terminalSCCs: Set<StateClass>[];\n readonly goalClasses: Set<StateClass>;\n readonly canReachGoal: Set<StateClass>;\n readonly isGoalLive: boolean;\n readonly isL4Live: boolean;\n readonly isComplete: boolean;\n readonly report: string;\n}\n\n/** Information about XOR branch coverage for a single transition. */\nexport interface XorBranchInfo {\n readonly totalBranches: number;\n readonly takenBranches: Set<number>;\n readonly untakenBranches: Set<number>;\n readonly branchOutputs: ReadonlyArray<ReadonlySet<Place<any>>>;\n}\n\n/** Result of XOR branch analysis. */\nexport interface XorBranchAnalysis {\n readonly transitionBranches: Map<Transition, XorBranchInfo>;\n unreachableBranches(): Map<Transition, Set<number>>;\n isXorComplete(): boolean;\n report(): string;\n}\n\n/**\n * Formal analyzer for Time Petri Nets using the State Class Graph method.\n * Implements Berthomieu-Diaz (1991) analysis.\n */\nexport class TimePetriNetAnalyzer {\n private readonly net: PetriNet;\n private readonly initialMarking: MarkingState;\n private readonly goalPlaces: Set<Place<any>>;\n private readonly maxClasses: number;\n private readonly environmentPlaces: Set<EnvironmentPlace<any>>;\n private readonly environmentMode: EnvironmentAnalysisMode;\n\n /** @internal Called by builder — use `TimePetriNetAnalyzer.forNet()` instead. */\n static create(\n net: PetriNet,\n initialMarking: MarkingState,\n goalPlaces: Set<Place<any>>,\n maxClasses: number,\n environmentPlaces: Set<EnvironmentPlace<any>>,\n environmentMode: EnvironmentAnalysisMode,\n ): TimePetriNetAnalyzer {\n return new TimePetriNetAnalyzer(net, initialMarking, goalPlaces, maxClasses, environmentPlaces, environmentMode);\n }\n\n private constructor(\n net: PetriNet,\n initialMarking: MarkingState,\n goalPlaces: Set<Place<any>>,\n maxClasses: number,\n environmentPlaces: Set<EnvironmentPlace<any>>,\n environmentMode: EnvironmentAnalysisMode,\n ) {\n this.net = net;\n this.initialMarking = initialMarking;\n this.goalPlaces = goalPlaces;\n this.maxClasses = maxClasses;\n this.environmentPlaces = environmentPlaces;\n this.environmentMode = environmentMode;\n }\n\n static forNet(net: PetriNet): TimePetriNetAnalyzerBuilder {\n return new TimePetriNetAnalyzerBuilder(net);\n }\n\n /** Performs formal liveness analysis. */\n analyze(): LivenessResult {\n const report: string[] = [];\n report.push('=== TIME PETRI NET FORMAL ANALYSIS ===\\n');\n report.push(`Method: State Class Graph (Berthomieu-Diaz 1991)`);\n report.push(`Net: ${this.net.name}`);\n report.push(`Places: ${this.net.places.size}`);\n report.push(`Transitions: ${this.net.transitions.size}`);\n report.push(`Goal places: [${[...this.goalPlaces].map(p => p.name).join(', ')}]\\n`);\n\n // Phase 1: Build State Class Graph\n report.push('Phase 1: Building State Class Graph...');\n if (this.environmentPlaces.size > 0) {\n report.push(` Environment places: ${this.environmentPlaces.size}`);\n report.push(` Environment mode: ${this.environmentMode.type}`);\n }\n const scg = StateClassGraph.build(this.net, this.initialMarking, this.maxClasses, this.environmentPlaces, this.environmentMode);\n report.push(` State classes: ${scg.size()}`);\n report.push(` Edges: ${scg.edgeCount()}`);\n report.push(` Complete: ${scg.isComplete() ? 'YES' : 'NO (truncated)'}`);\n\n if (!scg.isComplete()) {\n report.push(` WARNING: State class graph truncated at ${this.maxClasses} classes. Analysis may be incomplete.`);\n }\n report.push('');\n\n // Phase 2: Identify goal state classes\n report.push('Phase 2: Identifying goal state classes...');\n const goalClasses = new Set<StateClass>();\n for (const sc of scg.stateClasses()) {\n if (sc.marking.hasTokensInAny(this.goalPlaces)) {\n goalClasses.add(sc);\n }\n }\n report.push(` Goal state classes: ${goalClasses.size}\\n`);\n\n // Phase 3: Compute SCCs\n report.push('Phase 3: Computing Strongly Connected Components...');\n const successorFn = (sc: StateClass) => scg.successors(sc);\n const allSCCs = computeSCCs(scg.stateClasses(), successorFn);\n const terminalSCCs = findTerminalSCCs(scg.stateClasses(), successorFn);\n\n report.push(` Total SCCs: ${allSCCs.length}`);\n report.push(` Terminal SCCs: ${terminalSCCs.length}\\n`);\n\n // Phase 4: Check goal liveness\n report.push('Phase 4: Verifying Goal Liveness...');\n report.push(' Property: From every reachable state, a goal state is reachable');\n\n const terminalSCCsWithGoal: Set<StateClass>[] = [];\n const terminalSCCsWithoutGoal: Set<StateClass>[] = [];\n\n for (const scc of terminalSCCs) {\n let hasGoal = false;\n for (const sc of scc) {\n if (goalClasses.has(sc)) { hasGoal = true; break; }\n }\n (hasGoal ? terminalSCCsWithGoal : terminalSCCsWithoutGoal).push(scc);\n }\n\n report.push(` Terminal SCCs with goal: ${terminalSCCsWithGoal.length}`);\n report.push(` Terminal SCCs without goal: ${terminalSCCsWithoutGoal.length}`);\n\n const canReachGoal = computeBackwardReachability(scg, goalClasses);\n const statesNotReachingGoal = scg.size() - canReachGoal.size;\n\n report.push(` States that can reach goal: ${canReachGoal.size}/${scg.size()}\\n`);\n\n const isGoalLive = terminalSCCsWithoutGoal.length === 0 && statesNotReachingGoal === 0;\n\n // Phase 5: Check classical liveness (L4)\n report.push('Phase 5: Verifying Classical Liveness (L4)...');\n report.push(' Property: Every transition can fire from every reachable marking');\n\n const allTransitions = new Set(this.net.transitions);\n const terminalSCCsMissingTransitions: Set<StateClass>[] = [];\n\n for (const scc of terminalSCCs) {\n const transitionsInSCC = new Set<Transition>();\n for (const sc of scc) {\n for (const t of scg.enabledTransitions(sc)) {\n const edges = scg.branchEdges(sc, t);\n for (const edge of edges) {\n if (scc.has(edge.target)) {\n transitionsInSCC.add(t);\n }\n }\n }\n }\n let missingAny = false;\n for (const t of allTransitions) {\n if (!transitionsInSCC.has(t)) { missingAny = true; break; }\n }\n if (missingAny) {\n terminalSCCsMissingTransitions.push(scc);\n const missing = [...allTransitions].filter(t => !transitionsInSCC.has(t));\n report.push(` Terminal SCC missing transitions: [${missing.map(t => t.name).join(', ')}]`);\n }\n }\n\n const isL4Live = terminalSCCsMissingTransitions.length === 0 && scg.isComplete();\n\n // Summary\n report.push('\\n=== ANALYSIS RESULT ===\\n');\n\n if (isGoalLive && scg.isComplete()) {\n report.push('GOAL LIVENESS VERIFIED');\n report.push(' From every reachable state class, a goal marking is reachable.');\n } else if (isGoalLive && !scg.isComplete()) {\n report.push('GOAL LIVENESS LIKELY (incomplete proof)');\n } else {\n report.push('GOAL LIVENESS VIOLATION');\n if (terminalSCCsWithoutGoal.length > 0) {\n report.push(` ${terminalSCCsWithoutGoal.length} terminal SCC(s) have no goal state.`);\n }\n if (statesNotReachingGoal > 0) {\n report.push(` ${statesNotReachingGoal} state class(es) cannot reach goal.`);\n }\n }\n\n report.push('');\n\n if (isL4Live) {\n report.push('CLASSICAL LIVENESS (L4) VERIFIED');\n } else {\n report.push('CLASSICAL LIVENESS (L4) NOT VERIFIED');\n if (terminalSCCsMissingTransitions.length > 0) {\n report.push(\" Some terminal SCCs don't contain all transitions.\");\n }\n if (!scg.isComplete()) {\n report.push(' (State class graph incomplete - cannot prove L4)');\n }\n }\n\n return {\n stateClassGraph: scg,\n allSCCs,\n terminalSCCs,\n goalClasses,\n canReachGoal,\n isGoalLive,\n isL4Live,\n isComplete: scg.isComplete(),\n report: report.join('\\n'),\n };\n }\n\n /** Analyzes XOR branch coverage for a built state class graph. */\n static analyzeXorBranches(scg: StateClassGraph): XorBranchAnalysis {\n const result = new Map<Transition, XorBranchInfo>();\n\n for (const transition of scg.net.transitions) {\n if (transition.outputSpec === null) continue;\n\n const allBranches = enumerateBranches(transition.outputSpec);\n if (allBranches.length <= 1) continue;\n\n const takenBranches = new Set<number>();\n for (const sc of scg.stateClasses()) {\n const edges = scg.branchEdges(sc, transition);\n for (const edge of edges) {\n takenBranches.add(edge.branchIndex);\n }\n }\n\n const untakenBranches = new Set<number>();\n for (let i = 0; i < allBranches.length; i++) {\n if (!takenBranches.has(i)) untakenBranches.add(i);\n }\n\n result.set(transition, {\n totalBranches: allBranches.length,\n takenBranches,\n untakenBranches,\n branchOutputs: allBranches,\n });\n }\n\n return createXorBranchAnalysis(result);\n }\n}\n\nfunction createXorBranchAnalysis(transitionBranches: Map<Transition, XorBranchInfo>): XorBranchAnalysis {\n return {\n transitionBranches,\n unreachableBranches(): Map<Transition, Set<number>> {\n const result = new Map<Transition, Set<number>>();\n for (const [t, info] of transitionBranches) {\n if (info.untakenBranches.size > 0) {\n result.set(t, info.untakenBranches);\n }\n }\n return result;\n },\n isXorComplete(): boolean {\n for (const info of transitionBranches.values()) {\n if (info.untakenBranches.size > 0) return false;\n }\n return true;\n },\n report(): string {\n if (transitionBranches.size === 0) return 'No XOR transitions in net.';\n\n const lines: string[] = [];\n lines.push('XOR Branch Coverage Analysis');\n lines.push('============================\\n');\n\n for (const [t, info] of transitionBranches) {\n lines.push(`Transition: ${t.name}`);\n lines.push(` Branches: ${info.totalBranches}`);\n lines.push(` Taken: [${[...info.takenBranches].join(', ')}]`);\n\n if (info.untakenBranches.size > 0) {\n lines.push(` UNREACHABLE: [${[...info.untakenBranches].join(', ')}]`);\n for (const idx of info.untakenBranches) {\n const places = [...info.branchOutputs[idx]!].map(p => p.name).join(', ');\n lines.push(` Branch ${idx} outputs: [${places}]`);\n }\n } else {\n lines.push(' All branches reachable');\n }\n lines.push('');\n }\n\n if (this.isXorComplete()) {\n lines.push('RESULT: All XOR branches are reachable.');\n } else {\n lines.push('RESULT: Some XOR branches are unreachable!');\n }\n\n return lines.join('\\n');\n },\n };\n}\n\nfunction computeBackwardReachability(scg: StateClassGraph, goals: Set<StateClass>): Set<StateClass> {\n const reachable = new Set(goals);\n const queue = [...goals];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const pred of scg.predecessors(current)) {\n if (!reachable.has(pred)) {\n reachable.add(pred);\n queue.push(pred);\n }\n }\n }\n\n return reachable;\n}\n\n/** Builder for TimePetriNetAnalyzer. */\nexport class TimePetriNetAnalyzerBuilder {\n private readonly net: PetriNet;\n private _initialMarking: MarkingState = MarkingState.empty();\n private readonly _goalPlaces = new Set<Place<any>>();\n private _maxClasses = 100_000;\n private readonly _environmentPlaces = new Set<EnvironmentPlace<any>>();\n private _environmentMode: EnvironmentAnalysisMode = ignore();\n\n constructor(net: PetriNet) {\n this.net = net;\n }\n\n initialMarking(marking: MarkingState): this {\n this._initialMarking = marking;\n return this;\n }\n\n goalPlaces(...places: Place<any>[]): this {\n for (const p of places) this._goalPlaces.add(p);\n return this;\n }\n\n maxClasses(max: number): this {\n this._maxClasses = max;\n return this;\n }\n\n environmentPlaces(...places: EnvironmentPlace<any>[]): this {\n for (const ep of places) this._environmentPlaces.add(ep);\n return this;\n }\n\n environmentMode(mode: EnvironmentAnalysisMode): this {\n this._environmentMode = mode;\n return this;\n }\n\n build(): TimePetriNetAnalyzer {\n if (this._goalPlaces.size === 0) {\n throw new Error('At least one goal place must be specified');\n }\n return TimePetriNetAnalyzer.create(\n this.net,\n this._initialMarking,\n this._goalPlaces,\n this._maxClasses,\n this._environmentPlaces,\n this._environmentMode,\n );\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/verification/analysis/scc-analyzer.ts","../../src/verification/analysis/time-petri-net-analyzer.ts"],"sourcesContent":["/**\n * Strongly Connected Component analysis using Tarjan's algorithm.\n * Generic over node type T. Uses a key function for Map-based lookups.\n */\n\n/** Computes all SCCs in a graph. O(V + E) via Tarjan's algorithm. */\nexport function computeSCCs<T>(\n nodes: Iterable<T>,\n successors: (node: T) => Iterable<T>,\n): Set<T>[] {\n const nodeArray = [...nodes];\n const indexMap = new Map<T, number>();\n const lowlink = new Map<T, number>();\n const onStack = new Set<T>();\n const stack: T[] = [];\n const sccs: Set<T>[] = [];\n let index = 0;\n\n function strongConnect(v: T): void {\n indexMap.set(v, index);\n lowlink.set(v, index);\n index++;\n stack.push(v);\n onStack.add(v);\n\n for (const w of successors(v)) {\n if (!indexMap.has(w)) {\n strongConnect(w);\n lowlink.set(v, Math.min(lowlink.get(v)!, lowlink.get(w)!));\n } else if (onStack.has(w)) {\n lowlink.set(v, Math.min(lowlink.get(v)!, indexMap.get(w)!));\n }\n }\n\n if (lowlink.get(v) === indexMap.get(v)) {\n const scc = new Set<T>();\n let w: T;\n do {\n w = stack.pop()!;\n onStack.delete(w);\n scc.add(w);\n } while (w !== v);\n sccs.push(scc);\n }\n }\n\n for (const node of nodeArray) {\n if (!indexMap.has(node)) {\n strongConnect(node);\n }\n }\n\n return sccs;\n}\n\n/** Finds terminal (bottom) SCCs — SCCs with no outgoing edges to other SCCs. */\nexport function findTerminalSCCs<T>(\n nodes: Iterable<T>,\n successors: (node: T) => Iterable<T>,\n): Set<T>[] {\n const allSCCs = computeSCCs(nodes, successors);\n\n const terminal: Set<T>[] = [];\n for (const scc of allSCCs) {\n let isTerminal = true;\n for (const node of scc) {\n for (const succ of successors(node)) {\n if (!scc.has(succ)) {\n isTerminal = false;\n break;\n }\n }\n if (!isTerminal) break;\n }\n if (isTerminal) {\n terminal.push(scc);\n }\n }\n\n return terminal;\n}\n","import type { Place } from '../../core/place.js';\nimport type { EnvironmentPlace } from '../../core/place.js';\nimport type { Transition } from '../../core/transition.js';\nimport type { PetriNet } from '../../core/petri-net.js';\nimport { enumerateBranches } from '../../core/out.js';\nimport { MarkingState } from '../marking-state.js';\nimport { StateClassGraph } from './state-class-graph.js';\nimport type { StateClass } from './state-class.js';\nimport { computeSCCs, findTerminalSCCs } from './scc-analyzer.js';\nimport type { EnvironmentAnalysisMode } from './environment-analysis-mode.js';\nimport { ignore } from './environment-analysis-mode.js';\n\n/** Result of liveness analysis. */\nexport interface LivenessResult {\n readonly stateClassGraph: StateClassGraph;\n readonly allSCCs: Set<StateClass>[];\n readonly terminalSCCs: Set<StateClass>[];\n readonly goalClasses: Set<StateClass>;\n readonly canReachGoal: Set<StateClass>;\n readonly isGoalLive: boolean;\n readonly isL4Live: boolean;\n readonly isComplete: boolean;\n readonly report: string;\n}\n\n/** Information about XOR branch coverage for a single transition. */\nexport interface XorBranchInfo {\n readonly totalBranches: number;\n readonly takenBranches: Set<number>;\n readonly untakenBranches: Set<number>;\n readonly branchOutputs: ReadonlyArray<ReadonlySet<Place<any>>>;\n}\n\n/** Result of XOR branch analysis. */\nexport interface XorBranchAnalysis {\n readonly transitionBranches: Map<Transition, XorBranchInfo>;\n unreachableBranches(): Map<Transition, Set<number>>;\n isXorComplete(): boolean;\n report(): string;\n}\n\n/**\n * Formal analyzer for Time Petri Nets using the State Class Graph method.\n * Implements Berthomieu-Diaz (1991) analysis.\n */\nexport class TimePetriNetAnalyzer {\n private readonly net: PetriNet;\n private readonly initialMarking: MarkingState;\n private readonly goalPlaces: Set<Place<any>>;\n private readonly maxClasses: number;\n private readonly environmentPlaces: Set<EnvironmentPlace<any>>;\n private readonly environmentMode: EnvironmentAnalysisMode;\n\n /** @internal Called by builder — use `TimePetriNetAnalyzer.forNet()` instead. */\n static create(\n net: PetriNet,\n initialMarking: MarkingState,\n goalPlaces: Set<Place<any>>,\n maxClasses: number,\n environmentPlaces: Set<EnvironmentPlace<any>>,\n environmentMode: EnvironmentAnalysisMode,\n ): TimePetriNetAnalyzer {\n return new TimePetriNetAnalyzer(net, initialMarking, goalPlaces, maxClasses, environmentPlaces, environmentMode);\n }\n\n private constructor(\n net: PetriNet,\n initialMarking: MarkingState,\n goalPlaces: Set<Place<any>>,\n maxClasses: number,\n environmentPlaces: Set<EnvironmentPlace<any>>,\n environmentMode: EnvironmentAnalysisMode,\n ) {\n this.net = net;\n this.initialMarking = initialMarking;\n this.goalPlaces = goalPlaces;\n this.maxClasses = maxClasses;\n this.environmentPlaces = environmentPlaces;\n this.environmentMode = environmentMode;\n }\n\n static forNet(net: PetriNet): TimePetriNetAnalyzerBuilder {\n return new TimePetriNetAnalyzerBuilder(net);\n }\n\n /** Performs formal liveness analysis. */\n analyze(): LivenessResult {\n const report: string[] = [];\n report.push('=== TIME PETRI NET FORMAL ANALYSIS ===\\n');\n report.push(`Method: State Class Graph (Berthomieu-Diaz 1991)`);\n report.push(`Net: ${this.net.name}`);\n report.push(`Places: ${this.net.places.size}`);\n report.push(`Transitions: ${this.net.transitions.size}`);\n report.push(`Goal places: [${[...this.goalPlaces].map(p => p.name).join(', ')}]\\n`);\n\n // Phase 1: Build State Class Graph\n report.push('Phase 1: Building State Class Graph...');\n if (this.environmentPlaces.size > 0) {\n report.push(` Environment places: ${this.environmentPlaces.size}`);\n report.push(` Environment mode: ${this.environmentMode.type}`);\n }\n const scg = StateClassGraph.build(this.net, this.initialMarking, this.maxClasses, this.environmentPlaces, this.environmentMode);\n report.push(` State classes: ${scg.size()}`);\n report.push(` Edges: ${scg.edgeCount()}`);\n report.push(` Complete: ${scg.isComplete() ? 'YES' : 'NO (truncated)'}`);\n\n if (!scg.isComplete()) {\n report.push(` WARNING: State class graph truncated at ${this.maxClasses} classes. Analysis may be incomplete.`);\n }\n report.push('');\n\n // Phase 2: Identify goal state classes\n report.push('Phase 2: Identifying goal state classes...');\n const goalClasses = new Set<StateClass>();\n for (const sc of scg.stateClasses()) {\n if (sc.marking.hasTokensInAny(this.goalPlaces)) {\n goalClasses.add(sc);\n }\n }\n report.push(` Goal state classes: ${goalClasses.size}\\n`);\n\n // Phase 3: Compute SCCs\n report.push('Phase 3: Computing Strongly Connected Components...');\n const successorFn = (sc: StateClass) => scg.successors(sc);\n const allSCCs = computeSCCs(scg.stateClasses(), successorFn);\n const terminalSCCs = findTerminalSCCs(scg.stateClasses(), successorFn);\n\n report.push(` Total SCCs: ${allSCCs.length}`);\n report.push(` Terminal SCCs: ${terminalSCCs.length}\\n`);\n\n // Phase 4: Check goal liveness\n report.push('Phase 4: Verifying Goal Liveness...');\n report.push(' Property: From every reachable state, a goal state is reachable');\n\n const terminalSCCsWithGoal: Set<StateClass>[] = [];\n const terminalSCCsWithoutGoal: Set<StateClass>[] = [];\n\n for (const scc of terminalSCCs) {\n let hasGoal = false;\n for (const sc of scc) {\n if (goalClasses.has(sc)) { hasGoal = true; break; }\n }\n (hasGoal ? terminalSCCsWithGoal : terminalSCCsWithoutGoal).push(scc);\n }\n\n report.push(` Terminal SCCs with goal: ${terminalSCCsWithGoal.length}`);\n report.push(` Terminal SCCs without goal: ${terminalSCCsWithoutGoal.length}`);\n\n const canReachGoal = computeBackwardReachability(scg, goalClasses);\n const statesNotReachingGoal = scg.size() - canReachGoal.size;\n\n report.push(` States that can reach goal: ${canReachGoal.size}/${scg.size()}\\n`);\n\n const isGoalLive = terminalSCCsWithoutGoal.length === 0 && statesNotReachingGoal === 0;\n\n // Phase 5: Check classical liveness (L4)\n report.push('Phase 5: Verifying Classical Liveness (L4)...');\n report.push(' Property: Every transition can fire from every reachable marking');\n\n const allTransitions = new Set(this.net.transitions);\n const terminalSCCsMissingTransitions: Set<StateClass>[] = [];\n\n for (const scc of terminalSCCs) {\n const transitionsInSCC = new Set<Transition>();\n for (const sc of scc) {\n for (const t of scg.enabledTransitions(sc)) {\n const edges = scg.branchEdges(sc, t);\n for (const edge of edges) {\n if (scc.has(edge.target)) {\n transitionsInSCC.add(t);\n }\n }\n }\n }\n let missingAny = false;\n for (const t of allTransitions) {\n if (!transitionsInSCC.has(t)) { missingAny = true; break; }\n }\n if (missingAny) {\n terminalSCCsMissingTransitions.push(scc);\n const missing = [...allTransitions].filter(t => !transitionsInSCC.has(t));\n report.push(` Terminal SCC missing transitions: [${missing.map(t => t.name).join(', ')}]`);\n }\n }\n\n const isL4Live = terminalSCCsMissingTransitions.length === 0 && scg.isComplete();\n\n // Summary\n report.push('\\n=== ANALYSIS RESULT ===\\n');\n\n if (isGoalLive && scg.isComplete()) {\n report.push('GOAL LIVENESS VERIFIED');\n report.push(' From every reachable state class, a goal marking is reachable.');\n } else if (isGoalLive && !scg.isComplete()) {\n report.push('GOAL LIVENESS LIKELY (incomplete proof)');\n } else {\n report.push('GOAL LIVENESS VIOLATION');\n if (terminalSCCsWithoutGoal.length > 0) {\n report.push(` ${terminalSCCsWithoutGoal.length} terminal SCC(s) have no goal state.`);\n }\n if (statesNotReachingGoal > 0) {\n report.push(` ${statesNotReachingGoal} state class(es) cannot reach goal.`);\n }\n }\n\n report.push('');\n\n if (isL4Live) {\n report.push('CLASSICAL LIVENESS (L4) VERIFIED');\n } else {\n report.push('CLASSICAL LIVENESS (L4) NOT VERIFIED');\n if (terminalSCCsMissingTransitions.length > 0) {\n report.push(\" Some terminal SCCs don't contain all transitions.\");\n }\n if (!scg.isComplete()) {\n report.push(' (State class graph incomplete - cannot prove L4)');\n }\n }\n\n return {\n stateClassGraph: scg,\n allSCCs,\n terminalSCCs,\n goalClasses,\n canReachGoal,\n isGoalLive,\n isL4Live,\n isComplete: scg.isComplete(),\n report: report.join('\\n'),\n };\n }\n\n /** Analyzes XOR branch coverage for a built state class graph. */\n static analyzeXorBranches(scg: StateClassGraph): XorBranchAnalysis {\n const result = new Map<Transition, XorBranchInfo>();\n\n for (const transition of scg.net.transitions) {\n if (transition.outputSpec === null) continue;\n\n const allBranches = enumerateBranches(transition.outputSpec);\n if (allBranches.length <= 1) continue;\n\n const takenBranches = new Set<number>();\n for (const sc of scg.stateClasses()) {\n const edges = scg.branchEdges(sc, transition);\n for (const edge of edges) {\n takenBranches.add(edge.branchIndex);\n }\n }\n\n const untakenBranches = new Set<number>();\n for (let i = 0; i < allBranches.length; i++) {\n if (!takenBranches.has(i)) untakenBranches.add(i);\n }\n\n result.set(transition, {\n totalBranches: allBranches.length,\n takenBranches,\n untakenBranches,\n branchOutputs: allBranches,\n });\n }\n\n return createXorBranchAnalysis(result);\n }\n}\n\nfunction createXorBranchAnalysis(transitionBranches: Map<Transition, XorBranchInfo>): XorBranchAnalysis {\n return {\n transitionBranches,\n unreachableBranches(): Map<Transition, Set<number>> {\n const result = new Map<Transition, Set<number>>();\n for (const [t, info] of transitionBranches) {\n if (info.untakenBranches.size > 0) {\n result.set(t, info.untakenBranches);\n }\n }\n return result;\n },\n isXorComplete(): boolean {\n for (const info of transitionBranches.values()) {\n if (info.untakenBranches.size > 0) return false;\n }\n return true;\n },\n report(): string {\n if (transitionBranches.size === 0) return 'No XOR transitions in net.';\n\n const lines: string[] = [];\n lines.push('XOR Branch Coverage Analysis');\n lines.push('============================\\n');\n\n for (const [t, info] of transitionBranches) {\n lines.push(`Transition: ${t.name}`);\n lines.push(` Branches: ${info.totalBranches}`);\n lines.push(` Taken: [${[...info.takenBranches].join(', ')}]`);\n\n if (info.untakenBranches.size > 0) {\n lines.push(` UNREACHABLE: [${[...info.untakenBranches].join(', ')}]`);\n for (const idx of info.untakenBranches) {\n const places = [...info.branchOutputs[idx]!].map(p => p.name).join(', ');\n lines.push(` Branch ${idx} outputs: [${places}]`);\n }\n } else {\n lines.push(' All branches reachable');\n }\n lines.push('');\n }\n\n if (this.isXorComplete()) {\n lines.push('RESULT: All XOR branches are reachable.');\n } else {\n lines.push('RESULT: Some XOR branches are unreachable!');\n }\n\n return lines.join('\\n');\n },\n };\n}\n\nfunction computeBackwardReachability(scg: StateClassGraph, goals: Set<StateClass>): Set<StateClass> {\n const reachable = new Set(goals);\n const queue = [...goals];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const pred of scg.predecessors(current)) {\n if (!reachable.has(pred)) {\n reachable.add(pred);\n queue.push(pred);\n }\n }\n }\n\n return reachable;\n}\n\n/** Builder for TimePetriNetAnalyzer. */\nexport class TimePetriNetAnalyzerBuilder {\n private readonly net: PetriNet;\n private _initialMarking: MarkingState = MarkingState.empty();\n private readonly _goalPlaces = new Set<Place<any>>();\n private _maxClasses = 100_000;\n private readonly _environmentPlaces = new Set<EnvironmentPlace<any>>();\n private _environmentMode: EnvironmentAnalysisMode = ignore();\n\n constructor(net: PetriNet) {\n this.net = net;\n }\n\n initialMarking(marking: MarkingState): this {\n this._initialMarking = marking;\n return this;\n }\n\n goalPlaces(...places: Place<any>[]): this {\n for (const p of places) this._goalPlaces.add(p);\n return this;\n }\n\n maxClasses(max: number): this {\n this._maxClasses = max;\n return this;\n }\n\n environmentPlaces(...places: EnvironmentPlace<any>[]): this {\n for (const ep of places) this._environmentPlaces.add(ep);\n return this;\n }\n\n environmentMode(mode: EnvironmentAnalysisMode): this {\n this._environmentMode = mode;\n return this;\n }\n\n build(): TimePetriNetAnalyzer {\n if (this._goalPlaces.size === 0) {\n throw new Error('At least one goal place must be specified');\n }\n return TimePetriNetAnalyzer.create(\n this.net,\n this._initialMarking,\n this._goalPlaces,\n this._maxClasses,\n this._environmentPlaces,\n this._environmentMode,\n );\n }\n}\n"],"mappings":"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","names":[]}