libpetri 3.0.1 → 4.0.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.
@@ -1796,4 +1796,4 @@ declare class PetriNetBuilder {
1796
1796
  private buildWithFusion;
1797
1797
  }
1798
1798
 
1799
- export { type VerificationHarness as $, type Arc as A, type Port as B, type Channel as C, type PortDirection as D, type EnvironmentPlace as E, FusionSet as F, SubnetDefBuilder as G, type SubnetInstance as H, type In as I, type Timing as J, type KeyFn as K, type LogFn as L, MAX_DURATION_MS as M, type NameId as N, type Out as O, PetriNet as P, type TimingDeadline as Q, type TimingDelayed as R, SubnetDef as S, type Token as T, type TimingExact as U, type TimingImmediate as V, type TimingWindow as W, TokenInput as X, TokenOutput as Y, type TransitionAction as Z, TransitionBuilder as _, type Place as a, type Unknown as a$, type VerificationResult as a0, all as a1, allPlaces as a2, and as a3, andPlaces as a4, arcPlace as a5, atLeast as a6, consumptionCount as a7, deadline as a8, delayed as a9, requiredCount as aA, resetArc as aB, timeout as aC, timeoutPlace as aD, tokenAt as aE, tokenOf as aF, transform as aG, transformAsync as aH, transformFrom as aI, unitToken as aJ, window as aK, withTimeout as aL, xor as aM, xorPlaces as aN, MarkingState as aO, type PInvariant as aP, type SmtProperty as aQ, MarkingStateBuilder as aR, type SmtVerificationResult as aS, type BranchPlaceBound as aT, type DeadlockFree as aU, type JoinedOrDeadLettered as aV, type MutualExclusion as aW, type PlaceBound as aX, type Proven as aY, type SmtStatistics as aZ, type TokenSupplier as a_, earliest as aa, enumerateBranches as ab, environmentPlace as ac, exact as ad, exactly as ae, fork as af, forwardInput as ag, hasDeadline as ah, immediate as ai, inhibitorArc as aj, inputArc as ak, isPassthrough as al, isUnit as am, keyForPlace as an, latest as ao, matchCorrelates as ap, matchKey as aq, matchSpec as ar, nameId as as, one as at, outPlace as au, outputArc as av, passthrough as aw, place as ax, produce as ay, readArc as az, Transition as b, type Unreachable as b0, type Verdict as b1, type Violated as b2, branchPlaceBound as b3, deadlockFree as b4, isProven as b5, isViolated as b6, joinedOrDeadLettered as b7, mutualExclusion as b8, pInvariant as b9, pInvariantToString as ba, placeBound as bb, propertyDescription as bc, unreachable as bd, TransitionContext as c, type ArcInhibitor as d, type ArcInput as e, type ArcOutput as f, type ArcRead as g, type ArcReset as h, ComposeBindings as i, FusionSetBuilder as j, type InAll as k, type InAtLeast as l, type InExactly as m, type InOne as n, Instance as o, Interface as p, InterfaceBuilder as q, type MatchKey as r, type MatchSpec as s, type OutAnd as t, type OutForwardInput as u, type OutPlace as v, type OutTimeout as w, type OutXor as x, type OutputEntry as y, PetriNetBuilder as z };
1799
+ export { type VerificationHarness as $, type Arc as A, type Port as B, type Channel as C, type PortDirection as D, type EnvironmentPlace as E, FusionSet as F, SubnetDefBuilder as G, type SubnetInstance as H, type In as I, type Timing as J, type KeyFn as K, type LogFn as L, MAX_DURATION_MS as M, type NameId as N, type Out as O, PetriNet as P, type TimingDeadline as Q, type TimingDelayed as R, SubnetDef as S, type Token as T, type TimingExact as U, type TimingImmediate as V, type TimingWindow as W, TokenInput as X, TokenOutput as Y, type TransitionAction as Z, TransitionBuilder as _, type Place as a, type Unknown as a$, type VerificationResult as a0, all as a1, allPlaces as a2, and as a3, andPlaces as a4, arcPlace as a5, atLeast as a6, consumptionCount as a7, deadline as a8, delayed as a9, requiredCount as aA, resetArc as aB, timeout as aC, timeoutPlace as aD, tokenAt as aE, tokenOf as aF, transform as aG, transformAsync as aH, transformFrom as aI, unitToken as aJ, window as aK, withTimeout as aL, xor as aM, xorPlaces as aN, type PInvariant as aO, MarkingState as aP, type SmtProperty as aQ, MarkingStateBuilder as aR, type SmtVerificationResult as aS, type BranchPlaceBound as aT, type DeadlockFree as aU, type JoinedOrDeadLettered as aV, type MutualExclusion as aW, type PlaceBound as aX, type Proven as aY, type SmtStatistics as aZ, type TokenSupplier as a_, earliest as aa, enumerateBranches as ab, environmentPlace as ac, exact as ad, exactly as ae, fork as af, forwardInput as ag, hasDeadline as ah, immediate as ai, inhibitorArc as aj, inputArc as ak, isPassthrough as al, isUnit as am, keyForPlace as an, latest as ao, matchCorrelates as ap, matchKey as aq, matchSpec as ar, nameId as as, one as at, outPlace as au, outputArc as av, passthrough as aw, place as ax, produce as ay, readArc as az, Transition as b, type Unreachable as b0, type Verdict as b1, type Violated as b2, branchPlaceBound as b3, deadlockFree as b4, isProven as b5, isViolated as b6, joinedOrDeadLettered as b7, mutualExclusion as b8, pInvariant as b9, pInvariantToString as ba, placeBound as bb, propertyDescription as bc, unreachable as bd, TransitionContext as c, type ArcInhibitor as d, type ArcInput as e, type ArcOutput as f, type ArcRead as g, type ArcReset as h, ComposeBindings as i, FusionSetBuilder as j, type InAll as k, type InAtLeast as l, type InExactly as m, type InOne as n, Instance as o, Interface as p, InterfaceBuilder as q, type MatchKey as r, type MatchSpec as s, type OutAnd as t, type OutForwardInput as u, type OutPlace as v, type OutTimeout as w, type OutXor as x, type OutputEntry as y, PetriNetBuilder as z };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_PANZOOM_OPTS,
3
3
  mount
