libpetri 2.12.1 → 3.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.
@@ -72,7 +72,6 @@ type Arc = ArcInput | ArcOutput | ArcInhibitor | ArcRead | ArcReset;
72
72
  interface ArcInput<T = any> {
73
73
  readonly type: 'input';
74
74
  readonly place: Place<T>;
75
- readonly guard?: (value: T) => boolean;
76
75
  }
77
76
  interface ArcOutput<T = any> {
78
77
  readonly type: 'output';
@@ -91,7 +90,7 @@ interface ArcReset<T = any> {
91
90
  readonly place: Place<T>;
92
91
  }
93
92
  /** Input arc: consumes token from place when transition fires. */
94
- declare function inputArc<T>(place: Place<T>, guard?: (value: T) => boolean): ArcInput<T>;
93
+ declare function inputArc<T>(place: Place<T>): ArcInput<T>;
95
94
  /** Output arc: produces token to place when transition fires. */
96
95
  declare function outputArc<T>(place: Place<T>): ArcOutput<T>;
97
96
  /** Inhibitor arc: blocks transition if place has tokens. */
@@ -102,15 +101,14 @@ declare function readArc<T>(place: Place<T>): ArcRead<T>;
102
101
  declare function resetArc<T>(place: Place<T>): ArcReset<T>;
103
102
  /** Returns the place this arc connects to. */
104
103
  declare function arcPlace(arc: Arc): Place<any>;
105
- /** Checks if an input arc has a guard predicate. */
106
- declare function hasGuard(arc: ArcInput): boolean;
107
- /** Checks if a token value matches an input arc's guard. */
108
- declare function matchesGuard<T>(arc: ArcInput<T>, value: T): boolean;
109
104
 
110
105
  /**
111
- * Input specification with cardinality and optional guard predicate.
112
- * CPN-compliant: cardinality determines how many tokens to consume,
113
- * guard filters which tokens are eligible.
106
+ * Input specification with cardinality. Purely structural (IO-006): cardinality
107
+ * determines how many tokens to consume; there is no per-token predicate.
108
+ *
109
+ * Conditional token selection is modeled with multiple conflicting transitions
110
+ * and XOR-on-input semantics rather than a predicate coupled to the enablement
111
+ * check.
114
112
  *
115
113
  * Inputs are always AND-joined (all must be satisfied to enable transition).
116
114
  * XOR on inputs is modeled via multiple transitions (conflict).
@@ -119,33 +117,29 @@ type In = InOne | InExactly | InAll | InAtLeast;
119
117
  interface InOne<T = any> {
120
118
  readonly type: 'one';
121
119
  readonly place: Place<T>;
122
- readonly guard?: (value: T) => boolean;
123
120
  }
124
121
  interface InExactly<T = any> {
125
122
  readonly type: 'exactly';
126
123
  readonly place: Place<T>;
127
124
  readonly count: number;
128
- readonly guard?: (value: T) => boolean;
129
125
  }
130
126
  interface InAll<T = any> {
131
127
  readonly type: 'all';
132
128
  readonly place: Place<T>;
133
- readonly guard?: (value: T) => boolean;
134
129
  }
135
130
  interface InAtLeast<T = any> {
136
131
  readonly type: 'at-least';
137
132
  readonly place: Place<T>;
138
133
  readonly minimum: number;
139
- readonly guard?: (value: T) => boolean;
140
134
  }
141
- /** Consume exactly 1 token (standard CPN semantics). Optional guard filters eligible tokens. */
142
- declare function one<T>(place: Place<T>, guard?: (value: T) => boolean): InOne<T>;
143
- /** Consume exactly N tokens (batching). Optional guard filters eligible tokens. */
144
- declare function exactly<T>(count: number, place: Place<T>, guard?: (value: T) => boolean): InExactly<T>;
145
- /** Consume all available tokens (must be 1+). Optional guard filters eligible tokens. */
146
- declare function all<T>(place: Place<T>, guard?: (value: T) => boolean): InAll<T>;
147
- /** Wait for N+ tokens, consume all when enabled. Optional guard filters eligible tokens. */
148
- declare function atLeast<T>(minimum: number, place: Place<T>, guard?: (value: T) => boolean): InAtLeast<T>;
135
+ /** Consume exactly 1 token (standard CPN semantics). */
136
+ declare function one<T>(place: Place<T>): InOne<T>;
137
+ /** Consume exactly N tokens (batching). */
138
+ declare function exactly<T>(count: number, place: Place<T>): InExactly<T>;
139
+ /** Consume all available tokens (must be 1+). */
140
+ declare function all<T>(place: Place<T>): InAll<T>;
141
+ /** Wait for N+ tokens, consume all when enabled. */
142
+ declare function atLeast<T>(minimum: number, place: Place<T>): InAtLeast<T>;
149
143
  /** Returns the minimum number of tokens required to enable. */
150
144
  declare function requiredCount(spec: In): number;
151
145
  /**
@@ -191,11 +185,11 @@ declare function nameId(value: string): NameId;
191
185
  * On firing, exactly those name-matched tokens are consumed (spec NU-020).
192
186
  *
193
187
  * This is the single *decidable* predicate — equality of opaque names — and is
194
- * deliberately NOT a general guard: it correlates the name dimension *across*
195
- * places (composition-structural, like cardinality) rather than evaluating an
196
- * arbitrary boolean per token. When both a unary input `guard` and a match are
197
- * present the guard filters first, then the name correlation runs over the
198
- * survivors (NU-021).
188
+ * deliberately NOT a general input predicate: it correlates the name dimension
189
+ * *across* places (composition-structural, like cardinality) rather than
190
+ * evaluating an arbitrary boolean per token. Input specifications themselves
191
+ * remain purely structural (IO-006); name correlation is the only per-token
192
+ * filter the enablement check ever applies (NU-021).
199
193
  */
200
194
 
201
195
  /**
@@ -228,7 +222,7 @@ declare function matchKey<T>(place: Place<T>, key: KeyFn<T>): MatchKey<T>;
228
222
  * ))
229
223
  *
230
224
  * @throws if fewer than two inputs are correlated (a match over a single place
231
- * is just a guard).
225
+ * correlates nothing).
232
226
  */
233
227
  declare function matchSpec(...keys: MatchKey[]): MatchSpec;
234
228
  /** Returns the name projection for `placeName`, or `undefined` if not correlated. */
@@ -577,15 +571,19 @@ declare class TransitionContext {
577
571
  type TransitionAction = (ctx: TransitionContext) => Promise<void>;
578
572
  /**
579
573
  * Identity action: produces no outputs.
574
+ * For transitions that only consume tokens without producing any.
580
575
  *
581
- * Returns a stable singleton reference (cached on first call). Reference
582
- * stability is relied on by {@link import('./internal/subnet-rewriter.js')
583
- * .composeActions} during channel composition (MOD-021) to short-circuit a
584
- * passthrough-on-both-sides merge to passthrough — saving a microtask hop
585
- * and matching the Java implementation's behaviour where both transitions'
586
- * default actions collapse to the builder's own passthrough default.
576
+ * Returns a stable singleton reference (CORE-051), so {@link isPassthrough}
577
+ * can recognise it.
587
578
  */
588
579
  declare function passthrough(): TransitionAction;
580
+ /**
581
+ * Whether `action` is the built-in {@link passthrough} — i.e. provably produces
582
+ * no output tokens. Identity-based, so a hand-written no-op is not claimed.
583
+ *
584
+ * @param action the action to test; `null` / `undefined` is not passthrough
585
+ */
586
+ declare function isPassthrough(action: TransitionAction | null | undefined): boolean;
589
587
  /**
590
588
  * Transform action: applies function to context, copies result to ALL output places.
591
589
  *
@@ -1539,8 +1537,12 @@ declare class PetriNet {
1539
1537
  bindActions(actionBindings: Map<string, TransitionAction> | Record<string, TransitionAction>): PetriNet;
1540
1538
  /**
1541
1539
  * Creates a new PetriNet with actions bound via a resolver function.
1540
+ *
1541
+ * The resolver is called once per transition with its name. Returning `null`
1542
+ * defers that transition — it keeps whatever action it already carries — which
1543
+ * is what makes staged binding (**MOD-024** AC7) work.
1542
1544
  */
1543
- bindActionsWithResolver(actionResolver: (name: string) => TransitionAction): PetriNet;
1545
+ bindActionsWithResolver(actionResolver: (name: string) => TransitionAction | null): PetriNet;
1544
1546
  static builder(name: string): PetriNetBuilder;
1545
1547
  }
1546
1548
  declare class PetriNetBuilder {
@@ -1738,7 +1740,8 @@ declare class PetriNetBuilder {
1738
1740
  * Map<string, Place<unknown>> convention — TypeScript Place identity is
1739
1741
  * name-based per `runtime/compiled-net.ts`).
1740
1742
  * 3. Walk every transition through {@link applyFusion} to rewrite arc place
1741
- * references.
1743
+ * references; input arcs colliding on a canonical place merge per
1744
+ * [MOD-021] (additive where summable, rejected otherwise).
1742
1745
  * 4. Re-derive the place set from the rewritten transitions plus any
1743
1746
  * caller-declared standalone places, dropping non-canonical members.
1744
1747
  * Caller-declared standalone places that happen to be non-canonical
@@ -1774,4 +1777,4 @@ declare class PetriNetBuilder {
1774
1777
  private buildWithFusion;
1775
1778
  }
1776
1779
 
1777
- 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 TokenSupplier 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, readArc as aA, requiredCount as aB, resetArc as aC, timeout as aD, timeoutPlace as aE, tokenAt as aF, tokenOf as aG, transform as aH, transformAsync as aI, transformFrom as aJ, unitToken as aK, window as aL, withTimeout as aM, xor as aN, xorPlaces as aO, MarkingState as aP, type PInvariant as aQ, MarkingStateBuilder as aR, type SmtProperty as aS, type SmtVerificationResult as aT, type BranchPlaceBound as aU, type DeadlockFree as aV, type JoinedOrDeadLettered as aW, type MutualExclusion as aX, type PlaceBound as aY, type Proven as aZ, type SmtStatistics 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, hasGuard as ai, immediate as aj, inhibitorArc as ak, inputArc as al, isUnit as am, keyForPlace as an, latest as ao, matchCorrelates as ap, matchKey as aq, matchSpec as ar, matchesGuard as as, nameId as at, one as au, outPlace as av, outputArc as aw, passthrough as ax, place as ay, produce as az, Transition as b, type Unknown as b0, type Unreachable as b1, type Verdict as b2, type Violated as b3, branchPlaceBound as b4, deadlockFree as b5, isProven as b6, isViolated as b7, joinedOrDeadLettered as b8, mutualExclusion as b9, pInvariant as ba, pInvariantToString as bb, placeBound as bc, propertyDescription as bd, unreachable as be, 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 };
1780
+ 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, MarkingStateBuilder as aQ, type SmtProperty 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,5 +1,5 @@
1
- import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aP as MarkingState, aQ as PInvariant, aR as MarkingStateBuilder, aS as SmtProperty, aT as SmtVerificationResult } from '../petri-net-Byc3gSgJ.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 branchPlaceBound, b5 as deadlockFree, b6 as isProven, b7 as isViolated, b8 as joinedOrDeadLettered, b9 as mutualExclusion, ba as pInvariant, bb as pInvariantToString, bc as placeBound, bd as propertyDescription, be as unreachable } from '../petri-net-Byc3gSgJ.js';
1
+ import { b as Transition, a as Place, P as PetriNet, E as EnvironmentPlace, aO as MarkingState, aP as PInvariant, aQ as MarkingStateBuilder, aR as SmtProperty, aS as SmtVerificationResult } from '../petri-net-UQBBkvLl.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-UQBBkvLl.js';
3
3
  import { Expr, init, Bool, FuncDecl } from 'z3-solver';
