libpetri 2.13.0 → 3.0.1

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.
Files changed (48) hide show
  1. package/README.md +89 -130
  2. package/dist/chunk-6NH64RCU.js +1016 -0
  3. package/dist/chunk-6NH64RCU.js.map +1 -0
  4. package/dist/{chunk-7VJ5CYUU.js → chunk-JZIEWVAV.js} +905 -62
  5. package/dist/chunk-JZIEWVAV.js.map +1 -0
  6. package/dist/{chunk-JVI5HFRX.js → chunk-VCDOKWVU.js} +2 -2
  7. package/dist/{chunk-E3ZWB645.js → chunk-YVIPJ6KM.js} +1 -1
  8. package/dist/chunk-YVIPJ6KM.js.map +1 -0
  9. package/dist/debug/index.d.ts +2 -2
  10. package/dist/debug/index.js +2 -2
  11. package/dist/doclet/index.d.ts +12 -3
  12. package/dist/doclet/index.js +8 -4
  13. package/dist/doclet/index.js.map +1 -1
  14. package/dist/doclet/resources/petrinet-diagrams.css +21 -0
  15. package/dist/doclet/resources/petrinet-diagrams.js +3575 -3573
  16. package/dist/dot-exporter-3STXYK74.js +9 -0
  17. package/dist/{render-ZGZEZ5RK.js → elk-place-YVNQFGXI.js} +3 -258
  18. package/dist/elk-place-YVNQFGXI.js.map +1 -0
  19. package/dist/{event-store-DKTenPbC.d.ts → event-store-BFX_yJ8I.d.ts} +1 -1
  20. package/dist/export/index.d.ts +1 -1
  21. package/dist/export/index.js +2 -2
  22. package/dist/index.d.ts +91 -38
  23. package/dist/index.js +368 -294
  24. package/dist/index.js.map +1 -1
  25. package/dist/pan-zoom-Cp51IkDl.d.ts +33 -0
  26. package/dist/{petri-net-C3LSY-vm.d.ts → petri-net-WSScMyDL.d.ts} +43 -29
  27. package/dist/preprocess-FN3F75JR.js +193 -0
  28. package/dist/preprocess-FN3F75JR.js.map +1 -0
  29. package/dist/render-QOHGDWNE.js +78 -0
  30. package/dist/render-QOHGDWNE.js.map +1 -0
  31. package/dist/render-dom/index.d.ts +28 -29
  32. package/dist/render-dom/index.js +14 -21
  33. package/dist/render-dom/index.js.map +1 -1
  34. package/dist/verification/index.d.ts +273 -7
  35. package/dist/verification/index.js +7 -1
  36. package/dist/verification/index.js.map +1 -1
  37. package/dist/viewer/index.d.ts +24 -32
  38. package/dist/viewer/index.js +9 -1003
  39. package/dist/viewer/index.js.map +1 -1
  40. package/dist/viewer/viewer.css +21 -0
  41. package/dist/viewer/viewer.iife.js +3575 -3573
  42. package/package.json +2 -2
  43. package/dist/chunk-7VJ5CYUU.js.map +0 -1
  44. package/dist/chunk-E3ZWB645.js.map +0 -1
  45. package/dist/dot-exporter-SHBYMMJ3.js +0 -9
  46. package/dist/render-ZGZEZ5RK.js.map +0 -1
  47. /package/dist/{chunk-JVI5HFRX.js.map → chunk-VCDOKWVU.js.map} +0 -0
  48. /package/dist/{dot-exporter-SHBYMMJ3.js.map → dot-exporter-3STXYK74.js.map} +0 -0
package/README.md CHANGED
@@ -1,172 +1,131 @@
1
- # libpetri
1
+ # libpetri for TypeScript
2
2
 