4
- } from "../chunk-6NH64RCU.js";
4
+ } from "../chunk-KO6TSB47.js";
5
5
 
6
6
  // src/render-dom/index.ts
7
7
  async function renderDotToContainer(dotSource, container, opts = {}) {
@@ -1,6 +1,5 @@
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
- import { Expr, init, Bool, FuncDecl } from 'z3-solver';
1
+ import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aO as PInvariant, aP as MarkingState, aQ as SmtProperty, aR as MarkingStateBuilder, aS as SmtVerificationResult } from '../petri-net-hduM6tJf.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-hduM6tJf.js';
4
3
 
5
4
  /**
6
5
  * A flattened transition with pre/post vectors for SMT encoding.
@@ -182,22 +181,35 @@ declare function flatten(net: PetriNet, environmentPlaces?: Set<EnvironmentPlace
182
181
  */
183
182
  declare function computePInvariants(matrix: IncidenceMatrix, flatNet: FlatNet, initialMarking: MarkingState): PInvariant[];
184
183
  /**
185
- * Computes minimal **P-semiflows**non-negative place weightings `y` with
186
- * `y·C = 0` via the Colom–Silva / Farkas method. Unlike {@link computePInvariants}
187
- * (a signed null-space basis), every returned `PInvariant.weights` is non-negative:
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`).
184
+ * VER-007the semiflow union. Appends every gate-validated P-semiflow that is not
185
+ * already a basis row (same weights, same constant) to `invariants`, returning the
186
+ * strengthened list and how many rows were added.
192
187
  *
193
- * Mirrors the Rust reference `compute_p_semiflows`.
188
+ * The null-space basis is one basis of many: elimination hands back mixed-sign rows
189
+ * and rows that fold a reset place into a chain whose other combinations avoid it,
190
+ * both lost to the exact gate — on a reset-heavy net every law of the chains those
191
+ * arcs touch, leaving IC3 to rediscover conservation it cannot within any practical
192
+ * budget. The Farkas rows ({@link computePSemiflows}) are the minimal laws of the
193
+ * net. Conjoining them alongside the basis is pure strengthening (`Semiflow.lean`,
194
+ * `semiflow_union_sound`) **provided both lists passed the same exact gate**
195
+ * (`semiflow_gate_is_necessary`) — the caller's obligation; this only merges.
194
196
  */
