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.
- package/README.md +89 -130
- package/dist/chunk-6NH64RCU.js +1016 -0
- package/dist/chunk-6NH64RCU.js.map +1 -0
- package/dist/{chunk-7VJ5CYUU.js → chunk-JZIEWVAV.js} +905 -62
- package/dist/chunk-JZIEWVAV.js.map +1 -0
- package/dist/{chunk-JVI5HFRX.js → chunk-VCDOKWVU.js} +2 -2
- package/dist/{chunk-E3ZWB645.js → chunk-YVIPJ6KM.js} +1 -1
- package/dist/chunk-YVIPJ6KM.js.map +1 -0
- package/dist/debug/index.d.ts +2 -2
- package/dist/debug/index.js +2 -2
- package/dist/doclet/index.d.ts +12 -3
- package/dist/doclet/index.js +8 -4
- package/dist/doclet/index.js.map +1 -1
- package/dist/doclet/resources/petrinet-diagrams.css +21 -0
- package/dist/doclet/resources/petrinet-diagrams.js +3575 -3573
- package/dist/dot-exporter-3STXYK74.js +9 -0
- package/dist/{render-ZGZEZ5RK.js → elk-place-YVNQFGXI.js} +3 -258
- package/dist/elk-place-YVNQFGXI.js.map +1 -0
- package/dist/{event-store-DKTenPbC.d.ts → event-store-BFX_yJ8I.d.ts} +1 -1
- package/dist/export/index.d.ts +1 -1
- package/dist/export/index.js +2 -2
- package/dist/index.d.ts +91 -38
- package/dist/index.js +368 -294
- package/dist/index.js.map +1 -1
- package/dist/pan-zoom-Cp51IkDl.d.ts +33 -0
- package/dist/{petri-net-C3LSY-vm.d.ts → petri-net-WSScMyDL.d.ts} +43 -29
- package/dist/preprocess-FN3F75JR.js +193 -0
- package/dist/preprocess-FN3F75JR.js.map +1 -0
- package/dist/render-QOHGDWNE.js +78 -0
- package/dist/render-QOHGDWNE.js.map +1 -0
- package/dist/render-dom/index.d.ts +28 -29
- package/dist/render-dom/index.js +14 -21
- package/dist/render-dom/index.js.map +1 -1
- package/dist/verification/index.d.ts +273 -7
- package/dist/verification/index.js +7 -1
- package/dist/verification/index.js.map +1 -1
- package/dist/viewer/index.d.ts +24 -32
- package/dist/viewer/index.js +9 -1003
- package/dist/viewer/index.js.map +1 -1
- package/dist/viewer/viewer.css +21 -0
- package/dist/viewer/viewer.iife.js +3575 -3573
- package/package.json +2 -2
- package/dist/chunk-7VJ5CYUU.js.map +0 -1
- package/dist/chunk-E3ZWB645.js.map +0 -1
- package/dist/dot-exporter-SHBYMMJ3.js +0 -9
- package/dist/render-ZGZEZ5RK.js.map +0 -1
- /package/dist/{chunk-JVI5HFRX.js.map → chunk-VCDOKWVU.js.map} +0 -0
- /package/dist/{dot-exporter-SHBYMMJ3.js.map → dot-exporter-3STXYK74.js.map} +0 -0
package/dist/render-dom/index.js
CHANGED
|
@@ -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
|
-
|
|
9
|
+
try {
|
|
10
|
+
opts.previousPanzoom.dispose();
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
22
13
|
}
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
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 *
|
|
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,
|
|
2
|
-
export {
|
|
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
|
-
* -
|
|
345
|
-
*
|
|
346
|
-
*
|
|
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
|
|
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-
|
|
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":[]}
|