3
- TypeScript implementation of a **Coloured Time Petri Net** (CTPN) engine with bitmap-based execution, formal verification via Z3, and DOT/Graphviz visualization.
3
+ [![npm](https://img.shields.io/npm/v/libpetri)](https://www.npmjs.com/package/libpetri)
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-6-blue)](https://www.typescriptlang.org/)
5
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](https://github.com/debe/libpetri/blob/main/LICENSE)
4
6
 
5
- ## Architecture
7
+ The TypeScript 6 implementation of libpetri: typed Coloured Time Petri Nets for Promise-based applications, with modular composition, two execution backends, observability, DOT export, and formal verification.
6
8
 
7
- ```
8
- src/
9
- ├── core/ # Net definition: places, transitions, arcs, timing, output specs
10
- ├── runtime/ # Async bitmap-based executor, marking, compiled net
11
- ├── event/ # Event store and net event types (discriminated union)
12
- ├── export/ # DOT (Graphviz) diagram exporter
13
- └── verification/ # SMT-based property verification (Z3)
14
- ```
15
-
16
- ### Core (`src/core/`)
17
-
18
- Immutable net definitions with typed, colored tokens.
19
-
20
- | Type | Description |
21
- |------|-------------|
22
- | `Place<T>` | Typed token container (phantom type for compile-time safety) |
23
- | `EnvironmentPlace<T>` | External event injection point |
24
- | `Transition` | Arc specs, timing, priority, guards, action binding |
25
- | `PetriNet` | Immutable net definition; `bindActions()` separates structure from runtime behavior |
26
- | `Out` | Discriminated union for output specs: `and`, `xor`, `place`, `timeout`, `forward-input` |
27
- | `In` | Input arc specs with cardinality: `one`, `exactly`, `all`, `at-least` |
28
- | `Timing` | TPN firing intervals: `immediate`, `deadline`, `delayed`, `window`, `exact` |
29
- | `TransitionAction` | `(ctx: TransitionContext) => Promise<void>` — async action bound to a transition |
30
-
31
- ### Runtime (`src/runtime/`)
32
-
33
- Async single-threaded executor using bitmap-based enablement tracking.
34
-
35
- | Type | Description |
36
- |------|-------------|
37
- | `BitmapNetExecutor` | Main executor — dirty-set tracking, priority scheduling, deadline enforcement |
38
- | `CompiledNet` | Precomputed bitmap masks and reverse indices for O(W) enablement checks |
39
- | `Marking` | Mutable FIFO token state per place |
40
-
41
- Key performance features:
42
- - `Uint32Array` bitmaps for place marking and transition dirty sets
43
- - Kernighan's bit-trick for dirty set iteration
44
- - Pre-allocated buffers to reduce GC pressure
45
- - Precomputed reverse index (place → affected transitions)
46
-
47
- ### Event (`src/event/`)
9
+ See the [project README](https://github.com/debe/libpetri#why-a-petri-net) for the motivation and an order workflow using every arc type, concurrent actions, and timeout routing.
48
10
 
49
- Observable execution events as a discriminated union (`NetEvent`).
11
+ ## Install
50
12
 
51
- Event types: `execution-started`, `execution-completed`, `transition-enabled`, `transition-started`, `transition-completed`, `transition-failed`, `transition-timed-out`, `action-timed-out`, `token-added`, `token-removed`, `log-message`, `marking-snapshot`.
52
-
53
- `InMemoryEventStore` captures events; `noopEventStore()` is a zero-cost singleton for production.
54
-
55
- ### Export (`src/export/`)
56
-
57
- `dotExport(net, config)` generates DOT (Graphviz) diagram syntax with proper Petri net visual conventions, including arc types (inhibitor, read, reset), timing annotations, and priority labels.
58
-
59
- ### Verification (`src/verification/`)
60
-
61
- SMT-based formal verification using Z3. Encodes the Petri net as an integer linear program and checks reachability properties.
62
-
63
- Supported properties:
64
- - **Deadlock freedom** — no reachable state where all transitions are disabled
65
- - **Mutual exclusion** — two places never both hold tokens simultaneously
66
- - **Place bounds** — token count in a place never exceeds a limit
67
- - **Unreachability** — a marking is never reachable
68
-
69
- Also computes **P-invariants** (Farkas variant) and supports IC3/PDR-style incremental verification.
70
-
71
- ### ν-nets (`src/runtime/`)
13
+ ```bash
14
+ npm install libpetri
15
+ ```
72
16
 
73
- Correlated fork/join by identity. A `MatchSpec` declares a `value → NameId` key projection over a transition's input places; a fork mints a fresh opaque name via `ctx.freshName()` into the token payload, and a join consumes only the sibling tokens that project to the same name. The deterministic `(oldest-timestamp, then name)` tie-break is byte-identical across implementations (NU-022), and an incremental matcher keeps correlated-join drain at O(N log N). A bounded `Budget` place is the decidability lever for verification.
17
+ libpetri is ESM-only. The core runtime has no browser-only assumption; optional viewer and documentation entry points declare their own peer dependencies.
74
18
 
75
- ## Quick Start
19
+ ## Quick start
76
20
 
77
21
  ```typescript
78
- import { place, PetriNet, Transition, one, outPlace, tokenOf, BitmapNetExecutor } from 'libpetri';
22
+ import {
23
+ BitmapNetExecutor, PetriNet, Transition,
24
+ one, outPlace, place, tokenOf,
25
+ } from 'libpetri';
79
26
 
80
- // Define places
81
27
  const input = place<string>('input');
82
28
  const output = place<string>('output');
83
29
 
84
- // Define transition
85
- const process = Transition.builder('process')
30
+ const uppercase = Transition.builder('uppercase')
86
31
  .inputs(one(input))
87
32
  .outputs(outPlace(output))
88
33
  .action(async (ctx) => {
89
- const value = ctx.input(input);
90
- ctx.output(output, value.toUpperCase());
34
+ ctx.output(output, ctx.input(input).toUpperCase());
91
35
  })
92
36
  .build();
93
37
 
94
- // Build net
95
- const net = PetriNet.builder('Example').transition(process).build();
96
-
97
- // Execute
38
+ const net = PetriNet.builder('example').transition(uppercase).build();
98
39
  const executor = new BitmapNetExecutor(
99
40
  net,
100
41
  new Map([[input, [tokenOf('hello')]]]),
101
42
  );
102
- const marking = await executor.run();
103
- console.log(marking.peekTokens(output)); // [Token { value: 'HELLO' }]
43
+
44
+ const result = await executor.run();
45
+ console.log(result.peekFirst(output)?.value); // HELLO
104
46
  ```
105
47
 
106
- ## Modular composition
48
+ ## Execution and concurrency
49
+
50
+ `BitmapNetExecutor` is the reference implementation. `PrecompiledNetExecutor` compiles the same net into flat arrays, opcode streams, and priority-partitioned ready queues for production hot paths.
51
+
52
+ The orchestrator owns the marking and invokes ready actions without awaiting earlier actions first. Promise continuations therefore overlap naturally, while marking updates remain serialized. CPU-heavy synchronous code still blocks the JavaScript event loop; move it to a worker or external service.
53
+
54
+ Use places and transitions for coordination rather than hiding concurrency inside `Promise.all`: the net can then visualize, trace, replay, and verify the fan-out and join.
107
55
 
108
- Build large nets by reusing open-net fragments. A `SubnetDef` is a structurally
109
- complete `PetriNet` plus a typed `Interface` of **ports** (typed places) and
110
- **channels** (transitions). Instantiating renames every internal element with a
111
- `prefix/name`; composing into a host substitutes port places and merges
112
- channel transitions.
56
+ ## Package entry points
57
+
58
+ | Import | Purpose |
59
+ |---|---|
60
+ | `libpetri` | Core model, runtime, events, and composition |
61
+ | `libpetri/export` | DOT mapping and rendering |
62
+ | `libpetri/verification` | Structural analysis, state classes, and Z3-backed SMT verification |
63
+ | `libpetri/debug` | Debug protocol and session archives |
64
+ | `libpetri/viewer` | Interactive DOT/SVG viewer, the canonical renderer |
65
+ | `libpetri/render-dom` | Thin compatibility wrapper over `libpetri/viewer` |
66
+ | `libpetri/doclet` | TypeDoc integration |
67
+
68
+ The model supports input, output, read, inhibitor, and reset arcs; immediate, deadline, delayed, window, and exact timing; AND/XOR/timeout routing; environment places; reusable subnets; place fusion; and ν-net identity correlation.
69
+
70
+ ## Visualization
71
+
72
+ `libpetri/viewer` is the canonical renderer. It lays nodes out with ELK, routes edges orthogonally, and draws the result through Graphviz `nop2`, then adds pan/zoom, cluster collapse, subnet toggling, and filtering. Every first-party surface uses it: the debug UI, the TypeDoc plugin here, the Java javadoc taglet, and the Rust docgen all embed the same bundle, so a net looks the same whichever port documented it.
113
73
 
114
74
  ```typescript
115
- import { PetriNet, SubnetDef, FusionSet, place } from 'libpetri';
116
-
117
- const items = place<string>('items');
118
- const slots = place<string>('slots');
119
- const put = place<string>('put');
120
- const get = place<string>('get');
121
-
122
- const buffer = SubnetDef.builder<void>('Buffer')
123
- .place(items).place(slots)
124
- .transition(enqueue).transition(dequeue)
125
- .inputPort('put', put)
126
- .outputPort('get', get)
127
- .build();
75
+ import { dotExport } from 'libpetri/export';
76
+ import { mount } from 'libpetri/viewer';
128
77
 
129
- const b1 = buffer.instantiate('b1').bindActions({ enqueue: enqueueImpl, dequeue: fork() });
130
- const b2 = buffer.instantiate('b2').bindActions({ enqueue: enqueueImpl, dequeue: fork() });
78
+ const handle = await mount(dotExport(net), document.getElementById('diagram')!, {
79
+ chrome: true,
80
+ });
81
+ handle.fit();
82
+ ```
131
83
 
132
- const producerToB1 = place<string>('p1_to_b1');
133
- const b1ToB2 = place<string>('b1_to_b2');
134
- const b2ToConsumer = place<string>('b2_to_c');
84
+ The viewer is browser-only and declares `@viz-js/viz`, `panzoom`, and `elkjs` as optional peer dependencies, so a headless runtime install does not pull in a rendering stack. Install all three wherever you mount it:
135
85
 
136
- const net = PetriNet.builder('Pipeline')
137
- .compose(b1, (bind) =>
138
- bind.bindPort('put', producerToB1).bindPort('get', b1ToB2))
139
- .compose(b2, (bind) =>
140
- bind.bindPort('put', b1ToB2).bindPort('get', b2ToConsumer))
141
- .fuse(FusionSet.of('sharedSlots', b1.port<string>('slots'), b2.port<string>('slots')))
142
- .build();
86
+ ```bash
87
+ npm install @viz-js/viz panzoom elkjs
143
88
  ```
144
89
 
145
- Composition produces a flat `PetriNet`. Ports merge places by structural
146
- rewrite; channels (`bindChannel`) merge transitions with arc union, timing
147
- intersection, and caller-wins identity. `FusionSet` declares N-ary place
148
- equivalence applied **after** all `compose(...)` calls, regardless of
149
- registration order. Per-instance action overrides are supplied via
150
- `Instance.bindActions({ originalName: action })`. See
151
- [`spec/11-modular-composition.md`](../spec/11-modular-composition.md).
90
+ Without `elkjs` the default layout throws and names the missing peer; `mount(dot, el, { layout: 'graphviz' })` falls back to stock Graphviz layout, which is the one supported way to render without it.
152
91
 
153
- ## Verification Example
92
+ Not every path through the package produces the same picture:
154
93
 
155
- ```typescript
156
- import { SmtVerifier, deadlockFree } from 'libpetri/verification';
94
+ | Path | Layout | Edges |
95
+ |---|---|---|
96
+ | `mount()` from `libpetri/viewer` | ELK placement, ELK routes via `nop2` | orthogonal |
97
+ | `renderDotToContainer()` from `libpetri/render-dom` | delegates to `mount()` | orthogonal |
98
+ | the TypeDoc plugin | embeds the viewer, mounts client-side | orthogonal |
99
+ | `dotToSvg()` from `libpetri/doclet` | stock Graphviz `dot` | diagonal splines |
100
+ | `dotExport()` piped to your own `dot -Tsvg` | stock Graphviz `dot` | diagonal splines |
101
+
102
+ If a diagram renders with diagonal edges where you expected right angles, it went through one of the bottom two rows, or through a viewer bundle older than 2.10.5. Generated doc pages record which one drew them in `data-libpetri-viewer` on the diagram container.
157
103
 
158
- const result = await SmtVerifier.forNet(net)
159
- .initialMarking(m => m.tokens(input, 1))
160
- .property(deadlockFree())
161
- .verify();
104
+ ### TypeDoc plugin
162
105
 
163
- console.log(result.verdict); // { type: 'proven', method: 'structural' }
106
+ Register the plugin and declare the block tag it reads:
107
+
108
+ ```json
109
+ {
110
+ "plugin": ["libpetri/doclet"],
111
+ "blockTags": ["@petrinet"]
112
+ }
164
113
  ```
165
114
 
166
- ## Build & Test
115
+ An `@petrinet` tag on a symbol that builds or exposes a net renders that net as a diagram in the generated page, with the DOT source in a collapsible block underneath. The viewer bundle is inlined into the HTML, so the output is self-contained and works offline with no `dot` binary and no network access.
116
+
117
+ ## Build and test
167
118
 
168
119
  ```bash
169
- npm run build # Build with tsup
170
- npm run check # Type-check with tsc --noEmit
171
- npm test # Run tests with vitest
120
+ npm install
121
+ npm run build
122
+ npm run check
123
+ npm test
172
124
  ```
125
+
126
+ ## Project links
127
+
128
+ - [Language-agnostic specification](https://github.com/debe/libpetri/blob/main/spec/00-index.md)
129
+ - [Lean soundness and backend-refinement proofs](https://github.com/debe/libpetri/blob/main/lean/README.md)
130
+ - [Changelog](https://github.com/debe/libpetri/blob/main/CHANGELOG.md)
131
+ - [Apache License 2.0](https://github.com/debe/libpetri/blob/main/LICENSE)