197
+ declare function strengthenWithSemiflows(invariants: readonly PInvariant[], semiflows: readonly PInvariant[]): {
198
+ readonly invariants: readonly PInvariant[];
199
+ readonly added: number;
200
+ };
195
201
  declare function computePSemiflows(matrix: IncidenceMatrix, flatNet: FlatNet, initialMarking: MarkingState): PInvariant[];
196
202
  /**
197
203
  * Checks if every place is covered by at least one P-invariant.
198
204
  * If true, the net is structurally bounded.
199
205
  */
200
206
  declare function isCoveredByInvariants(invariants: readonly PInvariant[], numPlaces: number): boolean;
207
+ /**
208
+ * The invariants in canonical order (VER-013): by ascending support, then weights,
209
+ * then constant, each compared lexicographically. The same order the Rust and Java
210
+ * verifiers apply, so the strengthened scripts are byte-identical.
211
+ */
212
+ declare function canonicalInvariantOrder(invariants: readonly PInvariant[]): PInvariant[];
201
213
 
202
214
  /**
203
215
  * @module structural-check
@@ -259,72 +271,129 @@ declare function findMinimalSiphons(flatNet: FlatNet): ReadonlySet<number>[];
259
271
  */
260
272
  declare function findMaximalTrapIn(flatNet: FlatNet, places: ReadonlySet<number>): ReadonlySet<number>;
261
273
 
