# Architecture of wasm4pm
Design, structure, and internals of the wasm4pm module.
## Overview
wasm4pm is a self-contained Rust crate compiled to WebAssembly. It implements all process mining algorithms natively — there is no dependency on an external Rust library. JavaScript receives opaque string handles; all data lives in WASM linear memory.
## Architecture Diagram
```
┌─────────────────────────────────────┐
│ JavaScript/TypeScript Application │
│ (Browser or Node.js) │
└──────────────┬──────────────────────┘
│
│ JavaScript API (handles + JSON strings)
│
┌──────────────▼──────────────────────┐
│ wasm4pm.js (WASM glue code) │
│ Auto-generated by wasm-bindgen │
└──────────────┬──────────────────────┘
│
│ wasm-bindgen (type marshalling)
│
┌──────────────▼──────────────────────┐
│ wasm4pm_bg.wasm │
│ (WebAssembly binary, ~2MB) │
└──────────────┬──────────────────────┘
│
│ Rust internals
│
┌──────────────▼──────────────────────┐
│ wasm4pm Rust Core │
│ src/{discovery, conformance, ...} │
└─────────────────────────────────────┘
```
## Source Modules
| `lib.rs` | Module registrations, `init()`, `get_version()` |
| `models.rs` | Data structures: `EventLog`, `Trace`, `Event`, `DFG`, `PetriNet`, `DeclareModel`, `StreamingDfgBuilder`, `ColumnarLog` |
| `state.rs` | `AppState` — global handle store, `with_object` / `with_object_mut` |
| `io.rs` | Load/export: XES, JSON, OCEL |
| `xes_format.rs` | XES XML parser (SIMD-accelerated byte scan) |
| `discovery.rs` | DFG, DECLARE (columnar single-pass) |
| `advanced_algorithms.rs` | Heuristic Miner, Inductive Miner, rework/bottleneck detection |
| `ilp_discovery.rs` | ILP Petri net, Optimized DFG |
| `genetic_discovery.rs` | Genetic Algorithm, PSO |
| `fast_discovery.rs` | A\*, Hill Climbing, variants, patterns, drift, clustering |
| `more_discovery.rs` | ACO, Simulated Annealing, Process Skeleton |
| `streaming.rs` | Streaming DFG builder for IoT/chunked ingestion |
| `conformance.rs` | Token-based replay |
| `analysis.rs` | Statistics, activities, case duration |
| `final_analytics.rs` | Variant entropy, transition matrix, trace similarity |
| `utilities.rs` | Shared helpers |
| `types.rs` | Type aliases |
## Memory Management
### Handle-Based Architecture
```
JavaScript WASM Runtime (AppState)
┌──────────────────┐ ┌────────────────────────┐
│ "obj_0" (string) │───────→│ EventLog │
│ "obj_1" (string) │───────→│ DirectlyFollowsGraph │
│ "obj_2" (string) │───────→│ PetriNet │
│ "obj_3" (string) │───────→│ StreamingDfgBuilder │
└──────────────────┘ └────────────────────────┘
```
Handles are opaque string IDs. Objects live in Rust-managed heap memory until `delete_object(handle)` is called.
### Memory Lifecycle
```
1. Load / create
load_eventlog_from_xes(content) → "obj_0"
2. Compute (zero-copy via with_object)
discover_dfg("obj_0", "concept:name") → JSON string
3. Cleanup
delete_object("obj_0")
```
### Streaming Memory Model
The `StreamingDfgBuilder` stores only running count tables plus per-case buffers for open (in-progress) traces. Once `streaming_dfg_close_trace` is called, the trace buffer is freed and its data exists only in the O(A²) count tables. This keeps memory independent of total event count.
```
Memory ≈ A² × 16 bytes (edge counts)
+ open_traces × avg_trace_len × 4 bytes (u32 buffers)
```
Where A = number of unique activities.
## Columnar Event Log
`EventLog::to_columnar(activity_key)` builds a zero-copy view:
```rust
pub struct ColumnarLog<'a> {
pub events: Vec<u32>, // flat array of activity ids
pub trace_offsets: Vec<usize>, // boundary sentinel per trace
pub vocab: Vec<&'a str>, // borrowed activity names
}
```
Integer-keyed `FxHashMap<(u32,u32), usize>` edge counting is ~6× more memory-efficient than `HashMap<(String,String), usize>` and hashes in O(1) vs O(len).
## Build System
Three WASM targets via `wasm-pack`:
| Bundler (default) | `npm run build` | Webpack, Vite, Rollup |
| Node.js | `npm run build:nodejs` | Server, CLI |
| Web | `npm run build:web` | Direct `<script>` tag |
Release profile: `opt-level = 3`, `lto = true`, `codegen-units = 1` — generates the smallest, fastest binary.
## Performance Characteristics
| DFG | O(E) | Single columnar scan |
| Hill Climbing | O(iter × E) | Marginal-gain rewrite (was O(iter × A × E)) |
| DECLARE | O(T × E × A) | Flat-array single pass |
| Heuristic Miner | O(E) | Columnar follows/precedes |
| Genetic Algorithm | O(G × P × E) | G=generations, P=population |
## API Contract
All `#[wasm_bindgen]` functions follow one of two shapes:
**Query** — returns JSON, no side effects:
```rust
pub fn discover_dfg(handle: &str, activity_key: &str) -> Result<String, JsValue>
```
**Mutating** — returns handle or stats JSON, stores result in `AppState`:
```rust
pub fn discover_heuristic_miner(handle: &str, ...) -> Result<String, JsValue>
// returns: {"handle": "obj_N", "nodes": N, "edges": N, ...}
```
**Streaming** — mutates `StreamingDfgBuilder` via `with_object_mut`:
```rust
pub fn streaming_dfg_add_event(handle: &str, case_id: &str, activity: &str) -> Result<String, JsValue>
// returns: {"ok": true, "event_count": N, "open_traces": N, ...}
```
## Compatibility Matrix
| Chrome 57+ | Yes |
| Firefox 52+ | Yes |
| Safari 11+ | Yes |
| Edge 79+ | Yes |
| Node.js 16+ | Yes (18+ recommended) |
## Security
- All inputs validated in Rust before use
- WASM sandbox prevents arbitrary code execution
- No filesystem or network access from WASM
- Handle system prevents use-after-free at the JavaScript boundary