4
4
 
5
5
  /**
@@ -341,9 +341,10 @@ type PrioritySemantics = 'none' | 'conflict';
341
341
  * - Operates on the marking projection (integer vectors) — no timing
342
342
  * - An untimed deadlock-freedom proof is stronger than needed
343
343
  * (timing can only restrict behavior)
344
- * - Guards are ignored over-approximation is sound for safety properties
345
- * - If a counterexample is found, it may be spurious in timed/guarded
346
- * semantics the report notes this
344
+ * - Input specifications are purely structural (IO-006) there is no per-arc
345
+ * predicate for the encoder to be blind to
346
+ * - If a counterexample is found, it may be spurious in timed semantics —
347
+ * the report notes this
347
348
  *
348
349
  * Verification Pipeline:
349
350
  * 1. Flatten — expand XOR, index places, build pre/post vectors
@@ -426,6 +427,8 @@ declare class SmtVerifier {
426
427
  prioritySemantics(semantics: PrioritySemantics): this;
427
428
  /**
428
429
  * Runs the verification pipeline.
430
+ *
431
+ * @throws Error if the net violates CORE-043 — verification rejects the same nets execution rejects.
429
432
  */
430
433
  verify(): Promise<SmtVerificationResult>;
431
434
  /**
@@ -646,7 +649,11 @@ declare class StateClassGraph {
646
649
  private readonly _predecessors;
647
650
  private readonly _complete;
648
651
  private constructor();
649
- /** Builds the state class graph for a Time Petri Net. */
652
+ /**
653
+ * Builds the state class graph for a Time Petri Net.
654
+ *
655
+ * @throws Error if the net violates CORE-043 — analysis rejects the same nets execution rejects.
656
+ */
650
657
  static build(net: PetriNet, initialMarking: MarkingState, maxClasses: number, environmentPlaces?: Set<EnvironmentPlace<any>>, environmentMode?: EnvironmentAnalysisMode): StateClassGraph;