274
+ /** Environment variable naming the z3 executable (default: `z3` on `PATH`). */
275
+ declare const Z3_ENV = "LIBPETRI_Z3";
276
+ /** Environment variable naming a directory that receives every script and reply. */
277
+ declare const DUMP_ENV = "LIBPETRI_SMT_DUMP";
278
+ /** A z3 release version, ordered numerically. */
279
+ interface Z3Version {
280
+ readonly major: number;
281
+ readonly minor: number;
282
+ readonly patch: number;
283
+ }
284
+ /**
285
+ * Oldest z3 the transport accepts: `-t`/`-T`, Spacer as `fp.engine`, and the
286
+ * `(get-model)` / `(get-proof)` printers the decoders read are stable from here.
287
+ */
288
+ declare const MIN_Z3_VERSION: Z3Version;
289
+ /** Parses the version out of a `z3 --version` reply (`Z3 version 4.16.0 - 64 bit`). */
290
+ declare function parseZ3Version(text: string): Z3Version | null;
291
+ declare function formatZ3Version(v: Z3Version): string;
292
+ /** A resolved z3 executable: where it is and which version answered the probe. */
293
+ interface Z3Solver {
294
+ /** The executable as resolved (a path, or a bare name on `PATH`). */
295
+ readonly program: string;
296
+ /** The version the probe reported. */
297
+ readonly version: Z3Version;
298
+ /** Where scripts and replies are written, or `null` for no dump. */
299
+ readonly dumpDir: string | null;
300
+ }
301
+ /** No usable z3 resolved; the message is the `unknown` reason the verifier reports. */
302
+ declare class Z3Unavailable extends Error {
303
+ constructor(message: string);
304
+ }
305
+ /** The process could not be started; the message is the `unknown` reason. */
306
+ declare class Z3ProcessError extends Error {
307
+ constructor(message: string);
308
+ }
309
+ /** How a z3 process ended. */
310
+ type Z3Exit = {
311
+ readonly kind: 'exited';
312
+ readonly code: number | null;
313
+ } | {
314
+ readonly kind: 'killed';
315
+ };
316
+ /** The raw reply of one z3 run. */
317
+ interface Z3Reply {
318
+ readonly stdout: string;
319
+ readonly stderr: string;
320
+ readonly exit: Z3Exit;
321
+ }
322
+ /** Resolves a specific executable (tests point this at a stub). No dump directory. */
323
+ declare function z3SolverAt(program: string, env?: NodeJS.ProcessEnv): Z3Solver;
324
+ /**
325
+ * Resolves the executable named by {@link Z3_ENV}, or `z3` on `PATH`, probes its
326
+ * version, and reads {@link DUMP_ENV}. Throws {@link Z3Unavailable}.
327
+ */
328
+ declare function resolveZ3(env?: NodeJS.ProcessEnv): Z3Solver;
329
+ /**
330
+ * True if a usable `z3` executable resolves: `LIBPETRI_Z3` if set, else `z3` on
331
+ * `PATH`, at or above {@link MIN_Z3_VERSION}. Without one every SMT path returns
332
+ * `unknown`; the test suites use this to skip loudly rather than fail.
333
+ */
334
+ declare function z3Available(env?: NodeJS.ProcessEnv): boolean;
335
+ /**
336
+ * Runs one script through one z3 process and resolves with the raw reply. `phase`
337
+ * names the dump files; `extraArgs` follow the standard argument list. The only
338
+ * rejection is a failed spawn: a solver that printed nothing, errored, timed out or
339
+ * was killed still comes back as a reply for the caller to classify
340
+ * ({@link failureReason}).
341
+ */
342
+ declare function runZ3Text(solver: Z3Solver, script: string, phase: string, timeoutMs: number, extraArgs?: readonly string[]): Promise<Z3Reply>;
343
+
262
344
  /**
263
345
  * @module certificate-checker
264
346
  *
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.
347
+ * Independent certificate check for IC3/PDR proofs.
348
+ *
349
+ * When Z3 Spacer answers `sat` on the CHC encoding ({@link module:smt-encoder}), the
350
+ * model it prints interprets `Reachable` as an inductive invariant, the proof
351
+ * certificate. This module re-verifies that certificate with plain (non-HORN) SMT
352
+ * queries in a SECOND z3 run, so a `proven` verdict no longer rests on the empirical
353
+ * HORN sat proven mapping alone, nor on the correctness of the P-invariant
354
+ * strengthening: the three verification conditions below are discharged against the
355
+ * UNSTRENGTHENED step relation ({@link encodeStepRelationSmt2}).
356
+ *
357
+ * The candidate invariant is `R' := R Inv`, where `R` is the pasted `Reachable`
358
+ * interpretation and `Inv` the validated P-invariant equalities the CHC encoding
359
+ * strengthened its rule bodies with: a Spacer model is only guaranteed inductive
360
+ * *relative to* that strengthening, so the conjuncts ride along in the candidate, but
361
+ * the RELATION stays unstrengthened, which means VC1/VC2 re-prove each conjunct's
362
+ * initiation and inductiveness from scratch. A wrong P-invariant cannot weaken this
363
+ * check: it fails init or consecution instead.
364
+ *
365
+ * 1. **VC1 (init)**: `¬R'(M₀)` is UNSAT.
366
+ * 2. **VC2 (consecution)**: `M 0 R'(M) T(M,M') ¬R'(M')` is UNSAT.
367
+ * 3. **VC3 (safety)**: `M 0 ∧ R'(M) ∧ Bad(M)` is UNSAT.
368
+ *
369
+ * The `M ≥ 0` conjunct is the state domain: markings are token counts, so the VCs
370
+ * range over ℕ^P; without it a certificate inductive over ℕ^P is refuted by a negative
371
+ * predecessor in ℤ^P.
372
+ *
373
+ * The certificate is the `(define-fun …)` block of the `(get-model)` reply, pasted
374
+ * verbatim: auxiliary definitions stay alongside `Reachable`, so every name resolves
375
+ * in the fresh script. The three VCs run under `(push)`/`(pop)` in ONE script; the
376
+ * emitted text is byte-identical to the Rust reference (`certificate_check.rs`) and
377
+ * the Java port.
378
+ *
379
+ * Outcomes are split the way the caller must treat them: `failed` names the first VC
380
+ * that was not UNSAT (with the solver status and, for SAT, a witness marking),
381
+ * `unavailable` means the check could not run at all (missing or malformed
382
+ * certificate, solver spawn failure, errored assert). Both withhold PROVEN; neither
383
+ * throws.
313
384
  */
314
385
 
315
- /** Z3 high-level context. Typed as `any` because z3-solver's TS types are incomplete. */
316
- type Z3Context$1 = any;
317
386
  /** Label of a validity condition, as it appears in the downgrade reason. */
