libpetri 3.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/{chunk-JZIEWVAV.js → chunk-FD3S4TZM.js} +1330 -1077
- package/dist/chunk-FD3S4TZM.js.map +1 -0
- package/dist/{chunk-6NH64RCU.js → chunk-GJAHGHGT.js} +2 -2
- package/dist/debug/index.d.ts +2 -2
- package/dist/doclet/index.d.ts +1 -1
- package/dist/doclet/resources/petrinet-diagrams.js +6364 -6360
- package/dist/{event-store-BFX_yJ8I.d.ts → event-store-B3ppVTpO.d.ts} +1 -1
- package/dist/export/index.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/{petri-net-WSScMyDL.d.ts → petri-net-p0ONpSAO.d.ts} +32 -2
- package/dist/render-dom/index.js +1 -1
- package/dist/verification/index.d.ts +307 -214
- package/dist/verification/index.js +39 -7
- package/dist/verification/index.js.map +1 -1
- package/dist/viewer/index.js +1 -1
- package/dist/viewer/viewer.iife.js +6364 -6360
- package/package.json +4 -7
- package/dist/chunk-JZIEWVAV.js.map +0 -1
- /package/dist/{chunk-6NH64RCU.js.map → chunk-GJAHGHGT.js.map} +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aO as
|
|
2
|
-
export {
|
|
3
|
-
import { Expr, init, Bool, FuncDecl } from 'z3-solver';
|
|
1
|
+
import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aO as EnvironmentAnalysisMode, aP as PInvariant, aQ as MarkingState, aR as SmtProperty, aS as MarkingStateBuilder, aT as SmtVerificationResult } from '../petri-net-p0ONpSAO.js';
|
|
2
|
+
export { aU as BranchPlaceBound, aV as DeadlockFree, aW as JoinedOrDeadLettered, aX as MutualExclusion, aY as PlaceBound, aZ as Proven, a_ as SmtStatistics, a$ as TokenSupplier, b0 as Unknown, b1 as Unreachable, b2 as Verdict, $ as VerificationHarness, a0 as VerificationResult, b3 as Violated, b4 as alwaysAvailable, b4 as analysisAlwaysAvailable, b5 as analysisBounded, b6 as analysisIgnore, b5 as bounded, b7 as branchPlaceBound, b8 as deadlockFree, b6 as ignore, b9 as isProven, ba as isViolated, bb as joinedOrDeadLettered, bc as mutualExclusion, bd as pInvariant, be as pInvariantToString, bf as placeBound, bg as propertyDescription, bh as unreachable } from '../petri-net-p0ONpSAO.js';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* A flattened transition with pre/post vectors for SMT encoding.
|
|
@@ -100,24 +99,6 @@ declare class IncidenceMatrix {
|
|
|
100
99
|
numPlaces(): number;
|
|
101
100
|
}
|
|
102
101
|
|
|
103
|
-
/**
|
|
104
|
-
* Analysis mode for environment places in state class graph construction.
|
|
105
|
-
*/
|
|
106
|
-
type EnvironmentAnalysisMode = {
|
|
107
|
-
readonly type: 'always-available';
|
|
108
|
-
} | {
|
|
109
|
-
readonly type: 'bounded';
|
|
110
|
-
readonly maxTokens: number;
|
|
111
|
-
} | {
|
|
112
|
-
readonly type: 'ignore';
|
|
113
|
-
};
|
|
114
|
-
/** Assumes environment places always have sufficient tokens. */
|
|
115
|
-
declare function alwaysAvailable(): EnvironmentAnalysisMode;
|
|
116
|
-
/** Analyzes with a bounded number of tokens in environment places. */
|
|
117
|
-
declare function bounded(maxTokens: number): EnvironmentAnalysisMode;
|
|
118
|
-
/** Treats environment places as regular places (default). */
|
|
119
|
-
declare function ignore(): EnvironmentAnalysisMode;
|
|
120
|
-
|
|
121
102
|
/**
|
|
122
103
|
* @module net-flattener
|
|
123
104
|
*
|
|
@@ -182,22 +163,35 @@ declare function flatten(net: PetriNet, environmentPlaces?: Set<EnvironmentPlace
|
|
|
182
163
|
*/
|
|
183
164
|
declare function computePInvariants(matrix: IncidenceMatrix, flatNet: FlatNet, initialMarking: MarkingState): PInvariant[];
|
|
184
165
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* a genuine P-semiflow, with `constant = y·M0`. A non-negative conservation law
|
|
189
|
-
* soundly **bounds** the token sum over its support: `Σ_{support} M(p) ≤ y·M0`. Used
|
|
190
|
-
* to bound the number of simultaneously-live colours in the name-coloured encoder
|
|
191
|
-
* (see `colourSlotBound`).
|
|
166
|
+
* VER-007 — the semiflow union. Appends every gate-validated P-semiflow that is not
|
|
167
|
+
* already a basis row (same weights, same constant) to `invariants`, returning the
|
|
168
|
+
* strengthened list and how many rows were added.
|
|
192
169
|
*
|
|
193
|
-
*
|
|
170
|
+
* The null-space basis is one basis of many: elimination hands back mixed-sign rows
|
|
171
|
+
* and rows that fold a reset place into a chain whose other combinations avoid it,
|
|
172
|
+
* both lost to the exact gate — on a reset-heavy net every law of the chains those
|
|
173
|
+
* arcs touch, leaving IC3 to rediscover conservation it cannot within any practical
|
|
174
|
+
* budget. The Farkas rows ({@link computePSemiflows}) are the minimal laws of the
|
|
175
|
+
* net. Conjoining them alongside the basis is pure strengthening (`Semiflow.lean`,
|
|
176
|
+
* `semiflow_union_sound`) **provided both lists passed the same exact gate**
|
|
177
|
+
* (`semiflow_gate_is_necessary`) — the caller's obligation; this only merges.
|
|
194
178
|
*/
|
|
179
|
+
declare function strengthenWithSemiflows(invariants: readonly PInvariant[], semiflows: readonly PInvariant[]): {
|
|
180
|
+
readonly invariants: readonly PInvariant[];
|
|
181
|
+
readonly added: number;
|
|
182
|
+
};
|
|
195
183
|
declare function computePSemiflows(matrix: IncidenceMatrix, flatNet: FlatNet, initialMarking: MarkingState): PInvariant[];
|
|
196
184
|
/**
|
|
197
185
|
* Checks if every place is covered by at least one P-invariant.
|
|
198
186
|
* If true, the net is structurally bounded.
|
|
199
187
|
*/
|
|
200
188
|
declare function isCoveredByInvariants(invariants: readonly PInvariant[], numPlaces: number): boolean;
|
|
189
|
+
/**
|
|
190
|
+
* The invariants in canonical order (VER-013): by ascending support, then weights,
|
|
191
|
+
* then constant, each compared lexicographically. The same order the Rust and Java
|
|
192
|
+
* verifiers apply, so the strengthened scripts are byte-identical.
|
|
193
|
+
*/
|
|
194
|
+
declare function canonicalInvariantOrder(invariants: readonly PInvariant[]): PInvariant[];
|
|
201
195
|
|
|
202
196
|
/**
|
|
203
197
|
* @module structural-check
|
|
@@ -259,72 +253,129 @@ declare function findMinimalSiphons(flatNet: FlatNet): ReadonlySet<number>[];
|
|
|
259
253
|
*/
|
|
260
254
|
declare function findMaximalTrapIn(flatNet: FlatNet, places: ReadonlySet<number>): ReadonlySet<number>;
|
|
261
255
|
|
|
256
|
+
/** Environment variable naming the z3 executable (default: `z3` on `PATH`). */
|
|
257
|
+
declare const Z3_ENV = "LIBPETRI_Z3";
|
|
258
|
+
/** Environment variable naming a directory that receives every script and reply. */
|
|
259
|
+
declare const DUMP_ENV = "LIBPETRI_SMT_DUMP";
|
|
260
|
+
/** A z3 release version, ordered numerically. */
|
|
261
|
+
interface Z3Version {
|
|
262
|
+
readonly major: number;
|
|
263
|
+
readonly minor: number;
|
|
264
|
+
readonly patch: number;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Oldest z3 the transport accepts: `-t`/`-T`, Spacer as `fp.engine`, and the
|
|
268
|
+
* `(get-model)` / `(get-proof)` printers the decoders read are stable from here.
|
|
269
|
+
*/
|
|
270
|
+
declare const MIN_Z3_VERSION: Z3Version;
|
|
271
|
+
/** Parses the version out of a `z3 --version` reply (`Z3 version 4.16.0 - 64 bit`). */
|
|
272
|
+
declare function parseZ3Version(text: string): Z3Version | null;
|
|
273
|
+
declare function formatZ3Version(v: Z3Version): string;
|
|
274
|
+
/** A resolved z3 executable: where it is and which version answered the probe. */
|
|
275
|
+
interface Z3Solver {
|
|
276
|
+
/** The executable as resolved (a path, or a bare name on `PATH`). */
|
|
277
|
+
readonly program: string;
|
|
278
|
+
/** The version the probe reported. */
|
|
279
|
+
readonly version: Z3Version;
|
|
280
|
+
/** Where scripts and replies are written, or `null` for no dump. */
|
|
281
|
+
readonly dumpDir: string | null;
|
|
282
|
+
}
|
|
283
|
+
/** No usable z3 resolved; the message is the `unknown` reason the verifier reports. */
|
|
284
|
+
declare class Z3Unavailable extends Error {
|
|
285
|
+
constructor(message: string);
|
|
286
|
+
}
|
|
287
|
+
/** The process could not be started; the message is the `unknown` reason. */
|
|
288
|
+
declare class Z3ProcessError extends Error {
|
|
289
|
+
constructor(message: string);
|
|
290
|
+
}
|
|
291
|
+
/** How a z3 process ended. */
|
|
292
|
+
type Z3Exit = {
|
|
293
|
+
readonly kind: 'exited';
|
|
294
|
+
readonly code: number | null;
|
|
295
|
+
} | {
|
|
296
|
+
readonly kind: 'killed';
|
|
297
|
+
};
|
|
298
|
+
/** The raw reply of one z3 run. */
|
|
299
|
+
interface Z3Reply {
|
|
300
|
+
readonly stdout: string;
|
|
301
|
+
readonly stderr: string;
|
|
302
|
+
readonly exit: Z3Exit;
|
|
303
|
+
}
|
|
304
|
+
/** Resolves a specific executable (tests point this at a stub). No dump directory. */
|
|
305
|
+
declare function z3SolverAt(program: string, env?: NodeJS.ProcessEnv): Z3Solver;
|
|
306
|
+
/**
|
|
307
|
+
* Resolves the executable named by {@link Z3_ENV}, or `z3` on `PATH`, probes its
|
|
308
|
+
* version, and reads {@link DUMP_ENV}. Throws {@link Z3Unavailable}.
|
|
309
|
+
*/
|
|
310
|
+
declare function resolveZ3(env?: NodeJS.ProcessEnv): Z3Solver;
|
|
311
|
+
/**
|
|
312
|
+
* True if a usable `z3` executable resolves: `LIBPETRI_Z3` if set, else `z3` on
|
|
313
|
+
* `PATH`, at or above {@link MIN_Z3_VERSION}. Without one every SMT path returns
|
|
314
|
+
* `unknown`; the test suites use this to skip loudly rather than fail.
|
|
315
|
+
*/
|
|
316
|
+
declare function z3Available(env?: NodeJS.ProcessEnv): boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Runs one script through one z3 process and resolves with the raw reply. `phase`
|
|
319
|
+
* names the dump files; `extraArgs` follow the standard argument list. The only
|
|
320
|
+
* rejection is a failed spawn: a solver that printed nothing, errored, timed out or
|
|
321
|
+
* was killed still comes back as a reply for the caller to classify
|
|
322
|
+
* ({@link failureReason}).
|
|
323
|
+
*/
|
|
324
|
+
declare function runZ3Text(solver: Z3Solver, script: string, phase: string, timeoutMs: number, extraArgs?: readonly string[]): Promise<Z3Reply>;
|
|
325
|
+
|
|
262
326
|
/**
|
|
263
327
|
* @module certificate-checker
|
|
264
328
|
*
|
|
265
|
-
* Independent
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
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.
|
|
329
|
+
* Independent certificate check for IC3/PDR proofs.
|
|
330
|
+
*
|
|
331
|
+
* When Z3 Spacer answers `sat` on the CHC encoding ({@link module:smt-encoder}), the
|
|
332
|
+
* model it prints interprets `Reachable` as an inductive invariant, the proof
|
|
333
|
+
* certificate. This module re-verifies that certificate with plain (non-HORN) SMT
|
|
334
|
+
* queries in a SECOND z3 run, so a `proven` verdict no longer rests on the empirical
|
|
335
|
+
* HORN sat ⇒ proven mapping alone, nor on the correctness of the P-invariant
|
|
336
|
+
* strengthening: the three verification conditions below are discharged against the
|
|
337
|
+
* UNSTRENGTHENED step relation ({@link encodeStepRelationSmt2}).
|
|
338
|
+
*
|
|
339
|
+
* The candidate invariant is `R' := R ∧ Inv`, where `R` is the pasted `Reachable`
|
|
340
|
+
* interpretation and `Inv` the validated P-invariant equalities the CHC encoding
|
|
341
|
+
* strengthened its rule bodies with: a Spacer model is only guaranteed inductive
|
|
342
|
+
* *relative to* that strengthening, so the conjuncts ride along in the candidate, but
|
|
343
|
+
* the RELATION stays unstrengthened, which means VC1/VC2 re-prove each conjunct's
|
|
344
|
+
* initiation and inductiveness from scratch. A wrong P-invariant cannot weaken this
|
|
345
|
+
* check: it fails init or consecution instead.
|
|
346
|
+
*
|
|
347
|
+
* 1. **VC1 (init)**: `¬R'(M₀)` is UNSAT.
|
|
348
|
+
* 2. **VC2 (consecution)**: `M ≥ 0 ∧ R'(M) ∧ T(M,M') ∧ ¬R'(M')` is UNSAT.
|
|
349
|
+
* 3. **VC3 (safety)**: `M ≥ 0 ∧ R'(M) ∧ Bad(M)` is UNSAT.
|
|
350
|
+
*
|
|
351
|
+
* The `M ≥ 0` conjunct is the state domain: markings are token counts, so the VCs
|
|
352
|
+
* range over ℕ^P; without it a certificate inductive over ℕ^P is refuted by a negative
|
|
353
|
+
* predecessor in ℤ^P.
|
|
354
|
+
*
|
|
355
|
+
* The certificate is the `(define-fun …)` block of the `(get-model)` reply, pasted
|
|
356
|
+
* verbatim: auxiliary definitions stay alongside `Reachable`, so every name resolves
|
|
357
|
+
* in the fresh script. The three VCs run under `(push)`/`(pop)` in ONE script; the
|
|
358
|
+
* emitted text is byte-identical to the Rust reference (`certificate_check.rs`) and
|
|
359
|
+
* the Java port.
|
|
360
|
+
*
|
|
361
|
+
* Outcomes are split the way the caller must treat them: `failed` names the first VC
|
|
362
|
+
* that was not UNSAT (with the solver status and, for SAT, a witness marking),
|
|
363
|
+
* `unavailable` means the check could not run at all (missing or malformed
|
|
364
|
+
* certificate, solver spawn failure, errored assert). Both withhold PROVEN; neither
|
|
365
|
+
* throws.
|
|
313
366
|
*/
|
|
314
367
|
|
|
315
|
-
/** Z3 high-level context. Typed as `any` because z3-solver's TS types are incomplete. */
|
|
316
|
-
type Z3Context$1 = any;
|
|
317
368
|
/** Label of a validity condition, as it appears in the downgrade reason. */
|
|
318
369
|
type CertificateVc = 'initiation (VC1)' | 'consecution (VC2)' | 'safety (VC3)';
|
|
319
370
|
/**
|
|
320
371
|
* Outcome of the certificate check.
|
|
321
372
|
*
|
|
322
|
-
* `passed` — all three validity conditions are UNSAT; the proven verdict is
|
|
323
|
-
*
|
|
324
|
-
* `failed` — a validity condition was not UNSAT; `detail` carries the solver
|
|
325
|
-
*
|
|
326
|
-
* `unavailable` — the check could not run (missing/
|
|
327
|
-
*
|
|
373
|
+
* `passed` — all three validity conditions are UNSAT; the proven verdict is certified
|
|
374
|
+
* independently of the Fixedpoint engine.
|
|
375
|
+
* `failed` — a validity condition was not UNSAT; `detail` carries the solver status
|
|
376
|
+
* and, when the solver produced a model, a witness marking.
|
|
377
|
+
* `unavailable` — the check could not run (missing/malformed certificate, solver
|
|
378
|
+
* failure), so no VC is implicated.
|
|
328
379
|
*
|
|
329
380
|
* The caller must withhold PROVEN on `failed` and `unavailable` alike.
|
|
330
381
|
*/
|
|
@@ -342,20 +393,27 @@ type CertificateCheckOutcome = {
|
|
|
342
393
|
readonly invariant: string | null;
|
|
343
394
|
};
|
|
344
395
|
/**
|
|
345
|
-
* Re-
|
|
396
|
+
* Re-verifies an extracted proof certificate against the unstrengthened step relation.
|
|
346
397
|
*
|
|
347
|
-
* @param
|
|
348
|
-
*
|
|
398
|
+
* @param certificate the `(define-fun …)` block extracted verbatim from the Spacer
|
|
399
|
+
* model (`null` when the solver printed none)
|
|
349
400
|
* @param flatNet the flat net the CHC query was encoded from
|
|
350
401
|
* @param initialMarking the verified initial marking (VC1)
|
|
351
402
|
* @param property the verified property (VC3)
|
|
352
403
|
* @param invariants the exactly-validated P-invariants the CHC bodies were
|
|
353
|
-
* strengthened with; conjoined into the CANDIDATE certificate and re-proven
|
|
354
|
-
*
|
|
404
|
+
* strengthened with; conjoined into the CANDIDATE certificate and re-proven by the
|
|
405
|
+
* three VCs (never conjoined into the step relation)
|
|
355
406
|
* @param sinkPlaces declared sink places (deadlock-freedom VC3)
|
|
356
|
-
* @param
|
|
407
|
+
* @param solver the resolved z3 executable
|
|
408
|
+
* @param timeoutMs per-invocation solver budget in milliseconds
|
|
409
|
+
*/
|
|
410
|
+
declare function checkCertificate(certificate: string | null, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[], sinkPlaces: ReadonlySet<Place<any>>, solver: Z3Solver, timeoutMs: number): Promise<CertificateCheckOutcome>;
|
|
411
|
+
/**
|
|
412
|
+
* The certificate-check script for the given inputs, exactly as
|
|
413
|
+
* {@link checkCertificate} would send it (VER-013 script parity): what the
|
|
414
|
+
* cross-language golden tests diff.
|
|
357
415
|
*/
|
|
358
|
-
declare function
|
|
416
|
+
declare function vcScript(certificate: string, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, sinkPlaces: ReadonlySet<Place<any>>, invariants: readonly PInvariant[]): string;
|
|
359
417
|
|
|
360
418
|
/**
|
|
361
419
|
* Name-correlation fragment classifier for the ν-aware state class graph
|
|
@@ -428,29 +486,6 @@ type FragmentMode = 'base' | 'extended';
|
|
|
428
486
|
*/
|
|
429
487
|
type PrioritySemantics = 'none' | 'conflict';
|
|
430
488
|
|
|
431
|
-
/**
|
|
432
|
-
* IC3/PDR-based safety verifier for Petri nets using Z3's Spacer engine.
|
|
433
|
-
*
|
|
434
|
-
* Proves safety properties (especially deadlock-freedom) without
|
|
435
|
-
* enumerating all reachable states. IC3 constructs inductive invariants
|
|
436
|
-
* incrementally, which works well for bounded nets.
|
|
437
|
-
*
|
|
438
|
-
* Key design decisions:
|
|
439
|
-
* - Operates on the marking projection (integer vectors) — no timing
|
|
440
|
-
* - An untimed deadlock-freedom proof is stronger than needed
|
|
441
|
-
* (timing can only restrict behavior)
|
|
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
|
|
446
|
-
*
|
|
447
|
-
* Verification Pipeline:
|
|
448
|
-
* 1. Flatten — expand XOR, index places, build pre/post vectors
|
|
449
|
-
* 2. Structural pre-check — siphon/trap analysis (may prove early)
|
|
450
|
-
* 3. P-invariants — compute conservation laws for strengthening
|
|
451
|
-
* 4. SMT encode + query — IC3/PDR via Z3 Spacer
|
|
452
|
-
* 5. Decode result — proof or counterexample trace
|
|
453
|
-
*/
|
|
454
489
|
declare class SmtVerifier {
|
|
455
490
|
private readonly net;
|
|
456
491
|
private _initialMarking;
|
|
@@ -462,6 +497,7 @@ declare class SmtVerifier {
|
|
|
462
497
|
private _timeoutMs;
|
|
463
498
|
private _certificateCheck;
|
|
464
499
|
private _counterexampleReplay;
|
|
500
|
+
private _semiflowInvariants;
|
|
465
501
|
private _nuMaxClasses;
|
|
466
502
|
private _fragmentMode;
|
|
467
503
|
private readonly _carrierPlaces;
|
|
@@ -510,6 +546,40 @@ declare class SmtVerifier {
|
|
|
510
546
|
* `SmtVerificationResult.counterexampleConfirmed` for how each outcome lands.
|
|
511
547
|
*/
|
|
512
548
|
counterexampleReplay(enabled: boolean): this;
|
|
549
|
+
/**
|
|
550
|
+
* Also hands the validated **P-semiflows** to the encoders as invariants
|
|
551
|
+
* (VER-007; default: disabled — the encoders then see only the null-space basis).
|
|
552
|
+
*
|
|
553
|
+
* Every validated semiflow is a conservation law in its own right (`y >= 0`,
|
|
554
|
+
* `y·C = 0`, `y·M0` exact, zero weight on every reset / consume-all place), and
|
|
555
|
+
* the Farkas enumeration returns the *minimal* laws of the net. The null-space
|
|
556
|
+
* basis the encoders get by default is one basis of many: elimination hands back
|
|
557
|
+
* mixed-sign rows (discarded as not semi-positive) or rows that fold a reset place
|
|
558
|
+
* into a chain whose other combinations avoid it (dropped by the H1 guard). On a
|
|
559
|
+
* net with a few reset arcs that can lose every law of the chains those arcs
|
|
560
|
+
* touch, and without them IC3 has to rediscover the conservation of each chain —
|
|
561
|
+
* on a ~100-place net it does not within any practical budget.
|
|
562
|
+
*
|
|
563
|
+
* **Turn this on if the net has any `all()` / `atLeast(n)` or reset arc on a busy
|
|
564
|
+
* place** — draining an input queue is the everyday case. Every basis row whose
|
|
565
|
+
* support touches such a place fails the H1 guard and is dropped, so the encoders
|
|
566
|
+
* run on a deficient invariant set and nothing in the report says a law is missing
|
|
567
|
+
* beyond the `Dropped` lines.
|
|
568
|
+
*
|
|
569
|
+
* This reaches the **name-coloured** encoder (NU-050) as well as the flat one, and
|
|
570
|
+
* it matters most there. On a 113-place ν-net, whole-net deadlock-freedom went from
|
|
571
|
+
* `unknown` after 50 minutes to `proven` in about 15 seconds with this option as the
|
|
572
|
+
* only change; on the flat path, reachability-safety queries that timed out at 120 s
|
|
573
|
+
* close in about a second.
|
|
574
|
+
*
|
|
575
|
+
* Soundness is unchanged: the semiflows pass the same exact re-validation as the
|
|
576
|
+
* basis rows, the union is pure strengthening (`Semiflow.lean`,
|
|
577
|
+
* `semiflow_union_sound`), and the certificate check re-proves the strengthened
|
|
578
|
+
* invariant — that check is flat-path only, so a coloured `proven` reports
|
|
579
|
+
* `Certificate check: not applicable (name-coloured encoding)`. Off by default so
|
|
580
|
+
* reports stay byte-equal.
|
|
581
|
+
*/
|
|
582
|
+
semiflowInvariants(enabled: boolean): this;
|
|
513
583
|
/**
|
|
514
584
|
* Sets the class-count cap for the ν-aware state-class-graph analysis (NU-050,
|
|
515
585
|
* Route B). When the symbolic name-aware graph would exceed this, the analysis
|
|
@@ -547,6 +617,33 @@ declare class SmtVerifier {
|
|
|
547
617
|
* dead-letter-drain stalls the eager, priority-ordered executor never produces.
|
|
548
618
|
*/
|
|
549
619
|
prioritySemantics(semantics: PrioritySemantics): this;
|
|
620
|
+
/**
|
|
621
|
+
* The name-coloured plan and its encoding, or a null plan when the net is outside
|
|
622
|
+
* the fragment (NU-050) and a null encoding when the property names a place the net
|
|
623
|
+
* does not resolve.
|
|
624
|
+
*
|
|
625
|
+
* {@link verify} and {@link encodeScripts} share this deliberately. They used to
|
|
626
|
+
* invoke `buildColouredPlan` and `encodeColoured` separately, so handing the encoder
|
|
627
|
+
* the wrong one of the two lists changed only one of them — and the script-parity
|
|
628
|
+
* goldens are generated from `encodeScripts`. Unifying the invocation closes that. It
|
|
629
|
+
* does not make the two paths identical: each still computes its own invariant and
|
|
630
|
+
* semiflow lists, so they can still drift through the arguments rather than the call.
|
|
631
|
+
*
|
|
632
|
+
* `invariants` is what the encoder conjoins into every rule body (the null-space
|
|
633
|
+
* basis, unioned with the semiflows when VER-007 is enabled); `semiflows` sets the
|
|
634
|
+
* colour-slot bound k (NU-053). They are not the same list.
|
|
635
|
+
*/
|
|
636
|
+
private colouredAttempt;
|
|
637
|
+
/**
|
|
638
|
+
* The SMT-LIB2 scripts {@link verify} would send to z3 for this configuration,
|
|
639
|
+
* without running a solver (VER-013 AC1): the HORN query (flat, or name-coloured
|
|
640
|
+
* when a declared budget puts the net on Route A's exact encoding) and, for the
|
|
641
|
+
* flat encoding, the certificate-check script built around
|
|
642
|
+
* {@link placeholderCertificate}. This is what the cross-language golden tests diff
|
|
643
|
+
* byte for byte. Route B, the structural pre-check and the unresolved-place
|
|
644
|
+
* refusal are bypassed: it is what Route A encodes.
|
|
645
|
+
*/
|
|
646
|
+
encodeScripts(): EncodedScripts;
|
|
550
647
|
/**
|
|
551
648
|
* Runs the verification pipeline.
|
|
552
649
|
*
|
|
@@ -574,146 +671,142 @@ declare class SmtVerifier {
|
|
|
574
671
|
*/
|
|
575
672
|
private applyNuGuard;
|
|
576
673
|
}
|
|
674
|
+
/** The scripts {@link SmtVerifier.encodeScripts} reports. */
|
|
675
|
+
interface EncodedScripts {
|
|
676
|
+
/** The HORN query, flat or name-coloured. */
|
|
677
|
+
readonly horn: string;
|
|
678
|
+
/** The certificate-check script around {@link placeholderCertificate}; `null` for the name-coloured encoding. */
|
|
679
|
+
readonly certificate: string | null;
|
|
680
|
+
/** Whether `horn` is the name-coloured encoding. */
|
|
681
|
+
readonly coloured: boolean;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* `(define-fun Reachable ((x!0 Int) …) Bool true)`: the certificate stand-in the
|
|
685
|
+
* golden certificate scripts are built around (a real certificate is solver output
|
|
686
|
+
* and never part of a golden).
|
|
687
|
+
*/
|
|
688
|
+
declare function placeholderCertificate(placeCount: number): string;
|
|
577
689
|
|
|
578
690
|
/**
|
|
579
|
-
*
|
|
691
|
+
* @module spacer-runner
|
|
692
|
+
*
|
|
693
|
+
* Runs Z3 Spacer on a HORN script through one `z3` process (VER-013) and
|
|
694
|
+
* classifies the reply in verdict terms.
|
|
695
|
+
*
|
|
696
|
+
* HORN/Spacer convention (shared with the Rust and Java verifiers and corroborated
|
|
697
|
+
* by the certificate check): with the query `(assert (not Error))`, z3 prints `sat`
|
|
698
|
+
* when the property is PROVEN (an inductive invariant excluding every violating
|
|
699
|
+
* state exists) and `unsat` when it is VIOLATED (no such invariant; the refutation
|
|
700
|
+
* proof carries the counterexample states).
|
|
580
701
|
*/
|
|
702
|
+
|
|
703
|
+
/** Result of a Spacer query. */
|
|
581
704
|
type QueryResult = QueryProven | QueryViolated | QueryUnknown;
|
|
582
|
-
/** Property proven
|
|
705
|
+
/** Property proven (z3 `sat`). */
|
|
583
706
|
interface QueryProven {
|
|
584
707
|
readonly type: 'proven';
|
|
585
|
-
readonly invariantFormula: string | null;
|
|
586
|
-
readonly levelInvariants: readonly string[];
|
|
587
708
|
/**
|
|
588
|
-
* The
|
|
589
|
-
*
|
|
590
|
-
* context. Consumed by the certificate checker; `null` when the solver
|
|
591
|
-
* configuration produced no answer.
|
|
709
|
+
* The `(define-fun …)` block of the model, verbatim (the certificate the
|
|
710
|
+
* certificate checker re-validates), or `null` when no model printed.
|
|
592
711
|
*/
|
|
593
|
-
readonly
|
|
712
|
+
readonly invariantFormula: string | null;
|
|
594
713
|
}
|
|
595
|
-
/**
|
|
714
|
+
/** Property violated (z3 `unsat`). */
|
|
596
715
|
interface QueryViolated {
|
|
597
716
|
readonly type: 'violated';
|
|
598
|
-
|
|
717
|
+
/** The raw solver reply; the refutation proof in it is decoded by the counterexample decoder. */
|
|
718
|
+
readonly answer: string;
|
|
599
719
|
}
|
|
600
|
-
/** Solver could not determine (timeout, resource limit). */
|
|
720
|
+
/** Solver could not determine (timeout, resource limit, transport failure). */
|
|
601
721
|
interface QueryUnknown {
|
|
602
722
|
readonly type: 'unknown';
|
|
603
723
|
readonly reason: string;
|
|
604
724
|
}
|
|
605
725
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*/
|
|
609
|
-
interface SpacerContext {
|
|
610
|
-
/** The Z3 high-level context for building expressions. */
|
|
611
|
-
readonly ctx: ReturnType<Awaited<ReturnType<typeof init>>['Context']>;
|
|
612
|
-
/** The Z3 Fixedpoint solver instance (Spacer engine). Z3 types are complex; using any. */
|
|
613
|
-
readonly fp: any;
|
|
614
|
-
/** Queries whether the error state is reachable. */
|
|
615
|
-
query(errorExpr: Bool, reachableDecl?: FuncDecl): Promise<QueryResult>;
|
|
616
|
-
/** Releases Z3 resources. */
|
|
617
|
-
dispose(): void;
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Creates a Spacer runner with the given timeout.
|
|
621
|
-
*
|
|
622
|
-
* Uses Z3's Spacer engine (CHC solver based on IC3/PDR) to prove or
|
|
623
|
-
* disprove safety properties.
|
|
726
|
+
* Runs `smt2` with `fp.engine=spacer`. `phase` names the dump files (`horn` or
|
|
727
|
+
* `horn-coloured`).
|
|
624
728
|
*/
|
|
625
|
-
declare function
|
|
729
|
+
declare function runZ3Spacer(solver: Z3Solver, timeoutMs: number, smt2: string, phase: string): Promise<QueryResult>;
|
|
626
730
|
|
|
627
731
|
/**
|
|
628
732
|
* @module smt-encoder
|
|
629
733
|
*
|
|
630
|
-
* Encodes a flattened Petri net as Constrained Horn Clauses (CHC)
|
|
631
|
-
*
|
|
632
|
-
* **CHC encoding strategy**: The net's state space is modeled as integer vectors
|
|
633
|
-
* (one variable per place = token count). Three rule types:
|
|
734
|
+
* Encodes a flattened Petri net as Constrained Horn Clauses (CHC) in SMT-LIB2 text
|
|
735
|
+
* for Z3's Spacer engine (VER-013).
|
|
634
736
|
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
* one rule per flat transition (XOR branches are separate transitions)
|
|
638
|
-
* 3. **Error**: `Error() :- Reachable(M) ∧ violation(M)` — safety property violation
|
|
737
|
+
* The net's state space is modeled as integer vectors (one variable per place = token
|
|
738
|
+
* count). Three rule types:
|
|
639
739
|
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
740
|
+
* 1. **Init**: `(assert (Reachable M0))` — the initial marking is reachable
|
|
741
|
+
* 2. **Transition**: `Reachable(M') :- Reachable(M) ∧ enabled(M,t) ∧ fire(M,M',t) ∧
|
|
742
|
+
* M' ≥ 0 ∧ invariants(M') ∧ env-bounds(M')` — one rule per flat transition, plus
|
|
743
|
+
* one env-injection rule per injected environment place (VER-006)
|
|
744
|
+
* 3. **Error**: `Error :- Reachable(M) ∧ violation(M)`; `(assert (not Error))`, so
|
|
745
|
+
* `sat` is PROVEN and `unsat` is VIOLATED
|
|
642
746
|
*
|
|
643
|
-
*
|
|
747
|
+
* The emitted script is byte-identical to the Rust reference (`smt_encoder.rs`) and
|
|
748
|
+
* the Java port for the same input: places in code-point order of their names, the
|
|
749
|
+
* property's places, sinks, env bounds and injections in place-index order,
|
|
750
|
+
* invariants in the order the verifier canonicalised.
|
|
644
751
|
*/
|
|
645
752
|
|
|
646
|
-
/**
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
|
|
652
|
-
*/
|
|
653
|
-
interface EncodingResult {
|
|
654
|
-
readonly errorExpr: Bool;
|
|
655
|
-
readonly reachableDecl: FuncDecl;
|
|
753
|
+
/** An encoded SMT-LIB2 script. */
|
|
754
|
+
interface SmtEncoding {
|
|
755
|
+
/** The script text. */
|
|
756
|
+
readonly smt2: string;
|
|
757
|
+
/** The number of flat places (the arity of `Reachable` in the flat encoding). */
|
|
758
|
+
readonly placeCount: number;
|
|
656
759
|
}
|
|
657
760
|
/**
|
|
658
|
-
* Encodes
|
|
761
|
+
* Encodes the net and property as a HORN script.
|
|
659
762
|
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
* - Reachable(M') :- Reachable(M) AND enabled(M,t) AND fire(M,M',t) — transition rules
|
|
663
|
-
* - Error() :- Reachable(M) AND property_violation(M) — safety property
|
|
763
|
+
* @param produceProofs emit `:produce-proofs` and `(get-proof)` so an `unsat` reply
|
|
764
|
+
* carries the refutation the replay decodes
|
|
664
765
|
*/
|
|
665
|
-
declare function encode(
|
|
666
|
-
|
|
766
|
+
declare function encode(flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[], sinkPlaces?: ReadonlySet<Place<any>>, produceProofs?: boolean): SmtEncoding;
|
|
667
767
|
/**
|
|
668
|
-
*
|
|
669
|
-
*
|
|
768
|
+
* The net's one-step relation `T(M, M')` as one plain SMT-LIB2 formula over the free
|
|
769
|
+
* variables `m0..` / `m0p..`: the disjunction of every flat transition firing and
|
|
770
|
+
* every env-injection step (VER-006). This is the UNSTRENGTHENED relation the
|
|
771
|
+
* certificate check validates against: it shares the condition emitters with the CHC
|
|
772
|
+
* path but omits the P-invariant conjuncts, so a certificate poisoned by a wrong
|
|
773
|
+
* invariant cannot re-certify itself.
|
|
670
774
|
*/
|
|
671
|
-
|
|
672
|
-
|
|
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;
|
|
775
|
+
declare function encodeStepRelationSmt2(flatNet: FlatNet): string;
|
|
776
|
+
|
|
682
777
|
/**
|
|
683
|
-
*
|
|
778
|
+
* @module counterexample-decoder
|
|
779
|
+
*
|
|
780
|
+
* Decodes z3's refutation output into replayable counterexample material.
|
|
781
|
+
*
|
|
782
|
+
* There is exactly one decoder: {@link decodeStateSet}, which collects the ground
|
|
783
|
+
* `Reachable` facts of a `:produce-proofs` refutation into a SET. The ordered trace
|
|
784
|
+
* a caller sees is reconstructed from that set by the abstract replayer; the proof
|
|
785
|
+
* printer's traversal order is not a firing order and was never safe to read as one.
|
|
786
|
+
*
|
|
787
|
+
* Applications with non-ground arguments (rule bodies quantify `Reachable` over
|
|
788
|
+
* variables) or the wrong arity are skipped; a malformed proof simply yields a
|
|
789
|
+
* smaller (possibly empty) set, never a throw. Byte-for-byte mirror of the Rust
|
|
790
|
+
* `counterexample::decode_state_set`.
|
|
684
791
|
*/
|
|
792
|
+
|
|
793
|
+
/** Result of counterexample decoding. */
|
|
685
794
|
interface DecodedTrace {
|
|
686
795
|
/**
|
|
687
|
-
* Reachable
|
|
688
|
-
*
|
|
689
|
-
* May contain duplicates. Kept for raw reporting; the replayer consumes
|
|
690
|
-
* {@link states} instead.
|
|
691
|
-
*/
|
|
692
|
-
readonly trace: readonly MarkingState[];
|
|
693
|
-
/** Rule names encountered during the walk (same traversal-order caveat). */
|
|
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.
|
|
796
|
+
* The ground `Reachable` markings of the proof as an order-free set (text order
|
|
797
|
+
* preserved for display), what the abstract replayer chains into a firing order.
|
|
698
798
|
*/
|
|
699
799
|
readonly states: ReadonlySet<MarkingState>;
|
|
700
|
-
/**
|
|
701
|
-
|
|
702
|
-
* returned); `null` when the walk completed cleanly.
|
|
703
|
-
*/
|
|
704
|
-
readonly failure: DecodeFailure | null;
|
|
800
|
+
/** Why nothing was decoded; `null` when `states` is non-empty. */
|
|
801
|
+
readonly note: string | null;
|
|
705
802
|
}
|
|
803
|
+
/** Decodes the states of a z3 reply; a note says so when none were found. */
|
|
804
|
+
declare function decode(answer: string, flatNet: FlatNet): DecodedTrace;
|
|
706
805
|
/**
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
* When Spacer finds a counterexample (property violation), it produces
|
|
710
|
-
* a derivation tree showing how the error state is reachable. This function
|
|
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`.
|
|
806
|
+
* Collects the ground `Reachable(...)` applications from a z3 refutation proof into
|
|
807
|
+
* a state set, in text order.
|
|
715
808
|
*/
|
|
716
|
-
declare function
|
|
809
|
+
declare function decodeStateSet(answer: string, flatNet: FlatNet): ReadonlySet<MarkingState>;
|
|
717
810
|
|
|
718
811
|
/**
|
|
719
812
|
* @module abstract-replayer
|
|
@@ -1005,4 +1098,4 @@ declare class TimePetriNetAnalyzerBuilder {
|
|
|
1005
1098
|
build(): TimePetriNetAnalyzer;
|
|
1006
1099
|
}
|
|
1007
1100
|
|
|
1008
|
-
export { type AbstractState,
|
|
1101
|
+
export { type AbstractState, EnvironmentAnalysisMode as AnalysisEnvironmentMode, type BranchEdge, type CertificateCheckOutcome, type CertificateVc, DBM, DUMP_ENV, type DecodedTrace, type EncodedScripts, EnvironmentAnalysisMode, type FlatNet, type FlatTransition, IncidenceMatrix, type LivenessResult, MIN_Z3_VERSION, MarkingState, MarkingStateBuilder, PInvariant, type PrioritySemantics, type QueryProven, type QueryResult, type QueryUnknown, type QueryViolated, type ReplayOptions, type ReplayOutcome, type ReplayStep, type SmtEncoding, SmtProperty, SmtVerificationResult, SmtVerifier, StateClass, StateClassGraph, type StructuralCheckResult, TimePetriNetAnalyzer, TimePetriNetAnalyzerBuilder, type XorBranchAnalysis, type XorBranchInfo, type Z3Exit, Z3ProcessError, type Z3Reply, type Z3Solver, Z3Unavailable, type Z3Version, Z3_ENV, canonicalInvariantOrder, checkCertificate, computePInvariants, computePSemiflows, computeSCCs, decode, decodeStateSet, encode, encodeStepRelationSmt2, findMaximalTrapIn, findMinimalSiphons, findTerminalSCCs, flatNetIndexOf, flatNetPlaceCount, flatNetTransitionCount, flatTransition, flatten, formatZ3Version, isCoveredByInvariants, parseZ3Version, placeholderCertificate, replayCounterexample, resolveZ3, runZ3Spacer, runZ3Text, strengthenWithSemiflows, structuralCheck, vcScript, z3Available, z3SolverAt };
|