651
658
  stateClasses(): readonly StateClass[];
652
659
  size(): number;
@@ -35,7 +35,7 @@ import {
35
35
  propertyDescription,
36
36
  structuralCheck,
37
37
  unreachable
38
- } from "../chunk-V3WTQRHC.js";
38
+ } from "../chunk-5W6SVYPD.js";
39
39
  import "../chunk-ATT7U5H5.js";
40
40
 
41
41
  // src/verification/analysis/scc-analyzer.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libpetri",
3
- "version": "2.12.1",
3
+ "version": "3.0.0",
4
4
  "description": "Coloured Time Petri Net engine — TypeScript port",
5
5
  "homepage": "https://libpetri.org",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/match-spec.ts"],"sourcesContent":["/**\n * ν-net join correlation ([[MatchSpec]]).\n *\n * A {@link MatchSpec} declares that a subset of a transition's **input** places\n * must be correlated by **name equality**: the transition is enabled only when\n * there exists a single {@link NameId} `n` such that every correlated input\n * supplies (at least) its required token count whose projected name equals `n`.\n * On firing, exactly those name-matched tokens are consumed (spec NU-020).\n *\n * This is the single *decidable* predicate — equality of opaque names — and is\n * deliberately NOT a general guard: it correlates the name dimension *across*\n * places (composition-structural, like cardinality) rather than evaluating an\n * arbitrary boolean per token. When both a unary input `guard` and a match are\n * present the guard filters first, then the name correlation runs over the\n * survivors (NU-021).\n */\nimport type { Place } from './place.js';\nimport type { NameId } from './name.js';\n\n/**\n * A name projection: maps a token's value to its {@link NameId}. A projection\n * that yields no name (returns `null`/`undefined` at runtime) is treated as\n * \"no name\" — that token never correlates — mirroring the Java/Rust `KeyFn`\n * contract; the binding selector handles a nullish result defensively.\n */\nexport type KeyFn<T = any> = (value: T) => NameId;\n\n/** One correlated input: the place plus its name projection. */\nexport interface MatchKey<T = any> {\n readonly place: Place<T>;\n readonly key: KeyFn<T>;\n}\n\n/** Correlated fork/join match specification (ν-net join side). */\nexport interface MatchSpec {\n readonly keys: readonly MatchKey[];\n}\n\n/** Builds one correlated input for a {@link MatchSpec}. */\nexport function matchKey<T>(place: Place<T>, key: KeyFn<T>): MatchKey<T> {\n return { place, key };\n}\n\n/**\n * Builds a {@link MatchSpec} from two or more correlated inputs.\n *\n * @example\n * Transition.builder('join')\n * .inputs(one(branchA), one(branchB))\n * .match(matchSpec(\n * matchKey(branchA, (m: Msg) => nameId(m.correlationId)),\n * matchKey(branchB, (m: Msg) => nameId(m.correlationId)),\n * ))\n *\n * @throws if fewer than two inputs are correlated (a match over a single place\n * is just a guard).\n */\nexport function matchSpec(...keys: MatchKey[]): MatchSpec {\n if (keys.length < 2) {\n throw new Error(`MatchSpec must correlate at least 2 input places, got ${keys.length}`);\n }\n return { keys };\n}\n\n/** Returns the name projection for `placeName`, or `undefined` if not correlated. */\nexport function keyForPlace(spec: MatchSpec, placeName: string): KeyFn | undefined {\n for (const k of spec.keys) {\n if (k.place.name === placeName) return k.key;\n }\n return undefined;\n}\n\n/** True when `placeName` is one of the correlated inputs. */\nexport function matchCorrelates(spec: MatchSpec, placeName: string): boolean {\n return spec.keys.some(k => k.place.name === placeName);\n}\n"],"mappings":";AAuCO,SAAS,SAAY,OAAiB,KAA4B;AACvE,SAAO,EAAE,OAAO,IAAI;AACtB;AAgBO,SAAS,aAAa,MAA6B;AACxD,MAAI,KAAK,SAAS,GAAG;AACnB,UAAM,IAAI,MAAM,yDAAyD,KAAK,MAAM,EAAE;AAAA,EACxF;AACA,SAAO,EAAE,KAAK;AAChB;AAGO,SAAS,YAAY,MAAiB,WAAsC;AACjF,aAAW,KAAK,KAAK,MAAM;AACzB,QAAI,EAAE,MAAM,SAAS,UAAW,QAAO,EAAE;AAAA,EAC3C;AACA,SAAO;AACT;AAGO,SAAS,gBAAgB,MAAiB,WAA4B;AAC3E,SAAO,KAAK,KAAK,KAAK,OAAK,EAAE,MAAM,SAAS,SAAS;AACvD;","names":[]}