318
387
  type CertificateVc = 'initiation (VC1)' | 'consecution (VC2)' | 'safety (VC3)';
319
388
  /**
320
389
  * Outcome of the certificate check.
321
390
  *
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.
391
+ * `passed` — all three validity conditions are UNSAT; the proven verdict is certified
392
+ * independently of the Fixedpoint engine.
393
+ * `failed` — a validity condition was not UNSAT; `detail` carries the solver status
394
+ * and, when the solver produced a model, a witness marking.
395
+ * `unavailable` — the check could not run (missing/malformed certificate, solver
396
+ * failure), so no VC is implicated.
328
397
  *
329
398
  * The caller must withhold PROVEN on `failed` and `unavailable` alike.
330
399
  */
@@ -342,20 +411,27 @@ type CertificateCheckOutcome = {
342
411
  readonly invariant: string | null;
343
412
  };
344
413
  /**
345
- * Re-validates the IC3 certificate for a proven flat-encoding verdict.
414
+ * Re-verifies an extracted proof certificate against the unstrengthened step relation.
346
415
  *
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)
416
+ * @param certificate the `(define-fun …)` block extracted verbatim from the Spacer
417
+ * model (`null` when the solver printed none)
349
418
  * @param flatNet the flat net the CHC query was encoded from
350
419
  * @param initialMarking the verified initial marking (VC1)
351
420
  * @param property the verified property (VC3)
352
421
  * @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)
422
+ * strengthened with; conjoined into the CANDIDATE certificate and re-proven by the
423
+ * three VCs (never conjoined into the step relation)
355
424
  * @param sinkPlaces declared sink places (deadlock-freedom VC3)
356
- * @param timeoutMs per-VC solver timeout in milliseconds
425
+ * @param solver the resolved z3 executable
426
+ * @param timeoutMs per-invocation solver budget in milliseconds
427
+ */
428
+ 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>;
429
+ /**
430
+ * The certificate-check script for the given inputs, exactly as
431
+ * {@link checkCertificate} would send it (VER-013 script parity): what the
432
+ * cross-language golden tests diff.
357
433
  */
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>;
434
+ declare function vcScript(certificate: string, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, sinkPlaces: ReadonlySet<Place<any>>, invariants: readonly PInvariant[]): string;
359
435
 
360
436
  /**
361
437
  * Name-correlation fragment classifier for the ν-aware state class graph
@@ -462,6 +538,7 @@ declare class SmtVerifier {
462
538
  private _timeoutMs;
463
539
  private _certificateCheck;
464
540
  private _counterexampleReplay;
541
+ private _semiflowInvariants;
465
542
  private _nuMaxClasses;
466
543
  private _fragmentMode;
467
544
  private readonly _carrierPlaces;
@@ -510,6 +587,27 @@ declare class SmtVerifier {
510
587
  * `SmtVerificationResult.counterexampleConfirmed` for how each outcome lands.
511
588
  */
512
589
  counterexampleReplay(enabled: boolean): this;
590
+ /**
591
+ * Also hands the validated **P-semiflows** to the encoders as invariants
592
+ * (VER-007; default: disabled — the encoders then see only the null-space basis).
593
+ *
594
+ * Every validated semiflow is a conservation law in its own right (`y >= 0`,
595
+ * `y·C = 0`, `y·M0` exact, zero weight on every reset / consume-all place), and
596
+ * the Farkas enumeration returns the *minimal* laws of the net. The null-space
597
+ * basis the encoders get by default is one basis of many: elimination hands back
598
+ * mixed-sign rows (discarded as not semi-positive) or rows that fold a reset place
599
+ * into a chain whose other combinations avoid it (dropped by the H1 guard). On a
600
+ * net with a few reset arcs that can lose every law of the chains those arcs
601
+ * touch, and without them IC3 has to rediscover the conservation of each chain —
602
+ * on a ~100-place net it does not within any practical budget. With the semiflows
603
+ * in, the same reachability-safety queries close in about a second.
604
+ *
605
+ * Soundness is unchanged: the semiflows pass the same exact re-validation as the
606
+ * basis rows, the union is pure strengthening (`Semiflow.lean`,
607
+ * `semiflow_union_sound`), and the certificate check re-proves the strengthened
608
+ * invariant. Off by default so reports stay byte-equal.
609
+ */
610
+ semiflowInvariants(enabled: boolean): this;
513
611
  /**
514
612
  * Sets the class-count cap for the ν-aware state-class-graph analysis (NU-050,
515
613
  * Route B). When the symbolic name-aware graph would exceed this, the analysis
@@ -547,6 +645,16 @@ declare class SmtVerifier {
547
645
  * dead-letter-drain stalls the eager, priority-ordered executor never produces.
548
646
  */
