libpetri 4.0.0 → 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.
@@ -3528,6 +3528,7 @@ function counterexamplePath(scg, target) {
3528
3528
  }
3529
3529
 
3530
3530
  // src/verification/smt-verifier.ts
3531
+ var IGNORE_MODE_VACUITY_REASON = "environment places present but not modeled (mode=ignore); a proof would be vacuous \u2014 use alwaysAvailable() or bounded(k) to model external injection";
3531
3532
  var SmtVerifier = class _SmtVerifier {
3532
3533
  constructor(net) {
3533
3534
  this.net = net;
@@ -3636,13 +3637,26 @@ var SmtVerifier = class _SmtVerifier {
3636
3637
  * into a chain whose other combinations avoid it (dropped by the H1 guard). On a
3637
3638
  * net with a few reset arcs that can lose every law of the chains those arcs
3638
3639
  * touch, and without them IC3 has to rediscover the conservation of each chain —
3639
- * on a ~100-place net it does not within any practical budget. With the semiflows
3640
- * in, the same reachability-safety queries close in about a second.
3640
+ * on a ~100-place net it does not within any practical budget.
3641
+ *
3642
+ * **Turn this on if the net has any `all()` / `atLeast(n)` or reset arc on a busy
3643
+ * place** — draining an input queue is the everyday case. Every basis row whose
3644
+ * support touches such a place fails the H1 guard and is dropped, so the encoders
3645
+ * run on a deficient invariant set and nothing in the report says a law is missing
3646
+ * beyond the `Dropped` lines.
3647
+ *
3648
+ * This reaches the **name-coloured** encoder (NU-050) as well as the flat one, and
3649
+ * it matters most there. On a 113-place ν-net, whole-net deadlock-freedom went from
3650
+ * `unknown` after 50 minutes to `proven` in about 15 seconds with this option as the
3651
+ * only change; on the flat path, reachability-safety queries that timed out at 120 s
3652
+ * close in about a second.
3641
3653
  *
3642
3654
  * Soundness is unchanged: the semiflows pass the same exact re-validation as the
3643
3655
  * basis rows, the union is pure strengthening (`Semiflow.lean`,
3644
3656
  * `semiflow_union_sound`), and the certificate check re-proves the strengthened
3645
- * invariant. Off by default so reports stay byte-equal.
3657
+ * invariant that check is flat-path only, so a coloured `proven` reports
3658
+ * `Certificate check: not applicable (name-coloured encoding)`. Off by default so
3659
+ * reports stay byte-equal.
3646
3660
  */
3647
3661
  semiflowInvariants(enabled) {
3648
3662
  this._semiflowInvariants = enabled;
@@ -3702,6 +3716,48 @@ var SmtVerifier = class _SmtVerifier {
3702
3716
  this._prioritySemantics = semantics;
3703
3717
  return this;
3704
3718
  }
3719
+ /**
3720
+ * The name-coloured plan and its encoding, or a null plan when the net is outside
3721
+ * the fragment (NU-050) and a null encoding when the property names a place the net
3722
+ * does not resolve.
3723
+ *
3724
+ * {@link verify} and {@link encodeScripts} share this deliberately. They used to
3725
+ * invoke `buildColouredPlan` and `encodeColoured` separately, so handing the encoder
3726
+ * the wrong one of the two lists changed only one of them — and the script-parity
3727
+ * goldens are generated from `encodeScripts`. Unifying the invocation closes that. It
3728
+ * does not make the two paths identical: each still computes its own invariant and
3729
+ * semiflow lists, so they can still drift through the arguments rather than the call.
3730
+ *
3731
+ * `invariants` is what the encoder conjoins into every rule body (the null-space
3732
+ * basis, unioned with the semiflows when VER-007 is enabled); `semiflows` sets the
3733
+ * colour-slot bound k (NU-053). They are not the same list.
3734
+ */
3735
+ colouredAttempt(flatNet, invariants, semiflows) {
3736
+ const hasMatch = [...this.net.transitions].some((t) => t.matchSpec !== null);
3737
+ const nuBounded = this._budgetPlaces.size > 0;
3738
+ if (!hasMatch || !nuBounded) return { plan: null, encoding: null };
3739
+ const plan = buildColouredPlan(
3740
+ this.net,
3741
+ flatNet,
3742
+ this._initialMarking,
3743
+ this._budgetPlaces,
3744
+ this._fragmentMode,
3745
+ this._carrierPlaces,
3746
+ semiflows
3747
+ );
3748
+ if (plan == null) return { plan: null, encoding: null };
3749
+ return {
3750
+ plan,
3751
+ encoding: encodeColoured(
3752
+ plan,
3753
+ flatNet,
3754
+ this._initialMarking,
3755
+ this._property,
3756
+ invariants,
3757
+ this._sinkPlaces
3758
+ )
3759
+ };
3760
+ }
3705
3761
  /**
3706
3762
  * The SMT-LIB2 scripts {@link verify} would send to z3 for this configuration,
3707
3763
  * without running a solver (VER-013 AC1): the HORN query (flat, or name-coloured
@@ -3713,8 +3769,6 @@ var SmtVerifier = class _SmtVerifier {
3713
3769
  */
3714
3770
  encodeScripts() {
3715
3771
  requireOutputProducingActions(this.net);
3716
- const hasMatch = [...this.net.transitions].some((t) => t.matchSpec !== null);
3717
- const nuBounded = this._budgetPlaces.size > 0;
3718
3772
  const flatNet = flatten(this.net, this._environmentPlaces, this._environmentMode);
3719
3773
  const matrix = IncidenceMatrix.from(flatNet);
3720
3774
  const { valid: basis } = validateInvariantsExact(
@@ -3732,20 +3786,9 @@ var SmtVerifier = class _SmtVerifier {
3732
3786
  let invariants = basis;
3733
3787
  if (this._semiflowInvariants) invariants = strengthenWithSemiflows(basis, semiflows).invariants;
3734
3788
  invariants = canonicalInvariantOrder(invariants);
3735
- if (hasMatch && nuBounded) {
3736
- const plan = buildColouredPlan(
3737
- this.net,
3738
- flatNet,
3739
- this._initialMarking,
3740
- this._budgetPlaces,
3741
- this._fragmentMode,
3742
- this._carrierPlaces,
3743
- semiflows
3744
- );
3745
- if (plan != null) {
3746
- const coloured = encodeColoured(plan, flatNet, this._initialMarking, this._property, invariants, this._sinkPlaces);
3747
- if (coloured != null) return { horn: coloured.smt2, certificate: null, coloured: true };
3748
- }
3789
+ const attempt = this.colouredAttempt(flatNet, invariants, semiflows);
3790
+ if (attempt.encoding != null) {
3791
+ return { horn: attempt.encoding.smt2, certificate: null, coloured: true };
3749
3792
  }
3750
3793
  const horn = encode(flatNet, this._initialMarking, this._property, invariants, this._sinkPlaces, this._counterexampleReplay).smt2;
3751
3794
  const certificate = vcScript(
@@ -3796,8 +3839,13 @@ var SmtVerifier = class _SmtVerifier {
3796
3839
  if (outcome.transitions.length > 0) {
3797
3840
  report.push(` Counterexample trace: ${outcome.trace.length} states, ${outcome.transitions.length} transitions`);
3798
3841
  }
3842
+ let routeBVerdict = outcome.verdict;
3843
+ if (routeBVerdict.type === "proven" && this._environmentPlaces.size > 0 && this._environmentMode.type === "ignore") {
3844
+ report.push(` Downgraded to UNKNOWN: ${IGNORE_MODE_VACUITY_REASON}`);
3845
+ routeBVerdict = { type: "unknown", reason: IGNORE_MODE_VACUITY_REASON };
3846
+ }
3799
3847
  return buildResult(
3800
- outcome.verdict,
3848
+ routeBVerdict,
3801
3849
  report.join("\n"),
3802
3850
  [],
3803
3851
  [],
@@ -3903,15 +3951,6 @@ var SmtVerifier = class _SmtVerifier {
3903
3951
  }
3904
3952
  report.push("");
3905
3953
  report.push("Phase 4: IC3/PDR verification via Z3 Spacer...");
3906
- const colouredPlan = hasMatch && nuBounded ? buildColouredPlan(
3907
- this.net,
3908
- flatNet,
3909
- this._initialMarking,
3910
- this._budgetPlaces,
3911
- this._fragmentMode,
3912
- this._carrierPlaces,
3913
- semiflows
3914
- ) : null;
3915
3954
  const stats = {
3916
3955
  places: flatNet.places.length,
3917
3956
  transitions: flatNet.transitions.length,
@@ -3932,12 +3971,14 @@ var SmtVerifier = class _SmtVerifier {
3932
3971
  return buildResult({ type: "unknown", reason }, report.join("\n"), invariants, [], [], [], performance.now() - start, stats);
3933
3972
  }
3934
3973
  report.push(` Solver: z3 ${formatZ3Version(solver.version)}`);
3974
+ const colouredAttempt = this.colouredAttempt(flatNet, invariants, semiflows);
3975
+ const colouredPlan = colouredAttempt.plan;
3935
3976
  let encoding;
3936
3977
  if (colouredPlan != null) {
3937
3978
  report.push(
3938
3979
  ` \u03BD-encoding: name-coloured (exact within budget k=${colouredPlan.k}; ${colouredPlan.coloured.length} coloured place(s))`
3939
3980
  );
3940
- const coloured = encodeColoured(colouredPlan, flatNet, this._initialMarking, this._property, invariants, this._sinkPlaces);
3981
+ const coloured = colouredAttempt.encoding;
3941
3982
  if (coloured == null) {
3942
3983
  const reason = "property names a place that does not resolve in the net; refusing to certify (the encoding would be vacuously proven)";
3943
3984
  report.push(" Status: UNKNOWN (unresolved property place)\n");
@@ -3966,7 +4007,7 @@ var SmtVerifier = class _SmtVerifier {
3966
4007
  switch (queryResult.type) {
3967
4008
  case "proven": {
3968
4009
  if (this._environmentPlaces.size > 0 && this._environmentMode.type === "ignore") {
3969
- const reason = "environment places present but not modeled (mode=ignore); a proof would be vacuous \u2014 use alwaysAvailable() or bounded(k) to model external injection";
4010
+ const reason = IGNORE_MODE_VACUITY_REASON;
3970
4011
  report.push(` Status: UNSAT, but vacuous under ignore mode
3971
4012
  `);
3972
4013
  report.push("=== RESULT ===\n");
@@ -4362,4 +4403,4 @@ export {
4362
4403
  isProven,
4363
4404
  isViolated
4364
4405
  };
4365
- //# sourceMappingURL=chunk-WYCGGQAW.js.map
4406
+ //# sourceMappingURL=chunk-FD3S4TZM.js.map