libpetri 0.3.2
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 +121 -0
- package/dist/chunk-FN773SSE.js +87 -0
- package/dist/chunk-FN773SSE.js.map +1 -0
- package/dist/chunk-VQ4XMJTD.js +107 -0
- package/dist/chunk-VQ4XMJTD.js.map +1 -0
- package/dist/export/index.d.ts +153 -0
- package/dist/export/index.js +411 -0
- package/dist/export/index.js.map +1 -0
- package/dist/index.d.ts +498 -0
- package/dist/index.js +1972 -0
- package/dist/index.js.map +1 -0
- package/dist/petri-net-C3Jy5HCt.d.ts +543 -0
- package/dist/verification/index.d.ts +505 -0
- package/dist/verification/index.js +1201 -0
- package/dist/verification/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
import { P as Place, b as Transition, a as PetriNet, E as EnvironmentPlace } from '../petri-net-C3Jy5HCt.js';
|
|
2
|
+
import { Expr, init, Bool, FuncDecl } from 'z3-solver';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Immutable snapshot of a Petri net marking for state space analysis.
|
|
6
|
+
*
|
|
7
|
+
* Maps places (by name) to integer token counts. Only stores places with count > 0.
|
|
8
|
+
* Used for invariant computation and structural verification, not runtime execution.
|
|
9
|
+
*/
|
|
10
|
+
declare class MarkingState {
|
|
11
|
+
private readonly tokenCounts;
|
|
12
|
+
private readonly placesByName;
|
|
13
|
+
/** @internal Use {@link MarkingState.builder} or {@link MarkingState.empty} to create instances. */
|
|
14
|
+
constructor(key: symbol, tokenCounts: Map<string, number>, placesByName: Map<string, Place<any>>);
|
|
15
|
+
/** Returns the token count for a place (0 if absent). */
|
|
16
|
+
tokens(place: Place<any>): number;
|
|
17
|
+
/** Checks if a place has at least one token. */
|
|
18
|
+
hasTokens(place: Place<any>): boolean;
|
|
19
|
+
/** Checks if any of the given places has tokens. */
|
|
20
|
+
hasTokensInAny(places: Iterable<Place<any>>): boolean;
|
|
21
|
+
/** Returns all places with tokens > 0. */
|
|
22
|
+
placesWithTokens(): Place<any>[];
|
|
23
|
+
/** Returns the total number of tokens. */
|
|
24
|
+
totalTokens(): number;
|
|
25
|
+
/** Checks if no tokens exist anywhere. */
|
|
26
|
+
isEmpty(): boolean;
|
|
27
|
+
toString(): string;
|
|
28
|
+
static empty(): MarkingState;
|
|
29
|
+
static builder(): MarkingStateBuilder;
|
|
30
|
+
}
|
|
31
|
+
declare class MarkingStateBuilder {
|
|
32
|
+
private readonly tokenCounts;
|
|
33
|
+
private readonly placesByName;
|
|
34
|
+
/** Sets the token count for a place. */
|
|
35
|
+
tokens(place: Place<any>, count: number): this;
|
|
36
|
+
/** Adds tokens to a place. */
|
|
37
|
+
addTokens(place: Place<any>, count: number): this;
|
|
38
|
+
build(): MarkingState;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A flattened transition with pre/post vectors for SMT encoding.
|
|
43
|
+
*
|
|
44
|
+
* Each Transition with XOR outputs is expanded into multiple FlatTransitions
|
|
45
|
+
* (one per branch). Non-XOR transitions map 1:1.
|
|
46
|
+
*/
|
|
47
|
+
interface FlatTransition {
|
|
48
|
+
/** Display name (e.g. "Search_b0", "Search_b1"). */
|
|
49
|
+
readonly name: string;
|
|
50
|
+
/** The original transition. */
|
|
51
|
+
readonly source: Transition;
|
|
52
|
+
/** Which XOR branch (-1 if no XOR). */
|
|
53
|
+
readonly branchIndex: number;
|
|
54
|
+
/** Tokens consumed per place (indexed by place index). */
|
|
55
|
+
readonly preVector: readonly number[];
|
|
56
|
+
/** Tokens produced per place (indexed by place index). */
|
|
57
|
+
readonly postVector: readonly number[];
|
|
58
|
+
/** Place indices where inhibitor arcs block firing. */
|
|
59
|
+
readonly inhibitorPlaces: readonly number[];
|
|
60
|
+
/** Place indices requiring a token without consuming. */
|
|
61
|
+
readonly readPlaces: readonly number[];
|
|
62
|
+
/** Place indices set to 0 on firing. */
|
|
63
|
+
readonly resetPlaces: readonly number[];
|
|
64
|
+
/** True at index i means place i uses All/AtLeast semantics. */
|
|
65
|
+
readonly consumeAll: readonly boolean[];
|
|
66
|
+
}
|
|
67
|
+
declare function flatTransition(name: string, source: Transition, branchIndex: number, preVector: number[], postVector: number[], inhibitorPlaces: number[], readPlaces: number[], resetPlaces: number[], consumeAll: boolean[]): FlatTransition;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A flattened Petri net with indexed places and XOR-expanded transitions.
|
|
71
|
+
*
|
|
72
|
+
* Intermediate representation between the high-level PetriNet and Z3 CHC encoding.
|
|
73
|
+
*/
|
|
74
|
+
interface FlatNet {
|
|
75
|
+
/** Ordered list of places (index = position). */
|
|
76
|
+
readonly places: readonly Place<any>[];
|
|
77
|
+
/** Reverse lookup: place name -> index. */
|
|
78
|
+
readonly placeIndex: ReadonlyMap<string, number>;
|
|
79
|
+
/** XOR-expanded flat transitions. */
|
|
80
|
+
readonly transitions: readonly FlatTransition[];
|
|
81
|
+
/** For bounded environment places: place name -> max tokens. */
|
|
82
|
+
readonly environmentBounds: ReadonlyMap<string, number>;
|
|
83
|
+
}
|
|
84
|
+
declare function flatNetPlaceCount(net: FlatNet): number;
|
|
85
|
+
declare function flatNetTransitionCount(net: FlatNet): number;
|
|
86
|
+
declare function flatNetIndexOf(net: FlatNet, place: Place<any>): number;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Incidence matrix for a flattened Petri net.
|
|
90
|
+
*
|
|
91
|
+
* The incidence matrix C is defined as C[t][p] = post[t][p] - pre[t][p].
|
|
92
|
+
* It captures the net effect of each transition on each place.
|
|
93
|
+
*
|
|
94
|
+
* P-invariants are solutions to y^T * C = 0, found via null space
|
|
95
|
+
* computation on C^T.
|
|
96
|
+
*/
|
|
97
|
+
declare class IncidenceMatrix {
|
|
98
|
+
private readonly _pre;
|
|
99
|
+
private readonly _post;
|
|
100
|
+
private readonly _incidence;
|
|
101
|
+
private readonly _numTransitions;
|
|
102
|
+
private readonly _numPlaces;
|
|
103
|
+
private constructor();
|
|
104
|
+
/**
|
|
105
|
+
* Computes the incidence matrix from a FlatNet.
|
|
106
|
+
*/
|
|
107
|
+
static from(flatNet: FlatNet): IncidenceMatrix;
|
|
108
|
+
/**
|
|
109
|
+
* Returns C^T (transpose of incidence matrix), dimensions [P][T].
|
|
110
|
+
* Used for P-invariant computation: null space of C^T gives P-invariants.
|
|
111
|
+
*/
|
|
112
|
+
transposedIncidence(): number[][];
|
|
113
|
+
/** Returns the pre-matrix (tokens consumed). T×P. */
|
|
114
|
+
pre(): readonly (readonly number[])[];
|
|
115
|
+
/** Returns the post-matrix (tokens produced). T×P. */
|
|
116
|
+
post(): readonly (readonly number[])[];
|
|
117
|
+
/** Returns the incidence matrix C[t][p] = post - pre. T×P. */
|
|
118
|
+
incidence(): readonly (readonly number[])[];
|
|
119
|
+
numTransitions(): number;
|
|
120
|
+
numPlaces(): number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @module net-flattener
|
|
125
|
+
*
|
|
126
|
+
* Flattens a PetriNet into integer-indexed pre/post vectors for SMT encoding.
|
|
127
|
+
*
|
|
128
|
+
* **XOR expansion**: Transitions with XOR output specs are expanded into multiple
|
|
129
|
+
* flat transitions — one per deterministic branch. Each branch produces tokens to
|
|
130
|
+
* exactly one XOR child's places. This converts non-deterministic output routing
|
|
131
|
+
* into separate transitions that the SMT solver can reason about independently.
|
|
132
|
+
*
|
|
133
|
+
* **Vector construction**: For each flat transition, builds:
|
|
134
|
+
* - `preVector[p]`: tokens consumed from place p (input cardinality)
|
|
135
|
+
* - `postVector[p]`: tokens produced to place p (from the selected branch)
|
|
136
|
+
* - `consumeAll[p]`: true for `all`/`at-least` inputs (consume everything)
|
|
137
|
+
* - Index arrays for inhibitor, read, and reset arcs
|
|
138
|
+
*
|
|
139
|
+
* Places are sorted by name for stable, deterministic indexing across runs.
|
|
140
|
+
*/
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* How to treat environment places during analysis.
|
|
144
|
+
*/
|
|
145
|
+
type EnvironmentAnalysisMode = {
|
|
146
|
+
readonly type: 'unbounded';
|
|
147
|
+
} | {
|
|
148
|
+
readonly type: 'bounded';
|
|
149
|
+
readonly maxTokens: number;
|
|
150
|
+
};
|
|
151
|
+
declare function unbounded(): EnvironmentAnalysisMode;
|
|
152
|
+
declare function bounded(maxTokens: number): EnvironmentAnalysisMode;
|
|
153
|
+
/**
|
|
154
|
+
* Flattens a PetriNet into a FlatNet suitable for SMT encoding.
|
|
155
|
+
*
|
|
156
|
+
* Flattening involves:
|
|
157
|
+
* 1. Assigning each place a stable integer index (sorted by name)
|
|
158
|
+
* 2. Expanding XOR outputs into separate flat transitions (one per branch)
|
|
159
|
+
* 3. Building pre/post vectors from input/output specs
|
|
160
|
+
* 4. Recording inhibitor, read, and reset arcs
|
|
161
|
+
* 5. Setting environment bounds for bounded analysis mode
|
|
162
|
+
*/
|
|
163
|
+
declare function flatten(net: PetriNet, environmentPlaces?: Set<EnvironmentPlace<any>>, environmentMode?: EnvironmentAnalysisMode): FlatNet;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* A P-invariant (place invariant) of a Petri net.
|
|
167
|
+
*
|
|
168
|
+
* A P-invariant is a vector y such that y^T * C = 0, where C is the
|
|
169
|
+
* incidence matrix. This means that for any reachable marking M:
|
|
170
|
+
* sum(y_i * M_i) = constant, where constant = sum(y_i * M0_i).
|
|
171
|
+
*
|
|
172
|
+
* P-invariants provide structural bounds on places and are used as
|
|
173
|
+
* strengthening lemmas for the IC3/PDR engine.
|
|
174
|
+
*/
|
|
175
|
+
interface PInvariant {
|
|
176
|
+
/** Weight vector (one entry per place index). */
|
|
177
|
+
readonly weights: readonly number[];
|
|
178
|
+
/** The invariant value sum(y_i * M0_i). */
|
|
179
|
+
readonly constant: number;
|
|
180
|
+
/** Set of place indices where weight != 0. */
|
|
181
|
+
readonly support: ReadonlySet<number>;
|
|
182
|
+
}
|
|
183
|
+
declare function pInvariant(weights: number[], constant: number, support: Set<number>): PInvariant;
|
|
184
|
+
declare function pInvariantToString(inv: PInvariant): string;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @module p-invariant-computer
|
|
188
|
+
*
|
|
189
|
+
* Computes P-invariants of a Petri net via integer Gaussian elimination (Farkas' algorithm).
|
|
190
|
+
*
|
|
191
|
+
* **Algorithm**: A P-invariant is a non-negative integer vector y such that y^T · C = 0
|
|
192
|
+
* (where C is the incidence matrix). This expresses a conservation law: the weighted
|
|
193
|
+
* token sum Σ(y_i · M[i]) is constant across all reachable markings.
|
|
194
|
+
*
|
|
195
|
+
* **Farkas variant**: Constructs the augmented matrix [C^T | I_P] and row-reduces
|
|
196
|
+
* the C^T portion to zero using integer elimination (no floating point). Rows where
|
|
197
|
+
* the C^T part becomes all-zero yield invariant vectors from the identity part.
|
|
198
|
+
* Row normalization by GCD keeps values small during elimination.
|
|
199
|
+
*
|
|
200
|
+
* **Integer Gaussian elimination**: Each elimination step multiplies rows by pivot
|
|
201
|
+
* coefficients (a·row - b·pivotRow) to avoid fractions. This preserves integer
|
|
202
|
+
* arithmetic throughout, critical for exact invariant computation.
|
|
203
|
+
*
|
|
204
|
+
* Invariants are used to strengthen SMT queries (added as constraints on M').
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Computes P-invariants of a Petri net via integer Gaussian elimination.
|
|
209
|
+
*
|
|
210
|
+
* P-invariants are non-negative integer vectors y where y^T * C = 0.
|
|
211
|
+
* They express conservation laws: the weighted token sum is constant
|
|
212
|
+
* across all reachable markings.
|
|
213
|
+
*
|
|
214
|
+
* Algorithm: compute the null space of C^T using integer row reduction
|
|
215
|
+
* with an augmented identity matrix (Farkas' algorithm variant).
|
|
216
|
+
*/
|
|
217
|
+
declare function computePInvariants(matrix: IncidenceMatrix, flatNet: FlatNet, initialMarking: MarkingState): PInvariant[];
|
|
218
|
+
/**
|
|
219
|
+
* Checks if every place is covered by at least one P-invariant.
|
|
220
|
+
* If true, the net is structurally bounded.
|
|
221
|
+
*/
|
|
222
|
+
declare function isCoveredByInvariants(invariants: readonly PInvariant[], numPlaces: number): boolean;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @module structural-check
|
|
226
|
+
*
|
|
227
|
+
* Structural deadlock pre-check using siphon/trap analysis (Commoner's theorem).
|
|
228
|
+
*
|
|
229
|
+
* **Commoner's theorem**: A Petri net is deadlock-free if every siphon contains
|
|
230
|
+
* an initially marked trap.
|
|
231
|
+
*
|
|
232
|
+
* **Siphon**: A set of places S where every transition that outputs to S also
|
|
233
|
+
* inputs from S. Key property: once all places in a siphon become empty,
|
|
234
|
+
* they can never be re-marked. An empty siphon can cause deadlock.
|
|
235
|
+
*
|
|
236
|
+
* **Trap**: A set of places S where every transition that inputs from S also
|
|
237
|
+
* outputs to S. Key property: once any place in a trap is marked,
|
|
238
|
+
* the trap remains marked forever.
|
|
239
|
+
*
|
|
240
|
+
* **Algorithm**: For each place, compute the minimal siphon containing it via
|
|
241
|
+
* fixed-point expansion. For each siphon, find the maximal trap within it
|
|
242
|
+
* (fixed-point contraction). If every siphon contains an initially-marked
|
|
243
|
+
* trap, deadlock-freedom is proven structurally — no SMT query needed.
|
|
244
|
+
*
|
|
245
|
+
* Limited to nets with ≤50 places to bound enumeration cost.
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Result of structural deadlock check using siphon/trap analysis.
|
|
250
|
+
*/
|
|
251
|
+
type StructuralCheckResult = {
|
|
252
|
+
readonly type: 'no-potential-deadlock';
|
|
253
|
+
} | {
|
|
254
|
+
readonly type: 'potential-deadlock';
|
|
255
|
+
readonly siphon: ReadonlySet<number>;
|
|
256
|
+
} | {
|
|
257
|
+
readonly type: 'inconclusive';
|
|
258
|
+
readonly reason: string;
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Structural deadlock pre-check using siphon/trap analysis.
|
|
262
|
+
*
|
|
263
|
+
* Commoner's theorem: a Petri net is deadlock-free if every siphon
|
|
264
|
+
* contains a marked trap.
|
|
265
|
+
*
|
|
266
|
+
* A siphon is a set of places S such that every transition with
|
|
267
|
+
* an output in S also has an input in S. Once empty, a siphon stays empty.
|
|
268
|
+
*
|
|
269
|
+
* A trap is a set of places S such that every transition with
|
|
270
|
+
* an input in S also has an output in S. Once marked, a trap stays marked.
|
|
271
|
+
*/
|
|
272
|
+
declare function structuralCheck(flatNet: FlatNet, initialMarking: MarkingState): StructuralCheckResult;
|
|
273
|
+
/**
|
|
274
|
+
* Finds minimal siphons by checking all non-empty subsets of deadlock-enabling places.
|
|
275
|
+
* Uses a fixed-point approach: start from each place and grow the siphon.
|
|
276
|
+
*/
|
|
277
|
+
declare function findMinimalSiphons(flatNet: FlatNet): ReadonlySet<number>[];
|
|
278
|
+
/**
|
|
279
|
+
* Finds the maximal trap within a given set of places.
|
|
280
|
+
* Uses fixed-point: start with the full set and remove places that violate the trap condition.
|
|
281
|
+
*/
|
|
282
|
+
declare function findMaximalTrapIn(flatNet: FlatNet, places: ReadonlySet<number>): ReadonlySet<number>;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Safety properties that can be verified via IC3/PDR.
|
|
286
|
+
*
|
|
287
|
+
* Each property is encoded as an error condition: if a reachable state
|
|
288
|
+
* violates the property, Spacer finds a counterexample. If no violation
|
|
289
|
+
* is reachable, the property is proven.
|
|
290
|
+
*/
|
|
291
|
+
type SmtProperty = DeadlockFree | MutualExclusion | PlaceBound | Unreachable;
|
|
292
|
+
/** Deadlock-freedom: no reachable marking has all transitions disabled. */
|
|
293
|
+
interface DeadlockFree {
|
|
294
|
+
readonly type: 'deadlock-free';
|
|
295
|
+
}
|
|
296
|
+
/** Mutual exclusion: two places never have tokens simultaneously. */
|
|
297
|
+
interface MutualExclusion {
|
|
298
|
+
readonly type: 'mutual-exclusion';
|
|
299
|
+
readonly p1: Place<any>;
|
|
300
|
+
readonly p2: Place<any>;
|
|
301
|
+
}
|
|
302
|
+
/** Place bound: a place never exceeds a given token count. */
|
|
303
|
+
interface PlaceBound {
|
|
304
|
+
readonly type: 'place-bound';
|
|
305
|
+
readonly place: Place<any>;
|
|
306
|
+
readonly bound: number;
|
|
307
|
+
}
|
|
308
|
+
/** Unreachability: the given places never all have tokens simultaneously. */
|
|
309
|
+
interface Unreachable {
|
|
310
|
+
readonly type: 'unreachable';
|
|
311
|
+
readonly places: ReadonlySet<Place<any>>;
|
|
312
|
+
}
|
|
313
|
+
declare function deadlockFree(): DeadlockFree;
|
|
314
|
+
declare function mutualExclusion(p1: Place<any>, p2: Place<any>): MutualExclusion;
|
|
315
|
+
declare function placeBound(place: Place<any>, bound: number): PlaceBound;
|
|
316
|
+
declare function unreachable(places: ReadonlySet<Place<any>>): Unreachable;
|
|
317
|
+
/** Human-readable description of a property. */
|
|
318
|
+
declare function propertyDescription(prop: SmtProperty): string;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Verification verdict.
|
|
322
|
+
*/
|
|
323
|
+
type Verdict = Proven | Violated | Unknown;
|
|
324
|
+
/** Property proven safe. No reachable state violates it. */
|
|
325
|
+
interface Proven {
|
|
326
|
+
readonly type: 'proven';
|
|
327
|
+
readonly method: string;
|
|
328
|
+
readonly inductiveInvariant: string | null;
|
|
329
|
+
}
|
|
330
|
+
/** Property violated. A counterexample trace is available. */
|
|
331
|
+
interface Violated {
|
|
332
|
+
readonly type: 'violated';
|
|
333
|
+
}
|
|
334
|
+
/** Could not determine. */
|
|
335
|
+
interface Unknown {
|
|
336
|
+
readonly type: 'unknown';
|
|
337
|
+
readonly reason: string;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Solver statistics.
|
|
341
|
+
*/
|
|
342
|
+
interface SmtStatistics {
|
|
343
|
+
readonly places: number;
|
|
344
|
+
readonly transitions: number;
|
|
345
|
+
readonly invariantsFound: number;
|
|
346
|
+
readonly structuralResult: string;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Result of SMT-based verification.
|
|
350
|
+
*/
|
|
351
|
+
interface SmtVerificationResult {
|
|
352
|
+
readonly verdict: Verdict;
|
|
353
|
+
readonly report: string;
|
|
354
|
+
readonly invariants: readonly PInvariant[];
|
|
355
|
+
readonly discoveredInvariants: readonly string[];
|
|
356
|
+
readonly counterexampleTrace: readonly MarkingState[];
|
|
357
|
+
readonly counterexampleTransitions: readonly string[];
|
|
358
|
+
readonly elapsedMs: number;
|
|
359
|
+
readonly statistics: SmtStatistics;
|
|
360
|
+
}
|
|
361
|
+
declare function isProven(result: SmtVerificationResult): boolean;
|
|
362
|
+
declare function isViolated(result: SmtVerificationResult): boolean;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* IC3/PDR-based safety verifier for Petri nets using Z3's Spacer engine.
|
|
366
|
+
*
|
|
367
|
+
* Proves safety properties (especially deadlock-freedom) without
|
|
368
|
+
* enumerating all reachable states. IC3 constructs inductive invariants
|
|
369
|
+
* incrementally, which works well for bounded nets.
|
|
370
|
+
*
|
|
371
|
+
* Key design decisions:
|
|
372
|
+
* - Operates on the marking projection (integer vectors) — no timing
|
|
373
|
+
* - An untimed deadlock-freedom proof is stronger than needed
|
|
374
|
+
* (timing can only restrict behavior)
|
|
375
|
+
* - Guards are ignored — over-approximation is sound for safety properties
|
|
376
|
+
* - If a counterexample is found, it may be spurious in timed/guarded
|
|
377
|
+
* semantics — the report notes this
|
|
378
|
+
*
|
|
379
|
+
* Verification Pipeline:
|
|
380
|
+
* 1. Flatten — expand XOR, index places, build pre/post vectors
|
|
381
|
+
* 2. Structural pre-check — siphon/trap analysis (may prove early)
|
|
382
|
+
* 3. P-invariants — compute conservation laws for strengthening
|
|
383
|
+
* 4. SMT encode + query — IC3/PDR via Z3 Spacer
|
|
384
|
+
* 5. Decode result — proof or counterexample trace
|
|
385
|
+
*/
|
|
386
|
+
declare class SmtVerifier {
|
|
387
|
+
private readonly net;
|
|
388
|
+
private _initialMarking;
|
|
389
|
+
private _property;
|
|
390
|
+
private readonly _environmentPlaces;
|
|
391
|
+
private _environmentMode;
|
|
392
|
+
private _timeoutMs;
|
|
393
|
+
private constructor();
|
|
394
|
+
static forNet(net: PetriNet): SmtVerifier;
|
|
395
|
+
initialMarking(marking: MarkingState): this;
|
|
396
|
+
initialMarking(configurator: (builder: MarkingStateBuilder) => void): this;
|
|
397
|
+
property(property: SmtProperty): this;
|
|
398
|
+
environmentPlaces(...places: EnvironmentPlace<any>[]): this;
|
|
399
|
+
environmentMode(mode: EnvironmentAnalysisMode): this;
|
|
400
|
+
timeout(ms: number): this;
|
|
401
|
+
/**
|
|
402
|
+
* Runs the verification pipeline.
|
|
403
|
+
*/
|
|
404
|
+
verify(): Promise<SmtVerificationResult>;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Result of a Spacer query.
|
|
409
|
+
*/
|
|
410
|
+
type QueryResult = QueryProven | QueryViolated | QueryUnknown;
|
|
411
|
+
/** Property proven: no reachable error state (UNSAT). */
|
|
412
|
+
interface QueryProven {
|
|
413
|
+
readonly type: 'proven';
|
|
414
|
+
readonly invariantFormula: string | null;
|
|
415
|
+
readonly levelInvariants: readonly string[];
|
|
416
|
+
}
|
|
417
|
+
/** Counterexample found (SAT). The answer is the derivation tree. */
|
|
418
|
+
interface QueryViolated {
|
|
419
|
+
readonly type: 'violated';
|
|
420
|
+
readonly answer: Expr | null;
|
|
421
|
+
}
|
|
422
|
+
/** Solver could not determine (timeout, resource limit). */
|
|
423
|
+
interface QueryUnknown {
|
|
424
|
+
readonly type: 'unknown';
|
|
425
|
+
readonly reason: string;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* The Z3 context and helpers returned by SpacerRunner.create().
|
|
429
|
+
* Exposes the context object for building expressions.
|
|
430
|
+
*/
|
|
431
|
+
interface SpacerContext {
|
|
432
|
+
/** The Z3 high-level context for building expressions. */
|
|
433
|
+
readonly ctx: ReturnType<Awaited<ReturnType<typeof init>>['Context']>;
|
|
434
|
+
/** The Z3 Fixedpoint solver instance (Spacer engine). Z3 types are complex; using any. */
|
|
435
|
+
readonly fp: any;
|
|
436
|
+
/** Queries whether the error state is reachable. */
|
|
437
|
+
query(errorExpr: Bool, reachableDecl?: FuncDecl): Promise<QueryResult>;
|
|
438
|
+
/** Releases Z3 resources. */
|
|
439
|
+
dispose(): void;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Creates a Spacer runner with the given timeout.
|
|
443
|
+
*
|
|
444
|
+
* Uses Z3's Spacer engine (CHC solver based on IC3/PDR) to prove or
|
|
445
|
+
* disprove safety properties.
|
|
446
|
+
*/
|
|
447
|
+
declare function createSpacerRunner(timeoutMs: number): Promise<SpacerContext>;
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @module smt-encoder
|
|
451
|
+
*
|
|
452
|
+
* Encodes a flattened Petri net as Constrained Horn Clauses (CHC) for Z3's Spacer engine.
|
|
453
|
+
*
|
|
454
|
+
* **CHC encoding strategy**: The net's state space is modeled as integer vectors
|
|
455
|
+
* (one variable per place = token count). Three rule types:
|
|
456
|
+
*
|
|
457
|
+
* 1. **Init**: `Reachable(M0)` — the initial marking is reachable
|
|
458
|
+
* 2. **Transition**: `Reachable(M') :- Reachable(M) ∧ enabled(M,t) ∧ fire(M,M',t)` —
|
|
459
|
+
* one rule per flat transition (XOR branches are separate transitions)
|
|
460
|
+
* 3. **Error**: `Error() :- Reachable(M) ∧ violation(M)` — safety property violation
|
|
461
|
+
*
|
|
462
|
+
* Transition rules include: non-negativity constraints on M', P-invariant strengthening
|
|
463
|
+
* clauses, and environment bounds for bounded analysis.
|
|
464
|
+
*
|
|
465
|
+
* Z3 types are complex and partially untyped; the ctx/fp parameters use `any`.
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
/** Z3 high-level context. Typed as `any` because z3-solver's TS types are incomplete. */
|
|
469
|
+
type Z3Context = any;
|
|
470
|
+
/** Z3 Fixedpoint solver instance. Typed as `any` because z3-solver's TS types are incomplete. */
|
|
471
|
+
type Z3Fixedpoint = any;
|
|
472
|
+
/**
|
|
473
|
+
* Result of CHC encoding.
|
|
474
|
+
*/
|
|
475
|
+
interface EncodingResult {
|
|
476
|
+
readonly errorExpr: Bool;
|
|
477
|
+
readonly reachableDecl: FuncDecl;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Encodes a flattened Petri net as Constrained Horn Clauses (CHC) for Z3's Spacer engine.
|
|
481
|
+
*
|
|
482
|
+
* CHC rules:
|
|
483
|
+
* - Reachable(M0) — initial state is reachable
|
|
484
|
+
* - Reachable(M') :- Reachable(M) AND enabled(M,t) AND fire(M,M',t) — transition rules
|
|
485
|
+
* - Error() :- Reachable(M) AND property_violation(M) — safety property
|
|
486
|
+
*/
|
|
487
|
+
declare function encode(ctx: Z3Context, fp: Z3Fixedpoint, flatNet: FlatNet, initialMarking: MarkingState, property: SmtProperty, invariants: readonly PInvariant[]): EncodingResult;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Result of counterexample decoding.
|
|
491
|
+
*/
|
|
492
|
+
interface DecodedTrace {
|
|
493
|
+
readonly trace: readonly MarkingState[];
|
|
494
|
+
readonly transitions: readonly string[];
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Decodes Z3 Spacer counterexample answers into Petri net marking traces.
|
|
498
|
+
*
|
|
499
|
+
* When Spacer finds a counterexample (property violation), it produces
|
|
500
|
+
* a derivation tree showing how the error state is reachable. This function
|
|
501
|
+
* extracts the marking at each step to produce a human-readable trace.
|
|
502
|
+
*/
|
|
503
|
+
declare function decode(ctx: any, answer: Expr | null, flatNet: FlatNet): DecodedTrace;
|
|
504
|
+
|
|
505
|
+
export { type DeadlockFree, type DecodedTrace, type EncodingResult, type EnvironmentAnalysisMode, type FlatNet, type FlatTransition, IncidenceMatrix, MarkingState, MarkingStateBuilder, type MutualExclusion, type PInvariant, type PlaceBound, type Proven, type QueryProven, type QueryResult, type QueryUnknown, type QueryViolated, type SmtProperty, type SmtStatistics, type SmtVerificationResult, SmtVerifier, type SpacerContext, type StructuralCheckResult, type Unknown, type Unreachable, type Verdict, type Violated, bounded, computePInvariants, createSpacerRunner, deadlockFree, decode, encode, findMaximalTrapIn, findMinimalSiphons, flatNetIndexOf, flatNetPlaceCount, flatNetTransitionCount, flatTransition, flatten, isCoveredByInvariants, isProven, isViolated, mutualExclusion, pInvariant, pInvariantToString, placeBound, propertyDescription, structuralCheck, unbounded, unreachable };
|