549
647
  prioritySemantics(semantics: PrioritySemantics): this;
648
+ /**
649
+ * The SMT-LIB2 scripts {@link verify} would send to z3 for this configuration,
650
+ * without running a solver (VER-013 AC1): the HORN query (flat, or name-coloured
651
+ * when a declared budget puts the net on Route A's exact encoding) and, for the
652
+ * flat encoding, the certificate-check script built around
653
+ * {@link placeholderCertificate}. This is what the cross-language golden tests diff
654
+ * byte for byte. Route B, the structural pre-check and the unresolved-place
655
+ * refusal are bypassed: it is what Route A encodes.
656
+ */
657
+ encodeScripts(): EncodedScripts;
550
658
  /**
551
659
  * Runs the verification pipeline.
552
660
  *
@@ -574,146 +682,142 @@ declare class SmtVerifier {
574
682
  */
575
683
  private applyNuGuard;
576
684
  }
685
+ /** The scripts {@link SmtVerifier.encodeScripts} reports. */
686
+ interface EncodedScripts {
687
+ /** The HORN query, flat or name-coloured. */
688
+ readonly horn: string;
689
+ /** The certificate-check script around {@link placeholderCertificate}; `null` for the name-coloured encoding. */
690
+ readonly certificate: string | null;
691
+ /** Whether `horn` is the name-coloured encoding. */
692
+ readonly coloured: boolean;
693
+ }
694
+ /**
695
+ * `(define-fun Reachable ((x!0 Int) …) Bool true)`: the certificate stand-in the
696
+ * golden certificate scripts are built around (a real certificate is solver output
697
+ * and never part of a golden).
698
+ */
699
+ declare function placeholderCertificate(placeCount: number): string;
577
700
 
578
701
  /**
579
- * Result of a Spacer query.
702
+ * @module spacer-runner
703
+ *
704
+ * Runs Z3 Spacer on a HORN script through one `z3` process (VER-013) and
705
+ * classifies the reply in verdict terms.
706
+ *
707
+ * HORN/Spacer convention (shared with the Rust and Java verifiers and corroborated
708
+ * by the certificate check): with the query `(assert (not Error))`, z3 prints `sat`
709
+ * when the property is PROVEN (an inductive invariant excluding every violating
710
+ * state exists) and `unsat` when it is VIOLATED (no such invariant; the refutation
711
+ * proof carries the counterexample states).
580
712
  */
713
+
714
+ /** Result of a Spacer query. */
581
715
  type QueryResult = QueryProven | QueryViolated | QueryUnknown;
582
- /** Property proven: no reachable error state (UNSAT). */
716
+ /** Property proven (z3 `sat`). */
583
717
  interface QueryProven {
584
718
  readonly type: 'proven';
585
- readonly invariantFormula: string | null;
586
- readonly levelInvariants: readonly string[];
587
719
  /**
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.
720
+ * The `(define-fun …)` block of the model, verbatim (the certificate the
721
+ * certificate checker re-validates), or `null` when no model printed.
592
722
  */
593
- readonly answer: Expr | null;
723
+ readonly invariantFormula: string | null;
594
724
  }
595
- /** Counterexample found (SAT). The answer is the derivation tree. */
725
+ /** Property violated (z3 `unsat`). */
596
726
  interface QueryViolated {
597
727
  readonly type: 'violated';
598
- readonly answer: Expr | null;
728
+ /** The raw solver reply; the refutation proof in it is decoded by the counterexample decoder. */
729
+ readonly answer: string;
599
730
  }
600
- /** Solver could not determine (timeout, resource limit). */
731
+ /** Solver could not determine (timeout, resource limit, transport failure). */
601
732
  interface QueryUnknown {
602
733
  readonly type: 'unknown';
603
734
  readonly reason: string;
604
735
  }
605
736
  /**
606
- * The Z3 context and helpers returned by SpacerRunner.create().
607
- * Exposes the context object for building expressions.
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.
737
+ * Runs `smt2` with `fp.engine=spacer`. `phase` names the dump files (`horn` or
738
+ * `horn-coloured`).
624
739
  */
625
- declare function createSpacerRunner(timeoutMs: number): Promise<SpacerContext>;
740
+ declare function runZ3Spacer(solver: Z3Solver, timeoutMs: number, smt2: string, phase: string): Promise<QueryResult>;
626
741
 
627
742
  /**
628
743
  * @module smt-encoder
629
744
  *
630
- * Encodes a flattened Petri net as Constrained Horn Clauses (CHC) for Z3's Spacer engine.
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:
745
+ * Encodes a flattened Petri net as Constrained Horn Clauses (CHC) in SMT-LIB2 text
746
+ * for Z3's Spacer engine (VER-013).
634
747
  *
635
- * 1. **Init**: `Reachable(M0)` the initial marking is reachable
636
- * 2. **Transition**: `Reachable(M') :- Reachable(M) ∧ enabled(M,t) ∧ fire(M,M',t)` —
637
- * one rule per flat transition (XOR branches are separate transitions)
638
- * 3. **Error**: `Error() :- Reachable(M) ∧ violation(M)` — safety property violation
748
+ * The net's state space is modeled as integer vectors (one variable per place = token
749
+ * count). Three rule types:
639
750
  *
640
- * Transition rules include: non-negativity constraints on M', P-invariant strengthening
641
- * clauses, and environment bounds for bounded analysis.
751
+ * 1. **Init**: `(assert (Reachable M0))` the initial marking is reachable
752
+ * 2. **Transition**: `Reachable(M') :- Reachable(M) enabled(M,t) ∧ fire(M,M',t) ∧
753
+ * M' ≥ 0 ∧ invariants(M') ∧ env-bounds(M')` — one rule per flat transition, plus
754
+ * one env-injection rule per injected environment place (VER-006)
755
+ * 3. **Error**: `Error :- Reachable(M) ∧ violation(M)`; `(assert (not Error))`, so
756
+ * `sat` is PROVEN and `unsat` is VIOLATED
642
757
  *
643
- * Z3 types are complex and partially untyped; the ctx/fp parameters use `any`.
758
+ * The emitted script is byte-identical to the Rust reference (`smt_encoder.rs`) and
759
+ * the Java port for the same input: places in code-point order of their names, the
760
+ * property's places, sinks, env bounds and injections in place-index order,
761
+ * invariants in the order the verifier canonicalised.
644
762
  */
645
763
 
646
- /** Z3 high-level context. Typed as `any` because z3-solver's TS types are incomplete. */
647
- type Z3Context = any;
648
- /** Z3 Fixedpoint solver instance. Typed as `any` because z3-solver's TS types are incomplete. */
649
- type Z3Fixedpoint = any;
650
- /**
651
- * Result of CHC encoding.
652
- */
653
- interface EncodingResult {
654
- readonly errorExpr: Bool;
655
- readonly reachableDecl: FuncDecl;
764
+ /** An encoded SMT-LIB2 script. */
765
+ interface SmtEncoding {
766
+ /** The script text. */
767
+ readonly smt2: string;
768
+ /** The number of flat places (the arity of `Reachable` in the flat encoding). */
769
+ readonly placeCount: number;
656
770
  }
657
771
  /**
658
- * Encodes a flattened Petri net as Constrained Horn Clauses (CHC) for Z3's Spacer engine.
772
+ * Encodes the net and property as a HORN script.
659
773
  *
660
- * CHC rules:
661
- * - Reachable(M0) initial state is reachable
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
774
+ * @param produceProofs emit `:produce-proofs` and `(get-proof)` so an `unsat` reply
775
+ * carries the refutation the replay decodes
664
776
  */
665
- declare function encode(ctx: Z3Context, fp: Z3Fixedpoint, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[], sinkPlaces?: ReadonlySet<Place<any>>): EncodingResult;
666
-
777
+ declare function encode(flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[], sinkPlaces?: ReadonlySet<Place<any>>, produceProofs?: boolean): SmtEncoding;
667
778
  /**
668
- * Structured reason why decoding degraded (never thrown decoding a
669
- * counterexample must not crash a violated verdict).
779
+ * The net's one-step relation `T(M, M')` as one plain SMT-LIB2 formula over the free
780
+ * variables `m0..` / `m0p..`: the disjunction of every flat transition firing and
781
+ * every env-injection step (VER-006). This is the UNSTRENGTHENED relation the
782
+ * certificate check validates against: it shares the condition emitters with the CHC
783
+ * path but omits the P-invariant conjuncts, so a certificate poisoned by a wrong
784
+ * invariant cannot re-certify itself.
670
785
  */
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;
786
+ declare function encodeStepRelationSmt2(flatNet: FlatNet): string;
787
+
682
788
  /**
683
- * Result of counterexample decoding.
789
+ * @module counterexample-decoder
790
+ *
791
+ * Decodes z3's refutation output into replayable counterexample material.
792
+ *
793
+ * There is exactly one decoder: {@link decodeStateSet}, which collects the ground
794
+ * `Reachable` facts of a `:produce-proofs` refutation into a SET. The ordered trace
795
+ * a caller sees is reconstructed from that set by the abstract replayer; the proof
796
+ * printer's traversal order is not a firing order and was never safe to read as one.
797
+ *
798
+ * Applications with non-ground arguments (rule bodies quantify `Reachable` over
799
+ * variables) or the wrong arity are skipped; a malformed proof simply yields a
800
+ * smaller (possibly empty) set, never a throw. Byte-for-byte mirror of the Rust
801
+ * `counterexample::decode_state_set`.
684
802
  */
803
+
804
+ /** Result of counterexample decoding. */
685
805
  interface DecodedTrace {
686
806
  /**
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
- */
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.
807
+ * The ground `Reachable` markings of the proof as an order-free set (text order
808
+ * preserved for display), what the abstract replayer chains into a firing order.
698
809
  */
699
810
  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;
811
+ /** Why nothing was decoded; `null` when `states` is non-empty. */
812
+ readonly note: string | null;
705
813
  }
814
+ /** Decodes the states of a z3 reply; a note says so when none were found. */
815
+ declare function decode(answer: string, flatNet: FlatNet): DecodedTrace;
706
816
  /**
707
- * Decodes Z3 Spacer counterexample answers into Petri net marking traces.
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`.
817
+ * Collects the ground `Reachable(...)` applications from a z3 refutation proof into
818
+ * a state set, in text order.
715
819
  */
716
- declare function decode(ctx: any, answer: Expr | null, flatNet: FlatNet): DecodedTrace;
820
+ declare function decodeStateSet(answer: string, flatNet: FlatNet): ReadonlySet<MarkingState>;
717
821
 
718
822
  /**
719
823
  * @module abstract-replayer
@@ -1005,4 +1109,4 @@ declare class TimePetriNetAnalyzerBuilder {
1005
1109
  build(): TimePetriNetAnalyzer;
1006
1110
  }
1007
1111
 
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 };
1112
+ export { type AbstractState, type EnvironmentAnalysisMode as AnalysisEnvironmentMode, type BranchEdge, type CertificateCheckOutcome, type CertificateVc, DBM, DUMP_ENV, type DecodedTrace, type EncodedScripts, type 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, alwaysAvailable, alwaysAvailable as analysisAlwaysAvailable, bounded as analysisBounded, ignore as analysisIgnore, bounded, canonicalInvariantOrder, checkCertificate, computePInvariants, computePSemiflows, computeSCCs, decode, decodeStateSet, encode, encodeStepRelationSmt2, findMaximalTrapIn, findMinimalSiphons, findTerminalSCCs, flatNetIndexOf, flatNetPlaceCount, flatNetTransitionCount, flatTransition, flatten, formatZ3Version, ignore, isCoveredByInvariants, parseZ3Version, placeholderCertificate, replayCounterexample, resolveZ3, runZ3Spacer, runZ3Text, strengthenWithSemiflows, structuralCheck, vcScript, z3Available, z3SolverAt };